Theory Friend_Traceback

theory Friend_Traceback
imports Traceback_Intro
begin


subsection ‹Tracing Back Friendship Status›

text ‹We prove the following traceback property:
If, at some point t› on a system trace, the users UID› and UID'› are friends,
then one of the following holds:
\begin{itemize}
\item Either UID› had issued a friend request to UID'›, eventually followed by an approval
(i.e., a successful UID›-friend creation action) by UID'› such that between
that approval and t› there was no successful UID'›-unfriending (i.e., friend deletion)
by UID› or UID›-unfriending by UID'›
\item Or vice versa (with UID› and UID'› swapped)
\end{itemize}

This property is captured by the predicate proper›, which decomposes any valid system trace tr
starting in the initial state
for which the target state tgtOf (last tr)› has UID› and UID'› as friends,
as follows: tr is the concatenation of tr1›, trn›, tr2›, trnn› and tr3› where
\begin{itemize}
\item trn› represents the time of the relevant friend request
\item trnn› represents the time of the approval of this request
\item tr3› contains no unfriending between the two users
\end{itemize}

The main theorem states that proper tr›
holds for any trace tr› that leads to UID› and UID'› being friends.
›

consts UID :: userID
consts UID' :: userID

text SFRC› means ``is a successful friend request creation''›

fun SFRC :: "userID  userID  (state,act,out) trans  bool" where
"SFRC uidd uidd' (Trans s (Cact (cFriendReq uid p uid' _)) ou s') = (ou = outOK  (uid,uid') = (uidd,uidd'))"
|
"SFRC uidd uidd' _ = False"

text SFC› means ``is a successful friend creation'' ›

fun SFC :: "userID  userID  (state,act,out) trans  bool" where
"SFC uidd uidd' (Trans s (Cact (cFriend uid p uid')) ou s') = (ou = outOK  (uid,uid') = (uidd,uidd'))"
|
"SFC uidd uidd' _ = False"

text SFD› means ``is a successful friend deletion'' ›

fun SFD :: "userID  userID  (state,act,out) trans  bool" where
"SFD uidd uidd' (Trans s (Dact (dFriend uid p uid')) ou s') = (ou = outOK  (uid,uid') = (uidd,uidd'))"
|
"SFD uidd uidd' _ = False"

definition proper1 :: "(state,act,out) trans trace  bool" where
"proper1 tr 
  trr trnn tr3. tr = trr @ trnn # tr3 
                 (SFC UID UID' trnn  SFC UID' UID trnn) 
                 never (SFD UID UID') tr3  never (SFD UID' UID) tr3"

lemma SFC_validTrans:
assumes "validTrans trn"
and "¬ UID' ∈∈ friendIDs (srcOf trn) UID"
and "UID' ∈∈ friendIDs (tgtOf trn) UID"
shows "SFC UID UID' trn  SFC UID' UID trn"
proof(cases trn)
  case (Trans s a ou s')
  then show ?thesis
    using assms
    by (cases a) (auto elim: step_elims simp: all_defs)
qed

lemma SFD_validTrans:
assumes "validTrans trn"
and "UID' ∈∈ friendIDs (tgtOf trn) UID"
shows "¬ SFD UID UID' trn  ¬ SFD UID' UID trn"
proof(cases trn)
  case (Trans s a ou s')
  then show ?thesis
    using assms
    by (cases a) (auto elim: step_elims simp: all_defs)
qed

lemma SFC_SFD:
assumes "SFC uid1 uid2 trn" shows "¬ SFD uid3 uid4 trn"
proof(cases trn)
  case (Trans s a ou s') note trn = Trans
  show ?thesis using assms unfolding trn
  by (cases "a") auto
qed

lemma proper1_valid:
assumes "valid tr"
and "¬ UID' ∈∈ friendIDs (srcOf (hd tr)) UID"
and "UID' ∈∈ friendIDs (tgtOf (last tr)) UID"
shows "proper1 tr"
using assms unfolding valid_valid2 proof induct
  case (Singl trn)
  then show ?case unfolding proper1_def using SFC_validTrans
  by (intro exI[of _ "[]"] exI[of _ trn]) auto
next
  case (Rcons tr trn)
  show ?case
  proof(cases "UID' ∈∈ friendIDs (srcOf trn) UID")
    case False
    hence "SFC UID UID' trn  SFC UID' UID trn"
    using Rcons SFC_validTrans by auto
    thus ?thesis unfolding proper1_def
    apply - apply (rule exI[of _ tr]) by (intro exI[of _ trn] exI[of _ "[]"]) auto
  next
    case True
    hence "proper1 tr" using Rcons by auto
    then obtain trr trnn tr3 where
    tr: "tr = trr @ trnn # tr3" and
    SFC: "SFC UID UID' trnn  SFC UID' UID trnn" and
    n: "never (SFD UID UID') tr3  never (SFD UID' UID) tr3"
    unfolding proper1_def by auto
    have "UID' ∈∈ friendIDs (tgtOf trn) UID" using Rcons.prems(2) by auto
    hence SFD: "¬ SFD UID UID' trn  ¬ SFD UID' UID trn"
    using SFD_validTrans validTrans trn by auto
    show ?thesis using SFC n SFD unfolding proper1_def tr
    apply - apply (rule exI[of _ trr])
    by (intro exI[of _ trnn] exI[of _ "tr3 ## trn"]) simp
  qed
qed

lemma istate_friendIDs:
"¬ UID' ∈∈ friendIDs (istate) UID"
unfolding istate_def by simp

lemma proper1_valid_istate:
assumes "valid tr" and "srcOf (hd tr) = istate"
and "UID' ∈∈ friendIDs (tgtOf (last tr)) UID"
shows "proper1 tr"
using assms istate_friendIDs proper1_valid by auto

(*  *)

definition proper2 :: "userID  userID  (state,act,out) trans trace  bool" where
"proper2 uid uid' tr 
  tr1 trnn tr2. tr = tr1 @ trnn # tr2  SFRC uid uid' trnn"

lemma SFRC_validTrans:
assumes "validTrans trn"
and "¬ uid ∈∈ pendingFReqs (srcOf trn) uid'"
and "uid ∈∈ pendingFReqs (tgtOf trn) uid'"
shows "SFRC uid uid' trn"
proof(cases trn)
  case (Trans s a ou s')
  then show ?thesis
    using assms
    by (cases "a") (auto elim: step_elims simp: all_defs)
qed

lemma proper2_valid:
assumes "valid tr"
and "¬ uid ∈∈ pendingFReqs (srcOf (hd tr)) uid'"
and "uid ∈∈ pendingFReqs (tgtOf (last tr)) uid'"
shows "proper2 uid uid' tr"
using assms unfolding valid_valid2 proof induct
  case (Singl trn)
  thus ?case unfolding proper2_def using SFRC_validTrans
  by (intro exI[of _ "[]"] exI[of _ trn]) auto
next
  case (Rcons tr trn)
  show ?case
  proof(cases "uid ∈∈ pendingFReqs (srcOf trn) uid'")
    case False
    hence "SFRC uid uid' trn"
    using Rcons SFRC_validTrans by auto
    thus ?thesis unfolding proper2_def
    apply - apply (rule exI[of _ tr]) by (intro exI[of _ trn] exI[of _ "[]"]) auto
  next
    case True
    hence "proper2 uid uid' tr" using Rcons by auto
    then obtain trr trnn tr3 where
    tr: "tr = trr @ trnn # tr3" and SFRC: "SFRC uid uid' trnn"
    unfolding proper2_def by auto
    have "uid ∈∈ pendingFReqs (tgtOf trn) uid'" using Rcons.prems(2) by auto
    show ?thesis using SFRC unfolding proper2_def tr
    apply - apply (rule exI[of _ trr])
    by (intro exI[of _ trnn] exI[of _ "tr3 ## trn"]) simp
  qed
qed

lemma istate_pendingFReqs:
"¬ uid ∈∈ pendingFReqs (istate) uid'"
unfolding istate_def by simp

lemma proper2_valid_istate:
assumes "valid tr" and "srcOf (hd tr) = istate"
and "uid ∈∈ pendingFReqs (tgtOf (last tr)) uid'"
shows "proper2 uid uid' tr"
using assms istate_pendingFReqs proper2_valid by auto

(*  *)

lemma SFC_pendingFReqs:
assumes "validTrans trn"
and "SFC uid' uid trn"
shows "uid ∈∈ pendingFReqs (srcOf trn) uid'"
proof(cases trn)
  case (Trans s a ou s')
  then show ?thesis
    using assms
    by (cases "a") (auto elim: step_elims simp: all_defs)
qed


definition proper :: "(state,act,out) trans trace  bool" where
"proper tr 
  tr1 trn tr2 trnn tr3. tr = tr1 @ trn # tr2 @ trnn # tr3 
                 (SFRC UID' UID trn  SFC UID UID' trnn 
                  SFRC UID UID' trn  SFC UID' UID trnn) 
                 never (SFD UID UID') tr3  never (SFD UID' UID) tr3"

theorem friend_accountability:
assumes v: "valid tr" and i: "srcOf (hd tr) = istate"
and UID: "UID' ∈∈ friendIDs (tgtOf (last tr)) UID"
shows "proper tr"
proof-
  have "proper1 tr" using proper1_valid_istate[OF assms] .
  then obtain trr trnn tr3 where
  tr: "tr = trr @ trnn # tr3" and
  SFC: "SFC UID UID' trnn  SFC UID' UID trnn" (is "?A  ?B") and
  n: "never (SFD UID UID') tr3  never (SFD UID' UID) tr3"
  unfolding proper1_def by auto
  have trnn: "validTrans trnn" and trr: "valid trr" using tr
  apply (metis valid_Cons_iff append_self_conv2 assms(1) list.distinct(1) valid_append)
  by (metis SFC SFC_pendingFReqs append_self_conv2 i istate_pendingFReqs list.distinct(1) list.sel(1) tr v valid_Cons_iff valid_append)
  show ?thesis using SFC proof
    assume SFC: ?A
    have 0: "UID' ∈∈ pendingFReqs (srcOf trnn) UID"
    using SFC_pendingFReqs[OF trnn SFC] .
    hence "srcOf trnn  istate" unfolding istate_def by auto
    hence 2: "trr  []" using i unfolding tr by auto
    hence i: "srcOf (hd trr) = istate" using i unfolding tr by auto
    have "srcOf trnn = tgtOf (last trr)" using tr v valid_append 2 by auto
    hence 1: "UID' ∈∈ pendingFReqs (tgtOf (last trr)) UID" using 0 by simp
    have "proper2 UID' UID trr" using proper2_valid_istate[OF trr i 1] .
    then obtain tr1 trn tr2 where
    trr: "trr = tr1 @ trn # tr2" and SFRC: "SFRC UID' UID trn"
    unfolding proper2_def by auto
    show ?thesis unfolding proper_def
    apply(rule exI[of _ tr1], rule exI[of _ trn], rule exI[of _ tr2],
          rule exI[of _ trnn], rule exI[of _ tr3])
    unfolding tr trr using SFRC SFC n by simp
  next
    assume SFC: ?B
    have 0: "UID ∈∈ pendingFReqs (srcOf trnn) UID'"
    using SFC_pendingFReqs[OF trnn SFC] .
    hence "srcOf trnn  istate" unfolding istate_def by auto
    hence 2: "trr  []" using i unfolding tr by auto
    hence i: "srcOf (hd trr) = istate" using i unfolding tr by auto
    have "srcOf trnn = tgtOf (last trr)" using tr v valid_append 2 by auto
    hence 1: "UID ∈∈ pendingFReqs (tgtOf (last trr)) UID'" using 0 by simp
    have "proper2 UID UID' trr" using proper2_valid_istate[OF trr i 1] .
    then obtain tr1 trn tr2 where
    trr: "trr = tr1 @ trn # tr2" and SFRC: "SFRC UID UID' trn"
    unfolding proper2_def by auto
    show ?thesis unfolding proper_def
    apply(rule exI[of _ tr1], rule exI[of _ trn], rule exI[of _ tr2],
          rule exI[of _ trnn], rule exI[of _ tr3])
    unfolding tr trr using SFRC SFC n by simp
  qed
qed



end