Timings for apply_proof.v
- /home/gitlab-runner/builds/v6HyzL39/0/coq/coq/_bench/opam.OLD/ocaml-OLD/.opam-switch/build/coq-perennial.dev/./src/program_proof/vrsm/replica/apply_proof.v.timing
- /home/gitlab-runner/builds/v6HyzL39/0/coq/coq/_bench/opam.NEW/ocaml-NEW/.opam-switch/build/coq-perennial.dev/./src/program_proof/vrsm/replica/apply_proof.v.timing
From Perennial.base_logic Require Import lib.saved_prop.
From Perennial.program_proof Require Import grove_prelude.
From Perennial.goose_lang.lib Require Import waitgroup.
From iris.base_logic Require Export lib.ghost_var mono_nat.
From iris.algebra Require Import dfrac_agree mono_list.
From Perennial Require Import replica.protocol replica.definitions
replica.applybackup_proof replica.increasecommit_proof.
From Perennial.program_proof.reconnectclient Require Import proof.
From RecordUpdate Require Import RecordSet.
Import RecordSetNotations.
Context {params:pbParams.t}.
Lemma wp_Clerk__Apply γ γsrv ck op_sl q op (op_bytes:list u8) (Φ:val → iProp Σ) :
has_op_encoding op_bytes op →
is_Clerk ck γ γsrv -∗
own_slice_small op_sl byteT q op_bytes -∗
□((|={⊤∖↑pbN,∅}=> ∃ ops, own_int_log γ ops ∗
(⌜apply_postcond ops op⌝ -∗ own_int_log γ (ops ++ [op]) ={∅,⊤∖↑pbN}=∗
(∀ reply_sl, own_slice_small reply_sl byteT 1 (compute_reply ops op) -∗
own_slice_small op_sl byteT q op_bytes -∗
Φ (#(U64 0), slice_val reply_sl)%V)))
∗
(∀ (err:u64) unused_sl, ⌜err ≠ 0⌝ -∗ own_slice_small op_sl byteT q op_bytes -∗
Φ (#err, (slice_val unused_sl))%V )) -∗
WP Clerk__Apply #ck (slice_val op_sl) {{ Φ }}.
wp_apply (wp_ref_of_zero).
rewrite is_pb_rpcs_unfold.
wp_apply (wp_ReconnectingClient__Call2 with "Hcl_rpc [] Hop_sl Hrep").
iDestruct "Hsrv" as "[_ [_ [_ [_ [$ _]]]]]".
iDestruct "HΦ" as (?) "[Hlog HΦ]".
iMod ("HΦ" with "[//] Hlog") as "HΦ".
iIntros (? Hreply_enc) "Hop".
iIntros (?) "Hrep Hrep_sl".
wp_apply (ApplyReply.wp_Decode with "[Hrep_sl]").
iIntros (reply_ptr) "Hreply".
iApply ("HΦ" with "Hrepy_ret_sl Hop").
(* Apply failed for some reason, e.g. node is not primary *)
iIntros (Herr_nz ? Hreply_enc) "Hop".
iIntros (?) "Hrep Hrep_sl".
wp_apply (ApplyReply.wp_Decode with "[$Hrep_sl]").
iIntros (reply_ptr) "Hreply".
iApply ("HΦ" with "[] Hop").
replace (slice.nil) with (slice_val Slice.nil) by done.
iApply ("HΦ" with "[] [$]").
(*
Definition entry_pred_conv (σ : list (OpType * (list OpType → iProp Σ)))
(σgnames : list (OpType * gname)) : iProp Σ :=
⌜ σ.*1 = σgnames.*1 ⌝ ∗
[∗ list] k↦Φ;γ ∈ snd <$> σ; snd <$> σgnames, saved_pred_own γ DfracDiscarded Φ.
Definition is_ghost_lb' γ σ : iProp Σ :=
∃ σgnames, is_ghost_lb γ σgnames ∗ entry_pred_conv σ σgnames. *)
Lemma apply_eph_primary_step γ γsrv ops canBecomePrimary epoch committedNextIndex op Q :
apply_postcond (get_rwops ops) op →
(|={⊤∖↑ghostN,∅}=> ∃ σ, own_pb_log γ.(s_pb) σ ∗
(⌜apply_postcond (get_rwops σ) op⌝ -∗ own_pb_log γ.(s_pb) (σ ++ [(op, Q)]) ={∅,⊤∖↑ghostN}=∗ True)) -∗
£ 1 -∗
own_Primary_ghost_f γ γsrv canBecomePrimary true epoch committedNextIndex ops
={⊤∖↑pbAofN}=∗
own_Primary_ghost_f γ γsrv canBecomePrimary true epoch committedNextIndex (ops ++ [(op, Q)]) ∗
is_proposal_lb γ.(s_pb) epoch (ops ++ [(op, Q)]) ∗
is_proposal_facts γ.(s_pb) epoch (ops ++ [(op, Q)]) ∗
is_proposal_facts_prim γ.(s_prim) epoch (ops ++ [(op, Q)])
.
iIntros (?) "Hupd Hlc Hprim".
rewrite /own_Primary_ghost_f /tc_opaque.
iMod (fupd_mask_subseteq _);
last iMod (ghost_propose with "Hlc Hprim [Hupd]") as "(Hprim & #? & #?)".
iMod "Hupd" as (?) "[? Hupd]".
(* XXX: This is the point of having σ = ops? *)
iDestruct (is_proposal_facts_prim_mono with "Hprim_facts") as "#$".
Lemma apply_eph_step γ γsrv st op Q :
apply_postcond (get_rwops st.(server.ops_full_eph)) op →
st.(server.isPrimary) = true →
st.(server.sealed) = false →
£ 1 -∗
(|={⊤∖↑ghostN,∅}=> ∃ σ, own_pb_log γ.(s_pb) σ ∗
(⌜apply_postcond (get_rwops σ) op⌝ -∗ own_pb_log γ.(s_pb) (σ ++ [(op, Q)]) ={∅,⊤∖↑ghostN}=∗ True)) -∗
own_Server_ghost_eph_f st γ γsrv
={⊤∖↑pbAofN}=∗
own_Server_ghost_eph_f (st <| server.ops_full_eph := st.(server.ops_full_eph) ++ [(op, Q)] |>)
γ γsrv ∗
is_proposal_lb γ.(s_pb) st.(server.epoch) (st.(server.ops_full_eph) ++ [(op, Q)]) ∗
is_proposal_facts γ.(s_pb) st.(server.epoch) (st.(server.ops_full_eph) ++ [(op, Q)]) ∗
is_proposal_facts_prim γ.(s_prim) st.(server.epoch) (st.(server.ops_full_eph) ++ [(op, Q)]) ∗
is_epoch_lb γsrv.(r_pb) st.(server.epoch)
.
intros ? Hprim Hunsealed.
iIntros "Hlc Hupd Hghost".
rewrite /own_Server_ghost_eph_f /tc_opaque /=.
iMod (apply_eph_primary_step with "Hupd Hlc Hprimary") as "(Hprimary & #? & #? & #?)".
Definition own_slice_elt {V} {H:IntoVal V} (sl:Slice.t) (idx:u64) typ q (v:V) : iProp Σ :=
(sl.(Slice.ptr) +ₗ[typ] (int.Z idx)) ↦[typ]{q} (to_val v).
Lemma slice_elements_split {V} {H:IntoVal V} sl typ q (l:list V):
own_slice_small sl typ q l -∗
[∗ list] i ↦ v ∈ l, own_slice_elt sl i typ q v.
rewrite /own_slice_small /slice.own_slice_small.
iDestruct "Hsl" as "(Hsl & #Hsz & #Hcap)".
iAssert (⌜int.Z sz <= 2^64⌝%Z)%I with "[]" as "#Hsz2".
iInduction l as [|] "IH" forall (ptr sz).
iDestruct (array_cons with "Hsl") as "[Helt Hsl]".
replace (ty_size typ * int.Z 0%nat)%Z with (0%Z) by word.
iSpecialize ("IH" $! (ptr +ₗ[typ] 1) with "[] [Hsl] []").
rewrite cons_length in H1.
instantiate (1:=(word.sub sz 1)).
iExactEq "Hsl"; repeat f_equal; word.
generalize (word.sub sz 1).
iApply (big_sepL_impl with "[$]").
replace (int.Z (S k)) with (1 + int.Z k)%Z.
rewrite cons_length fmap_length in H1.
apply lookup_lt_Some in H2.
Lemma wp_SliceSet_elt {V typ} `{!IntoVal V} `{!IntoValForType V typ} (sl:Slice.t) (i:u64) (v v':V) :
{{{
own_slice_elt sl i typ 1 v
}}}
SliceSet typ (slice_val sl) #i (to_val v')
{{{
RET #(); own_slice_elt sl i typ 1 v'
}}}.
wp_apply (wp_StoreAt with "[$Hown]").
Lemma wp_forSlice' {V} {H:IntoVal V} ϕ I sl ty q (l:list V) (body:val) :
(∀ (i:u64) (v:V),
{{{
⌜int.nat i < length l⌝ ∗ ⌜l !! (int.nat i) = Some v⌝ ∗ ϕ (int.nat i) v ∗ I i
}}}
body #i (to_val v)
{{{
RET #(); I (word.add i 1)
}}}
) -∗
{{{
own_slice_small sl ty q l ∗
([∗ list] i ↦ v ∈ l, ϕ i v) ∗
I 0
}}}
forSlice ty body (slice_val sl)
{{{
RET #(); I (length l)
}}}
.
iIntros (?) "!# (Hsl & Hl & HI) HΦ".
iDestruct (own_slice_small_sz with "Hsl") as %Hsz.
wp_apply (wp_forSlice (λ i, I i ∗ [∗ list] j ↦ v ∈ (drop (int.nat i) l), ϕ (j + int.nat i) v) %I
with "[] [$Hsl Hl HI]").
replace (int.nat (U64 0)) with (0) by word.
setoid_rewrite <- plus_n_O.
iIntros (???Φ) "!# ([HI Hl] & % & %) HΦ".
assert ((drop (int.nat i) l) !! 0 = Some x) as ?.
iDestruct (big_sepL_take_drop _ _ 1 with "Hl") as "[Hϕ Hl]".
wp_apply ("Hwp" with "[HI Hϕ]").
iDestruct (big_sepL_lookup_acc with "Hϕ") as "[H _]".
replace (int.nat (u64_instance.u64.(word.add) i 1%Z)) with (int.nat i + 1) by word.
iApply (big_sepL_impl with "Hl").
replace (k + (int.nat i + 1)) with (1 + k + int.nat i) by word.
Lemma establish_committed_log_fact γ epoch σ :
committed_by γ.(s_pb) epoch σ -∗
is_proposal_lb γ.(s_pb) epoch σ -∗
□ committed_log_fact γ epoch σ.
iIntros "#Hcom #Hprop_lb".
iIntros (????) "#Hprop_lb2 #Hprop_facts2".
destruct (decide (int.nat epoch = int.nat epoch')).
assert (epoch = epoch'); last subst.
destruct H0; last by lia.
by iDestruct (fmlist_ptsto_lb_longer with "Hprop_lb Hprop_lb2") as %?.
iDestruct "Hprop_facts2" as "[Hmax _]".
Local Instance a x y : Decision (apply_postcond x y).
apply pb_record.(Sm.apply_postcond_dec).
Lemma become_backup st γ γsrv :
own_Server_ghost_eph_f st γ γsrv -∗
own_Server_ghost_eph_f (st <| server.isPrimary := false |>) γ γsrv
.
rewrite /own_Server_ghost_eph_f /tc_opaque.
repeat iExists _; iFrame "∗#%".
rewrite /own_Primary_ghost_f /tc_opaque /=.
Lemma wp_Server__Apply_internal (s:loc) γ γsrv op_sl op_bytes op Q :
{{{
is_Server s γ γsrv ∗
readonly (own_slice_small op_sl byteT 1 op_bytes) ∗
⌜has_op_encoding op_bytes op⌝ ∗
(£ 1 -∗ £ 1 -∗ |={⊤∖↑ghostN,∅}=> ∃ σ, own_pb_log γ.(s_pb) σ ∗
(⌜apply_postcond (get_rwops σ) op⌝ -∗ own_pb_log γ.(s_pb) (σ ++ [(op, Q)]) ={∅,⊤∖↑ghostN}=∗ True))
}}}
Server__Apply #s (slice_val op_sl)
{{{
reply_ptr reply, RET #reply_ptr; £ 1 ∗ £ 1 ∗ £ 1 ∗ ApplyReply.own_q reply_ptr reply ∗
if (decide (reply.(ApplyReply.err) = 0%Z)) then
∃ opsfull,
let ops := (get_rwops opsfull) in
⌜reply.(ApplyReply.ret) = compute_reply ops op⌝ ∗
is_pb_log_lb γ.(s_pb) (opsfull ++ [(op, Q)])
else
True
}}}
.
iIntros (Φ) "[#His Hpre] HΦ".
iDestruct "Hpre" as "(#Hsl & %Hghostop_op & Hupd)".
wp_pure1_credit "Hcred3".
wp_apply (wp_allocStruct).
iIntros (reply_ptr) "Hreply".
iDestruct (struct_fields_split with "Hreply") as "HH".
replace (slice.nil) with (slice_val (Slice.nil)) by done.
wp_apply (acquire_spec with "HmuInv").
iIntros "[Hlocked Hown]".
wp_pure1_credit "Hcred1".
wp_pure1_credit "Hcred2".
iSpecialize ("Hupd" with "Hlc1 Hlc2").
(* return error "not primary" *)
wp_apply (release_spec with "[-HΦ Err Reply Hcred1 Hcred2 Hcred3]").
iSplitR "HghostEph"; last iFrame.
iFrame "Hstate ∗#"; iFrame "%".
instantiate (1:=(ApplyReply.mkC _ _)).
iApply own_slice_small_nil.
wp_apply (release_spec with "[-HΦ Err Reply Hcred1 Hcred2 Hcred3]").
iSplitR "HghostEph"; last iFrame.
iApply ("HΦ" $! _ (ApplyReply.mkC 1 [])).
iApply own_slice_small_nil.
(* XXX: this is ultimately to support the statemachine code making
"assumptions" by providing a non-trivial post-condition. E.g. if the state
machine apply() function loops forever when integer overflow occurs.
*)
destruct (decide (apply_postcond (get_rwops st.(server.ops_full_eph)) op)).
iDestruct (is_StateMachine_acc_apply with "HisSm") as "HH".
wp_apply ("HapplySpec" with "[HisSm $Hstate $Hsl]").
(* make ephemeral proposal *)
iMod (fupd_mask_subseteq (⊤∖↑pbAofN)) as "Hmask".
iMod (apply_eph_step with "Hlc Hupd HghostEph") as "(HghostEph & #Hprop_lb & #Hprop_facts & #Hprim_facts & #Hepoch_lb)".
iDestruct (is_StateMachine_acc_apply with "HisSm") as "HH".
wp_apply ("HapplySpec" with "[HisSm $Hstate $Hsl]").
iMod (applybackup_step with "Hprop_lb Hprop_facts Hprim_facts Hghost") as "Hghost".
rewrite /get_rwops fmap_app /=.
iIntros (reply_sl q waitFn) "(%Hop_post & Hreply & Hstate & HwaitSpec)".
wp_apply (std_proof.wp_SumAssumeNoOverflow).
wp_apply (release_spec with "[-HΦ Hreply Err Reply Hcred1 Hcred2 Hcred3 HwaitSpec]").
iSplitR "HghostEph"; last iFrame.
rewrite /= Heqb Heqb0 /=.
replace (get_rwops (st.(server.ops_full_eph) ++ [(op, Q)])) with (get_rwops st.(server.ops_full_eph) ++ [op]); last first.
unfold no_overflow in HnextIndexNoOverflow.
unfold no_overflow in HnextIndexNoOverflow |- *.
wp_apply (wp_NewWaitGroup_free).
wp_apply (wp_allocStruct).
iDestruct (struct_fields_split with "Hargs") as "HH".
iMod (readonly_alloc_1 with "epoch") as "#Hargs_epoch".
iMod (readonly_alloc_1 with "index") as "#Hargs_index".
iMod (readonly_alloc_1 with "op") as "#Hargs_op".
iDestruct "Hprimary" as "[%Hbad|Hprimary]"; first by exfalso.
iMod (readonly_load with "Hclerkss_sl") as (?) "Hclerkss_sl2".
iDestruct (own_slice_small_sz with "Hclerkss_sl2") as %Hclerkss_sz.
wp_apply (wp_RandomUint64).
set (clerkIdx:=(word.modu randint clerks_sl.(Slice.sz))).
assert (int.nat clerkIdx < length clerkss) as Hlookup_clerks.
(* FIXME: better lemmas about mod? *)
rewrite Hclerkss_len in Hclerkss_sz.
replace (clerks_sl.(Slice.sz)) with (U64 (32)); last first.
unfold numClerks in Hclerkss_sz.
enough (int.Z randint `mod` 32 < int.Z 32)%Z.
assert (∃ clerks_sl_inner, clerkss !! int.nat clerkIdx%Z = Some clerks_sl_inner) as [clerks_sl_inner Hclerkss_lookup].
wp_apply (wp_SliceGet with "[$Hclerkss_sl2]").
iIntros (errs_sl) "Herrs_sl".
iMod (fupd_mask_subseteq (↑pbN)) as "Hmask".
iMod (free_WaitGroup_alloc pbN _
(λ i,
∃ (err:u64) γsrv',
⌜backups !! int.nat i = Some γsrv'⌝ ∗
readonly (own_slice_elt errs_sl i uint64T 1 err) ∗
□ if (decide (err = U64 0)) then
is_accepted_lb γsrv'.(r_pb) st.(server.epoch) (st.(server.ops_full_eph) ++ [_])
else
True
)%I
with "Hwg") as (γwg) "Hwg".
iDestruct (big_sepL_lookup_acc with "Hclerkss_rpc") as "[Hclerks_rpc _]".
iDestruct (own_slice_to_small with "Herrs_sl") as "Herrs_sl".
iMod (readonly_load with "Hclerks_sl") as (?) "Hclerks_sl2".
iDestruct (own_slice_small_sz with "Hclerks_sl2") as %Hclerks_sz.
wp_apply (wp_forSlice' _ (λ j, (own_WaitGroup pbN wg γwg j _))%I with "[] [$Hwg Herrs_sl $Hclerks_sl2]").
iDestruct (slice_elements_split with "Herrs_sl") as "Herrs".
iDestruct (big_sepL2_const_sepL_r _ clerks with "[$Herrs]") as "Herrs".
by rewrite replicate_length.
rewrite big_sepL2_replicate_r; last done.
iDestruct (big_sepL2_to_sepL_1 with "Hclerks_rpc") as "H2".
iDestruct (big_sepL_sep with "[$Herrs]") as "$".
iIntros (Φ) "!# (% & %Hlookup & Hϕ & Hwg) HΦ".
iRename "Hepoch_lb" into "Hlocal_epoch_lb".
iDestruct "Hϕ" as "(Herr & (% & (% & #Hck & #Hepoch_lb)))".
wp_apply (wp_WaitGroup__Add with "[$Hwg]").
iDestruct (own_WaitGroup_to_is_WaitGroup with "[$Hwg]") as "#His_wg".
wp_apply (wp_fork with "[Hwg_tok Herr]").
wp_apply (wp_Clerk__ApplyAsBackup with "[$Hck $Hepoch_lb]").
iFrame "Hprop_lb Hprop_facts #".
rewrite /no_overflow in Hno_overflow HnextIndexNoOverflow.
rewrite /get_rwops fmap_app app_length.
rewrite HnextIndexNoOverflow /get_rwops.
wp_bind (#(bool_decide _) || _)%E.
wp_apply (wp_or with "[]"); first iAccu.
iEval (replace (#err) with (to_val err) by done).
replace (U64 (int.nat i)) with (i) by word.
wp_apply (wp_SliceSet_elt with "Herr").
iSplitR; first by iPureIntro.
iMod (readonly_alloc_1 with "Herr") as "#Herr_ptr".
wp_apply (wp_WaitGroup__Done with "[$Hwg_tok $His_wg Herr_ptr Hpost]").
wp_apply (wp_WaitGroup__Wait with "Hwg").
iIntros "Hprimary_acc_lb".
iDestruct "Hprimary_acc_lb" as "(_ & _ & #Hprimary_acc_lb)".
iIntros (err_ptr) "Herr".
set (conf:=(γsrv::backups)).
iAssert (∃ (j err:u64),
"Hj" ∷ j_ptr ↦[uint64T] #j ∗
"%Hj_ub" ∷ ⌜int.nat j ≤ length clerks⌝ ∗
"Herr" ∷ err_ptr ↦[uint64T] #err ∗
"#Hrest" ∷ □ if (decide (err = (U64 0)%Z)) then
(∀ (k:u64) γsrv', ⌜int.nat k ≤ int.nat j⌝ -∗ ⌜conf !! (int.nat k) = Some γsrv'⌝ -∗
is_accepted_lb γsrv'.(r_pb) st.(server.epoch) (st.(server.ops_full_eph) ++ [_]))
else
True
)%I with "[Hi Herr]" as "Hloop".
replace (int.nat 0%Z) with (0) in H by word.
replace (int.nat k) with (0) in H0 by word.
iFrame "Hprimary_acc_lb".
iMod (readonly_load with "Hclerks_sl") as (?) "Htemp".
iDestruct (own_slice_small_sz with "Htemp") as %Hclerk_sz.
iDestruct (big_sepS_elem_of_acc _ _ j with "Hwg_post") as "[HH _]".
iDestruct "HH" as "[%Hbad|HH]".
rewrite Hclerks_sz in Hbad.
eassert (int.nat (int.nat (_:u64)) = int.nat (_:u64)) as ->.
instantiate (1:=clerks_sl_inner.(Slice.sz)).
iDestruct "HH" as (??) "(%HbackupLookup & Herr2 & Hpost)".
iEval (simpl) in "Herr2".
iMod (readonly_load with "Herr2") as (?) "Herr3".
destruct (bool_decide (_)) as [] eqn:Herr; wp_pures.
rewrite bool_decide_eq_true in Herr.
replace (err0) with (U64 0%Z) by naive_solver.
destruct (decide (err = 0%Z)).
assert (int.nat k ≤ int.nat j ∨ int.nat k = int.nat (word.add j 1%Z)) as [|].
replace (int.nat (word.add j 1%Z)) with (int.nat j + 1) in * by word.
destruct (decide (_)); last by exfalso.
replace (γsrv'0) with (γsrv'); last first.
replace (int.nat (word.add j 1%Z)) with (S (int.nat j)) in H0 by word.
rewrite lookup_cons in H0.
rewrite H0 in HbackupLookup.
iDestruct "Hpost" as "#$".
destruct (decide (err0 = _)).
destruct (decide (err = 0%Z)); last first.
rewrite bool_decide_false; last naive_solver.
wp_apply (acquire_spec with "[$]").
iIntros "[Hlocked Hown]".
iClear "HopAppliedConds_conds HcommittedNextIndex_is_cond HisSm HisPrimary_is_cond".
iDestruct (become_backup with "HghostEph") as "HghostEph".
wp_apply (release_spec with "[-HΦ Hreply Err Reply Hcred1 Hcred2 Hcred3]").
repeat iExists _; iSplitR "HghostEph"; last iFrame.
repeat iExists _; iFrame "∗#".
iApply ("HΦ" $! reply_ptr (ApplyReply.mkC _ _)).
rewrite decide_False; last naive_solver.
wp_apply (release_spec with "[-HΦ Hreply Err Reply Hcred1 Hcred2 Hcred3]").
repeat iExists _; iSplitR "HghostEph"; last iFrame.
repeat iExists _; iFrame "∗#".
iApply ("HΦ" $! reply_ptr (ApplyReply.mkC _ _)).
rewrite decide_False; last naive_solver.
(* otherwise, no error *)
iAssert (committed_by γ.(s_pb) st.(server.epoch) _) with "[]" as "#HcommitBy".
rewrite elem_of_list_fmap in H.
destruct H as (? & ? & H).
apply elem_of_list_lookup_1 in H as [k Hlookup_conf].
replace (int.nat j) with (length clerks); last first.
epose proof (lookup_lt_Some _ _ _ Hlookup_conf) as HH.
replace (k) with (int.nat k) in *; last first.
rewrite cons_length /= in HH.
rewrite -Hclerks_conf in HH.
(* FIXME: why manually rewrite? *)
rewrite cons_length in HH.
iMod (ghost_commit with "His_repl_inv HcommitBy Hprop_lb Hprop_facts") as "#Hcommit".
rewrite bool_decide_true; last naive_solver.
wp_apply (wp_Server__IncreaseCommit with "[] [-] []").
repeat iExists _; iFrame "#".
instantiate (1:=(λ _, True)%I).
instantiate (1:=ApplyReply.mkC _ _).
repeat iExists _; iFrame.
destruct (decide _); last first.
iExists _; iFrame "Hcommit".
rewrite fmap_length app_length /=.
rewrite fmap_length in Hno_overflow HnextIndexNoOverflow.
iApply establish_committed_log_fact.
(* this is from the "doomed" path in the proof. *)
Lemma wp_Server__Apply (s:loc) γ γsrv op_sl op (enc_op:list u8) Ψ (Φ: val → iProp Σ) :
is_Server s γ γsrv -∗
readonly (own_slice_small op_sl byteT 1 enc_op) -∗
(∀ reply, Ψ reply -∗ ∀ reply_ptr, ApplyReply.own_q reply_ptr reply -∗ Φ #reply_ptr) -∗
Apply_core_spec γ op enc_op Ψ -∗
WP (Server__Apply #s (slice_val op_sl)) {{ Φ }}
.
iApply (wp_frame_wand with "HΨ").
iDestruct "HΦ" as "(%Hop_enc & #Hupd & Hfail_Φ)".
iMod (ghost_var_alloc (())) as (γtok) "Htok".
set (OpPred :=
(λ ops, inv escrowN (
Ψ (ApplyReply.mkC 0 (compute_reply ops op)) ∨
ghost_var γtok 1 ()
))).
iMod (saved_pred_alloc OpPred DfracDiscarded) as (γghost_op) "#Hsaved"; first done.
wp_apply (wp_Server__Apply_internal _ _ _ _ _ op γghost_op
with "[$Hsrv $Hop_sl Hupd]").
iSplitR; first by iPureIntro.
iDestruct (propose_rw_op_valid _ _ _ _
(λ σ, apply_postcond (get_rwops σ) op)
with "Hlc [$] [Hupd]") as "$".
iInv "HhelpingInv" as "HH" "Hclose".
iDestruct "HH" as (?) "(Hghost & >Hlog & #HQs)".
iDestruct "Hghost" as (σgnames) "(>Hghost&>%Hfst_eq&#Hsaved')".
iMod (fupd_mask_subseteq (⊤∖↑pbN)) as "Hmask".
iDestruct "Hupd" as (σ0) "[Hlog2 Hupd]".
iDestruct (own_valid_2 with "Hlog Hlog2") as %Hvalid.
apply mono_list_auth_dfrac_op_valid_L in Hvalid.
destruct Hvalid as [_ <-].
iMod (own_update_2 with "Hlog Hlog2") as "Hlog".
rewrite -mono_list_auth_dfrac_op.
instantiate (1:=_ ++ [op]).
iEval (rewrite -Qp.half_half -dfrac_op_own mono_list_auth_dfrac_op) in "Hlog".
iDestruct "Hlog" as "[Hlog Hlog2]".
iMod ("Hupd" with "[%] Hlog2") as "Hupd".
rewrite /get_rwops Hfst_eq.
iAssert (|={↑escrowN}=> inv escrowN ((Ψ (ApplyReply.mkC 0 (compute_reply (get_rwops opsfullQ) op)))
∨ ghost_var γtok 1 ()))%I
with "[Hupd]" as "Hinv2".
iMod (inv_alloc with "[-]") as "$"; last done.
iMod (fupd_mask_subseteq (↑escrowN)) as "Hmask".
iMod "Hinv2" as "#HΦ_inv".
iMod ("Hclose" with "[HQs Hghost Hlog]").
iExists (opsfullQ ++ [(op, OpPred)]); iFrame.
iApply big_sepL2_singleton.
rewrite /get_rwops fmap_app.
apply prefix_app_cases in H as [Hprefix_of_old|Hnew].
assert (opsfullQ = opsPrePre) as ->.
apply (f_equal reverse) in H0.
rewrite reverse_snoc in H0.
rewrite reverse_snoc in H0.
apply (f_equal reverse) in H2.
rewrite reverse_involutive in H2.
rewrite reverse_involutive in H2.
eassert (_ = lastEnt) as <-.
eapply (suffix_snoc_inv_1 _ _ _ opsPrePre).
iIntros "(Hcred & Hcred2 & Hcred3 & Hreply & Hpost)".
destruct (decide (reply.(ApplyReply.err) = U64 0)).
iDestruct "Hpost" as (?) "(%Hrep & #Hghost_lb)".
iInv "HhelpingInv" as "HH" "Hclose".
iDestruct "HH" as (?) "(Hghost & >Hlog & #HQs)".
iDestruct "Hghost" as (σgnames) "(>Hghost&>%Hfst_eq&#Hsaved')".
iApply (lc_fupd_add_later with "Hcred").
iMod (own_pre_log_get_ineq with "[$] Hghost Hghost_lb") as "[Hghost %Hvalid]".
destruct Hvalid as (σtail&Hvalid').
iDestruct (big_sepL2_length with "Hsaved'") as %Hlen.
rewrite ?fmap_length in Hlen.
assert (∃ σ0a op' Q' σ0b,
opsfullQ = σ0a ++ [(op', Q')] ++ σ0b ∧
length σ0a = length opsfull ∧
length σ0b = length σtail) as (σ0a&op'&Q'&σ0b&Heq0&Hlena&Hlenb).
destruct (nth_error opsfullQ (length opsfull)) as [(op', Q')|] eqn:Hnth; last first.
apply nth_error_None in Hnth.
rewrite ?app_length /= in Hlen.
edestruct (nth_error_split opsfullQ (length opsfull)) as (l1&l2&Heq&Hlen'); eauto.
rewrite Heq /=; split_and!; eauto.
rewrite Heq ?app_length /= in Hlen.
(* weird, lia fails directly but if you replace lengths with a nat then it works... *)
remember (length l2) as k.
remember (length σtail) as k'.
iDestruct ("HQs" $! (σ0a ++ [(op', Q')]) _ (_, _) with "[] []") as "#HQ".
iPureIntro; eexists; eauto.
iMod ("Hclose" with "[Hghost Hlog]") as "_".
rewrite ?fmap_app -app_assoc.
iDestruct (big_sepL2_app_inv with "Hsaved'") as "(H1&H2)".
iDestruct "H2" as "(HsavedQ'&?)".
iDestruct (saved_pred_agree _ _ _ _ _ (get_rwops σ0a) with "Hsaved [$]") as "HQequiv".
iApply (lc_fupd_add_later with "[$]").
iRewrite -"HQequiv" in "HQ".
iInv "HQ" as "Hescrow" "Hclose".
iDestruct "Hescrow" as "[HΦ|>Hbad]"; last first.
iDestruct (ghost_var_valid_2 with "Htok Hbad") as %Hbad.
iMod ("Hclose" with "[$Htok]").
iMod (lc_fupd_elim_later with "Hcred2 HΦ") as "HΦ".
rewrite ?fmap_app -app_assoc in Hfst_eq.
apply app_inj_1 in Hfst_eq; last (rewrite ?fmap_length //).
destruct Hfst_eq as (Hfst_eq&_).
iApply ("HΨ" with "[Hfail_Φ]").