cluster/isabelle/Zen.thy (2,866 lines of code) (raw):
section \<open>Safety Properties\<close>
text \<open>This section describes the invariants that hold in the system, shows that the implementation
preserves the invariants, and shows that the invariants imply the required safety properties.\<close>
theory Zen
imports Implementation OneSlot
begin
subsection \<open>Invariants on messages\<close>
text \<open>Firstly, a set of invariants that hold on the set of messages that
have ever been sent, without considering the state of any individual
node.\<close>
fun nat_inductive_def :: "'a \<Rightarrow> (nat \<Rightarrow> 'a \<Rightarrow> 'a) \<Rightarrow> nat \<Rightarrow> 'a"
where
"nat_inductive_def zeroCase sucCase 0 = zeroCase"
| "nat_inductive_def zeroCase sucCase (Suc i) = sucCase i (nat_inductive_def zeroCase sucCase i)"
locale zenMessages =
fixes messages :: "RoutedMessage set"
fixes isMessageFromTo :: "Node \<Rightarrow> Message \<Rightarrow> Destination \<Rightarrow> bool" ("(_) \<midarrow>\<langle> _ \<rangle>\<rightarrow> (_)" [1000,55,1000])
defines "s \<midarrow>\<langle> m \<rangle>\<rightarrow> d \<equiv> \<lparr> sender = s, destination = d, payload = m \<rparr> \<in> messages"
fixes isMessageFrom :: "Node \<Rightarrow> Message \<Rightarrow> bool" ("(_) \<midarrow>\<langle> _ \<rangle>\<leadsto>" [1000,55])
defines "s \<midarrow>\<langle> m \<rangle>\<leadsto> \<equiv> \<exists> d. s \<midarrow>\<langle> m \<rangle>\<rightarrow> d"
fixes isMessageTo :: "Message \<Rightarrow> Destination \<Rightarrow> bool" ("\<langle> _ \<rangle>\<rightarrow> (_)" [55,1000])
defines "\<langle> m \<rangle>\<rightarrow> d \<equiv> \<exists> s. s \<midarrow>\<langle> m \<rangle>\<rightarrow> d"
fixes isMessage :: "Message \<Rightarrow> bool" ("\<langle> _ \<rangle>\<leadsto>" [55])
defines "\<langle> m \<rangle>\<leadsto> \<equiv> \<exists> s. s \<midarrow>\<langle> m \<rangle>\<leadsto>"
(* value proposed in a slot & a term *)
fixes v :: "Slot \<Rightarrow> Term \<Rightarrow> Value"
defines "v i t \<equiv> THE x. \<langle> PublishRequest i t x \<rangle>\<leadsto>"
(* whether a slot is committed *)
fixes isCommitted :: "Slot \<Rightarrow> bool"
defines "isCommitted i \<equiv> \<exists> t. \<langle> ApplyCommit i t \<rangle>\<leadsto>"
(* whether all preceding slots are committed *)
fixes committedTo :: "Slot \<Rightarrow> bool" ("committed\<^sub><")
defines "committed\<^sub>< i \<equiv> \<forall> j < i. isCommitted j"
(* the committed value in a slot *)
fixes v\<^sub>c :: "Slot \<Rightarrow> Value"
defines "v\<^sub>c i \<equiv> v i (SOME t. \<langle> ApplyCommit i t \<rangle>\<leadsto>)"
(* the configuration of a slot *)
fixes V :: "Slot \<Rightarrow> Node set"
defines "V \<equiv> nat_inductive_def V\<^sub>0 (\<lambda>i Vi. if isReconfiguration (v\<^sub>c i) then getConf (v\<^sub>c i) else Vi)"
(* predicate to say whether an applicable Vote has been sent *)
fixes promised :: "Slot \<Rightarrow> Node \<Rightarrow> Node \<Rightarrow> Term \<Rightarrow> bool"
defines "promised i s dn t \<equiv> \<exists> i' \<le> i. \<exists> a. s \<midarrow>\<langle> Vote i' t a \<rangle>\<rightarrow> (OneNode dn)"
(* set of previously-accepted terms *)
fixes prevAccepted :: "Slot \<Rightarrow> Term \<Rightarrow> Node set \<Rightarrow> Term set"
defines "prevAccepted i t senders
\<equiv> {t'. \<exists> s \<in> senders. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> }"
fixes lastCommittedClusterStateBefore :: "Slot \<Rightarrow> ClusterState"
defines "lastCommittedClusterStateBefore \<equiv> nat_inductive_def CS\<^sub>0
(\<lambda>i CSi. case v\<^sub>c i of ClusterStateDiff diff \<Rightarrow> diff CSi | _ \<Rightarrow> CSi)"
(* ASSUMPTIONS *)
assumes Vote_future:
"\<And>i i' s t t' a.
\<lbrakk> s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>; i < i'; t' < t \<rbrakk>
\<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>"
assumes Vote_None:
"\<And>i s t t'.
\<lbrakk> s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto>; t' < t \<rbrakk>
\<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>"
assumes Vote_Some_lt:
"\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>
\<Longrightarrow> t' < t"
assumes Vote_Some_PublishResponse:
"\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>
\<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>"
assumes Vote_Some_max:
"\<And>i s t t' t''. \<lbrakk> s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>; t' < t''; t'' < t \<rbrakk>
\<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>"
assumes Vote_not_broadcast:
"\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast"
assumes Vote_unique_destination:
"\<And>i s t a a' d d'. \<lbrakk> s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d; s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<rbrakk>
\<Longrightarrow> d = d'"
assumes PublishRequest_committedTo:
"\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committedTo i"
assumes PublishRequest_quorum:
"\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>
\<Longrightarrow> \<exists> q \<in> majorities (V i). (\<forall> n \<in> q. promised i n s t) \<and>
(prevAccepted i t q = {}
\<or> (\<exists> t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t'
\<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))"
assumes PublishRequest_function:
"\<And>i t x x'. \<lbrakk> \<langle> PublishRequest i t x \<rangle>\<leadsto>; \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<rbrakk>
\<Longrightarrow> x = x'"
assumes finite_messages:
"finite messages"
assumes PublishResponse_PublishRequest:
"\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists> x. \<langle> PublishRequest i t x \<rangle>\<leadsto>"
assumes ApplyCommit_quorum:
"\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto>
\<Longrightarrow> \<exists> q \<in> majorities (V i). \<forall> s \<in> q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
assumes CatchUpResponse_committedTo:
"\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i"
assumes CatchUpResponse_V:
"\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf"
assumes CatchUpResponse_lastCommittedClusterStateBefore:
"\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs"
definition (in zenMessages) votedFor :: "Node \<Rightarrow> Node \<Rightarrow> Term \<Rightarrow> bool"
where "votedFor n\<^sub>1 n\<^sub>2 t \<equiv> \<exists> i. promised i n\<^sub>1 n\<^sub>2 t"
lemma (in zenMessages) votedFor_unique:
assumes "votedFor n n\<^sub>1 t"
assumes "votedFor n n\<^sub>2 t"
shows "n\<^sub>1 = n\<^sub>2"
using assms unfolding votedFor_def by (meson Destination.inject Vote_unique_destination promised_def)
lemma (in zenMessages) V_simps[simp]:
"V 0 = V\<^sub>0"
"V (Suc i) = (if isReconfiguration (v\<^sub>c i) then getConf (v\<^sub>c i) else V i)"
unfolding V_def by simp_all
lemma (in zenMessages) lastCommittedClusterStateBefore_simps[simp]:
"lastCommittedClusterStateBefore 0 = CS\<^sub>0"
"lastCommittedClusterStateBefore (Suc i) = (case v\<^sub>c i of ClusterStateDiff diff \<Rightarrow> diff | _ \<Rightarrow> id) (lastCommittedClusterStateBefore i)"
unfolding lastCommittedClusterStateBefore_def by (simp, cases "v\<^sub>c i", auto)
declare [[goals_limit = 40]]
subsubsection \<open>Utility lemmas\<close>
text \<open>Some results that are useful later:\<close>
lemma (in zenMessages) V_finite: "finite (V i)"
by (induct i, simp_all add: finite_V\<^sub>0 getConf_finite)
lemma (in zenMessages) V_intersects: "majorities (V i) \<frown> majorities (V i)"
using V_finite majorities_intersect by simp
lemma (in zenMessages) ApplyCommit_PublishResponse:
assumes "\<langle> ApplyCommit i t \<rangle>\<leadsto>"
obtains s where "s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
by (meson ApplyCommit_quorum majorities_member assms)
lemma (in zenMessages) ApplyCommit_PublishRequest:
assumes "\<langle> ApplyCommit i t \<rangle>\<leadsto>"
shows "\<langle> PublishRequest i t (v i t) \<rangle>\<leadsto>"
by (metis ApplyCommit_PublishResponse PublishResponse_PublishRequest assms the_equality v_def PublishRequest_function)
lemma (in zenMessages) PublishRequest_Vote:
assumes "s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>"
obtains i' n a where "i' \<le> i" "n \<midarrow>\<langle> Vote i' t a \<rangle>\<rightarrow> (OneNode s)"
by (meson PublishRequest_quorum majorities_member assms isMessage_def promised_def)
lemma (in zenMessages) finite_prevAccepted: "finite (prevAccepted i t ns)"
proof -
fix t\<^sub>0
define f :: "RoutedMessage \<Rightarrow> Term" where "f \<equiv> \<lambda> m. case payload m of Vote _ _ (SomeTerm t') \<Rightarrow> t' | _ \<Rightarrow> t\<^sub>0"
have "prevAccepted i t ns \<subseteq> f ` messages"
apply (simp add: prevAccepted_def f_def isMessageFrom_def isMessageFromTo_def, intro subsetI)
using image_iff by fastforce
with finite_messages show ?thesis using finite_surj by auto
qed
lemma (in zenMessages) promised_long_def: "\<exists>d. promised i s d t
\<equiv> (s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto>
\<or> (\<exists>i'<i. \<exists>a. s \<midarrow>\<langle> Vote i' t a \<rangle>\<leadsto>))
\<or> (\<exists>t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>)"
(is "?LHS == ?RHS")
proof -
have "?LHS = ?RHS"
apply (intro iffI)
apply (metis TermOption.exhaust isMessageFrom_def nat_less_le promised_def)
by (metis Destination.exhaust Vote_not_broadcast isMessageFrom_def isMessageTo_def nat_less_le not_le promised_def)
thus "?LHS == ?RHS" by simp
qed
lemma (in zenMessages) Vote_value_function:
assumes "s \<midarrow>\<langle> Vote i t a\<^sub>1 \<rangle>\<leadsto>" and "s \<midarrow>\<langle> Vote i t a\<^sub>2 \<rangle>\<leadsto>"
shows "a\<^sub>1 = a\<^sub>2"
proof (cases a\<^sub>1)
case NO_TERM
with assms show ?thesis
by (metis TermOption.exhaust Vote_None Vote_Some_PublishResponse Vote_Some_lt)
next
case (SomeTerm t\<^sub>1)
with assms obtain t\<^sub>2 where a\<^sub>2: "a\<^sub>2 = SomeTerm t\<^sub>2"
using Vote_None Vote_Some_PublishResponse Vote_Some_lt TermOption.exhaust by metis
from SomeTerm a\<^sub>2 assms show ?thesis
by (metis Vote_Some_PublishResponse Vote_Some_lt less_linear Vote_Some_max)
qed
lemma (in zenMessages) shows finite_messages_insert: "finite (insert m messages)"
using finite_messages by auto
lemma (in zenMessages) isCommitted_committedTo:
assumes "isCommitted i"
shows "committed\<^sub>< i"
using ApplyCommit_PublishRequest PublishRequest_committedTo assms isCommitted_def by blast
lemma (in zenMessages) isCommitted_committedTo_Suc:
assumes "isCommitted i"
shows "committed\<^sub>< (Suc i)"
using assms committedTo_def isCommitted_committedTo less_antisym by blast
lemma (in zenMessages) promised_unique:
assumes "promised i s d t" and "promised i' s d' t"
shows "d = d'"
by (meson Destination.inject Vote_unique_destination assms promised_def)
lemma (in zenMessages) PublishResponse_PublishRequest_v:
assumes "\<langle> PublishResponse i t \<rangle>\<leadsto>"
shows "\<langle> PublishRequest i t (v i t) \<rangle>\<leadsto>"
proof -
from assms obtain s where "s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" unfolding isMessage_def by blast
with PublishResponse_PublishRequest
obtain x where x: "\<langle> PublishRequest i t x \<rangle>\<leadsto>" by blast
have "v i t = x" unfolding v_def using x by (intro the_equality PublishRequest_function)
with x show ?thesis by simp
qed
lemma (in zenMessages) Vote_PublishRequest_v:
assumes "\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>"
shows "\<langle> PublishRequest i t' (v i t') \<rangle>\<leadsto>"
using assms Vote_Some_PublishResponse PublishResponse_PublishRequest_v
unfolding isMessage_def by metis
subsubsection \<open>Relationship to @{term oneSlot}\<close>
text \<open>This shows that each slot @{term i} in Zen satisfies the assumptions of the @{term
oneSlot} model above.\<close>
lemma (in zenMessages) zen_is_oneSlot:
fixes i
shows "oneSlot (majorities (V i)) (v i)
(\<lambda> s t. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto>
\<or> (\<exists> i' < i. \<exists> a. s \<midarrow>\<langle> Vote i' t a \<rangle>\<leadsto>))
(\<lambda> s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>)
(\<lambda> t. \<exists> x. \<langle> PublishRequest i t x \<rangle>\<leadsto>)
(\<lambda> s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>)
(\<lambda> t. \<langle> ApplyCommit i t \<rangle>\<leadsto>)"
proof (unfold_locales, fold prevAccepted_def promised_long_def)
from V_intersects show "majorities (V i) \<frown> majorities (V i)".
next
fix s t t'
assume "t' < t" "s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<or> (\<exists>i'<i. \<exists>a. s \<midarrow>\<langle> Vote i' t a \<rangle>\<leadsto>)"
thus "\<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>"
using Vote_None Vote_future by auto
next
fix s t t'
assume j: "s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>"
from j show "t' < t" using Vote_Some_lt by blast
from j show "s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>" using Vote_Some_PublishResponse by blast
fix t'' assume "t' < t''" "t'' < t"
with j show "\<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>" using Vote_Some_max by blast
next
fix t
assume "\<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>"
then obtain x s where "s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>" by (auto simp add: isMessage_def)
from PublishRequest_quorum [OF this] PublishResponse_PublishRequest
show "\<exists>q \<in> majorities (V i). (\<forall>n\<in>q. \<exists>d. promised i n d t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> (\<exists>x. \<langle> PublishRequest i t' x \<rangle>\<leadsto>) \<and> t' < t))"
unfolding isMessageFrom_def by (meson PublishResponse_PublishRequest_v)
next
fix s t assume "s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
thus "\<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>"
by (simp add: PublishResponse_PublishRequest)
next
fix t assume "\<langle> ApplyCommit i t \<rangle>\<leadsto>"
thus "\<exists>q \<in> majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
by (simp add: ApplyCommit_quorum)
next
fix t\<^sub>0
define f :: "RoutedMessage \<Rightarrow> Term"
where "f \<equiv> \<lambda> m. case payload m of PublishRequest i t x \<Rightarrow> t | _ \<Rightarrow> t\<^sub>0"
have "{t. \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>} \<subseteq> f ` messages"
apply (unfold isMessage_def isMessageFrom_def isMessageFromTo_def)
using f_def image_iff by fastforce
moreover have "finite (f ` messages)"
by (simp add: finite_messages)
ultimately show "finite {t. \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>}"
using finite_subset by blast
qed
text \<open>From this it follows that all committed values are equal.\<close>
theorem (in zenMessages) consistent:
assumes "\<langle> ApplyCommit i t\<^sub>1 \<rangle>\<leadsto>"
assumes "\<langle> ApplyCommit i t\<^sub>2 \<rangle>\<leadsto>"
assumes "\<langle> PublishRequest i t\<^sub>1 v\<^sub>1 \<rangle>\<leadsto>"
assumes "\<langle> PublishRequest i t\<^sub>2 v\<^sub>2 \<rangle>\<leadsto>"
shows "v\<^sub>1 = v\<^sub>2"
proof -
from oneSlot.consistent [OF zen_is_oneSlot] assms
have "v i t\<^sub>1 = v i t\<^sub>2" by blast
moreover have "v\<^sub>1 = v i t\<^sub>1" using ApplyCommit_PublishRequest assms PublishRequest_function by blast
moreover have "v\<^sub>2 = v i t\<^sub>2" using ApplyCommit_PublishRequest assms PublishRequest_function by blast
ultimately show ?thesis by simp
qed
lemma (in zenMessages) ApplyCommit_v\<^sub>c:
assumes "\<langle> ApplyCommit i t \<rangle>\<leadsto>"
shows "v\<^sub>c i = v i t"
proof (unfold v\<^sub>c_def, intro someI2 [where Q = "\<lambda>t'. v i t' = v i t"])
from assms show "\<langle> ApplyCommit i t \<rangle>\<leadsto>" .
fix t' assume "\<langle> ApplyCommit i t' \<rangle>\<leadsto>"
thus "v i t' = v i t" by (intro oneSlot.consistent [OF zen_is_oneSlot] assms)
qed
lemma (in zenMessages) ApplyCommit_PublishRequest_v\<^sub>c:
assumes "\<langle> ApplyCommit i t \<rangle>\<leadsto>"
shows "\<langle> PublishRequest i t (v\<^sub>c i) \<rangle>\<leadsto>"
unfolding ApplyCommit_v\<^sub>c [OF assms]
using ApplyCommit_PublishRequest assms .
subsection \<open>Invariants on node states\<close>
text \<open>A set of invariants which relate the states of the individual nodes to the set of messages sent.\<close>
locale zen = zenMessages +
fixes nodeState :: "Node \<Rightarrow> NodeData"
assumes currentNode_nodeState: "\<And>n. currentNode (nodeState n) = n"
assumes committedTo_firstUncommittedSlot:
"\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))"
assumes currentVotingNodes_firstUncommittedSlot:
"\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))"
assumes firstUncommittedSlot_PublishRequest:
"\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>"
assumes firstUncommittedSlot_PublishResponse:
"\<And>i n t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
assumes lastAcceptedTerm_None: "\<And>n t. lastAcceptedTerm (nodeState n) = NO_TERM
\<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>"
assumes lastAcceptedTerm_Some_sent: "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t
\<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>"
assumes lastAcceptedTerm_Some_max: "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t
\<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto>
\<Longrightarrow> t' \<le> t"
assumes lastAcceptedTerm_Some_currentTerm: "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t
\<Longrightarrow> t \<le> currentTerm (nodeState n)"
assumes lastAcceptedTerm_Some_value: "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t
\<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>"
assumes Vote_currentTerm:
"\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)"
assumes Vote_slot_function:
"\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'"
assumes PublishRequest_currentTerm:
"\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto>
\<Longrightarrow> t \<le> currentTerm (nodeState n)"
assumes PublishRequest_publishPermitted_currentTerm:
"\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto>
\<Longrightarrow> publishPermitted (nodeState n)
\<Longrightarrow> t < currentTerm (nodeState n)"
assumes joinVotes:
"\<And> n n'. n' \<in> joinVotes (nodeState n)
\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))"
assumes electionWon_isQuorum:
"\<And>n. electionWon (nodeState n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))"
assumes joinVotes_max: "\<And>n n' a'.
\<lbrakk> \<not> (\<exists> x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n))
(currentTerm (nodeState n)) x \<rangle>\<leadsto>);
n' \<in> joinVotes (nodeState n);
n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n))
(currentTerm (nodeState n))
a' \<rangle>\<rightarrow> (OneNode n) \<rbrakk>
\<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)"
assumes publishVotes: "\<And>n n'. n' \<in> publishVotes (nodeState n)
\<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n))
(currentTerm (nodeState n)) \<rangle>\<leadsto>"
assumes currentClusterState_lastCommittedClusterStateBefore:
"\<And>n. currentClusterState (nodeState n)
= lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))"
lemma (in zen) joinVotes_votedFor:
assumes "n' \<in> joinVotes (nodeState n)"
shows "votedFor n' n (currentTerm (nodeState n))"
using joinVotes assms unfolding votedFor_def by auto
locale zenStep = zen +
fixes messages' :: "RoutedMessage set"
fixes nodeState' :: "Node \<Rightarrow> NodeData"
fixes n\<^sub>0 :: Node
assumes messages_subset: "messages \<subseteq> messages'"
fixes nd :: NodeData
defines "nd \<equiv> nodeState n\<^sub>0"
fixes nd' :: NodeData
defines "nd' \<equiv> nodeState' n\<^sub>0"
assumes nodeState_unchanged: "\<And>n. n \<noteq> n\<^sub>0 \<Longrightarrow> nodeState' n = nodeState n"
(* updated definitions from zenMessages *)
fixes isMessageFromTo' :: "Node \<Rightarrow> Message \<Rightarrow> Destination \<Rightarrow> bool" ("(_) \<midarrow>\<langle> _ \<rangle>\<rightarrow>' (_)" [1000,55,1000])
defines "s \<midarrow>\<langle> m \<rangle>\<rightarrow>' d \<equiv> \<lparr> sender = s, destination = d, payload = m \<rparr> \<in> messages'"
fixes isMessageFrom' :: "Node \<Rightarrow> Message \<Rightarrow> bool" ("(_) \<midarrow>\<langle> _ \<rangle>\<leadsto>'" [1000,55])
defines "s \<midarrow>\<langle> m \<rangle>\<leadsto>' \<equiv> \<exists> d. s \<midarrow>\<langle> m \<rangle>\<rightarrow>' d"
fixes isMessageTo' :: "Message \<Rightarrow> Destination \<Rightarrow> bool" ("\<langle> _ \<rangle>\<rightarrow>' (_)" [55,1000])
defines "\<langle> m \<rangle>\<rightarrow>' d \<equiv> \<exists> s. s \<midarrow>\<langle> m \<rangle>\<rightarrow>' d"
fixes isMessage' :: "Message \<Rightarrow> bool" ("\<langle> _ \<rangle>\<leadsto>'" [55])
defines "\<langle> m \<rangle>\<leadsto>' \<equiv> \<exists> s. s \<midarrow>\<langle> m \<rangle>\<leadsto>'"
(* value proposed in a slot & a term *)
fixes v' :: "nat \<Rightarrow> Term \<Rightarrow> Value"
defines "v' i t \<equiv> THE x. \<langle> PublishRequest i t x \<rangle>\<leadsto>'"
(* whether a slot is committed *)
fixes isCommitted' :: "nat \<Rightarrow> bool"
defines "isCommitted' i \<equiv> \<exists> t. \<langle> ApplyCommit i t \<rangle>\<leadsto>'"
(* whether all preceding slots are committed *)
fixes committedTo' :: "nat \<Rightarrow> bool" ("committed\<^sub><'")
defines "committed\<^sub><' i \<equiv> \<forall> j < i. isCommitted' j"
(* the committed value in a slot *)
fixes v\<^sub>c' :: "nat \<Rightarrow> Value"
defines "v\<^sub>c' i \<equiv> v' i (SOME t. \<langle> ApplyCommit i t \<rangle>\<leadsto>')"
(* the configuration of a slot *)
fixes V' :: "Slot \<Rightarrow> Node set"
defines "V' \<equiv> nat_inductive_def V\<^sub>0 (\<lambda>i Vi. if isReconfiguration (v\<^sub>c' i) then getConf (v\<^sub>c' i) else Vi)"
(* predicate to say whether an applicable Vote has been sent *)
fixes promised' :: "nat \<Rightarrow> Node \<Rightarrow> Node \<Rightarrow> Term \<Rightarrow> bool"
defines "promised' i s dn t \<equiv> \<exists> i' \<le> i. \<exists> a. s \<midarrow>\<langle> Vote i' t a \<rangle>\<rightarrow>' (OneNode dn)"
(* set of previously-accepted terms *)
fixes prevAccepted' :: "nat \<Rightarrow> Term \<Rightarrow> Node set \<Rightarrow> Term set"
defines "prevAccepted' i t senders
\<equiv> {t'. \<exists> s \<in> senders. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>' }"
fixes lastCommittedClusterStateBefore' :: "nat \<Rightarrow> ClusterState"
defines "lastCommittedClusterStateBefore' \<equiv> nat_inductive_def CS\<^sub>0
(\<lambda>i CSi. case v\<^sub>c' i of ClusterStateDiff diff \<Rightarrow> diff CSi | _ \<Rightarrow> CSi)"
fixes sendTo :: "Destination \<Rightarrow> (NodeData * Message option) \<Rightarrow> RoutedMessage set"
defines "sendTo d result \<equiv> case snd result of
None \<Rightarrow> messages | Some m \<Rightarrow> insert \<lparr> sender = n\<^sub>0, destination = d, payload = m \<rparr> messages"
lemma (in zenStep) nodeState'_def: "nodeState' n \<equiv> if n = n\<^sub>0 then nd' else nodeState n"
using nodeState_unchanged nd'_def by presburger
lemma (in zenStep) V'_simps[simp]:
"V' 0 = V\<^sub>0"
"V' (Suc i) = (if isReconfiguration (v\<^sub>c' i) then getConf (v\<^sub>c' i) else V' i)"
unfolding V'_def by simp_all
lemma (in zenStep) lastCommittedClusterStateBefore'_simps[simp]:
"lastCommittedClusterStateBefore' 0 = CS\<^sub>0"
"lastCommittedClusterStateBefore' (Suc i) = (case v\<^sub>c' i of ClusterStateDiff diff \<Rightarrow> diff | _ \<Rightarrow> id) (lastCommittedClusterStateBefore' i)"
unfolding lastCommittedClusterStateBefore'_def by (simp, cases "v\<^sub>c' i", auto)
lemma (in zenStep) sendTo_simps[simp]:
"sendTo d (nd'', None) = messages"
"sendTo d (nd'', Some m) = insert \<lparr> sender = n\<^sub>0, destination = d, payload = m \<rparr> messages"
by (auto simp add: sendTo_def)
lemma currentTerm_ensureCurrentTerm[simp]: "currentTerm nd \<le> t \<Longrightarrow> currentTerm (ensureCurrentTerm t nd) = t"
by (auto simp add: ensureCurrentTerm_def)
lemma (in zenStep)
assumes "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>' \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>'"
assumes "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto>' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>'"
assumes "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>' \<Longrightarrow> t' < t"
assumes "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>' \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>'"
assumes "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>' \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>'"
assumes "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow>' d \<Longrightarrow> d \<noteq> Broadcast"
assumes "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow>' d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow>' d' \<Longrightarrow> d = d'"
assumes "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto>' \<Longrightarrow> committed\<^sub><' i"
assumes "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>' \<Longrightarrow> \<exists>q\<in>majorities (V' i). (\<forall>n\<in>q. promised' i n s t) \<and> (prevAccepted' i t q = {} \<or> (\<exists>t'. v' i t = v' i t' \<and> maxTerm (prevAccepted' i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto>' \<and> t' < t))"
assumes "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto>' \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto>' \<Longrightarrow> x = x'"
assumes "finite messages'"
assumes "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>' \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>'"
assumes "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto>' \<Longrightarrow> \<exists>q\<in>majorities (V' i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>'"
assumes "\<And>n. currentNode (nodeState' n) = n"
assumes "\<And>n. committed\<^sub><' (firstUncommittedSlot (nodeState' n))"
assumes "\<And>n. currentVotingNodes (nodeState' n) = V' (firstUncommittedSlot (nodeState' n))"
assumes "\<And>i n t x. firstUncommittedSlot (nodeState' n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>'"
assumes "\<And>i n t. firstUncommittedSlot (nodeState' n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>'"
assumes "\<And>n t. lastAcceptedTerm (nodeState' n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \<rangle>\<leadsto>'"
assumes "\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \<rangle>\<leadsto>'"
assumes "\<And>n t t'. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t' \<rangle>\<leadsto>' \<Longrightarrow> t' \<le> t"
assumes "\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t (lastAcceptedValue (nodeState' n)) \<rangle>\<leadsto>'"
assumes "\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState' n)"
assumes "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>' \<Longrightarrow> t \<le> currentTerm (nodeState' n)"
assumes "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>' \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto>' \<Longrightarrow> i = i'"
assumes "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \<rangle>\<leadsto>' \<Longrightarrow> t \<le> currentTerm (nodeState' n)"
assumes "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \<rangle>\<leadsto>' \<Longrightarrow> publishPermitted (nodeState' n) \<Longrightarrow> t < currentTerm (nodeState' n)"
assumes "\<And>n n'. n' \<in> joinVotes (nodeState' n) \<Longrightarrow> promised' (firstUncommittedSlot (nodeState' n)) n' n (currentTerm (nodeState' n))"
assumes "\<And>n. electionWon (nodeState' n) \<Longrightarrow> isQuorum (nodeState' n) (joinVotes (nodeState' n))"
assumes "\<And>n n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState' n)) x \<rangle>\<leadsto>') \<Longrightarrow> n' \<in> joinVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState' n)) a' \<rangle>\<rightarrow>' (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState' n)"
assumes "\<And>n n'. n' \<in> publishVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState' n)) \<rangle>\<leadsto>'"
assumes "\<And>n. currentClusterState (nodeState' n) = lastCommittedClusterStateBefore' (firstUncommittedSlot (nodeState' n))"
assumes "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>' \<Longrightarrow> committed\<^sub><' i"
assumes "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>' \<Longrightarrow> V' i = conf"
assumes "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>' \<Longrightarrow> lastCommittedClusterStateBefore' i = cs"
shows zenI: "zen messages' nodeState'"
apply (unfold_locales)
apply (fold isMessageFromTo'_def)
apply (fold isMessageTo'_def)
apply (fold isMessageFrom'_def)
apply (fold isMessage'_def)
apply (fold v'_def)
apply (fold isCommitted'_def)
apply (fold committedTo'_def)
apply (fold v\<^sub>c'_def)
apply (fold V'_def)
apply (fold promised'_def)
apply (fold prevAccepted'_def)
apply (fold lastCommittedClusterStateBefore'_def)
using assms proof - qed
lemma (in zenStep)
assumes "zen messages' nodeState'" "messages' \<subseteq> messages''" "\<And>n. n \<noteq> n\<^sub>0 \<Longrightarrow> nodeState' n = nodeState'' n"
shows zenStepI1: "zenStep messages' nodeState' messages'' nodeState'' n\<^sub>0"
proof (intro_locales)
from `zen messages' nodeState'`
show "zenMessages messages'" "zen_axioms messages' nodeState'"
unfolding zen_def by simp_all
from assms
show "zenStep_axioms messages' nodeState' messages'' nodeState'' n\<^sub>0"
by (intro zenStep_axioms.intro, auto)
qed
lemma (in zenStep)
assumes "messages \<subseteq> messages''" "\<And>n. n \<noteq> n\<^sub>0 \<Longrightarrow> nodeState n = nodeState'' n"
shows zenStepI2: "zenStep messages nodeState messages'' nodeState'' n\<^sub>0"
proof (intro_locales)
from assms
show "zenStep_axioms messages nodeState messages'' nodeState'' n\<^sub>0"
by (intro zenStep_axioms.intro, auto)
qed
lemma (in zenStep) Broadcast_to_OneNode:
fixes x
assumes nodeState': "nodeState' = nodeState"
assumes sent: "n\<^sub>0 \<midarrow>\<langle> m \<rangle>\<rightarrow> Broadcast"
assumes messages': "messages' = sendTo (OneNode d) (nd'', Some m)"
shows "zen messages' nodeState'"
proof -
have messages': "messages' = insert \<lparr>sender = n\<^sub>0, destination = OneNode d, payload = m \<rparr> messages"
by (simp add: messages')
from Vote_not_broadcast sent have not_Vote: "\<And>i t a. m \<noteq> Vote i t a"
unfolding isMessageTo_def by blast
from sent not_Vote have message_simps:
"\<And>s m'. (s \<midarrow>\<langle> m' \<rangle>\<leadsto>') = (s \<midarrow>\<langle> m' \<rangle>\<leadsto>)"
"\<And>m'. (\<langle> m' \<rangle>\<leadsto>') = (\<langle> m' \<rangle>\<leadsto>)"
"\<And>s d i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>d i t a. (\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (\<langle> Vote i t a \<rangle>\<rightarrow> d)"
by (auto simp add: isMessageFromTo'_def isMessageTo'_def isMessage'_def isMessageFrom'_def,
auto simp add: isMessageFromTo_def isMessageTo_def isMessage_def isMessageFrom_def messages')
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)"
"\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)"
"\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)"
"\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
"\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)"
"\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)"
by (unfold nodeState', auto)
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def message_simps)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def message_simps)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def message_simps)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def message_simps)
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def message_simps)
show ?thesis
apply (intro zenI)
apply (unfold message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t".
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))".
from joinVotes_max show " \<And>n n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)".
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from joinVotes show "\<And>n n'. n' \<in> joinVotes (nodeState n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>".
from PublishRequest_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from PublishRequest_publishPermitted_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState n) \<Longrightarrow> t < currentTerm (nodeState n)".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)".
qed
qed
lemma (in zenStep) send_spontaneous_message:
assumes messages': "messages' = sendTo d\<^sub>0 (nd, Some m)"
assumes spontaneous: "case m of StartJoin _ \<Rightarrow> True | ClientValue _ \<Rightarrow> True | Reboot \<Rightarrow> True | CatchUpRequest \<Rightarrow> True | _ \<Rightarrow> False"
assumes nodeState': "nodeState' = nodeState"
shows "zen messages' nodeState'"
proof -
have messages': "messages' = insert \<lparr>sender = n\<^sub>0, destination = d\<^sub>0, payload = m \<rparr> messages"
by (simp add: messages')
from spontaneous
have message_simps[simp]:
"\<And>s d i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>s d i t. (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<rightarrow> d)"
"\<And>s d i t x. (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<rightarrow> d)"
"\<And>s d i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)"
"\<And>d i t a. (\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>d i t. (\<langle> PublishResponse i t \<rangle>\<rightarrow>' d) = (\<langle> PublishResponse i t \<rangle>\<rightarrow> d)"
"\<And>d i t x. (\<langle> PublishRequest i t x \<rangle>\<rightarrow>' d) = (\<langle> PublishRequest i t x \<rangle>\<rightarrow> d)"
"\<And>d i t. (\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = (\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)"
"\<And>s i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>') = (s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>)"
"\<And>s i t. (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>') = (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>)"
"\<And>s i t x. (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>') = (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>)"
"\<And>s i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>') = (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>)"
"\<And>d i t a. (\<langle> Vote i t a \<rangle>\<leadsto>') = (\<langle> Vote i t a \<rangle>\<leadsto>)"
"\<And>d i t. (\<langle> PublishResponse i t \<rangle>\<leadsto>') = (\<langle> PublishResponse i t \<rangle>\<leadsto>)"
"\<And>d i t x. (\<langle> PublishRequest i t x \<rangle>\<leadsto>') = (\<langle> PublishRequest i t x \<rangle>\<leadsto>)"
"\<And>d i t. (\<langle> ApplyCommit i t \<rangle>\<leadsto>') = (\<langle> ApplyCommit i t \<rangle>\<leadsto>)"
"\<And>s d i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d)"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d)"
"\<And>s i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>)"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>)"
by (auto simp add: isMessageFromTo'_def isMessageTo'_def isMessage'_def isMessageFrom'_def,
auto simp add: isMessageFromTo_def isMessageTo_def isMessage_def isMessageFrom_def messages')
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)"
"\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)"
"\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)"
"\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
"\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)"
"\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)"
by (unfold nodeState', auto)
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def)
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)
show ?thesis
apply (intro zenI)
apply (unfold message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t".
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))".
from joinVotes_max show " \<And>n n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)".
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from joinVotes show "\<And>n n'. n' \<in> joinVotes (nodeState n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>".
from PublishRequest_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from PublishRequest_publishPermitted_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState n) \<Longrightarrow> t < currentTerm (nodeState n)".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)".
qed
qed
lemma (in zenStep) send_StartJoin:
assumes messages': "messages' = sendTo d\<^sub>0 (nd, Some (StartJoin t\<^sub>0))"
assumes nodeState': "nodeState' = nodeState"
shows "zen messages' nodeState'"
using assms by (intro send_spontaneous_message, auto)
lemma (in zenStep) send_ClientValue:
assumes messages': "messages' = sendTo d\<^sub>0 (nd, Some (ClientValue x\<^sub>0))"
assumes nodeState': "nodeState' = nodeState"
shows "zen messages' nodeState'"
using assms by (intro send_spontaneous_message, auto)
lemma (in zenStep) send_CatchUpRequest:
assumes messages': "messages' = sendTo d\<^sub>0 (nd, Some CatchUpRequest)"
assumes nodeState': "nodeState' = nodeState"
shows "zen messages' nodeState'"
using assms by (intro send_spontaneous_message, auto)
lemma (in zenStep) send_Reboot:
assumes messages': "messages' = sendTo d\<^sub>0 (nd, Some Reboot)"
assumes nodeState': "nodeState' = nodeState"
shows "zen messages' nodeState'"
using assms by (intro send_spontaneous_message, auto)
lemma (in zenStep) ensureCurrentTerm_invariants:
assumes nd': "nd' = ensureCurrentTerm t nd"
assumes messages': "messages' = messages"
shows "zen messages' nodeState'"
proof (cases "t \<le> currentTerm nd")
case True
hence "nodeState' = nodeState"
by (intro ext, unfold nodeState'_def, auto simp add: nd' ensureCurrentTerm_def nd_def)
with zen_axioms messages' show ?thesis by simp
next
case False hence t: "currentTerm nd < t" by simp
have message_simps[simp]:
"\<And>s p d. (s \<midarrow>\<langle> p \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> p \<rangle>\<rightarrow> d)"
"\<And>p d. (\<langle> p \<rangle>\<rightarrow>' d) = (\<langle> p \<rangle>\<rightarrow> d)"
"\<And>s p. (s \<midarrow>\<langle> p \<rangle>\<leadsto>') = (s \<midarrow>\<langle> p \<rangle>\<leadsto>)"
"\<And>p. (\<langle> p \<rangle>\<leadsto>') = (\<langle> p \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q"
"\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)"
"\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)"
"currentTerm (nodeState' n\<^sub>0) = t"
"electionWon (nodeState' n\<^sub>0) = False"
"joinVotes (nodeState' n\<^sub>0) = {}"
"publishPermitted (nodeState' n\<^sub>0) = True"
"publishVotes (nodeState' n\<^sub>0) = {}"
using t
by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' ensureCurrentTerm_def
lastAcceptedTerm_def lastAcceptedValue_def)
have currentTerm_increases: "\<And>n. currentTerm (nodeState n) \<le> currentTerm (nodeState' n)"
using nd_def nodeState'_def property_simps t by auto
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have promised_eq: "\<And>i n n' t. promised' i n n' t = promised i n n' t" by (simp add: promised_def promised'_def)
have prevAccepted_eq: "\<And>i t q. prevAccepted' i t q = prevAccepted i t q" by (simp add: prevAccepted_def prevAccepted'_def)
show ?thesis
apply (intro zenI)
apply (unfold message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
from Vote_currentTerm currentTerm_increases
show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState' n)"
using dual_order.trans by blast
from PublishRequest_publishPermitted_currentTerm currentTerm_increases property_simps
show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState' n) \<Longrightarrow> t < currentTerm (nodeState' n)"
by (metis False PublishRequest_currentTerm dual_order.trans leI nd_def nodeState_unchanged)
from joinVotes
show "\<And>n n'. n' \<in> joinVotes (nodeState' n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState' n))"
unfolding nodeState'_def by (auto simp add: nd'_def)
from PublishRequest_currentTerm currentTerm_increases
show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState' n)"
using dual_order.trans by blast
from publishVotes
show "\<And>n n'. n' \<in> publishVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState' n)) \<rangle>\<leadsto>"
unfolding nodeState'_def by (auto simp add: nd'_def)
from electionWon_isQuorum show "\<And>n. electionWon (nodeState' n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState' n))"
unfolding nodeState'_def by (auto simp add: nd'_def)
from lastAcceptedTerm_Some_currentTerm currentTerm_increases
show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState' n)"
using dual_order.trans by blast
show "\<And>n n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState' n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState' n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)"
by (metis ex_in_conv joinVotes_max nodeState_unchanged property_simps(10))
qed
qed
lemma (in zenStep) sendVote_invariants:
assumes messages': "messages' = sendTo (OneNode d\<^sub>0) (nd'',
Some (Vote (firstUncommittedSlot nd) (currentTerm nd) (lastAcceptedTerm nd)))"
assumes nd': "nd' = nd"
assumes not_sent: "\<And>i a. \<not> n\<^sub>0 \<midarrow>\<langle> Vote i (currentTerm nd) a \<rangle>\<leadsto>"
assumes not_accepted: "\<And>t'. lastAcceptedTerm nd = SomeTerm t' \<Longrightarrow> t' < currentTerm nd"
shows "zen messages' nodeState'"
proof -
have messages': "messages' = insert \<lparr>sender = n\<^sub>0, destination = OneNode d\<^sub>0,
payload = Vote (firstUncommittedSlot nd) (currentTerm nd) (lastAcceptedTerm nd)\<rparr> messages"
by (simp add: messages')
have nodeState'[simp]: "nodeState' = nodeState"
by (intro ext, auto simp add: nodeState'_def nd' nd_def)
have message_simps[simp]:
"\<And>s d i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)"
"\<And>s d i t x. (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<rightarrow> d)"
"\<And>s d i t. (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<rightarrow> d)"
"\<And>d i t. (\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = (\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)"
"\<And>d i t x. (\<langle> PublishRequest i t x \<rangle>\<rightarrow>' d) = (\<langle> PublishRequest i t x \<rangle>\<rightarrow> d)"
"\<And>d i t. (\<langle> PublishResponse i t \<rangle>\<rightarrow>' d) = (\<langle> PublishResponse i t \<rangle>\<rightarrow> d)"
"\<And>s i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>') = (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>)"
"\<And>s i t x. (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>') = (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>)"
"\<And>s i t. (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>') = (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>)"
"\<And>i t. (\<langle> ApplyCommit i t \<rangle>\<leadsto>') = (\<langle> ApplyCommit i t \<rangle>\<leadsto>)"
"\<And>i t x. (\<langle> PublishRequest i t x \<rangle>\<leadsto>') = (\<langle> PublishRequest i t x \<rangle>\<leadsto>)"
"\<And>i t. (\<langle> PublishResponse i t \<rangle>\<leadsto>') = (\<langle> PublishResponse i t \<rangle>\<leadsto>)"
"\<And>s d i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d)"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d)"
"\<And>s i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>)"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have Vote':
"\<And>s d i t' a. (s \<midarrow>\<langle> Vote i t' a \<rangle>\<rightarrow>' d) =
((s \<midarrow>\<langle> Vote i t' a \<rangle>\<rightarrow> d)
\<or> (s, i, t', a, d) = (n\<^sub>0, firstUncommittedSlot nd, currentTerm nd, lastAcceptedTerm nd, OneNode d\<^sub>0))"
"\<And>d i t' a. (\<langle> Vote i t' a \<rangle>\<rightarrow>' d) =
((\<langle> Vote i t' a \<rangle>\<rightarrow> d)
\<or> (i, t', a, d) = (firstUncommittedSlot nd, currentTerm nd, lastAcceptedTerm nd, OneNode d\<^sub>0))"
"\<And>s i t' a. (s \<midarrow>\<langle> Vote i t' a \<rangle>\<leadsto>') =
((s \<midarrow>\<langle> Vote i t' a \<rangle>\<leadsto>)
\<or> (s, i, t', a) = (n\<^sub>0, firstUncommittedSlot nd, currentTerm nd, lastAcceptedTerm nd))"
"\<And>i t' a. (\<langle> Vote i t' a \<rangle>\<leadsto>') =
((\<langle> Vote i t' a \<rangle>\<leadsto>)
\<or> (i, t', a) = (firstUncommittedSlot nd, currentTerm nd, lastAcceptedTerm nd))"
by (unfold isMessageFromTo'_def isMessageFromTo_def isMessageTo'_def isMessageTo_def
isMessageFrom'_def isMessageFrom_def isMessage'_def isMessage_def, auto simp add: messages')
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have promised_eq: "\<And>i s dn t. promised' i s dn t = (promised i s dn t \<or> (firstUncommittedSlot nd \<le> i \<and> s = n\<^sub>0 \<and> dn = d\<^sub>0 \<and> t = currentTerm nd))"
unfolding promised'_def promised_def Vote' by auto
have prevAccepted_eq: "\<And>i t q. prevAccepted' i t q = prevAccepted i t q \<union> {t'. n\<^sub>0 \<in> q \<and> i = firstUncommittedSlot nd \<and> t = currentTerm nd \<and> lastAcceptedTerm nd = SomeTerm t'}"
unfolding prevAccepted_def prevAccepted'_def Vote' by auto
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q"
"\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)"
"\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)"
"\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
"\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)"
"\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)"
by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' addElectionVote_def Let_def)
show "zen messages' nodeState'"
apply (intro zenI)
apply (unfold message_simps property_simps committedTo_eq V_eq lastCommittedClusterStateBefore_eq v_eq)
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))".
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>".
from PublishRequest_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from PublishRequest_publishPermitted_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState n) \<Longrightarrow> t < currentTerm (nodeState n)".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>' \<Longrightarrow> t \<le> currentTerm (nodeState n)"
unfolding Vote' by (auto simp add: nd_def)
from joinVotes show "\<And>n n'. n' \<in> joinVotes (nodeState n) \<Longrightarrow> promised' (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))"
unfolding promised_eq by simp
from Vote_future firstUncommittedSlot_PublishResponse
show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>' \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>"
unfolding Vote' nd_def by auto
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto>' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>"
unfolding Vote' using Vote_future lastAcceptedTerm_None nd' nd'_def by auto
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>' \<Longrightarrow> t' < t"
unfolding Vote' using not_accepted lastAcceptedTerm_def
by (smt fst_conv TermOption.distinct(1) snd_conv)
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>' \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>"
unfolding Vote' using lastAcceptedTerm_Some_sent nd' nd'_def nd_def
by (smt Pair_inject TermOption.distinct(1))
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>' \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>"
unfolding Vote' nd_def
by (smt Pair_inject TermOption.distinct(1) \<open>\<And>t' t na. \<lbrakk>lastAcceptedTerm (nodeState na) = SomeTerm t; na \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState na)) t' \<rangle>\<leadsto>\<rbrakk> \<Longrightarrow> t' \<le> t\<close> leD)
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow>' d \<Longrightarrow> d \<noteq> Broadcast"
unfolding Vote' by blast
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow>' d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow>' d' \<Longrightarrow> d = d'"
unfolding Vote' using isMessageFrom_def not_sent by auto
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>' \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto>' \<Longrightarrow> i = i'"
unfolding Vote'
by (metis Vote'(3) Message.inject(2) RoutedMessage.ext_inject insert_iff isMessageFrom'_def isMessageFromTo'_def isMessageFromTo_def isMessageFrom_def messages' not_sent)
from joinVotes_max show "\<And>n n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow>' (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)"
unfolding Vote'
by (smt Vote'(1) Message.inject(2) RoutedMessage.ext_inject insert_iff isMessageFromTo'_def isMessageFrom_def joinVotes messages' not_sent promised_def zen.Vote_slot_function zenMessages.Vote_value_function zenMessages_axioms zen_axioms)
fix i s t x
assume "s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>"
from PublishRequest_quorum [OF this]
obtain q where q_majority: "q \<in> majorities (V i)"
and q_promised: "\<And>n. n \<in> q \<Longrightarrow> promised i n s t"
and q_value: "prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t)" by blast
from not_sent q_promised
have no_new_terms: "{t'. n\<^sub>0 \<in> q \<and> i = firstUncommittedSlot nd \<and> t = currentTerm nd \<and> lastAcceptedTerm nd = SomeTerm t'} = {}"
unfolding isMessageFrom_def promised_def by blast
hence prevAccepted_eq: "prevAccepted' i t q = prevAccepted i t q"
unfolding prevAccepted_eq by auto
show "\<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised' i n s t) \<and> (prevAccepted' i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted' i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))"
proof (intro bexI conjI)
from q_majority show "q \<in> majorities (V i)" .
from q_promised show "\<forall>n\<in>q. promised' i n s t" unfolding promised_eq by simp
from q_value show "prevAccepted' i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted' i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t)"
unfolding prevAccepted_eq by simp
qed
qed
qed
lemma (in zenStep) handleStartJoin_invariants:
fixes t
defines "result \<equiv> handleStartJoin t nd"
assumes nd': "nd' = fst result"
assumes sent: "s \<midarrow>\<langle> StartJoin t \<rangle>\<leadsto>"
assumes messages': "messages' = sendTo (OneNode s) result"
shows "zen messages' nodeState'"
proof (cases "currentTerm nd < t")
case False
hence result: "result = (nd, None)" by (simp add: result_def handleStartJoin_def)
have "messages' = messages" by (auto simp add: messages' result)
moreover
have "nodeState' = nodeState" by (intro ext, unfold nodeState'_def, simp add: nd' result nd_def)
moreover note zen_axioms
ultimately show ?thesis by simp
next
case True
hence new_term: "currentTerm nd < t" by simp
have result: "result = (ensureCurrentTerm t nd, Some (Vote (firstUncommittedSlot nd) t (lastAcceptedTerm nd)))"
by (simp add: result_def handleStartJoin_def True)
have nd': "nd' = ensureCurrentTerm t nd" by (simp add: nd' result)
have zen1: "zen messages nodeState'"
proof (intro zenStep.ensureCurrentTerm_invariants)
show "messages = messages" ..
from nd' show "nodeState' n\<^sub>0 = ensureCurrentTerm t (nodeState n\<^sub>0)" by (simp add: nd'_def nd_def)
show "zenStep messages nodeState messages nodeState' n\<^sub>0"
by (intro_locales, intro zenStep_axioms.intro nodeState_unchanged, simp_all)
qed
with nodeState_unchanged messages_subset
have zenStep1: "zenStep messages nodeState' messages' nodeState' n\<^sub>0"
by (intro_locales, simp add: zen_def, intro zenStep_axioms.intro, auto)
have nodeState': "nodeState' = (\<lambda> n. if n = n\<^sub>0 then nd' else nodeState' n)"
by (auto simp add: nodeState'_def)
have nd'_eq: "nodeState' n\<^sub>0 = nd'"
by (simp add: nodeState'_def)
from True
have currentTerm_nd': "currentTerm nd' = t" by (auto simp add: nd')
have [simp]: "firstUncommittedSlot nd' = firstUncommittedSlot nd"
"lastAcceptedTerm nd' = lastAcceptedTerm nd"
by (auto simp add: nd' ensureCurrentTerm_def lastAcceptedTerm_def
lastAcceptedValue_def)
show "zen messages' nodeState'"
proof (intro zenStep.sendVote_invariants [OF zenStep1], unfold nd'_eq currentTerm_nd', simp_all add: messages' result)
show "\<And>i a. \<forall>d. \<lparr>sender = n\<^sub>0, destination = d, payload = Vote i t a\<rparr> \<notin> messages"
using nd_def new_term zen.Vote_currentTerm zen_axioms by fastforce
show "\<And>t'. lastAcceptedTerm nd = SomeTerm t' \<Longrightarrow> t' < t" using True lastAcceptedTerm_Some_currentTerm unfolding nd_def by fastforce
qed
qed
lemma (in zenStep) addElectionVote_invariants:
assumes nd': "nd' = addElectionVote s i a nd"
assumes messages': "messages' = messages"
assumes sent: "s \<midarrow>\<langle> Vote i (currentTerm nd) a \<rangle>\<rightarrow> (OneNode n\<^sub>0)"
assumes precondition:
"i < firstUncommittedSlot nd \<or> (i = firstUncommittedSlot nd \<and> a \<le> lastAcceptedTerm nd)"
shows "zen messages' nodeState'"
proof -
from precondition have slot: "i \<le> firstUncommittedSlot nd" by auto
have message_simps[simp]:
"\<And>s p d. (s \<midarrow>\<langle> p \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> p \<rangle>\<rightarrow> d)"
"\<And>p d. (\<langle> p \<rangle>\<rightarrow>' d) = (\<langle> p \<rangle>\<rightarrow> d)"
"\<And>s p. (s \<midarrow>\<langle> p \<rangle>\<leadsto>') = (s \<midarrow>\<langle> p \<rangle>\<leadsto>)"
"\<And>p. (\<langle> p \<rangle>\<leadsto>') = (\<langle> p \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q"
"\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)"
"\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)"
"\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' addElectionVote_def Let_def
lastAcceptedValue_def lastAcceptedTerm_def)
have updated_properties:
"\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n) \<union> (if n = n\<^sub>0 then {s} else {})"
"\<And>n. electionWon (nodeState' n) = (if n = n\<^sub>0 then isQuorum nd (insert s (joinVotes nd)) else electionWon (nodeState n))"
unfolding nodeState'_def by (auto simp add: nd' addElectionVote_def Let_def nd_def)
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def)
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
show "zen messages' nodeState'"
apply (intro zenI)
apply (unfold message_simps property_simps committedTo_eq v_eq V_eq promised_eq lastCommittedClusterStateBefore_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t".
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>".
from PublishRequest_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from PublishRequest_publishPermitted_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState n) \<Longrightarrow> t < currentTerm (nodeState n)".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState' n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState' n))"
unfolding updated_properties by (auto simp add: nd_def)
fix n
from joinVotes nd_def precondition sent
show "\<And>n'. n' \<in> joinVotes (nodeState' n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))"
using precondition sent unfolding updated_properties nd_def apply (cases "n = n\<^sub>0", simp_all)
using nd_def promised_def slot by blast
fix n' a'
assume fresh_request: "\<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>)"
and n'_joinVotes: "n' \<in> joinVotes (nodeState' n)"
and n'_vote: "n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n)"
show "a' \<le> lastAcceptedTerm (nodeState n)"
proof (cases "n = n\<^sub>0")
case False
with fresh_request n'_joinVotes n'_vote joinVotes_max
show ?thesis by (simp add: updated_properties)
next
case n_eq: True
show ?thesis
proof (cases "n' = s")
case n'_eq: True
have i: "i = firstUncommittedSlot nd"
proof (intro Vote_slot_function)
from n'_vote show "n' \<midarrow>\<langle> Vote (firstUncommittedSlot nd) (currentTerm nd) a' \<rangle>\<leadsto>"
unfolding isMessageFrom_def nd_def n_eq by auto
from sent show "n' \<midarrow>\<langle> Vote i (currentTerm nd) a \<rangle>\<leadsto>"
unfolding isMessageFrom_def nd_def n'_eq by auto
qed
have a: "a = a'"
proof (intro Vote_value_function)
from n'_vote show "n' \<midarrow>\<langle> Vote (firstUncommittedSlot nd) (currentTerm nd) a' \<rangle>\<leadsto>"
unfolding isMessageFrom_def nd_def n_eq by auto
from sent show "n' \<midarrow>\<langle> Vote (firstUncommittedSlot nd) (currentTerm nd) a \<rangle>\<leadsto>"
unfolding isMessageFrom_def nd_def n'_eq i by auto
qed
from precondition show ?thesis by (auto simp add: i a n_eq nd_def)
next
case False with n'_joinVotes have n'_joinVotes: "n' \<in> joinVotes nd" by (simp add: nd_def n_eq updated_properties)
with fresh_request n'_vote joinVotes_max show ?thesis unfolding nd_def n_eq by auto
qed
qed
qed
qed
lemma (in zenStep) publishValue_invariants:
fixes x
defines "result \<equiv> publishValue x nd"
assumes nd': "nd' = fst result"
assumes messages': "messages' = sendTo Broadcast result"
assumes x: "lastAcceptedTerm nd \<noteq> NO_TERM \<Longrightarrow> x = lastAcceptedValue nd"
shows "zen messages' nodeState'"
proof (cases "electionWon nd \<and> publishPermitted nd")
case False
hence result: "result = (nd, None)" by (simp add: result_def publishValue_def)
have "messages' = messages" by (auto simp add: messages' result)
moreover
have "nodeState' = nodeState" by (intro ext, unfold nodeState'_def, simp add: nd' result nd_def)
moreover note zen_axioms
ultimately show ?thesis by simp
next
case won: True
hence result: "result = (nd \<lparr> publishPermitted := False \<rparr>,
Some (PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x))"
by (simp add: result_def publishValue_def)
have messages': "messages' = insert \<lparr>sender = n\<^sub>0, destination = Broadcast, payload = PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x\<rparr> messages"
by (simp add: messages' result)
have message_simps:
"\<And>s d i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>s d i t. (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<rightarrow> d)"
"\<And>s d i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)"
"\<And>d i t a. (\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>d i t. (\<langle> PublishResponse i t \<rangle>\<rightarrow>' d) = (\<langle> PublishResponse i t \<rangle>\<rightarrow> d)"
"\<And>d i t. (\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = (\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)"
"\<And>s i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>') = (s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>)"
"\<And>s i t. (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>') = (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>)"
"\<And>s i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>') = (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>)"
"\<And>d i t a. (\<langle> Vote i t a \<rangle>\<leadsto>') = (\<langle> Vote i t a \<rangle>\<leadsto>)"
"\<And>d i t. (\<langle> PublishResponse i t \<rangle>\<leadsto>') = (\<langle> PublishResponse i t \<rangle>\<leadsto>)"
"\<And>d i t. (\<langle> ApplyCommit i t \<rangle>\<leadsto>') = (\<langle> ApplyCommit i t \<rangle>\<leadsto>)"
"\<And>s d i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d)"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d)"
"\<And>s i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>)"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>)"
by (auto simp add: isMessageFromTo'_def isMessageTo'_def isMessage'_def isMessageFrom'_def,
auto simp add: isMessageFromTo_def isMessageTo_def isMessage_def isMessageFrom_def messages')
have PublishRequest': "\<And>s d i t x'. (s \<midarrow>\<langle> PublishRequest i t x' \<rangle>\<rightarrow>' d) = ((s \<midarrow>\<langle> PublishRequest i t x' \<rangle>\<rightarrow> d)
\<or> (s, d, i, t, x') = (n\<^sub>0, Broadcast, firstUncommittedSlot nd, currentTerm nd, x))"
"\<And>s i t x'. (s \<midarrow>\<langle> PublishRequest i t x' \<rangle>\<leadsto>') = ((s \<midarrow>\<langle> PublishRequest i t x' \<rangle>\<leadsto>)
\<or> (s, i, t, x') = (n\<^sub>0, firstUncommittedSlot nd, currentTerm nd, x))"
"\<And>d i t x'. (\<langle> PublishRequest i t x' \<rangle>\<rightarrow>' d) = ((\<langle> PublishRequest i t x' \<rangle>\<rightarrow> d)
\<or> (d, i, t, x') = (Broadcast, firstUncommittedSlot nd, currentTerm nd, x))"
"\<And>i t x'. (\<langle> PublishRequest i t x' \<rangle>\<leadsto>') = ((\<langle> PublishRequest i t x' \<rangle>\<leadsto>)
\<or> (i, t, x') = (firstUncommittedSlot nd, currentTerm nd, x))"
by (auto simp add: isMessageFromTo'_def isMessageFrom'_def isMessageTo'_def isMessage'_def,
auto simp add: messages' isMessageFromTo_def isMessageFrom_def isMessageTo_def isMessage_def)
have fresh_request: "\<And>x. \<not> \<langle> PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x \<rangle>\<leadsto>"
proof (intro notI)
fix x'
assume "\<langle> PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x' \<rangle>\<leadsto>"
with won obtain s d where
s: "s \<midarrow>\<langle> PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x' \<rangle>\<rightarrow> d"
by (auto simp add: isMessage_def isMessageFrom_def)
with PublishRequest_quorum [where s = s and i = "firstUncommittedSlot nd" and t = "currentTerm nd" and x = x']
obtain q where q: "q \<in> majorities (V (firstUncommittedSlot nd))" and promised: "\<And>n. n \<in> q \<Longrightarrow> promised (firstUncommittedSlot nd) n s (currentTerm nd)"
by (auto simp add: isMessageFrom_def, blast)
from won have "isQuorum nd (joinVotes nd)"
by (unfold nd_def, intro electionWon_isQuorum, simp)
with currentVotingNodes_firstUncommittedSlot [of n\<^sub>0]
have "joinVotes nd \<in> majorities (V (firstUncommittedSlot nd))" using nd_def isQuorum_def by auto
from q this V_intersects have "q \<inter> joinVotes nd \<noteq> {}"
by (auto simp add: intersects_def)
then obtain n where n: "n \<in> q" "n \<in> joinVotes nd" by auto
from promised [OF `n \<in> q`]
obtain i' a' where "n \<midarrow>\<langle> Vote i' (currentTerm nd) a' \<rangle>\<rightarrow> (OneNode s)"
by (auto simp add: promised_def)
moreover from joinVotes n
obtain i'' a'' where "n \<midarrow>\<langle> Vote i'' (currentTerm nd) a'' \<rangle>\<rightarrow> (OneNode n\<^sub>0)"
by (auto simp add: nd_def promised_def, blast)
ultimately have "OneNode s = OneNode n\<^sub>0"
by (intro Vote_unique_destination)
with s have "n\<^sub>0 \<midarrow>\<langle> PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x' \<rangle>\<leadsto>"
by (auto simp add: isMessageFrom_def)
hence "currentTerm nd < currentTerm (nodeState n\<^sub>0)"
proof (intro PublishRequest_publishPermitted_currentTerm, fold nd_def)
from won show "publishPermitted nd" by (simp add: nd_def)
qed
thus False by (simp add: nd_def)
qed
have v_eq: "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> v' i t = v i t"
proof -
fix i t x'
assume "\<langle> PublishRequest i t x' \<rangle>\<leadsto>"
with fresh_request have ne: "(i, t) \<noteq> (firstUncommittedSlot nd, currentTerm nd)" by auto
have sent_eq: "\<And>x''. \<langle> PublishRequest i t x'' \<rangle>\<leadsto>' = \<langle> PublishRequest i t x'' \<rangle>\<leadsto>"
proof (intro iffI)
fix x''
show "\<langle> PublishRequest i t x'' \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x'' \<rangle>\<leadsto>'" by (simp add: PublishRequest')
assume "\<langle> PublishRequest i t x'' \<rangle>\<leadsto>'" with ne show "\<langle> PublishRequest i t x'' \<rangle>\<leadsto>"
by (unfold PublishRequest', auto)
qed
show "v' i t = v i t"
by (unfold v'_def v_def sent_eq, simp)
qed
have isCommitted_eq: "isCommitted' = isCommitted"
by (intro ext, simp add: isCommitted_def isCommitted'_def message_simps)
have committedTo_eq: "committed\<^sub><' = committed\<^sub><"
by (intro ext, simp add: committedTo_def committedTo'_def isCommitted_eq)
have v\<^sub>c_eq: "\<And>i. isCommitted i \<Longrightarrow> v\<^sub>c' i = v\<^sub>c i"
proof -
fix i assume i: "isCommitted i"
define t where "t \<equiv> SOME t. \<langle> ApplyCommit i t \<rangle>\<leadsto>"
have t: "\<langle> ApplyCommit i t \<rangle>\<leadsto>"
proof -
from i obtain t where t: "\<langle> ApplyCommit i t \<rangle>\<leadsto>" by (auto simp add: isCommitted_def)
thus ?thesis by (unfold t_def, intro someI)
qed
hence v_eq: "v' i t = v i t" by (intro v_eq [OF ApplyCommit_PublishRequest])
have "v\<^sub>c' i = v' i t" by (simp add: v\<^sub>c'_def t_def message_simps)
also note v_eq
also have "v i t = v\<^sub>c i" by (simp add: v\<^sub>c_def t_def)
finally show "?thesis i" by simp
qed
have V_eq: "\<And>i. committed\<^sub>< i \<Longrightarrow> V' i = V i"
proof -
fix i assume i: "committed\<^sub>< i"
thus "?thesis i"
proof (induct i)
case (Suc i')
hence prems: "committed\<^sub>< i'" "isCommitted i'" unfolding committedTo_def by auto
thus ?case using Suc v\<^sub>c_eq by simp
qed simp
qed
have lastCommittedClusterStateBefore_eq: "\<And>i. committed\<^sub>< i \<Longrightarrow> lastCommittedClusterStateBefore' i = lastCommittedClusterStateBefore i"
proof -
fix i assume "committed\<^sub>< i"
thus "?thesis i"
proof (induct i)
case (Suc i')
hence prems: "committed\<^sub>< i'" "isCommitted i'" unfolding committedTo_def by auto
thus ?case using Suc v\<^sub>c_eq by (cases "v\<^sub>c i'", simp_all)
qed simp
qed
have promised_eq: "\<And>i n n' t. promised' i n n' t = promised i n n' t"
by (simp add: promised_def promised'_def message_simps)
have prevAccepted_eq: "\<And>i t q. prevAccepted' i t q = prevAccepted i t q"
by (simp add: prevAccepted_def prevAccepted'_def message_simps)
from committedTo_firstUncommittedSlot V_eq
have V_slot_eq: "\<And>n. V' (firstUncommittedSlot (nodeState n)) = V (firstUncommittedSlot (nodeState n))" by blast
have lastCommittedClusterStateBefore_slot_eq: "\<And>n. lastCommittedClusterStateBefore' (firstUncommittedSlot (nodeState n)) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))"
by (intro lastCommittedClusterStateBefore_eq committedTo_firstUncommittedSlot)
have v_prevAccepted_eq: "\<And>i t q. prevAccepted i t q \<noteq> {} \<Longrightarrow> v' i (maxTerm (prevAccepted i t q)) = v i (maxTerm (prevAccepted i t q))"
proof -
fix i t q
assume nonempty: "prevAccepted i t q \<noteq> {}"
have "maxTerm (prevAccepted i t q) \<in> prevAccepted i t q"
by (intro maxTerm_mem finite_prevAccepted nonempty)
hence "\<langle> Vote i t (SomeTerm (maxTerm (prevAccepted i t q))) \<rangle>\<leadsto>"
by (auto simp add: prevAccepted_def isMessage_def)
hence "\<langle> PublishResponse i (maxTerm (prevAccepted i t q)) \<rangle>\<leadsto>"
using Vote_Some_PublishResponse unfolding isMessage_def by blast
then obtain x' where "\<langle> PublishRequest i (maxTerm (prevAccepted i t q)) x' \<rangle>\<leadsto>"
using PublishResponse_PublishRequest unfolding isMessage_def by blast
thus "?thesis i t q" by (intro v_eq)
qed
have nd': "nd' = nd \<lparr> publishPermitted := False \<rparr>" by (simp add: nd' result)
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q"
"\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)"
"\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
"\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)"
"\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)"
by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' addElectionVote_def Let_def
lastAcceptedTerm_def lastAcceptedValue_def)
show ?thesis
apply (intro zenI)
apply (unfold message_simps committedTo_eq V_slot_eq
lastCommittedClusterStateBefore_slot_eq property_simps promised_eq prevAccepted_eq)
proof -
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t".
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))".
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from joinVotes show "\<And>n n'. n' \<in> joinVotes (nodeState n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)".
{
fix i conf cs assume a: "\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>"
with CatchUpResponse_committedTo show "committed\<^sub>< i" .
with a V_eq lastCommittedClusterStateBefore_eq CatchUpResponse_V CatchUpResponse_lastCommittedClusterStateBefore
show "V' i = conf" "lastCommittedClusterStateBefore' i = cs" by auto
}
from lastAcceptedTerm_Some_value PublishRequest'
show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>'"
by (meson isMessage'_def isMessageFrom'_def isMessageFrom_def isMessage_def)
from PublishRequest_currentTerm
show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto>' \<Longrightarrow> t \<le> currentTerm (nodeState n)"
using PublishRequest' isMessageFrom'_def isMessageFrom_def nd_def by fastforce
from fresh_request PublishRequest_function
show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto>' \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto>' \<Longrightarrow> x = x'"
unfolding PublishRequest' by auto
from messages' finite_messages show "finite messages'" by simp
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>'"
unfolding PublishRequest' by blast
from ApplyCommit_quorum V_eq isCommitted_committedTo
show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V' i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
unfolding isCommitted_def by fastforce
fix n
from firstUncommittedSlot_PublishRequest
show "\<And>i t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>'"
by (cases "n = n\<^sub>0", unfold nodeState'_def PublishRequest' isMessageFrom'_def isMessageFrom_def, auto simp add: nd' nd_def)
from PublishRequest_publishPermitted_currentTerm
show "\<And>t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto>' \<Longrightarrow> publishPermitted (nodeState' n) \<Longrightarrow> t < currentTerm (nodeState n)"
unfolding isMessageFrom'_def PublishRequest'
by (cases "n = n\<^sub>0", auto simp add: nodeState'_def nd' isMessageFrom_def)
show PublishRequest_committedTo': "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto>' \<Longrightarrow> committed\<^sub>< i"
using PublishRequest_committedTo committedTo_firstUncommittedSlot
by (auto simp add: committedTo_def PublishRequest' nd_def)
from joinVotes_max
show "\<And>n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>') \<Longrightarrow> n' \<in> joinVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)"
by (cases "n = n\<^sub>0", auto simp add: nodeState'_def nd' PublishRequest')
{
fix i s t x'
assume "s \<midarrow>\<langle> PublishRequest i t x' \<rangle>\<leadsto>'"
thus "\<exists>q\<in>majorities (V' i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v' i t = v' i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))"
unfolding PublishRequest'
proof (elim disjE)
assume sent: "s \<midarrow>\<langle> PublishRequest i t x' \<rangle>\<leadsto>"
from sent have [simp]: "V' i = V i" by (intro V_eq PublishRequest_committedTo, auto simp add: isMessage_def)
from sent have [simp]: "v' i t = v i t" by (intro v_eq, auto simp add: isMessage_def)
from PublishRequest_quorum [OF sent]
obtain q where q_quorum: "q \<in> majorities (V i)"
and q_promised: "\<And>n. n \<in> q \<Longrightarrow> promised i n s t"
and q_value: "prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t)"
by blast
show ?thesis
proof (cases "prevAccepted i t q = {}")
case True with q_quorum q_promised show ?thesis by auto
next
case False
with q_value obtain t' where t': "v i t = v i t'" "maxTerm (prevAccepted i t q) \<le> t'" "\<langle> PublishResponse i t' \<rangle>\<leadsto>" "t' < t" by blast
show ?thesis
proof (intro bexI conjI disjI2 exI ballI)
from q_promised show "\<And>n. n \<in> q \<Longrightarrow> promised i n s t" .
from t' show "maxTerm (prevAccepted i t q) \<le> t'" "\<langle> PublishResponse i t' \<rangle>\<leadsto>" "t' < t" by simp_all
from q_quorum show "q \<in> majorities (V' i)" by simp
have "v' i t = v i t" by simp
also have "... = v i t'" using t' by simp
also have "... = v' i t'" unfolding v_def v'_def PublishRequest' using t'
by (metis PublishResponse_PublishRequest_v fresh_request fst_conv snd_conv)
finally show "v' i t = v' i t'" .
qed
qed
next
assume "(s, i, t, x') = (n\<^sub>0, firstUncommittedSlot nd, currentTerm nd, x)"
hence [simp]: "s = n\<^sub>0" "i = firstUncommittedSlot nd" "t = currentTerm nd" "x' = x" by simp_all
have Vi: "V' i = V i"
using committedTo_firstUncommittedSlot by (intro V_eq, simp add: nd_def)
define q where "q \<equiv> joinVotes nd"
show ?thesis
proof (intro bexI conjI ballI)
from won have "isQuorum nd q" unfolding nd_def q_def by (intro electionWon_isQuorum, simp)
with currentVotingNodes_firstUncommittedSlot Vi show "q \<in> majorities (V' i)" by (auto simp add: nd_def isQuorum_def)
fix n assume "n \<in> q"
with joinVotes show "promised i n s t" by (simp add: nd_def q_def)
next
show "prevAccepted i t q = {} \<or> (\<exists>t'. v' i t = v' i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t)"
proof (cases "prevAccepted i t q = {}")
case True thus ?thesis by simp
next
case False
then obtain t' n' where n'_vote: "n' \<in> q" and n'_sent: "n' \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto>"
unfolding prevAccepted_def by auto
from n'_sent n'_vote
have n'_sent: "n' \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<rightarrow> (OneNode n\<^sub>0)" unfolding isMessageFrom_def q_def nd_def
using \<open>t = currentTerm nd\<close> isMessageFromTo_def nd_def zen.joinVotes zenMessages.Vote_unique_destination zenMessages_axioms zen_axioms by blast
have t'_latis: "SomeTerm t' \<le> lastAcceptedTerm nd"
unfolding nd_def
proof (intro joinVotes_max)
from fresh_request
show "\<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n\<^sub>0)) (currentTerm (nodeState n\<^sub>0)) x \<rangle>\<leadsto>)"
unfolding nd_def by auto
from n'_vote show "n' \<in> joinVotes (nodeState n\<^sub>0)" by (simp add: q_def nd_def)
from n'_sent
show "n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n\<^sub>0)) (currentTerm (nodeState n\<^sub>0)) (SomeTerm t') \<rangle>\<rightarrow> (OneNode n\<^sub>0)"
by (simp add: nd_def)
qed
then obtain t'' where t'': "lastAcceptedTerm nd = SomeTerm t''"
by (cases "lastAcceptedTerm nd", auto)
show ?thesis
proof (intro disjI2 exI conjI)
from t''
have slots: "firstUncommittedSlot nd = firstUncommittedSlot nd"
by (cases "firstUncommittedSlot nd = firstUncommittedSlot nd", simp_all add: lastAcceptedTerm_def)
from t'' have lat: "lastAcceptedTerm nd = SomeTerm t''"
by (cases "firstUncommittedSlot nd = firstUncommittedSlot nd", simp_all add: lastAcceptedTerm_def)
from lastAcceptedTerm_Some_sent lat slots
show accepted: "\<langle> PublishResponse i t'' \<rangle>\<leadsto>" by (auto simp add: nd_def isMessage_def)
from fresh_request
have "\<And>x'. \<langle> PublishRequest i t x' \<rangle>\<leadsto>' \<Longrightarrow> x' = x" unfolding PublishRequest' by simp
hence "v' i t = x" unfolding v'_def using \<open>s \<midarrow>\<langle> PublishRequest i t x' \<rangle>\<leadsto>'\<close> isMessage'_def by blast
also from x have "x = lastAcceptedValue nd" by (simp add: t'')
also have "... = v i t''"
proof (intro PublishRequest_function)
from accepted PublishResponse_PublishRequest_v show "\<langle> PublishRequest i t'' (v i t'') \<rangle>\<leadsto>" by simp
from lat lastAcceptedTerm_Some_value slots
show "\<langle> PublishRequest i t'' (lastAcceptedValue nd) \<rangle>\<leadsto>"
by (simp add: nd_def)
qed
also have "... = v' i t''"
proof (intro sym [OF v_eq])
from accepted PublishResponse_PublishRequest_v show "\<langle> PublishRequest i t'' (v i t'') \<rangle>\<leadsto>" by simp
qed
finally show "v' i t = v' i t''" .
show "maxTerm (prevAccepted i t q) \<le> t''"
proof (intro maxTerm_le False finite_prevAccepted)
fix t''' assume "t''' \<in> prevAccepted i t q"
thus "t''' \<le> t''" unfolding prevAccepted_def apply auto
by (metis \<open>\<And>t s i' ia d' d a' a. \<lbrakk>s \<midarrow>\<langle> Vote ia t a \<rangle>\<rightarrow> d; s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d'\<rbrakk> \<Longrightarrow> d = d'\<close> fresh_request isMessageFrom_def joinVotes joinVotes_max le_SomeTerm nd_def promised_def q_def t'')
qed
have "t'' \<le> t" using \<open>t = currentTerm nd\<close> lastAcceptedTerm_Some_currentTerm lat nd_def by blast
moreover have "t'' \<noteq> t" apply (intro notI) using accepted fresh_request
using lastAcceptedTerm_Some_value lat nd_def slots by auto
ultimately show "t'' < t" by simp
qed
qed
qed
qed
}
qed
qed
lemma (in zenStep) handleVote_invariants:
fixes s i t a
defines "result \<equiv> handleVote s i t a nd"
assumes nd': "nd' = fst result"
assumes messages': "messages' = sendTo Broadcast result"
assumes sent: "s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> (OneNode n\<^sub>0)"
shows "zen messages' nodeState'"
proof (cases "t = currentTerm nd
\<and> (i < firstUncommittedSlot nd
\<or> (i = firstUncommittedSlot nd
\<and> (a \<le> lastAcceptedTerm nd)))")
case False
have [simp]: "result = (nd, None)" unfolding result_def handleVote_def by (simp add: False Let_def)
have [simp]: "messages' = messages" by (simp add: messages')
have [simp]: "nodeState' = nodeState" unfolding nodeState'_def by (intro ext, simp add: nd' nd_def)
from zen_axioms show ?thesis by simp
next
case True
hence True': "i \<le> firstUncommittedSlot nd"
"t = currentTerm nd"
"i < firstUncommittedSlot nd \<or> (i = firstUncommittedSlot nd \<and> a \<le> lastAcceptedTerm nd)"
by auto
define nd1 where "nd1 \<equiv> addElectionVote s i a nd"
define nodeState1 where "\<And>n. nodeState1 n \<equiv> if n = n\<^sub>0 then nd1 else nodeState n"
have zenStep1: "zenStep messages nodeState messages nodeState1 n\<^sub>0"
by (intro zenStepI2, auto simp add: nodeState1_def)
have zenStep2: "zenStep messages nodeState1 messages' nodeState' n\<^sub>0"
proof (intro zenStep.zenStepI1 [OF zenStep1] zenStep.addElectionVote_invariants [OF zenStep1] refl messages_subset,
fold nd_def isMessageFromTo_def)
show "nodeState1 n\<^sub>0 = addElectionVote s i a nd" by (simp add: nodeState1_def nd1_def)
from True' sent show "s \<midarrow>\<langle> Vote i (currentTerm nd) a \<rangle>\<rightarrow> (OneNode n\<^sub>0)" by simp
from True' show "i < firstUncommittedSlot nd \<or> (i = firstUncommittedSlot nd \<and> a \<le> lastAcceptedTerm nd)" by simp
show "\<And>n. n \<noteq> n\<^sub>0 \<Longrightarrow> nodeState1 n = nodeState' n" unfolding nodeState1_def nodeState'_def by simp
qed
note zenStep.publishValue_invariants
have latis_eq: "lastAcceptedTerm nd1 = lastAcceptedTerm nd"
by (simp add: nd1_def addElectionVote_def Let_def)
show ?thesis
proof (cases "lastAcceptedTerm nd1")
case (SomeTerm t')
with True' latis_eq
have handleVote_eq: "handleVote s i t a nd = publishValue (lastAcceptedValue nd1) nd1"
unfolding handleVote_def nd1_def by (simp add: addElectionVote_def Let_def)
show ?thesis
proof (intro zenStep.publishValue_invariants [OF zenStep2])
show "nodeState' n\<^sub>0 = fst (publishValue (lastAcceptedValue nd1) (nodeState1 n\<^sub>0))"
by (simp add: nodeState1_def nd1_def nodeState'_def nd' result_def handleVote_eq)
show "messages' = (case snd (publishValue (lastAcceptedValue nd1) (nodeState1 n\<^sub>0)) of None \<Rightarrow> messages | Some m \<Rightarrow> insert \<lparr>sender = n\<^sub>0, destination = Broadcast, payload = m\<rparr> messages)"
by (cases "publishValue (lastAcceptedValue nd1) nd1", cases "snd (publishValue (lastAcceptedValue nd1) nd1)",
simp_all add: nodeState1_def messages' result_def handleVote_eq)
show "lastAcceptedValue nd1 = lastAcceptedValue (nodeState1 n\<^sub>0)" by (simp add: nodeState1_def)
qed
next
case NO_TERM
with True' latis_eq
have handleVote_eq: "handleVote s i t a nd = (nd1, None)" unfolding handleVote_def nd1_def by simp
have [simp]: "messages' = messages" by (simp add: messages' result_def handleVote_eq)
have [simp]: "nodeState' = nodeState1" by (intro ext, simp add: nodeState'_def nodeState1_def nd' result_def handleVote_eq)
from zenStep2 show ?thesis by (simp add: zenStep_def)
qed
qed
lemma (in zenStep) handleClientValue_invariants:
fixes x
defines "result \<equiv> handleClientValue x nd"
assumes nd': "nd' = fst result"
assumes messages': "messages' = sendTo Broadcast result"
shows "zen messages' nodeState'"
proof (cases "lastAcceptedTerm nd")
case (SomeTerm t')
hence "handleClientValue x nd = (nd, None)" by (auto simp add: handleClientValue_def)
hence [simp]: "result = (nd, None)" by (simp add: result_def)
have [simp]: "messages' = messages" by (simp add: messages')
have [simp]: "nodeState' = nodeState" unfolding nodeState'_def by (intro ext, simp add: nd' nd_def)
from zen_axioms show ?thesis by simp
next
case NO_TERM
hence handleClientValue_eq[simp]: "handleClientValue x nd = publishValue x nd"
by (auto simp add: handleClientValue_def)
have result: "result = publishValue x nd"
unfolding result_def by simp
show ?thesis
proof (intro publishValue_invariants)
show "nd' = fst (publishValue x nd)" by (simp add: result nd')
show "messages' = sendTo Broadcast (publishValue x nd)" by (simp_all add: messages' result)
from NO_TERM show "lastAcceptedTerm nd \<noteq> NO_TERM \<Longrightarrow> x = lastAcceptedValue nd"
by simp
qed
qed
lemma (in zenStep) handlePublishRequest_invariants:
fixes i t x
defines "result \<equiv> handlePublishRequest i t x nd"
assumes nd': "nd' = fst result"
assumes messages': "messages' = sendTo (OneNode s) result"
assumes sent: "s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>"
shows "zen messages' nodeState'"
proof (cases "i = firstUncommittedSlot nd \<and> t = currentTerm nd")
case False
hence [simp]: "result = (nd, None)"
by (simp add: result_def handlePublishRequest_def)
have [simp]: "messages' = messages"
by (simp add: messages')
have [simp]: "nodeState' = nodeState"
unfolding nodeState'_def
by (intro ext, simp add: nd' nd_def)
from zen_axioms show ?thesis by simp
next
case precondition: True
hence result: "result = (nd\<lparr>lastAcceptedData := Some \<lparr> tvTerm = t, tvValue = x\<rparr> \<rparr>,
Some (PublishResponse i t))"
by (auto simp add: result_def handlePublishRequest_def)
have messages': "messages' = insert \<lparr> sender = n\<^sub>0, destination = OneNode s, payload = PublishResponse i t \<rparr> messages"
by (simp add: messages' result)
have message_simps[simp]:
"\<And>s d i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)"
"\<And>s d i t x. (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<rightarrow> d)"
"\<And>s d i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>d i t. (\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = (\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)"
"\<And>d i t x. (\<langle> PublishRequest i t x \<rangle>\<rightarrow>' d) = (\<langle> PublishRequest i t x \<rangle>\<rightarrow> d)"
"\<And>d i t a. (\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>s i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>') = (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>)"
"\<And>s i t x. (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>') = (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>)"
"\<And>s i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>') = (s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>)"
"\<And>i t. (\<langle> ApplyCommit i t \<rangle>\<leadsto>') = (\<langle> ApplyCommit i t \<rangle>\<leadsto>)"
"\<And>i t x. (\<langle> PublishRequest i t x \<rangle>\<leadsto>') = (\<langle> PublishRequest i t x \<rangle>\<leadsto>)"
"\<And>i t a. (\<langle> Vote i t a \<rangle>\<leadsto>') = (\<langle> Vote i t a \<rangle>\<leadsto>)"
"\<And>s d i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d)"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d)"
"\<And>s i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>)"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)"
"\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)"
"\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)"
"\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
"lastAcceptedTerm nd' = SomeTerm t"
"lastAcceptedValue nd' = x"
using precondition
by (unfold nodeState'_def, auto simp add: result nd' nd_def isQuorum_def
lastAcceptedTerm_def lastAcceptedValue_def)
have updated_properties:
"\<And>n. lastAcceptedTerm (nodeState' n) = (if n = n\<^sub>0 then SomeTerm t else lastAcceptedTerm (nodeState n))"
"\<And>n. lastAcceptedValue (nodeState' n) = (if n = n\<^sub>0 then x else lastAcceptedValue (nodeState n))"
by (unfold nodeState'_def, auto simp add: result nd' nd_def
lastAcceptedTerm_def lastAcceptedValue_def)
have PublishResponse': "\<And>s' d i t'. (s' \<midarrow>\<langle> PublishResponse i t' \<rangle>\<rightarrow>' d) =
((s' \<midarrow>\<langle> PublishResponse i t' \<rangle>\<rightarrow> d) \<or> (s', i, t', d) = (n\<^sub>0, firstUncommittedSlot nd, t, OneNode s))"
"\<And>d i t'. (\<langle> PublishResponse i t' \<rangle>\<rightarrow>' d) =
((\<langle> PublishResponse i t' \<rangle>\<rightarrow> d) \<or> (i, t', d) = (firstUncommittedSlot nd, t, OneNode s))"
"\<And>s' i t'. (s' \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>') =
((s' \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>) \<or> (s', i, t') = (n\<^sub>0, firstUncommittedSlot nd, t))"
"\<And>i t'. (\<langle> PublishResponse i t' \<rangle>\<leadsto>') =
((\<langle> PublishResponse i t' \<rangle>\<leadsto>) \<or> (i, t') = (firstUncommittedSlot nd, t))"
unfolding isMessageFromTo_def isMessageFromTo'_def isMessageFrom_def isMessageFrom'_def isMessageTo_def isMessageTo'_def isMessage_def isMessage'_def
by (auto simp add: messages' precondition)
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def)
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)
show ?thesis
apply (intro zenI)
apply (unfold message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from joinVotes show "\<And>n n'. n' \<in> joinVotes (nodeState n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from PublishRequest_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from PublishRequest_publishPermitted_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState n) \<Longrightarrow> t < currentTerm (nodeState n)".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>'"
using precondition unfolding PublishResponse' nd_def by (metis Vote_currentTerm Pair_inject leD)
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>'"
using precondition unfolding PublishResponse' nd_def by (metis Vote_currentTerm Pair_inject leD)
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>'"
using precondition unfolding PublishResponse' nd_def by metis
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>'"
using precondition unfolding PublishResponse' nd_def using Vote_currentTerm by fastforce
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto>' \<and> t' < t))"
unfolding PublishResponse' by meson
fix n
from firstUncommittedSlot_PublishResponse show "\<And>i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>'"
using precondition property_simps unfolding PublishResponse' nd_def by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_None show "\<And>i t. lastAcceptedTerm (nodeState' n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>'"
using precondition property_simps updated_properties unfolding PublishResponse' nd_def by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>'"
using precondition property_simps unfolding PublishResponse' nd_def
by (metis nd'_def nodeState_unchanged TermOption.inject)
from lastAcceptedTerm_Some_max show "\<And>t t'. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto>' \<Longrightarrow> t' \<le> t"
using precondition property_simps updated_properties unfolding PublishResponse' nd_def apply (cases "n = n\<^sub>0", auto)
by (meson TermOption.exhaust lastAcceptedTerm_None lastAcceptedTerm_Some_currentTerm le_trans)
from joinVotes_max show "\<And>n n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState' n)"
using precondition property_simps unfolding PublishResponse' nd_def
by (metis isMessage_def nodeState_unchanged sent)
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>'"
using precondition property_simps unfolding PublishResponse' nd_def
by blast
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>' \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>"
using precondition property_simps unfolding PublishResponse' nd_def
using isMessage_def sent by auto
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>'"
using precondition property_simps unfolding PublishResponse' nd_def
by meson
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState' n)) \<rangle>\<leadsto>"
using precondition property_simps unfolding PublishResponse' nd_def
by (metis isMessage_def nd'_def nodeState_unchanged TermOption.inject sent)
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)"
using precondition property_simps unfolding PublishResponse' nd_def
by (metis eq_imp_le TermOption.inject updated_properties(1))
qed
qed
lemma (in zenStep) addPublishVote_invariants:
assumes nd': "nd' = nd \<lparr> publishVotes := insert s (publishVotes nd) \<rparr>"
assumes messages': "messages' = messages"
assumes sent: "s \<midarrow>\<langle> PublishResponse (firstUncommittedSlot nd) (currentTerm nd) \<rangle>\<leadsto>"
shows "zen messages' nodeState'"
proof -
have message_simps[simp]:
"\<And>s p d. (s \<midarrow>\<langle> p \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> p \<rangle>\<rightarrow> d)"
"\<And>p d. (\<langle> p \<rangle>\<rightarrow>' d) = (\<langle> p \<rangle>\<rightarrow> d)"
"\<And>s p. (s \<midarrow>\<langle> p \<rangle>\<leadsto>') = (s \<midarrow>\<langle> p \<rangle>\<leadsto>)"
"\<And>p. (\<langle> p \<rangle>\<leadsto>') = (\<langle> p \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q"
"\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)"
"\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)"
"\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)"
"\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' addElectionVote_def Let_def
lastAcceptedTerm_def lastAcceptedValue_def)
have updated_properties[simp]:
"\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n) \<union> (if n = n\<^sub>0 then {s} else {})"
by (unfold nodeState'_def, auto simp add: nd' nd_def isQuorum_def)
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def)
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)
show ?thesis
apply (intro zenI)
apply (unfold message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t".
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))".
from joinVotes_max show "\<And>n n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from joinVotes show "\<And>n n'. n' \<in> joinVotes (nodeState n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>".
from PublishRequest_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from PublishRequest_publishPermitted_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState n) \<Longrightarrow> t < currentTerm (nodeState n)".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>"
unfolding updated_properties using sent apply auto by (metis empty_iff nd_def singleton_iff)
qed
qed
lemma (in zenStep) commitIfQuorate_invariants:
fixes s i t
defines "result \<equiv> commitIfQuorate nd"
assumes nd': "nd' = fst result"
assumes messages': "messages' = sendTo Broadcast result"
shows "zen messages' nodeState'"
proof (cases "isQuorum nd (publishVotes nd)")
case False
hence [simp]: "result = (nd, None)"
by (simp add: result_def commitIfQuorate_def)
have [simp]: "messages' = messages"
by (simp add: messages')
have [simp]: "nodeState' = nodeState"
unfolding nodeState'_def
by (intro ext, simp add: nd' nd_def)
from zen_axioms show ?thesis by simp
next
case isQuorum: True
hence result: "result = (nd, Some (ApplyCommit (firstUncommittedSlot nd) (currentTerm nd)))"
by (simp add: result_def commitIfQuorate_def)
have nodeState': "nodeState' = nodeState"
unfolding nodeState'_def
by (intro ext, simp add: nd' nd_def result)
have messages': "messages' = insert \<lparr> sender = n\<^sub>0, destination = Broadcast, payload = ApplyCommit (firstUncommittedSlot nd) (currentTerm nd) \<rparr> messages"
by (simp add: messages' result)
have message_simps[simp]:
"\<And>s d i t. (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<rightarrow> d)"
"\<And>s d i t x. (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<rightarrow> d)"
"\<And>s d i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>d i t. (\<langle> PublishResponse i t \<rangle>\<rightarrow>' d) = (\<langle> PublishResponse i t \<rangle>\<rightarrow> d)"
"\<And>d i t x. (\<langle> PublishRequest i t x \<rangle>\<rightarrow>' d) = (\<langle> PublishRequest i t x \<rangle>\<rightarrow> d)"
"\<And>d i t a. (\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>s i t. (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>') = (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>)"
"\<And>s i t x. (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>') = (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>)"
"\<And>s i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>') = (s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>)"
"\<And>i t. (\<langle> PublishResponse i t \<rangle>\<leadsto>') = (\<langle> PublishResponse i t \<rangle>\<leadsto>)"
"\<And>i t x. (\<langle> PublishRequest i t x \<rangle>\<leadsto>') = (\<langle> PublishRequest i t x \<rangle>\<leadsto>)"
"\<And>i t a. (\<langle> Vote i t a \<rangle>\<leadsto>') = (\<langle> Vote i t a \<rangle>\<leadsto>)"
"\<And>s d i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d)"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d)"
"\<And>s i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>)"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have ApplyCommit': "\<And>s d i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = ((s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)
\<or> (s, i, t, d) = (n\<^sub>0, firstUncommittedSlot nd, currentTerm nd, Broadcast))"
"\<And>s i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>') = ((s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>)
\<or> (s, i, t) = (n\<^sub>0, firstUncommittedSlot nd, currentTerm nd))"
"\<And>d i t. (\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = ((\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)
\<or> (i, t, d) = (firstUncommittedSlot nd, currentTerm nd, Broadcast))"
"\<And>i t. (\<langle> ApplyCommit i t \<rangle>\<leadsto>') = ((\<langle> ApplyCommit i t \<rangle>\<leadsto>)
\<or> (i, t) = (firstUncommittedSlot nd, currentTerm nd))"
unfolding isMessageFromTo_def isMessageFromTo'_def isMessageFrom_def isMessageFrom'_def isMessageTo_def isMessageTo'_def isMessage_def isMessage'_def
by (auto simp add: messages')
from committedTo_firstUncommittedSlot
have committedTo_current: "committed\<^sub>< (firstUncommittedSlot nd)"
by (simp add: nd_def)
have isCommitted_eq: "\<And>i. isCommitted' i = (isCommitted i \<or> i = firstUncommittedSlot nd)"
using isCommitted'_def isCommitted_def by (auto simp add: ApplyCommit')
have committedTo_eq: "\<And>i. committed\<^sub><' i = ((committed\<^sub>< i) \<or> (i = Suc (firstUncommittedSlot nd)))"
proof -
fix i
show "?thesis i"
proof (cases "isCommitted (firstUncommittedSlot nd)")
case True with isCommitted_eq have 1: "isCommitted' = isCommitted" by (intro ext, auto)
from True isCommitted_committedTo_Suc have 2: "committed\<^sub>< (Suc (firstUncommittedSlot nd))" by simp
from 1 2 show ?thesis by (simp add: committedTo'_def committedTo_def, blast)
next
case False
with committedTo_current isCommitted_committedTo
have isCommitted_lt[simp]: "\<And>j. isCommitted j = (j < firstUncommittedSlot nd)"
using committedTo_def nat_neq_iff by blast
have isCommitted'_le[simp]: "\<And>j. isCommitted' j = (j \<le> firstUncommittedSlot nd)"
by (auto simp add: isCommitted_eq)
show ?thesis
by (simp add: committedTo'_def committedTo_def, auto, presburger)
qed
qed
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
note oneSlot.consistent [OF oneSlot.commit [OF zen_is_oneSlot]]
have v\<^sub>c_eq: "\<And>i. isCommitted i \<Longrightarrow> v\<^sub>c' i = v\<^sub>c i"
proof -
fix i assume "isCommitted i" then obtain t where t: "\<langle> ApplyCommit i t \<rangle>\<leadsto>" unfolding isCommitted_def by blast
show "?thesis i"
proof (cases "i = firstUncommittedSlot nd")
case False thus ?thesis unfolding v\<^sub>c_def v\<^sub>c'_def v_eq ApplyCommit' by simp
next
case i: True
show "v\<^sub>c' i = v\<^sub>c i"
unfolding v\<^sub>c_def v\<^sub>c'_def v_eq
proof (intro oneSlot.consistent [OF oneSlot.commit [OF zen_is_oneSlot]])
from isQuorum show "publishVotes nd \<in> majorities (V i)" unfolding nd_def i isQuorum_def using currentVotingNodes_firstUncommittedSlot by simp
from publishVotes show "\<And>n. n \<in> publishVotes nd \<Longrightarrow> n \<midarrow>\<langle> PublishResponse i (currentTerm nd) \<rangle>\<leadsto>" unfolding nd_def i .
from t have "\<langle> ApplyCommit i (SOME t. \<langle> ApplyCommit i t \<rangle>\<leadsto>) \<rangle>\<leadsto>" by (intro someI)
thus "\<langle> ApplyCommit i (SOME t. \<langle> ApplyCommit i t \<rangle>\<leadsto>) \<rangle>\<leadsto> \<or> (SOME t. \<langle> ApplyCommit i t \<rangle>\<leadsto>) = currentTerm nd" by simp
show "\<langle> ApplyCommit i (SOME t. \<langle> ApplyCommit i t \<rangle>\<leadsto>') \<rangle>\<leadsto> \<or> (SOME t. \<langle> ApplyCommit i t \<rangle>\<leadsto>') = currentTerm nd"
proof (rule someI2)
from t show "\<langle> ApplyCommit i t \<rangle>\<leadsto>'"
"\<And>x. \<langle> ApplyCommit i x \<rangle>\<leadsto>' \<Longrightarrow> \<langle> ApplyCommit i x \<rangle>\<leadsto> \<or> x = currentTerm nd"
by (simp_all add: ApplyCommit' i)
qed
qed
qed
qed
have V_eq: "\<And>i. committed\<^sub>< i \<Longrightarrow> V' i = V i"
proof -
fix i assume i: "committed\<^sub>< i"
thus "?thesis i"
proof (induct i)
case (Suc i')
hence prems: "committed\<^sub>< i'" "isCommitted i'" unfolding committedTo_def by auto
thus ?case using Suc v\<^sub>c_eq by simp
qed simp
qed
hence V_era_eq: "\<And>n. V' (firstUncommittedSlot (nodeState n)) = V (firstUncommittedSlot (nodeState n))"
using committedTo_firstUncommittedSlot by blast
have lastCommittedClusterStateBefore_eq: "\<And>i. committed\<^sub>< i \<Longrightarrow> lastCommittedClusterStateBefore' i = lastCommittedClusterStateBefore i"
proof -
fix i assume "committed\<^sub>< i"
thus "?thesis i"
proof (induct i)
case (Suc i')
hence prems: "committed\<^sub>< i'" "isCommitted i'" unfolding committedTo_def by auto
thus ?case using Suc v\<^sub>c_eq by (cases "v\<^sub>c i'", simp_all)
qed simp
qed
hence lastCommittedClusterStateBefore_slot_eq:
"\<And>n. lastCommittedClusterStateBefore' (firstUncommittedSlot (nodeState n))
= lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))"
using committedTo_firstUncommittedSlot by blast
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def)
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)
show ?thesis
apply (intro zenI)
apply (unfold nodeState' message_simps V_era_eq lastCommittedClusterStateBefore_slot_eq promised_eq prevAccepted_eq v_eq)
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t".
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))".
from joinVotes_max show "\<And>n n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)".
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from joinVotes show "\<And>n n'. n' \<in> joinVotes (nodeState n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>".
from PublishRequest_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from PublishRequest_publishPermitted_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState n) \<Longrightarrow> t < currentTerm (nodeState n)".
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)".
{
fix i conf cs assume a: "\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>"
with CatchUpResponse_committedTo have committedTo: "committed\<^sub>< i" .
thus "committed\<^sub><' i" unfolding committedTo_eq by simp
from a committedTo V_eq lastCommittedClusterStateBefore_eq CatchUpResponse_V CatchUpResponse_lastCommittedClusterStateBefore
show "V' i = conf" "lastCommittedClusterStateBefore' i = cs" by auto
}
from committedTo_firstUncommittedSlot
show "\<And>n. committed\<^sub><' (firstUncommittedSlot (nodeState n))"
unfolding committedTo_eq by simp
from PublishRequest_committedTo
show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub><' i"
unfolding committedTo_eq by simp
from PublishRequest_quorum
show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V' i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))"
using V_eq PublishRequest_committedTo isMessage_def by metis
from ApplyCommit_quorum
show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto>' \<Longrightarrow> \<exists>q\<in>majorities (V' i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
using V_eq committedTo_firstUncommittedSlot unfolding ApplyCommit' committedTo_def isCommitted_def
by (metis ApplyCommit_PublishRequest_v\<^sub>c PublishRequest_committedTo V_eq isQuorum currentVotingNodes_firstUncommittedSlot nd_def prod.inject publishVotes isQuorum_def)
qed
qed
lemma (in zenStep) handlePublishResponse_invariants:
fixes s i t
defines "result \<equiv> handlePublishResponse s i t nd"
assumes nd': "nd' = fst result"
assumes messages': "messages' = sendTo Broadcast result"
assumes sent: "s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
shows "zen messages' nodeState'"
proof (cases "i = firstUncommittedSlot nd \<and> t = currentTerm nd")
case False
hence [simp]: "result = (nd, None)"
by (auto simp add: result_def handlePublishResponse_def Let_def)
have [simp]: "messages' = messages"
by (simp add: messages')
have [simp]: "nodeState' = nodeState"
unfolding nodeState'_def
by (intro ext, simp add: nd' nd_def)
from zen_axioms show ?thesis by simp
next
case True
hence i: "i = firstUncommittedSlot nd"
and t: "t = currentTerm nd"
by simp_all
define nd1 where "nd1 \<equiv> nd \<lparr>publishVotes := insert s (publishVotes nd)\<rparr>"
define nodeState1 where "nodeState1 \<equiv> \<lambda>n. if n = n\<^sub>0 then nd1 else nodeState n"
have result: "result = commitIfQuorate nd1"
by (simp add: result_def handlePublishResponse_def i t nd1_def)
have zenStep1: "zenStep messages nodeState messages nodeState1 n\<^sub>0"
by (intro zenStepI2, auto simp add: nodeState1_def)
have zenStep2: "zenStep messages nodeState1 messages' nodeState' n\<^sub>0"
proof (intro zenStep.zenStepI1 [OF zenStep1] zenStep.addPublishVote_invariants [OF zenStep1] refl messages_subset,
fold isMessageFromTo_def isMessageFrom_def nd_def)
show "nodeState1 n\<^sub>0 = nd\<lparr>publishVotes := insert s (publishVotes nd)\<rparr>"
by (simp add: nodeState1_def nd1_def)
from sent show "s \<midarrow>\<langle> PublishResponse (firstUncommittedSlot nd) (currentTerm nd) \<rangle>\<leadsto>" by (simp add: True)
show "\<And>n. n \<noteq> n\<^sub>0 \<Longrightarrow> nodeState1 n = nodeState' n" unfolding nodeState1_def nodeState'_def by simp
qed
show ?thesis
proof (intro zenStep.commitIfQuorate_invariants [OF zenStep2])
show "nodeState' n\<^sub>0 = fst (commitIfQuorate (nodeState1 n\<^sub>0))"
by (simp add: nodeState'_def nd' result nodeState1_def)
show "messages' = (case snd (commitIfQuorate (nodeState1 n\<^sub>0)) of None \<Rightarrow> messages | Some m \<Rightarrow> insert \<lparr>sender = n\<^sub>0, destination = Broadcast, payload = m\<rparr> messages)"
by (cases "commitIfQuorate (nodeState1 n\<^sub>0)", cases "snd (commitIfQuorate (nodeState1 n\<^sub>0))",
simp_all add: nodeState1_def messages' result_def handlePublishResponse_def i t nd1_def)
qed
qed
lemma (in zenStep) handleApplyCommit_invariants:
assumes nd': "nd' = handleApplyCommit i t nd"
assumes messages'[simp]: "messages' = messages"
assumes sent: "\<langle> ApplyCommit i t \<rangle>\<leadsto>"
shows "zen messages' nodeState'"
proof (cases "i = firstUncommittedSlot nd \<and> lastAcceptedTerm nd = SomeTerm t")
case False
hence nd'[simp]: "nd' = nd"
by (auto simp add: nd' handleApplyCommit_def)
have nodeState'[simp]: "nodeState' = nodeState" unfolding nodeState'_def by (intro ext, simp add: nd_def)
from zen_axioms show ?thesis unfolding nodeState' by simp
next
case True
hence i: "i = firstUncommittedSlot nd"
and t: "lastAcceptedTerm nd = SomeTerm t" by simp_all
have message_simps[simp]:
"\<And>s p d. (s \<midarrow>\<langle> p \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> p \<rangle>\<rightarrow> d)"
"\<And>p d. (\<langle> p \<rangle>\<rightarrow>' d) = (\<langle> p \<rangle>\<rightarrow> d)"
"\<And>s p. (s \<midarrow>\<langle> p \<rangle>\<leadsto>') = (s \<midarrow>\<langle> p \<rangle>\<leadsto>)"
"\<And>p. (\<langle> p \<rangle>\<leadsto>') = (\<langle> p \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def)
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)
from sent t
have lastAcceptedValue_eq: "v\<^sub>c i = lastAcceptedValue nd"
unfolding i nd_def using lastAcceptedTerm_Some_value [of n\<^sub>0 t]
by (intro PublishRequest_function [OF ApplyCommit_PublishRequest_v\<^sub>c])
show ?thesis
proof (cases "isReconfiguration (v\<^sub>c i)")
case False
have "\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)
\<and> currentTerm (nodeState' n) = currentTerm (nodeState n)
\<and> currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)
\<and> joinVotes (nodeState' n) = joinVotes (nodeState n)
\<and> electionWon (nodeState' n) = electionWon (nodeState n)
\<and> isQuorum (nodeState' n) = isQuorum (nodeState n)"
proof (cases "lastAcceptedValue nd")
case NoOp thus "\<And>n. ?thesis n"
unfolding nodeState'_def nd' handleApplyCommit_def i t applyAcceptedValue_def isQuorum_def nd_def
by simp
next
case ClusterStateDiff thus "\<And>n. ?thesis n"
unfolding nodeState'_def nd' handleApplyCommit_def i t applyAcceptedValue_def isQuorum_def nd_def
by simp
next
case Reconfigure with False lastAcceptedValue_eq show "\<And>n. ?thesis n" by simp
qed
hence property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)"
"\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)"
"\<And>n. isQuorum (nodeState' n) = isQuorum (nodeState n)"
by simp_all
have "\<And>n. firstUncommittedSlot (nodeState' n) = (if n = n\<^sub>0 then Suc (firstUncommittedSlot (nodeState n)) else firstUncommittedSlot (nodeState n))
\<and> publishPermitted (nodeState' n) = (publishPermitted (nodeState n) \<or> n = n\<^sub>0)
\<and> publishVotes (nodeState' n) = (if n = n\<^sub>0 then {} else publishVotes (nodeState n))
\<and> lastAcceptedTerm (nodeState' n) = (if n = n\<^sub>0 then NO_TERM else lastAcceptedTerm (nodeState n))"
proof (cases "lastAcceptedValue nd")
case NoOp
with i t show "\<And>n. ?thesis n"
by (unfold nodeState'_def, auto simp add: lastAcceptedValue_eq nd_def nd' applyAcceptedValue_def isQuorum_def handleApplyCommit_def lastAcceptedTerm_def)
next
case ClusterStateDiff
with i t show "\<And>n. ?thesis n"
by (unfold nodeState'_def, auto simp add: lastAcceptedValue_eq nd_def nd' applyAcceptedValue_def isQuorum_def handleApplyCommit_def lastAcceptedTerm_def)
next
case Reconfigure with False lastAcceptedValue_eq show "\<And>n. ?thesis n" by simp
qed
hence updated_properties:
"\<And>n. firstUncommittedSlot (nodeState' n) = (if n = n\<^sub>0 then Suc (firstUncommittedSlot (nodeState n)) else firstUncommittedSlot (nodeState n)) "
"\<And>n. publishPermitted (nodeState' n) = (publishPermitted (nodeState n) \<or> n = n\<^sub>0)"
"\<And>n. publishVotes (nodeState' n) = (if n = n\<^sub>0 then {} else publishVotes (nodeState n))"
"\<And>n. lastAcceptedTerm (nodeState' n) = (if n = n\<^sub>0 then NO_TERM else lastAcceptedTerm (nodeState n))"
by simp_all
show ?thesis
apply (intro zenI)
apply (unfold messages' message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages" .
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
fix n
from firstUncommittedSlot_PublishResponse show "\<And>i t. firstUncommittedSlot (nodeState' n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
using updated_properties by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_None show "\<And>i t. lastAcceptedTerm (nodeState' n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \<rangle>\<leadsto>"
using updated_properties firstUncommittedSlot_PublishResponse by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_Some_sent show "\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \<rangle>\<leadsto>"
using updated_properties by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_Some_max show "\<And>t t'. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t"
using updated_properties by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_Some_value show "\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t (lastAcceptedValue (nodeState' n)) \<rangle>\<leadsto>"
using updated_properties by (cases "n = n\<^sub>0", auto, simp add: nodeState'_def)
from lastAcceptedTerm_Some_currentTerm show "\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)"
using updated_properties by (cases "n = n\<^sub>0", auto)
from committedTo_firstUncommittedSlot show "committed\<^sub>< (firstUncommittedSlot (nodeState' n))"
unfolding updated_properties committedTo_def apply (cases "n = n\<^sub>0", auto)
using i isCommitted_def less_antisym nd_def sent by blast
from joinVotes_max show "\<And>n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState' n)"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto)
using isMessageFromTo_def zen.Vote_slot_function zen.joinVotes zen_axioms by fastforce
from publishVotes show "\<And>n'. n' \<in> publishVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto) done
from joinVotes show "\<And>n'. n' \<in> joinVotes (nodeState n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState' n)) n' n (currentTerm (nodeState n))"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto)
by (meson le_SucI promised_def)
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState' n))"
unfolding updated_properties using False i nd_def by (cases "n = n\<^sub>0", auto)
from firstUncommittedSlot_PublishRequest show "\<And>i t x. firstUncommittedSlot (nodeState' n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto) done
from PublishRequest_currentTerm show "\<And>t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto simp add: firstUncommittedSlot_PublishRequest) done
from PublishRequest_publishPermitted_currentTerm show "\<And>t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState' n) \<Longrightarrow> t < currentTerm (nodeState n)"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto simp add: firstUncommittedSlot_PublishRequest) done
from currentClusterState_lastCommittedClusterStateBefore
show "currentClusterState (nodeState' n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState' n))"
proof (cases "n = n\<^sub>0")
case False with currentClusterState_lastCommittedClusterStateBefore
show ?thesis unfolding nodeState'_def by auto
next
case True
show ?thesis
proof (cases "v\<^sub>c i")
case NoOp
with currentClusterState_lastCommittedClusterStateBefore True lastAcceptedValue_eq i t
show ?thesis
unfolding nodeState'_def
by (simp add: nd' nd_def applyAcceptedValue_def handleApplyCommit_def)
next
case Reconfigure with False show ?thesis by simp
next
case (ClusterStateDiff diff)
with lastAcceptedValue_eq have "lastAcceptedValue nd = ClusterStateDiff diff" by simp
with ClusterStateDiff True i t currentClusterState_lastCommittedClusterStateBefore
show ?thesis
unfolding nodeState'_def
by (simp add: nd' nd_def applyAcceptedValue_def handleApplyCommit_def)
qed
qed
qed
next
case True
then obtain newConfig where Reconfigure: "v\<^sub>c i = Reconfigure newConfig" by (cases "v\<^sub>c i", auto)
with lastAcceptedValue_eq have lastAcceptedValue_eq: "lastAcceptedValue nd = Reconfigure newConfig" by simp
hence property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
"\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)"
unfolding nodeState'_def by (auto simp add: nd' handleApplyCommit_def applyAcceptedValue_def nd_def
lastAcceptedTerm_def firstUncommittedSlot_def lastAcceptedValue_def)
have updated_properties:
"\<And>n. firstUncommittedSlot (nodeState' n) = (if n = n\<^sub>0 then Suc (firstUncommittedSlot (nodeState n)) else firstUncommittedSlot (nodeState n)) "
"\<And>n. publishPermitted (nodeState' n) = (publishPermitted (nodeState n) \<or> n = n\<^sub>0)"
"\<And>n. publishVotes (nodeState' n) = (if n = n\<^sub>0 then {} else publishVotes (nodeState n))"
"\<And>n. currentVotingNodes (nodeState' n) = (if n = n\<^sub>0 then set newConfig else currentVotingNodes (nodeState n))"
"\<And>n. electionWon (nodeState' n) = (if n = n\<^sub>0 then joinVotes nd \<in> majorities (set newConfig) else electionWon (nodeState n))"
"\<And>n. isQuorum (nodeState' n) = (if n = n\<^sub>0 then (\<lambda>q. q \<in> majorities (set newConfig)) else isQuorum (nodeState n))"
"\<And>n. currentVotingNodes (nodeState' n) = (if n = n\<^sub>0 then set newConfig else currentVotingNodes (nodeState n))"
"\<And>n. lastAcceptedTerm (nodeState' n) = (if n = n\<^sub>0 then NO_TERM else lastAcceptedTerm (nodeState n))"
"\<And>n. n \<noteq> n\<^sub>0 \<Longrightarrow> lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)"
unfolding nodeState'_def using i t lastAcceptedValue_eq
by (auto simp add: nd' handleApplyCommit_def applyAcceptedValue_def nd_def isQuorum_def lastAcceptedTerm_def)
show ?thesis
apply (intro zenI)
apply (unfold messages' message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages" .
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
fix n
from firstUncommittedSlot_PublishResponse show "\<And>i t. firstUncommittedSlot (nodeState' n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
using updated_properties by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_None show "\<And>i t. lastAcceptedTerm (nodeState' n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \<rangle>\<leadsto>"
using updated_properties firstUncommittedSlot_PublishResponse by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_Some_sent show "\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \<rangle>\<leadsto>"
using updated_properties by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_Some_max show "\<And>t t'. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t"
using updated_properties by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_Some_value show "\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t (lastAcceptedValue (nodeState' n)) \<rangle>\<leadsto>"
using updated_properties by (cases "n = n\<^sub>0", auto)
from committedTo_firstUncommittedSlot show "committed\<^sub>< (firstUncommittedSlot (nodeState' n))"
unfolding updated_properties committedTo_def apply (cases "n = n\<^sub>0", auto)
using i isCommitted_def less_antisym nd_def sent by blast
from electionWon_isQuorum show "\<And>n. electionWon (nodeState' n) \<Longrightarrow> isQuorum (nodeState' n) (joinVotes (nodeState n))"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto simp add: nd_def) done
from joinVotes_max show "\<And>n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState' n)"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto)
using isMessageFromTo_def zen.Vote_slot_function zen.joinVotes zen_axioms by fastforce
from publishVotes show "\<And>n'. n' \<in> publishVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto) done
from joinVotes show "\<And>n'. n' \<in> joinVotes (nodeState n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState' n)) n' n (currentTerm (nodeState n))"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto)
by (meson le_SucI promised_def)
from firstUncommittedSlot_PublishRequest show "\<And>i t x. firstUncommittedSlot (nodeState' n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto) done
from PublishRequest_currentTerm show "\<And>t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto simp add: firstUncommittedSlot_PublishRequest) done
from PublishRequest_publishPermitted_currentTerm show "\<And>t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState' n) \<Longrightarrow> t < currentTerm (nodeState n)"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto simp add: firstUncommittedSlot_PublishRequest) done
from currentClusterState_lastCommittedClusterStateBefore Reconfigure i nd_def
show "currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState' n))"
unfolding updated_properties committedTo_def by (cases "n = n\<^sub>0", auto)
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState' n) = V (firstUncommittedSlot (nodeState' n))"
unfolding updated_properties committedTo_def using Reconfigure i nd_def by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_Some_currentTerm show "\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto) done
qed
qed
qed
lemma (in zenStep) handleCatchUpRequest_invariants:
fixes s i t
defines "result \<equiv> handleCatchUpRequest nd"
assumes nd': "nd' = fst result"
assumes messages': "messages' = sendTo d\<^sub>0 result"
shows "zen messages' nodeState'"
proof -
have result: "result = (nd, Some (CatchUpResponse (firstUncommittedSlot nd) (currentVotingNodes nd) (currentClusterState nd)))"
by (simp add: result_def handleCatchUpRequest_def)
have nd'[simp]: "nd' = nd" by (simp add: nd' result)
have nodeState'[simp]: "nodeState' = nodeState" by (intro ext, simp add: nodeState'_def result nd_def)
have messages': "messages' = insert \<lparr> sender = n\<^sub>0, destination = d\<^sub>0, payload = CatchUpResponse (firstUncommittedSlot nd) (currentVotingNodes nd) (currentClusterState nd) \<rparr> messages"
by (simp add: messages' result)
have message_simps[simp]:
"\<And>s d i t. (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<rightarrow> d)"
"\<And>s d i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)"
"\<And>s d i t x. (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<rightarrow> d)"
"\<And>s d i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>d i t. (\<langle> PublishResponse i t \<rangle>\<rightarrow>' d) = (\<langle> PublishResponse i t \<rangle>\<rightarrow> d)"
"\<And>d i t. (\<langle> ApplyCommit i t \<rangle>\<rightarrow>' d) = (\<langle> ApplyCommit i t \<rangle>\<rightarrow> d)"
"\<And>d i t x. (\<langle> PublishRequest i t x \<rangle>\<rightarrow>' d) = (\<langle> PublishRequest i t x \<rangle>\<rightarrow> d)"
"\<And>d i t a. (\<langle> Vote i t a \<rangle>\<rightarrow>' d) = (\<langle> Vote i t a \<rangle>\<rightarrow> d)"
"\<And>s i t. (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>') = (s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>)"
"\<And>s i t. (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>') = (s \<midarrow>\<langle> ApplyCommit i t \<rangle>\<leadsto>)"
"\<And>s i t x. (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>') = (s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>)"
"\<And>s i t a. (s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>') = (s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto>)"
"\<And>i t. (\<langle> PublishResponse i t \<rangle>\<leadsto>') = (\<langle> PublishResponse i t \<rangle>\<leadsto>)"
"\<And>i t. (\<langle> ApplyCommit i t \<rangle>\<leadsto>') = (\<langle> ApplyCommit i t \<rangle>\<leadsto>)"
"\<And>i t x. (\<langle> PublishRequest i t x \<rangle>\<leadsto>') = (\<langle> PublishRequest i t x \<rangle>\<leadsto>)"
"\<And>i t a. (\<langle> Vote i t a \<rangle>\<leadsto>') = (\<langle> Vote i t a \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have CatchUpResponse':
"\<And>s d i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d
\<or> (s, i, conf, cs, d) = (n\<^sub>0, firstUncommittedSlot nd, currentVotingNodes nd, currentClusterState nd, d\<^sub>0))"
"\<And>d i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow>' d) = (\<langle> CatchUpResponse i conf cs \<rangle>\<rightarrow> d
\<or> (i, conf, cs, d) = (firstUncommittedSlot nd, currentVotingNodes nd, currentClusterState nd, d\<^sub>0))"
"\<And>s i conf cs. (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (s \<midarrow>\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>
\<or> (s, i, conf, cs) = (n\<^sub>0, firstUncommittedSlot nd, currentVotingNodes nd, currentClusterState nd))"
"\<And>i conf cs. (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>') = (\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>
\<or> (i, conf, cs) = (firstUncommittedSlot nd, currentVotingNodes nd, currentClusterState nd))"
unfolding isMessageFromTo_def isMessageFromTo'_def isMessageFrom_def isMessageFrom'_def isMessageTo_def isMessageTo'_def isMessage_def isMessage'_def
by (auto simp add: messages')
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def)
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)
show ?thesis
apply (intro zenI)
apply (unfold message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq promised_eq prevAccepted_eq nodeState')
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t".
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))".
from joinVotes_max show "\<And>n n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)".
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from joinVotes show "\<And>n n'. n' \<in> joinVotes (nodeState n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>".
from PublishRequest_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from PublishRequest_publishPermitted_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState n) \<Longrightarrow> t < currentTerm (nodeState n)".
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from CatchUpResponse_committedTo committedTo_firstUncommittedSlot
show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>' \<Longrightarrow> committed\<^sub>< i"
unfolding CatchUpResponse' nd_def by blast
from CatchUpResponse_V currentVotingNodes_firstUncommittedSlot
show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>' \<Longrightarrow> V i = conf"
unfolding CatchUpResponse' nd_def isQuorum_def by auto
from CatchUpResponse_lastCommittedClusterStateBefore currentClusterState_lastCommittedClusterStateBefore
show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>' \<Longrightarrow> lastCommittedClusterStateBefore i = cs"
unfolding CatchUpResponse' nd_def by auto
qed
qed
lemma (in zenStep) handleCatchUpResponse_invariants:
assumes nd': "nd' = handleCatchUpResponse i conf cs nd"
assumes messages'[simp]: "messages' = messages"
assumes sent: "\<langle> CatchUpResponse i conf cs \<rangle>\<leadsto>"
shows "zen messages' nodeState'"
proof (cases "firstUncommittedSlot nd < i")
case False
hence nd'[simp]: "nd' = nd"
by (auto simp add: nd' handleCatchUpResponse_def)
have nodeState'[simp]: "nodeState' = nodeState" unfolding nodeState'_def by (intro ext, simp add: nd_def)
from zen_axioms show ?thesis unfolding nodeState' by simp
next
case True
hence nd': "nd' = nd \<lparr> firstUncommittedSlot := i
, publishPermitted := True
, publishVotes := {}
, currentVotingNodes := conf
, currentClusterState := cs
, joinVotes := {}
, electionWon := False
, lastAcceptedData := None \<rparr>"
by (simp add: nd', simp add: handleCatchUpResponse_def)
have message_simps[simp]:
"\<And>s p d. (s \<midarrow>\<langle> p \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> p \<rangle>\<rightarrow> d)"
"\<And>p d. (\<langle> p \<rangle>\<rightarrow>' d) = (\<langle> p \<rangle>\<rightarrow> d)"
"\<And>s p. (s \<midarrow>\<langle> p \<rangle>\<leadsto>') = (s \<midarrow>\<langle> p \<rangle>\<leadsto>)"
"\<And>p. (\<langle> p \<rangle>\<leadsto>') = (\<langle> p \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def)
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
unfolding nodeState'_def by (auto simp add: nd' nd_def lastAcceptedTerm_def firstUncommittedSlot_def lastAcceptedValue_def)
have updated_properties:
"\<And>n. firstUncommittedSlot (nodeState' n) = (if n = n\<^sub>0 then i else firstUncommittedSlot (nodeState n)) "
"\<And>n. publishPermitted (nodeState' n) = (publishPermitted (nodeState n) \<or> n = n\<^sub>0)"
"\<And>n. publishVotes (nodeState' n) = (if n = n\<^sub>0 then {} else publishVotes (nodeState n))"
"\<And>n. currentVotingNodes (nodeState' n) = (if n = n\<^sub>0 then conf else currentVotingNodes (nodeState n))"
"\<And>n. joinVotes (nodeState' n) = (if n = n\<^sub>0 then {} else joinVotes (nodeState n))"
"\<And>n. electionWon (nodeState' n) = (electionWon (nodeState n) \<and> n \<noteq> n\<^sub>0)"
"\<And>n. currentVotingNodes (nodeState' n) = (if n = n\<^sub>0 then conf else currentVotingNodes (nodeState n))"
"\<And>n. isQuorum (nodeState' n) = (if n = n\<^sub>0 then (\<lambda>q. q \<in> majorities conf) else isQuorum (nodeState n))"
"\<And>n. currentClusterState (nodeState' n) = (if n = n\<^sub>0 then cs else currentClusterState (nodeState n))"
unfolding nodeState'_def
by (auto simp add: nd' nd_def isQuorum_def)
have "\<And>n. lastAcceptedTerm (nodeState' n) = (if n = n\<^sub>0 then NO_TERM else lastAcceptedTerm (nodeState n))"
using True unfolding lastAcceptedTerm_def updated_properties property_simps nd_def
using not_le by (simp add: nodeState'_def nd')
note updated_properties = updated_properties this
show ?thesis
apply (intro zenI)
apply (unfold messages' message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages" .
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState' n))"
unfolding updated_properties apply auto
using CatchUpResponse_committedTo sent by blast
from electionWon_isQuorum show "\<And>n. electionWon (nodeState' n) \<Longrightarrow> isQuorum (nodeState' n) (joinVotes (nodeState' n))"
unfolding updated_properties apply auto done
from joinVotes_max show "\<And>n n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState' n)"
unfolding updated_properties apply auto done
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>"
unfolding updated_properties apply auto done
from joinVotes show "\<And>n n'. n' \<in> joinVotes (nodeState' n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState' n)) n' n (currentTerm (nodeState n))"
unfolding updated_properties apply auto done
fix n
from firstUncommittedSlot_PublishRequest show "\<And>i t x. firstUncommittedSlot (nodeState' n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>"
unfolding updated_properties using True nd_def by (cases "n = n\<^sub>0", auto)
from PublishRequest_currentTerm show "\<And>t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto)
using True firstUncommittedSlot_PublishRequest nd_def by blast
from PublishRequest_publishPermitted_currentTerm show "\<And>t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState' n) \<Longrightarrow> t < currentTerm (nodeState n)"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto)
using True firstUncommittedSlot_PublishRequest nd_def by blast
from currentClusterState_lastCommittedClusterStateBefore show "currentClusterState (nodeState' n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState' n))"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto)
using CatchUpResponse_lastCommittedClusterStateBefore sent by blast
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState' n) = V (firstUncommittedSlot (nodeState' n))"
unfolding updated_properties using CatchUpResponse_V sent by (cases "n = n\<^sub>0", auto)
from firstUncommittedSlot_PublishResponse show "\<And>i t. firstUncommittedSlot (nodeState' n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto)
using True dual_order.strict_trans nd_def by blast
from lastAcceptedTerm_None show "\<And>i t. lastAcceptedTerm (nodeState' n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \<rangle>\<leadsto>"
unfolding updated_properties apply (cases "n = n\<^sub>0", auto)
using True firstUncommittedSlot_PublishResponse nd_def by blast
from lastAcceptedTerm_Some_sent show "\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \<rangle>\<leadsto>"
unfolding updated_properties by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_Some_max show "\<And>t t'. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t"
unfolding updated_properties by (cases "n = n\<^sub>0", auto)
from lastAcceptedTerm_Some_value show "\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t (lastAcceptedValue (nodeState' n)) \<rangle>\<leadsto>"
unfolding updated_properties lastAcceptedValue_def by (cases "n = n\<^sub>0", auto simp add: nodeState'_def)
from lastAcceptedTerm_Some_currentTerm show "\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)"
unfolding updated_properties by (cases "n = n\<^sub>0", auto)
qed
qed
lemma (in zenStep) handleDiscardJoinVotes_invariants:
assumes nd': "nd' = handleDiscardJoinVotes nd"
assumes messages': "messages' = messages"
shows "zen messages' nodeState'"
proof -
have message_simps[simp]:
"\<And>s p d. (s \<midarrow>\<langle> p \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> p \<rangle>\<rightarrow> d)"
"\<And>p d. (\<langle> p \<rangle>\<rightarrow>' d) = (\<langle> p \<rangle>\<rightarrow> d)"
"\<And>s p. (s \<midarrow>\<langle> p \<rangle>\<leadsto>') = (s \<midarrow>\<langle> p \<rangle>\<leadsto>)"
"\<And>p. (\<langle> p \<rangle>\<leadsto>') = (\<langle> p \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q"
"\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)"
"\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
"\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)"
"\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)"
by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' handleDiscardJoinVotes_def Let_def
lastAcceptedValue_def lastAcceptedTerm_def)
have updated_properties:
"\<And>n. joinVotes (nodeState' n) = (if n = n\<^sub>0 then {} else joinVotes (nodeState n))"
"\<And>n. electionWon (nodeState' n) = (electionWon (nodeState n) \<and> n \<noteq> n\<^sub>0)"
by (unfold nodeState'_def, auto simp add: nd' nd_def handleDiscardJoinVotes_def)
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def)
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)
show ?thesis
apply (intro zenI)
apply (unfold message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>" .
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t" .
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>" .
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from PublishRequest_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from PublishRequest_publishPermitted_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState n) \<Longrightarrow> t < currentTerm (nodeState n)".
from publishVotes show "\<And>n n'. n' \<in> publishVotes (nodeState n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState' n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState' n))"
unfolding updated_properties by simp
fix n
from joinVotes show "\<And>n'. n' \<in> joinVotes (nodeState' n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))"
unfolding updated_properties by (cases "n = n\<^sub>0", simp_all)
from joinVotes_max show "\<And>n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)"
unfolding updated_properties by (cases "n = n\<^sub>0", simp_all)
qed
qed
lemma (in zenStep) handleReboot_invariants:
assumes nd': "nd' = handleReboot nd"
assumes messages': "messages' = messages"
shows "zen messages' nodeState'"
proof -
have message_simps[simp]:
"\<And>s p d. (s \<midarrow>\<langle> p \<rangle>\<rightarrow>' d) = (s \<midarrow>\<langle> p \<rangle>\<rightarrow> d)"
"\<And>p d. (\<langle> p \<rangle>\<rightarrow>' d) = (\<langle> p \<rangle>\<rightarrow> d)"
"\<And>s p. (s \<midarrow>\<langle> p \<rangle>\<leadsto>') = (s \<midarrow>\<langle> p \<rangle>\<leadsto>)"
"\<And>p. (\<langle> p \<rangle>\<leadsto>') = (\<langle> p \<rangle>\<leadsto>)"
by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,
auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)
have property_simps[simp]:
"\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)"
"\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)"
"\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)"
"\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q"
"\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)"
"\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)"
"\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)"
"\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)"
by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' handleReboot_def Let_def
lastAcceptedValue_def lastAcceptedTerm_def)
have updated_properties:
"\<And>n. publishPermitted (nodeState' n) = (publishPermitted (nodeState n) \<and> n \<noteq> n\<^sub>0)"
"\<And>n. joinVotes (nodeState' n) = (if n = n\<^sub>0 then {} else joinVotes (nodeState n))"
"\<And>n. electionWon (nodeState' n) = (electionWon (nodeState n) \<and> n \<noteq> n\<^sub>0)"
"\<And>n. publishVotes (nodeState' n) = (if n = n\<^sub>0 then {} else publishVotes (nodeState n))"
by (unfold nodeState'_def, auto simp add: nd' nd_def handleReboot_def)
have v_eq[simp]: "v' = v" by (intro ext, auto simp add: v'_def v_def)
have v\<^sub>c_eq[simp]: "v\<^sub>c' = v\<^sub>c" by (intro ext, auto simp add: v\<^sub>c'_def v\<^sub>c_def)
have isCommitted_eq[simp]: "isCommitted' = isCommitted" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)
have committedTo_eq[simp]: "committed\<^sub><' = committed\<^sub><" by (intro ext, auto simp add: committedTo'_def committedTo_def)
have V_eq[simp]: "V' = V" using v\<^sub>c_eq V'_def V_def by blast
have promised_eq[simp]: "promised' = promised" by (intro ext, auto simp add: promised'_def promised_def)
have lastCommittedClusterStateBefore_eq[simp]: "lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore"
unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\<^sub>c_eq ..
have prevAccepted_eq[simp]: "prevAccepted' = prevAccepted" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)
show ?thesis
apply (intro zenI)
apply (unfold message_simps committedTo_eq V_eq v_eq
lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)
proof -
from finite_messages show "finite messages'" by (simp add: messages')
from Vote_future show "\<And>i i' s t t' a. s \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> i < i' \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i' t' \<rangle>\<leadsto>".
from Vote_None show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t NO_TERM \<rangle>\<leadsto> \<Longrightarrow> t' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_lt show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t".
from Vote_Some_PublishResponse show "\<And>i s t t'. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> s \<midarrow>\<langle> PublishResponse i t' \<rangle>\<leadsto>".
from Vote_Some_max show "\<And>i s t t' t''. s \<midarrow>\<langle> Vote i t (SomeTerm t') \<rangle>\<leadsto> \<Longrightarrow> t' < t'' \<Longrightarrow> t'' < t \<Longrightarrow> \<not> s \<midarrow>\<langle> PublishResponse i t'' \<rangle>\<leadsto>".
from Vote_not_broadcast show "\<And>i t a d. \<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> d \<noteq> Broadcast".
from Vote_unique_destination show "\<And>i' i s t a a' d d'. s \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> d \<Longrightarrow> s \<midarrow>\<langle> Vote i' t a' \<rangle>\<rightarrow> d' \<Longrightarrow> d = d'".
from currentNode_nodeState show "\<And>n. currentNode (nodeState n) = n" .
from committedTo_firstUncommittedSlot show "\<And>n. committed\<^sub>< (firstUncommittedSlot (nodeState n))" .
from firstUncommittedSlot_PublishResponse show "\<And>n i t. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>" .
from lastAcceptedTerm_None show "\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>".
from lastAcceptedTerm_Some_sent show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \<rangle>\<leadsto>" .
from lastAcceptedTerm_Some_max show "\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> n \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \<rangle>\<leadsto> \<Longrightarrow> t' \<le> t" .
from lastAcceptedTerm_Some_value show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \<rangle>\<leadsto>" .
from Vote_currentTerm show "\<And>n i t a. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from Vote_slot_function show "\<And>n i i' t a a'. n \<midarrow>\<langle> Vote i t a \<rangle>\<leadsto> \<Longrightarrow> n \<midarrow>\<langle> Vote i' t a' \<rangle>\<leadsto> \<Longrightarrow> i = i'".
from currentClusterState_lastCommittedClusterStateBefore show "\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))".
from PublishRequest_committedTo show "\<And>i t x. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from PublishRequest_quorum show "\<And>i s t x. s \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). (\<forall>n\<in>q. promised i n s t) \<and> (prevAccepted i t q = {} \<or> (\<exists>t'. v i t = v i t' \<and> maxTerm (prevAccepted i t q) \<le> t' \<and> \<langle> PublishResponse i t' \<rangle>\<leadsto> \<and> t' < t))".
from PublishRequest_function show "\<And>i t x x'. \<langle> PublishRequest i t x \<rangle>\<leadsto> \<Longrightarrow> \<langle> PublishRequest i t x' \<rangle>\<leadsto> \<Longrightarrow> x = x'".
from PublishResponse_PublishRequest show "\<And>i s t. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>x. \<langle> PublishRequest i t x \<rangle>\<leadsto>".
from ApplyCommit_quorum show "\<And>i t. \<langle> ApplyCommit i t \<rangle>\<leadsto> \<Longrightarrow> \<exists>q\<in>majorities (V i). \<forall>s\<in>q. s \<midarrow>\<langle> PublishResponse i t \<rangle>\<leadsto>".
from currentVotingNodes_firstUncommittedSlot show "\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))".
from firstUncommittedSlot_PublishRequest show "\<And>i n t x. firstUncommittedSlot (nodeState n) < i \<Longrightarrow> \<not> n \<midarrow>\<langle> PublishRequest i t x \<rangle>\<leadsto>".
from PublishRequest_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from CatchUpResponse_committedTo show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> committed\<^sub>< i".
from CatchUpResponse_V show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> V i = conf".
from CatchUpResponse_lastCommittedClusterStateBefore show "\<And>i conf cs. \<langle> CatchUpResponse i conf cs \<rangle>\<leadsto> \<Longrightarrow> lastCommittedClusterStateBefore i = cs".
from lastAcceptedTerm_Some_currentTerm show "\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \<Longrightarrow> t \<le> currentTerm (nodeState n)".
from electionWon_isQuorum show "\<And>n. electionWon (nodeState' n) \<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState' n))"
unfolding updated_properties by simp
from PublishRequest_publishPermitted_currentTerm show "\<And>n t x. n \<midarrow>\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \<rangle>\<leadsto> \<Longrightarrow> publishPermitted (nodeState' n) \<Longrightarrow> t < currentTerm (nodeState n)"
unfolding updated_properties by simp
fix n
from joinVotes show "\<And>n'. n' \<in> joinVotes (nodeState' n) \<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))"
unfolding updated_properties by (cases "n = n\<^sub>0", simp_all)
from publishVotes show "\<And>n'. n' \<in> publishVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \<rangle>\<leadsto>"
unfolding updated_properties by (cases "n = n\<^sub>0", simp_all)
from joinVotes_max show "\<And>n' a'. \<not> (\<exists>x. \<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \<rangle>\<leadsto>) \<Longrightarrow> n' \<in> joinVotes (nodeState' n) \<Longrightarrow> n' \<midarrow>\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \<rangle>\<rightarrow> (OneNode n) \<Longrightarrow> a' \<le> lastAcceptedTerm (nodeState n)"
unfolding updated_properties by (cases "n = n\<^sub>0", simp_all)
qed
qed
fun insertOption :: "RoutedMessage option \<Rightarrow> RoutedMessage set \<Rightarrow> RoutedMessage set"
where
"insertOption None = id"
| "insertOption (Some m) = insert m"
lemma currentNode_ensureCurrentTerm[simp]: "currentNode (ensureCurrentTerm t nd) = currentNode nd"
by (auto simp add: ensureCurrentTerm_def)
lemma currentNode_publishValue[simp]: "currentNode (fst (publishValue x nd)) = currentNode nd"
by (auto simp add: publishValue_def)
lemma currentNode_addElectionVote[simp]: "currentNode (addElectionVote s i a nd) = currentNode nd"
by (auto simp add: addElectionVote_def Let_def)
lemma currentNode_handleVote[simp]: "currentNode (fst (handleVote s i t a nd)) = currentNode nd"
by (auto simp add: handleVote_def Let_def)
text \<open>\pagebreak\<close>
lemma initial_state_satisfies_invariants:
shows "zen {} initialNodeState"
by (unfold_locales, simp_all add: initialNodeState_def isQuorum_def
lastAcceptedTerm_def lastAcceptedValue_def)
lemma (in zen) invariants_preserved_by_ProcessMessage:
fixes n\<^sub>0
assumes "m \<in> messages"
defines "nd \<equiv> nodeState n\<^sub>0"
defines "result \<equiv> ProcessMessage nd m"
defines "nodeState' \<equiv> \<lambda>n. if n = n\<^sub>0 then (fst result) else nodeState n"
defines "messages' \<equiv> insertOption (snd result) messages"
shows "zen messages' nodeState'"
proof -
{
assume r: "result = (nd, None)"
from r have "nodeState' = nodeState"
by (auto simp add: nodeState'_def nd_def)
moreover from r have "messages' = messages" by (simp add: messages'_def)
ultimately have "zen messages' nodeState'"
using zen_axioms by blast
}
note noop = this
from `m \<in> messages`
have m: "(sender m) \<midarrow>\<langle> payload m \<rangle>\<rightarrow> (destination m)"
by (cases m, auto simp add: isMessageFromTo_def)
have currentNode[simp]: "currentNode nd = n\<^sub>0" "\<And>n. currentNode (nodeState n) = n"
by (simp_all add: nd_def currentNode_nodeState)
have zenStep: "zenStep messages nodeState messages' nodeState' n\<^sub>0"
proof (intro_locales, intro zenStep_axioms.intro)
show "messages \<subseteq> messages'"
by (cases "snd result", auto simp add: messages'_def)
qed (simp add: nodeState'_def)
have [simp]: "nodeState n\<^sub>0 = nd" by (simp add: nd_def)
define broadcast' :: "(NodeData * Message option) \<Rightarrow> (NodeData * RoutedMessage option)" where
"\<And>p. broadcast' p \<equiv> case p of
(nd, Some m') \<Rightarrow> (nd, Some \<lparr>sender = currentNode nd,
destination = Broadcast,
payload = m' \<rparr>)
| (nd, None) \<Rightarrow> (nd, None)"
define respond' :: "(NodeData * Message option) \<Rightarrow> (NodeData * RoutedMessage option)" where
"\<And>p. respond' p \<equiv> case p of
(nd, Some m') \<Rightarrow> (nd, Some \<lparr>sender = currentNode nd,
destination = OneNode (sender m),
payload = m' \<rparr>)
| (nd, None) \<Rightarrow> (nd, None)"
have fst_broadcast[simp]: "\<And>p. fst (broadcast' p) = fst p"
unfolding broadcast'_def by (simp add: case_prod_unfold option.case_eq_if)
have fst_respond[simp]: "\<And>p. fst (respond' p) = fst p"
unfolding respond'_def by (simp add: case_prod_unfold option.case_eq_if)
show ?thesis
proof (cases "destination m = Broadcast \<or> destination m = OneNode (currentNode nd)")
case False
hence "result = (nd, None)"
unfolding result_def ProcessMessage_def Let_def by simp
thus ?thesis by (intro noop)
next
case dest_ok: True
have dest_True: "destination m \<in> {Broadcast, OneNode (currentNode nd)} = True"
using dest_ok by simp
show ?thesis
proof (cases "payload m")
case (StartJoin t)
have result: "result = respond' (handleStartJoin t nd)"
unfolding result_def respond'_def ProcessMessage_def dest_True StartJoin by auto
have currentNode_eq: "currentNode (nodeState' n\<^sub>0) = currentNode (nodeState n\<^sub>0)"
unfolding nodeState'_def result by (auto simp add: handleStartJoin_def)
show ?thesis
proof (intro zenStep.handleStartJoin_invariants [OF zenStep])
show "nodeState' n\<^sub>0 = fst (handleStartJoin t (nodeState n\<^sub>0))"
by (simp add: result nodeState'_def)
from currentNode_eq
show "messages' = (case snd (handleStartJoin t (nodeState n\<^sub>0)) of None \<Rightarrow> messages | Some m' \<Rightarrow> insert \<lparr>sender = n\<^sub>0, destination = OneNode (sender m), payload = m'\<rparr> messages)"
unfolding messages'_def result respond'_def nodeState'_def by (cases "handleStartJoin t nd", cases "snd (handleStartJoin t nd)", auto)
from m show "\<exists>d. \<lparr>sender = sender m, destination = d, payload = StartJoin t\<rparr> \<in> messages"
by (auto simp add: isMessageFromTo_def StartJoin)
qed
next
case (Vote i t a)
from Vote_not_broadcast m Vote dest_ok
have dest_m: "destination m = OneNode n\<^sub>0"
apply (cases "destination m")
using isMessageTo_def apply fastforce
by auto
from Vote_not_broadcast m Vote dest_ok
have m: "(sender m) \<midarrow>\<langle> Vote i t a \<rangle>\<rightarrow> (OneNode n\<^sub>0)"
apply (cases "destination m")
using isMessageTo_def apply fastforce
by auto
have result: "result = broadcast' (handleVote (sender m) i t a nd)"
unfolding result_def ProcessMessage_def Vote dest_True broadcast'_def by simp
have currentNode_eq: "currentNode (nodeState' n\<^sub>0) = currentNode (nodeState n\<^sub>0)"
unfolding nodeState'_def result by simp
show ?thesis
proof (intro zenStep.handleVote_invariants [OF zenStep])
show "nodeState' n\<^sub>0 = fst (handleVote (sender m) i t a (nodeState n\<^sub>0))"
by (simp add: result nodeState'_def)
from currentNode_eq
show "messages' = (case snd (handleVote (sender m) i t a (nodeState n\<^sub>0)) of None \<Rightarrow> messages | Some m \<Rightarrow> insert \<lparr>sender = n\<^sub>0, destination = Broadcast, payload = m\<rparr> messages)"
unfolding messages'_def result broadcast'_def nodeState'_def by (cases "handleVote (sender m) i t a nd", cases "snd (handleVote (sender m) i t a nd)", auto)
from m
show "\<lparr>sender = sender m, destination = OneNode n\<^sub>0, payload = Vote i t a\<rparr> \<in> messages"
by (auto simp add: Vote isMessageFromTo_def)
qed
next
case (ClientValue x)
have result: "result = broadcast' (handleClientValue x nd)"
unfolding result_def ProcessMessage_def ClientValue dest_True broadcast'_def by simp
have currentNode_eq: "currentNode (nodeState' n\<^sub>0) = currentNode (nodeState n\<^sub>0)"
unfolding nodeState'_def result by (simp add: handleClientValue_def)
show ?thesis
proof (intro zenStep.handleClientValue_invariants [OF zenStep])
show "nodeState' n\<^sub>0 = fst (handleClientValue x (nodeState n\<^sub>0))"
by (simp add: result nodeState'_def)
from currentNode_eq
show "messages' = (case snd (handleClientValue x (nodeState n\<^sub>0)) of None \<Rightarrow> messages | Some m \<Rightarrow> insert \<lparr>sender = n\<^sub>0, destination = Broadcast, payload = m\<rparr> messages)"
unfolding messages'_def result broadcast'_def nodeState'_def by (cases "handleClientValue x (nodeState n\<^sub>0)", cases "snd (handleClientValue x (nodeState n\<^sub>0))", auto)
qed
next
case (PublishRequest i t x)
have result: "result = respond' (handlePublishRequest i t x nd)"
unfolding result_def ProcessMessage_def PublishRequest dest_True by (simp add: respond'_def)
have currentNode_eq: "currentNode (nodeState' n\<^sub>0) = currentNode (nodeState n\<^sub>0)"
unfolding nodeState'_def result by (simp add: handlePublishRequest_def)
show ?thesis
proof (intro zenStep.handlePublishRequest_invariants [OF zenStep])
show "nodeState' n\<^sub>0 = fst (handlePublishRequest i t x (nodeState n\<^sub>0))"
by (simp add: nodeState'_def result)
from currentNode_eq
show "messages' = (case snd (handlePublishRequest i t x (nodeState n\<^sub>0)) of None \<Rightarrow> messages | Some m' \<Rightarrow> insert \<lparr>sender = n\<^sub>0, destination = OneNode (sender m), payload = m'\<rparr> messages)"
unfolding messages'_def result respond'_def nodeState'_def by (cases "handlePublishRequest i t x (nodeState n\<^sub>0)", cases "snd (handlePublishRequest i t x (nodeState n\<^sub>0))", auto)
from m
show "\<exists>d. \<lparr>sender = sender m, destination = d, payload = PublishRequest i t x\<rparr> \<in> messages"
by (auto simp add: PublishRequest isMessageFromTo_def)
qed
next
case (PublishResponse i t)
have result: "result = broadcast' (handlePublishResponse (sender m) i t nd)"
unfolding result_def ProcessMessage_def PublishResponse dest_True by (simp add: broadcast'_def)
show ?thesis
proof (intro zenStep.handlePublishResponse_invariants [OF zenStep])
show "nodeState' n\<^sub>0 = fst (handlePublishResponse (sender m) i t (nodeState n\<^sub>0))"
by (simp add: result nodeState'_def)
show "messages' = (case snd (handlePublishResponse (sender m) i t (nodeState n\<^sub>0)) of None \<Rightarrow> messages | Some m \<Rightarrow> insert \<lparr>sender = n\<^sub>0, destination = Broadcast, payload = m\<rparr> messages)"
by (simp_all add: messages'_def result broadcast'_def handlePublishResponse_def commitIfQuorate_def)
from m
show "\<exists>d. \<lparr>sender = sender m, destination = d, payload = PublishResponse i t\<rparr> \<in> messages"
by (auto simp add: PublishResponse isMessageFromTo_def)
qed
next
case (ApplyCommit i t)
have result: "result = (handleApplyCommit i t nd, None)"
unfolding result_def ProcessMessage_def ApplyCommit dest_True by simp
have currentNode_eq: "currentNode (nodeState' n\<^sub>0) = currentNode (nodeState n\<^sub>0)"
unfolding nodeState'_def result by (cases "lastAcceptedValue nd", simp_all add: handleApplyCommit_def applyAcceptedValue_def)
show ?thesis
proof (intro zenStep.handleApplyCommit_invariants [OF zenStep])
show "nodeState' n\<^sub>0 = handleApplyCommit i t (nodeState n\<^sub>0)"
by (simp add: result nodeState'_def)
show "messages' = messages"
by (simp add: result messages'_def)
from m show "\<exists>s d. \<lparr>sender = s, destination = d, payload = ApplyCommit i t\<rparr> \<in> messages"
by (auto simp add: ApplyCommit isMessageFromTo_def)
qed
next
case Reboot
have result: "result = (handleReboot nd, None)"
unfolding result_def ProcessMessage_def Reboot dest_True by simp
show ?thesis
proof (intro zenStep.handleReboot_invariants [OF zenStep])
show "nodeState' n\<^sub>0 = handleReboot (nodeState n\<^sub>0)"
by (simp add: nodeState'_def result)
show "messages' = messages"
by (simp add: result messages'_def)
qed
next
case DiscardJoinVotes
have result: "result = (handleDiscardJoinVotes nd, None)"
unfolding result_def ProcessMessage_def DiscardJoinVotes dest_True by simp
show ?thesis
proof (intro zenStep.handleDiscardJoinVotes_invariants [OF zenStep])
show "nodeState' n\<^sub>0 = handleDiscardJoinVotes (nodeState n\<^sub>0)"
by (simp add: nodeState'_def result)
show "messages' = messages"
by (simp add: result messages'_def)
qed
next
case CatchUpRequest
have result: "result = respond' (handleCatchUpRequest nd)"
unfolding result_def ProcessMessage_def CatchUpRequest dest_True by (simp add: respond'_def)
have currentNode_eq: "currentNode (nodeState' n\<^sub>0) = currentNode (nodeState n\<^sub>0)"
unfolding nodeState'_def result by (cases "lastAcceptedValue nd", simp_all add: handleCatchUpRequest_def)
show ?thesis
proof (intro zenStep.handleCatchUpRequest_invariants [OF zenStep])
show "nodeState' n\<^sub>0 = fst (handleCatchUpRequest (nodeState n\<^sub>0))"
by (simp add: nodeState'_def result)
show "messages' = (case snd (handleCatchUpRequest (nodeState n\<^sub>0)) of None \<Rightarrow> messages | Some m' \<Rightarrow> insert \<lparr>sender = n\<^sub>0, destination = OneNode (sender m), payload = m'\<rparr> messages)"
by (simp_all add: messages'_def result respond'_def handleCatchUpRequest_def)
qed
next
case (CatchUpResponse i conf cs)
have result: "result = (handleCatchUpResponse i conf cs nd, None)"
unfolding result_def ProcessMessage_def CatchUpResponse dest_True by simp
show ?thesis
proof (intro zenStep.handleCatchUpResponse_invariants [OF zenStep])
show "nodeState' n\<^sub>0 = handleCatchUpResponse i conf cs (nodeState n\<^sub>0)"
by (simp add: nodeState'_def result)
show "messages' = messages"
by (simp add: result messages'_def)
from m show "\<exists>s d. \<lparr>sender = s, destination = d, payload = CatchUpResponse i conf cs\<rparr> \<in> messages"
unfolding CatchUpResponse isMessageFromTo_def by auto
qed
qed
qed
qed
theorem (in zen) invariants_imply_consistent_states:
assumes
"firstUncommittedSlot (nodeState n\<^sub>1) = firstUncommittedSlot (nodeState n\<^sub>2)"
shows
"currentClusterState (nodeState n\<^sub>1) = currentClusterState (nodeState n\<^sub>2)"
proof -
have "currentClusterState (nodeState n\<^sub>1) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n\<^sub>1))"
using currentClusterState_lastCommittedClusterStateBefore .
also have "... = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n\<^sub>2))" using assms by simp
also have "... = currentClusterState (nodeState n\<^sub>2)"
using currentClusterState_lastCommittedClusterStateBefore ..
finally show ?thesis .
qed
end