aneris_examples.ccddb.examples.session_guarantees.mr

From iris.algebra Require Import agree gmap auth.
From iris.proofmode Require Import tactics.
From aneris.aneris_lang Require Import
     lang network notation tactics proofmode lifting.
From aneris.aneris_lang.lib Require Import lock network_helpers.
From aneris.aneris_lang.lib.serialization Require Import serialization.
From aneris_examples.ccddb.spec Require Import spec resources.
From aneris_examples.ccddb.examples.session_guarantees
     Require Import res sm_code sm_proof.
From aneris_examples.ccddb Require Import spec_util.

Import Network.

Context `{!anerisG Σ, !lockG Σ}.
Context `{!DB_params}.
Context `{!DB_time, !DB_events}.
Context `{!DB_resources Σ}.
Context `{!Maximals_Computing}.
Context `{!inG Σ (authUR (gmapUR nat (agreeR (leibnizO log_req))))}.

Section MonotonicReads.

  (* We assume that the set of db keys is non-empty and we know one of the keys *)
  Variable key : Key.
  Hypothesis Hkey_valid : key DB_keys.

  (* Monotonic reads example *)
  Definition mr_example : base_lang.val :=
    λ: "client_addr" "server_addr",
    let: "ops" := sm_setup "client_addr" in
    let: "init_fn" := Fst (Fst "ops") in
    let: "read_fn" := Snd (Fst "ops") in
    let: "write_fn" := Snd "ops" in
    "init_fn" "server_addr";;
    let: "v1" := "read_fn" "server_addr" #key in
    let: "v2" := "read_fn" "server_addr" #key in
    ("v1", "v2").

  Theorem mr_example_spec (A : gset socket_address) (ca sa : socket_address) (db_id : rep_id) :
    {{{ fixed A
         sa A
         sa (db_si db_id)
         ca A
         free_ports (ip_of_address ca) {[ port_of_address ca ]}
    }}}

      mr_example #ca #sa @[ip_of_address ca]

   {{{ p, RET p;
        vo1 vo2,
         (p = (vo1, vo2)%V)
            ((* Both reads return NONE, and the db's entry for the key is empty *)
              ( s,
                  (vo1 = NONEV)
                     (vo2 = NONEV)
                     Seen db_id s
                     (restrict_key key s = ))
              
              ((* The first read returns NONE, and the second returns a value with maximal
                timestamp *)

                 s v2 e,
                (vo1 = NONEV)
                   (vo2 = SOMEV v2)
                   Seen db_id s
                   (e.(AE_key) = key)
                   (e.(AE_val) = v2)
                   (e Maximals (restrict_key key s))
              )
              
              ((* Both reads return some value, and the second read returns a value that's not
                older than the first one (could be the same, more recent, or incomparable) *)

                 s v1 v2 e1 e2,
                  (vo1 = SOMEV v1)
                     (vo2 = SOMEV v2)
                     Seen db_id s
                     (e1.(AE_key) = key)
                     (e1.(AE_val) = v1)
                     (e2.(AE_key) = key)
                     (e2.(AE_val) = v2)
                     (e2 Maximals (restrict_key key s))
                     (¬ (e2 <ₜe1))
              )
   ) }}}.
  Proof.
    iIntros (ϕ) "(#Hfixed & #Hsa & #Hsi & #Hca & Hfree) Hcont".
    wp_lam. wp_pures.
    wp_apply (sm_setup_spec with "[$Hfree $Hfixed $Hca]").
    iIntros (fns) "Hpre".
    iDestruct "Hpre" as (init_fn read_fn write_fn)
                          "(-> & #Hinit_spec & #Hread_spec & #Hwrite_spec)".
    wp_pures.
    (* Init *)
    wp_apply ("Hinit_spec" with "[$Hsi]").
    rewrite /init_post.
    iIntros "Hinit". iDestruct "Hinit" as (s) "(#Hseen & #Hkeys & _)".
    (* Get snapshot for the key we want to read *)
    iAssert ( h : gmem, OwnMemSnapshot key h)%I as "#Hsnap";
    first by iDestruct (big_sepS_delete _ _ _ Hkey_valid with "Hkeys") as "[Hkey _]".
    iDestruct "Hsnap" as (h) "#Hsnap".
    (* First read *)
    wp_apply ("Hread_spec" with "[$Hsi $Hseen $Hsnap]"); [by iPureIntro |].
    iIntros (vo) "Hreadpost".
    rewrite /read_post.
    iDestruct "Hreadpost" as (s' h') "(#Hss' & #Hhh' & #Hseen' & #Hsnap' & [[-> #Hrestrict'] | Hsome'])"; simpl; wp_pures.
    - (* First read returns NONE *)
      (* Second read *)
      wp_apply ("Hread_spec" with "[$Hsi $Hseen' $Hsnap']"); [by iPureIntro |].
      iIntros (vo) "Hreadpost".
      rewrite /read_post.
      iDestruct "Hreadpost" as (s'' h'') "(#Hss'' & #Hhh'' & #Hseen'' & #Hsnap'' & [[-> #Hrestrict''] | Hsome''])"; wp_pures; iApply "Hcont".
      * (* Second read returns NONE *)
        iExists _, _. iSplit; first by iPureIntro.
        iLeft; eauto.
      * (* Second read returns SOME *)
        iExists _, _. iSplit; first by eauto.
        iDestruct "Hsome''" as (e2 v2) "(-> & #Hval2 & #Hkey2 & #Hmax2 & _)".
        iRight. iLeft. iExists _, _, _.
        iFrame "#". eauto.
    - (* First read returns SOME *)
      (* Second read *)
      wp_apply ("Hread_spec" with "[$Hsi $Hseen' $Hsnap']"); [by iPureIntro |].
      iIntros (vo2) "Hreadpost".
      rewrite /read_post.
      iDestruct "Hreadpost" as (s'' h'') "(#Hss'' & #Hhh'' & #Hseen'' & #Hsnap'' & [[-> #Hrestrict''] | Hsome''])"; wp_pures; iApply "Hcont".
      * (* Second read returns NONE: contradiction *)
        iDestruct "Hrestrict''" as %Hrestrict''.
        iDestruct "Hss''" as %Hss''.
        iDestruct "Hsome'" as (e' v') "(_ & #Hv' & #Hk' & #Hmax' & _)".
        iDestruct "Hmax'" as %Hmax'.
        exfalso.
        apply elem_of_Maximals in Hmax'.
        apply (restrict_key_mono _ _ _ _ Hss'') in Hmax'.
        set_solver.
      * (* Second read returns SOME *)
        iExists _, _.
        iSplit; first auto.
        iRight; iRight.
        iDestruct "Hsome'" as (e' v') "(-> & #Hv1 & #Hk1 & #Hmax1 & _)".
        iDestruct "Hsome''" as (e'' v'') "(-> & #Hv2 & #Hk2 & #Hmax2 & _)".
        iExists _, v', v'', e', e''.
        do 2 (iSplit; first auto).
        iFrame "#".
        iDestruct "Hmax2" as %Hmax2.
        iDestruct "Hmax1" as %Hmax1.
        iDestruct "Hss''" as %Hss''.
        iPureIntro.
        apply elem_of_Maximals in Hmax1.
        apply (restrict_key_mono _ _ _ _ Hss'') in Hmax1.
        apply Maximals_correct in Hmax2.
        destruct Hmax2 as (_ & Hforall).
          by apply Hforall.
    Qed.

End MonotonicReads.