Timings for 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/apps/exactlyonce/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/apps/exactlyonce/proof.v.timing
From Perennial.program_proof Require Import grove_prelude.
From Perennial.program_proof Require Import marshal_stateless_proof.
From iris.base_logic Require Import ghost_map.
From Perennial.goose_lang Require Import crash_borrow.
From Perennial.program_proof.vrsm.storage Require Import proof.
From Perennial.program_proof.vrsm Require Import replica.definitions replica.apply_proof clerk.clerk_proof.
From Perennial.program_proof.grove_shared Require Import erpc_lib.
From Perennial.program_proof Require Import map_marshal_proof.
From iris.algebra Require Import dfrac_agree mono_list.
From Perennial Require Import exactlyonce.vsm log.
From Perennial.algebra Require Import map.
From RecordUpdate Require Import RecordSet.
Import RecordSetNotations.
From Goose.github_com.mit_pdos.gokv.vrsm.apps Require Import exactlyonce.
Context `{low_record:Sm.t}.
Notation low_OpType := (@Sm.OpType low_record).
Notation low_has_op_encoding := (@Sm.has_op_encoding low_record).
Notation low_has_snap_encoding := (@Sm.has_snap_encoding low_record).
Notation low_compute_reply := (@Sm.compute_reply low_record).
Notation low_is_readonly_op := (@Sm.is_readonly_op low_record).
Instance low_op_eqdec : EqDecision (low_OpType).
apply (@Sm.OpType_EqDecision low_record).
Inductive EOp :=
| getcid : EOp
| eop : u64 → u64 -> low_OpType → EOp
| ro_eop : low_OpType → EOp
.
Record EState := mkEState
{
nextCID : u64;
lastSeq : gmap u64 u64 ;
lastReply : gmap u64 (list u8);
lowops : list low_OpType
}.
Global Instance etaEState : Settable _ :=
settable! (mkEState) <nextCID ; lastSeq ; lastReply ; lowops >.
Definition apply_op_and_get_reply (state:EState) (op:EOp) : EState * list u8 :=
match op with
| getcid => (state <| nextCID := (word.add state.(nextCID) 1) |>, u64_le state.(nextCID))
| eop cid seq op =>
if decide (int.nat seq <= int.nat (default (U64 0) (state.(lastSeq) !! cid))) then
(state, default [] (state.(lastReply) !! cid))
else
let rep:=(low_compute_reply state.(lowops) op) in
(state <| lastSeq := <[cid:=seq]> state.(lastSeq) |>
<| lastReply := <[cid:=rep]> state.(lastReply) |>
<| lowops := (state.(lowops) ++ [op]) |>, rep)
| ro_eop op => (state, (low_compute_reply state.(lowops) op))
end
.
Definition apply_op state op :=
(apply_op_and_get_reply state op).1
.
Definition init_state := mkEState 0 ∅ ∅ [].
Definition compute_state ops : EState :=
foldl apply_op init_state ops.
Definition compute_reply ops op : (list u8) :=
(apply_op_and_get_reply (compute_state ops) op).2
.
Definition esm_has_encoding op_bytes op :=
match op with
| getcid => op_bytes = [U8 1]
| eop cid seq lowop =>
∃ lowop_enc, low_has_op_encoding lowop_enc lowop ∧
op_bytes = [U8 0] ++ u64_le cid ++ u64_le seq ++ (lowop_enc)
| ro_eop lowop =>
∃ lowop_enc,
low_has_op_encoding lowop_enc lowop ∧
low_is_readonly_op lowop ∧
op_bytes = [U8 2] ++ (lowop_enc)
end
.
Definition esm_has_snap_encoding snap_bytes ops :=
let st := (compute_state ops) in
∃ low_snap_bytes enc_lastSeq enc_lastReply,
has_u64_map_encoding enc_lastSeq st.(lastSeq) ∧
has_byte_map_encoding enc_lastReply st.(lastReply) ∧
low_has_snap_encoding low_snap_bytes st.(lowops) ∧
snap_bytes = (u64_le st.(nextCID)) ++ (enc_lastSeq) ++ enc_lastReply ++ low_snap_bytes
.
Definition esm_is_readonly_op op :=
match op with
| getcid => False
| eop _ _ _=> False
| ro_eop lowop => low_is_readonly_op lowop
end
.
(* TODO: could strengthen this to export the lower-level postcond's *)
Definition esm_apply_postcond ops op :=
match op with
| getcid => (int.Z (word.add (compute_state ops).(nextCID) 1) =
(int.Z (compute_state ops).(nextCID)) + 1)%Z
| _ => True
end
.
Instance op_eqdec : EqDecision EOp.
Program Definition
esm_record:=
{|
Sm.OpType := EOp ;
Sm.has_op_encoding := esm_has_encoding ;
Sm.has_snap_encoding := esm_has_snap_encoding ;
Sm.compute_reply := compute_reply ;
Sm.is_readonly_op := esm_is_readonly_op ;
Sm.apply_postcond := esm_apply_postcond ;
|}.
rewrite /esm_apply_postcond /=.
Context `{!inG Σ (mono_listR (leibnizO low_OpType))}.
Context `{!gooseGlobalGS Σ, !urpcregG Σ, !erpcG Σ (list u8)}.
Definition own_esm st γ γerpc : iProp Σ :=
"Hlog" ∷ own_log γ st.(lowops) ∗
"HerpcServer" ∷ eRPCServer_own_ghost γerpc st.(lastSeq) st.(lastReply) ∗
"Hcids" ∷ ([∗ set] cid ∈ (fin_to_set u64), ⌜int.Z cid < int.Z st.(nextCID)⌝%Z ∨
(is_eRPCClient_ghost γerpc cid 1))
.
Definition esmN := nroot .@ "esm".
(* This is the invariant maintained by all the servers for the "centralized"
ghost state of the system. *)
Context {initconf:list u64}.
Local Instance esmParams : pbParams.t := pbParams.mk initconf (esm_record).
Context `{!pbG (pb_record:=esmParams.(pbParams.pb_record)) Σ}.
Definition is_esm_inv γpb γlog γerpc : iProp Σ :=
inv esmN (∃ ops,
own_op_log γpb ops ∗
own_esm (compute_state ops) γlog γerpc
)
.
Lemma alloc_esm γpb :
own_op_log γpb [] ={⊤}=∗
∃ γlog γerpc,
is_esm_inv γpb γlog γerpc ∗
is_eRPCServer γerpc ∗
own_log γlog ([]:list low_OpType)
.
iMod (own_alloc (●ML [])) as (γlog) "[Hlog Hlog2]".
apply mono_list_auth_valid.
iMod (make_rpc_server) as (γerpc) "(#? & Herpc & Hcids)".
iMod (inv_alloc with "[-]") as "$"; last done.
iApply (big_sepS_impl with "Hcids").
Context {low_record:Sm.t}.
Notation low_OpType := (@Sm.OpType low_record).
Notation low_has_op_encoding := (@Sm.has_op_encoding low_record).
Notation low_is_readonly_op := (@Sm.is_readonly_op low_record).
Notation low_compute_reply := (@Sm.compute_reply low_record).
Instance low_op_dec2 : EqDecision low_OpType.
apply (@Sm.OpType_EqDecision low_record).
Context `{!heapGS Σ, !urpcregG Σ, !erpcG Σ (list u8)}.
Notation esm_record := (esm_record (low_record:=low_record)).
Notation compute_state := (compute_state (low_record:=low_record)).
Notation EOp := (EOp (low_record:=low_record)).
Notation esm_is_InMemoryStateMachine := (is_InMemoryStateMachine (sm_record:=esm_record)).
Notation low_is_VersionedStateMachine := (is_VersionedStateMachine (sm_record:=low_record)).
Notation own_pb_Clerk := clerk_proof.own_Clerk.
Notation is_esm_inv := (is_esm_inv (low_record:=low_record)).
Context `{!inG Σ (mono_listR (leibnizO low_OpType))}.
Context {initconf:list u64}.
(* FIXME: can this second copy of the instance be avoided? *)
(* Existing Instance esmParams. *)
Local Instance esmParams2 : pbParams.t := esmParams (low_record:=low_record) (initconf:=initconf).
Context `{!pbG (pb_record:=esmParams2.(pbParams.pb_record)) Σ}.
Context `{!vsmG (sm_record:=low_record) Σ}.
Definition own_Clerk ck γoplog : iProp Σ :=
∃ (pb_ck:loc) γpb γerpc (cid seqno:u64),
"Hcid" ∷ ck ↦[exactlyonce.Clerk :: "cid"] #cid ∗
"Hseq" ∷ ck ↦[exactlyonce.Clerk :: "seq"] #seqno ∗
"Hown_ck" ∷ own_pb_Clerk pb_ck γpb ∗
"#Hpb_ck" ∷ readonly (ck ↦[exactlyonce.Clerk :: "ck"] #pb_ck) ∗
"#Hee_inv" ∷ is_esm_inv γpb γoplog γerpc ∗
"Herpc" ∷ is_eRPCClient_ghost γerpc cid seqno ∗
"#Herpc_inv" ∷ is_eRPCServer γerpc ∗
"%Hseqno_pos" ∷ ⌜ int.nat seqno > 0 ⌝
.
Lemma compute_state_snoc ops newop :
compute_state (ops ++ [newop]) = apply_op (compute_state ops) newop.
Lemma wp_Clerk__ApplyExactlyOnce ck γoplog lowop op_sl lowop_bytes Φ:
low_has_op_encoding lowop_bytes lowop →
own_Clerk ck γoplog -∗
own_slice op_sl byteT 1 lowop_bytes -∗
(|={⊤∖↑pbN∖↑prophReadN∖↑esmN,∅}=> ∃ oldops, own_log γoplog oldops ∗
(own_log γoplog (oldops ++ [lowop]) ={∅,⊤∖↑pbN∖↑prophReadN∖↑esmN}=∗
(∀ reply_sl, own_Clerk ck γoplog -∗ own_slice_small reply_sl byteT 1 (low_compute_reply oldops lowop)
-∗ Φ (slice_val reply_sl )))) -∗
WP Clerk__ApplyExactlyOnce #ck (slice_val op_sl) {{ Φ }}.
iIntros "Hclerk Hop Hupd".
wp_apply (wp_NewSliceWithCap).
iIntros (enc_ptr) "Henc".
replace (#(U8 0)) with (_.(to_val) (U8 0)).
iDestruct (own_slice_split with "Henc_sl") as "[Henc_sl Henc_cap]".
wp_apply (wp_SliceSet with "[Henc_sl]").
rewrite lookup_replicate.
iDestruct (own_slice_split with "[$Henc_sl $Henc_cap]") as "Henc_sl".
wp_apply (wp_WriteInt with "Henc_sl").
wp_apply (wp_WriteInt with "Henc_sl").
iDestruct (own_slice_to_small with "Hop") as "Hop".
wp_apply (wp_WriteBytes with "[$Henc_sl $Hop]").
iIntros (?) "[Henc_sl _]".
wp_apply (std_proof.wp_SumAssumeNoOverflow).
iIntros (Hseqno_overflow).
iMod (make_request ({| Req_CID:= _; Req_Seq:= _ |}) with "Herpc_inv Herpc [Hupd Hlc]") as "[Herpc Hreq]".
instantiate(1:=
(λ reply, ∀ reply_sl,
own_Clerk ck γoplog -∗
own_slice_small reply_sl byteT 1 reply -∗
Φ (slice_val reply_sl))
%I).
(* assert that it equals low_compute_reply *)
iDestruct "Hreq" as (?) "(#Hreq & Htok)".
iApply (wp_frame_wand with "[Hcid Hseq Herpc Htok Hlc2]").
iDestruct (own_slice_to_small with "Henc_sl") as "Henc_sl".
wp_apply (wp_Clerk__Apply with "Hown_ck [$Henc_sl]").
instantiate (1:= eop cid seqno lowop).
iInv "Hee_inv" as "Hi" "Hclose".
iDestruct "Hi" as (?) "[>Hpblog >Hee]".
destruct (decide (int.Z (default (U64 0) ((compute_state ops).(lastSeq) !! cid)) < int.Z seqno)%Z).
(* case: first time running request *)
iMod (server_takes_request with "Hreq HerpcServer") as "HH".
iDestruct "HH" as "(Hpre & Hupd & Hproc)".
iDestruct "Hupd" as "[Hupd >Hlc]".
iMod (lc_fupd_elim_later with "Hlc Hupd") as "Hupd".
iDestruct "Hupd" as (?) "[Hoplog2 Hupd]".
iDestruct (own_valid_2 with "Hlog Hoplog2") as %Hvalid.
rewrite mono_list_auth_dfrac_op_valid_L in Hvalid.
destruct Hvalid as [_ ?].
iCombine "Hlog Hoplog2" as "Hoplog".
iMod (own_update with "Hoplog") as "Hoplog".
instantiate (1:=_ ++ [lowop]).
iDestruct "Hoplog" as "[Hoplog Hoplog2]".
iMod ("Hupd" with "Hoplog2") as "Hupd".
iMod (server_completes_request _ _ _ with "Herpc_inv Hreq Hpre [Hupd] Hproc") as "[#Hreceipt HerpcServer]".
iMod ("Hclose" with "[HerpcServer Hpblog Hoplog Hcids]").
iExists _; iFrame "Hpblog".
rewrite compute_state_snoc.
rewrite decide_False; last first.
iIntros (?) "Hrep_sl _ Hpbck".
iMod (get_request_post with "Hreq Hreceipt Htok") as "HΦ".
iMod (lc_fupd_elim_later with "Hlc2 HΦ") as "HΦ".
iApply ("HΦ" with "[Herpc Hcid Hpbck Hseq] [Hrep_sl]").
rewrite decide_False; last first.
(* case: request already ran *)
assert (int.nat (default (U64 0) ((compute_state ops).(lastSeq) !! cid)) = int.nat seqno ∨
int.nat (default (U64 0) ((compute_state ops).(lastSeq) !! cid)) > int.nat seqno)
as [Hok|HStale] by word.
destruct (_ !! cid) eqn:X2; last first.
replace (int.nat 0%Z) with (0) in Hok by word.
iMod (server_replies_to_request _ {| Req_CID := cid ; Req_Seq:= _|} with "Herpc_inv HerpcServer") as "HH".
iDestruct "HH" as "[#Hreceipt HerpcServer]".
iMod ("Hclose" with "[HerpcServer Hpblog Hlog Hcids]").
iExists _; iFrame "Hpblog".
rewrite compute_state_snoc.
rewrite decide_True; last first.
iIntros (?) "Hrep_sl _ Hpbck".
replace (u) with (seqno); last first.
iMod (get_request_post with "Hreq Hreceipt Htok") as "HΦ".
iMod (lc_fupd_elim_later with "Hlc2 HΦ") as "HΦ".
iApply ("HΦ" with "[Herpc Hcid Hpbck Hseq] [Hrep_sl]").
rewrite decide_True; last first.
destruct (_ !! cid) eqn:X2; last first.
replace (int.nat 0%Z) with (0) in HStale by word.
iMod (smaller_seqno_stale_fact _ {| Req_CID := cid; Req_Seq := seqno |} with "Herpc_inv HerpcServer") as "HH".
iDestruct "HH" as "[HerpcServer #Hstale]".
iMod ("Hclose" with "[HerpcServer Hpblog Hlog Hcids]").
iExists _; iFrame "Hpblog".
rewrite compute_state_snoc.
rewrite decide_True; last first.
iDestruct (client_stale_seqno with "Hstale Herpc") as %Hstale2.
Lemma wp_Clerk__ApplyReadonly ck γoplog lowop op_sl lowop_bytes Φ:
low_is_readonly_op lowop →
low_has_op_encoding lowop_bytes lowop →
own_Clerk ck γoplog -∗
own_slice op_sl byteT 1 lowop_bytes -∗
(|={⊤∖↑pbN∖↑prophReadN∖↑esmN,∅}=> ∃ oldops, own_log γoplog oldops ∗
(own_log γoplog (oldops) ={∅,⊤∖↑pbN∖↑prophReadN∖↑esmN}=∗
(∀ reply_sl, own_Clerk ck γoplog -∗ own_slice_small reply_sl byteT 1 (low_compute_reply oldops lowop)
-∗ Φ (slice_val reply_sl )))) -∗
WP Clerk__ApplyReadonly #ck (slice_val op_sl) {{ Φ }}.
iIntros "Hclerk Hop Hupd".
wp_apply (wp_NewSliceWithCap).
iIntros (enc_ptr) "Henc".
replace (#(U8 2)) with (_.(to_val) (U8 2)).
iDestruct (own_slice_split with "Henc_sl") as "[Henc_sl Henc_cap]".
wp_apply (wp_SliceSet with "[Henc_sl]").
rewrite lookup_replicate.
iDestruct (own_slice_split with "[$Henc_sl $Henc_cap]") as "Henc_sl".
iDestruct (own_slice_to_small with "Hop") as "Hop".
wp_apply (wp_WriteBytes with "[$Henc_sl $Hop]").
iIntros (?) "[Henc_sl _]".
iDestruct (own_slice_to_small with "Henc_sl") as "Henc_sl".
wp_apply (wp_Clerk__ApplyReadonly with "Hown_ck [$Henc_sl]").
instantiate (1:= ro_eop lowop).
by rewrite /esm_record /esm_is_readonly_op /=.
iInv "Hee_inv" as ">Hi" "Hclose".
iDestruct "Hi" as (?) "[Hpblog Hee]".
iMod "Hupd" as (?) "[Hlog2 Hupd]".
iDestruct (own_valid_2 with "Hlog Hlog2") as %Hvalid.
apply mono_list_auth_dfrac_op_valid_L in Hvalid.
destruct Hvalid as [_ ?]; subst.
iMod ("Hupd" with "[$]") as "Hupd".
iMod ("Hclose" with "[Hpblog HerpcServer Hlog2 Hcids]").
iIntros (?) "Hsl Hsl2 Hck".
iApply ("Hupd" with "[-Hsl]").
repeat iExists _; iFrame "∗#%".
(* Now, the server proof. *)
Definition own_ghost_vnums γst (ops:list EOp) (latestVnum:u64) : iProp Σ :=
"HfutureVersions" ∷ ([∗ set] vnum ∈ (fin_to_set u64), ⌜int.nat vnum > length ops⌝ →
vnum ⤳[γst] []) ∗
"Hversions" ∷ ([∗ set] vnum ∈ (fin_to_set u64), ⌜int.nat vnum <= length ops⌝ →
vnum ⤳[γst] [] ∨ (is_state γst vnum (compute_state (take (int.nat vnum) ops)).(lowops))
) ∗
"#HlatestVersion" ∷
([∗ set] vnum ∈ (fin_to_set u64), □(⌜int.nat vnum <= length ops⌝ →
⌜int.nat latestVnum <= int.nat vnum⌝ →
(is_state γst vnum (compute_state ops).(lowops))))
.
Definition own_StateMachine (s:loc) (ops:list EOp) : iProp Σ :=
let st := (compute_state ops) in
∃ (lastSeq_ptr lastReply_ptr lowSm:loc) (latestVnum:u64) own_low γst,
"HnextCID" ∷ s ↦[eStateMachine:: "nextCID"] #st.(nextCID) ∗
"HlastSeq_ptr" ∷ s ↦[eStateMachine :: "lastSeq"] #lastSeq_ptr ∗
"HlastReply_ptr" ∷ s ↦[eStateMachine :: "lastReply"] #lastReply_ptr ∗
"HlastSeq" ∷ own_map lastSeq_ptr 1 st.(lastSeq) ∗
"HlastReply" ∷ own_byte_map lastReply_ptr st.(lastReply) ∗
"HesmNextIndex" ∷ s ↦[eStateMachine :: "esmNextIndex"] #(U64 (length ops)) ∗
"Hsm" ∷ s ↦[eStateMachine :: "sm"] #lowSm ∗
"Hghost" ∷ own_ghost_vnums γst ops latestVnum ∗
"#Hislow" ∷ low_is_VersionedStateMachine lowSm own_low ∗
"Hlowstate" ∷ own_low γst st.(lowops) latestVnum ∗
"%Hle" ∷ ⌜int.nat latestVnum <= length ops⌝ ∗
"%HnoOverflow" ∷ ⌜length ops = int.nat (length ops)⌝
.
Notation esm_is_InMemory_applyVolatileFn := (is_InMemory_applyVolatileFn (sm_record:=esm_record)).
Notation esm_is_InMemory_setStateFn := (is_InMemory_setStateFn (sm_record:=esm_record)).
Notation esm_is_InMemory_getStateFn := (is_InMemory_getStateFn (sm_record:=esm_record)).
Notation esm_is_InMemory_applyReadonlyFn := (is_InMemory_applyReadonlyFn (sm_record:=esm_record)).
Lemma u64_plus_1_le_no_overflow (y: u64) (n : nat) :
n + 1 = int.nat (u64_instance.u64.(word.add) n 1) →
U64 (n + 1)%Z ≠ y →
int.nat y ≤ n + 1 →
int.nat y ≤ n.
intros ? Hplus_1_neq Hle.
cut (int.nat y ≠ n + 1); first by lia.
Lemma ghost_no_low_changes γst ops latestVnum o l :
(length ops + 1 = int.nat (word.add (length ops) 1))%nat →
(compute_state ops).(lowops) = l →
(compute_state (ops ++ [o])).(lowops) = l →
own_ghost_vnums γst ops latestVnum ==∗
own_ghost_vnums γst (ops ++ [o]) latestVnum
.
intros HnoOverflow Heq1 Heq2.
iDestruct (big_sepS_elem_of_acc_impl (word.add (length ops) 1) with "HfutureVersions") as "[HH HfutureVersions]".
iSplitL "HfutureVersions".
iApply "HfutureVersions".
rewrite app_length in H1.
rewrite app_length /= in H.
iSpecialize ("HH" with "[%]").
iMod (ghost_map_points_to_update l with "HH") as "HH".
iMod (ghost_map_points_to_persist with "HH") as "#HH".
iDestruct (big_sepS_elem_of_acc_impl (U64 (length ops + 1)) with "Hversions") as "[_ Hversions]".
rewrite app_length /= in H1.
assert (int.nat y <= length ops).
apply u64_plus_1_le_no_overflow; auto.
iDestruct ("H" with "[%]") as "[$|H]".
rewrite app_length /= in H.
replace (Z.of_nat (length ops) + 1)%Z with (Z.of_nat (length ops + 1)) by
lia.
rewrite u64_Z_through_nat u64_Z //.
iApply (big_sepS_impl with "HlatestVersion").
rewrite app_length /= in H0.
destruct (decide (x = (word.add (length ops) 1))).
apply u64_plus_1_le_no_overflow; auto.
replace (Z.of_nat (length ops) + 1)%Z with (Z.of_nat (length ops + 1)) by
lia.
rewrite u64_Z_through_nat u64_Z //.
Instance int_nat_u64_inj: Inj eq eq (fun z : u64 => Z.to_nat (int.Z z)).
apply Z2Nat.inj; auto using encoding.unsigned_64_nonneg.
Lemma ghost_low_newop γst ops latestVnum op lowop l :
(length ops + 1 = int.nat (word.add (length ops) 1))%nat →
int.nat latestVnum <= length ops →
(compute_state ops).(lowops) = l →
(compute_state (ops ++ [op])).(lowops) = l ++ [lowop] →
own_ghost_vnums γst ops latestVnum ==∗
own_ghost_vnums γst (ops ++ [op]) (length (ops ++ [op])) ∗
(∀ (vnum':u64), ⌜int.nat latestVnum <= int.nat vnum'⌝ →
⌜int.nat vnum' < int.nat (length (ops ++ [op]))⌝ → is_state γst vnum' l) ∗
is_state γst (length (ops ++ [op])) (l ++ [lowop])
.
iDestruct (big_sepS_elem_of_acc_impl (word.add (length ops) 1) with "HfutureVersions") as "[HH HfutureVersions]".
iSpecialize ("HH" with "[%]").
iMod (ghost_map_points_to_update (l ++ [lowop]) with "HH") as "HH".
iMod (ghost_map_points_to_persist with "HH") as "#HH".
iSplitL "HfutureVersions".
iApply "HfutureVersions".
rewrite app_length in H4.
rewrite app_length /= in H2.
iDestruct (big_sepS_elem_of_acc_impl (U64 (length ops + 1)) with "Hversions") as "[_ Hversions]".
rewrite app_length /= in H4.
assert (int.nat y <= length ops).
apply u64_plus_1_le_no_overflow; auto.
iDestruct ("H" with "[%]") as "[$|H]".
rewrite app_length /= in H2.
replace (Z.of_nat (length ops) + 1)%Z with (Z.of_nat (length ops + 1)) by
lia.
rewrite u64_Z_through_nat u64_Z //.
iApply (big_sepS_impl with "HlatestVersion").
rewrite app_length /= in H4.
assert (x = (word.add (length ops) 1)).
rewrite app_length /= in H3.
rewrite HnoOverflow in H4.
rewrite u64_Z_through_nat in H4.
rewrite u64_Z_through_nat.
iDestruct (big_sepS_elem_of_acc _ _ vnum' with "HlatestVersion") as "[#H _]".
rewrite app_length /= in H3.
replace (int.nat (length ops + 1)) with (length ops + 1) in H3.
rewrite word.unsigned_add in HnoOverflow.
rewrite Z2Nat.id; last by lia.
rewrite encoding.word_wrap_wrap; auto; lia.
Lemma wp_eStateMachine__apply s :
{{{
True
}}}
eStateMachine__applyVolatile #s
{{{
applyFn, RET applyFn;
⌜val_ty applyFn (slice.T byteT -> slice.T byteT)⌝ ∗
esm_is_InMemory_applyVolatileFn applyFn (own_StateMachine s)
}}}
.
iIntros (???? Φ) "!# Hpre HΦ".
iDestruct "Hpre" as "(%Henc & #Hsl & Hown)".
set (st:=compute_state ops).
wp_apply (wp_ref_of_zero).
wp_apply std_proof.wp_SumAssumeNoOverflow.
iMod (readonly_load with "Hsl") as (?) "Hsl2".
wp_apply (wp_SliceGet with "[$Hsl2]").
wp_apply (wp_NewSliceWithCap).
wp_apply (wp_WriteInt with "[$Hrep_sl]").
wp_apply std_proof.wp_SumAssumeNoOverflow.
rewrite compute_state_snoc.
replace (compute_state ops) with (st) by done.
iMod (ghost_no_low_changes with "Hghost") as "Hghost".
rewrite compute_state_snoc.
iSplitR "Hrep_sl"; last first.
iDestruct (own_slice_to_small with "Hrep_sl") as "Hrep_sl".
iExactEq "HesmNextIndex".
destruct Henc as [? [HlowEnc Henc]].
iMod (readonly_load with "Hsl") as (?) "Hsl2".
wp_apply (wp_SliceGet with "[$Hsl2]").
wp_apply (wp_SliceGet with "[$Hsl2]").
iDestruct (own_slice_small_sz with "Hsl2") as %Hsl_sz.
wp_apply (wp_SliceSubslice_small with "[$Hsl2]").
iIntros (eeop_sl) "Hop_sl".
rewrite -> subslice_drop_take; last first.
rewrite singleton_length.
replace (1 + length (u64_le u ++ u64_le u0 ++ x) - int.nat 1%Z)
with (length (u64_le u ++ u64_le u0 ++ x)) by word.
replace (int.nat (U64 1)) with (length [U8 0]) by done.
rewrite take_ge; last word.
rename x into eeop_bytes.
wp_apply (wp_ReadInt with "Hop_sl").
wp_apply (wp_ReadInt with "Hop_sl").
wp_apply (wp_MapGet with "HlastSeq").
iIntros (??) "(%Hlookup & HlastSeq)".
wp_apply (wp_byteMapGet with "HlastReply").
iIntros (?) "[#Hrep_sl HlastReply]".
iMod (readonly_load with "Hrep_sl") as (?) "Hrep_sl2".
rewrite compute_state_snoc.
replace (compute_state ops) with (st) by done.
unfold apply_op_and_get_reply.
rewrite decide_True; last first.
apply (f_equal fst) in Hlookup.
rewrite map_get_val /= in Hlookup.
iSplitR "Hrep_sl2"; last first.
iMod (ghost_no_low_changes with "Hghost") as "$".
rewrite compute_state_snoc.
replace (compute_state ops) with (st) by done.
iExactEq "HesmNextIndex".
iAssert (_) with "Hislow" as "#Hislow2".
iMod (readonly_alloc (own_slice_small s'0 byteT 1 eeop_bytes) with "[Hop_sl]") as "#Hop_sl".
unfold is_Versioned_applyVolatileFn.
iMod (ghost_low_newop with "Hghost") as "Hghost".
instantiate (1:=eop u u0 o).
rewrite compute_state_snoc.
replace (compute_state ops) with (st) by done.
iDestruct "Hghost" as "(Hghost & HprevVers & HnewVer)".
wp_apply ("HapplyVolatile_spec" with "[$Hlowstate HprevVers HnewVer]").
iSplitR; first iPureIntro.
replace (compute_state ops) with st by done.
replace (compute_state ops) with st by done.
iIntros (??) "[Hlowstate Hrep_sl]".
iMod (readonly_alloc (own_slice_small reply_sl byteT 1 (low_compute_reply
{|
nextCID := nextCID0;
lastSeq := lastSeq0;
lastReply := lastReply0;
lowops := lowops0
|}.(lowops) o)) q0 with "[Hrep_sl]") as "#Hreply_sl".
iMod (readonly_load with "Hreply_sl") as (?) "Hreply_sl2".
wp_apply (wp_byteMapPut with "[$HlastReply Hreply_sl2]").
wp_apply (wp_MapInsert with "HlastSeq").
iMod (readonly_load with "Hreply_sl") as (?) "Hreply_sl2".
rewrite compute_state_snoc.
replace (compute_state ops) with (st) by done.
unfold apply_op_and_get_reply.
rewrite decide_False; last first.
apply (f_equal fst) in Hlookup.
rewrite map_get_val /= in Hlookup.
iSplitR "Hreply_sl2"; last first.
iExactEq "HesmNextIndex".
(* apply a readonly op *)
destruct Henc as [? (HlowEnc & Hro & Henc)].
iMod (readonly_load with "Hsl") as (?) "Hsl2".
wp_apply (wp_SliceGet with "[$Hsl2]").
wp_apply (wp_SliceGet with "[$Hsl2]").
wp_apply (wp_SliceGet with "[$Hsl2]").
iDestruct (own_slice_small_sz with "Hsl2") as %Hsl_sz.
wp_apply (wp_SliceSubslice_small with "[$Hsl2]").
iIntros (eeop_sl) "Hop_sl".
rewrite -> subslice_drop_take; last first.
rewrite singleton_length.
replace (1 + length x - int.nat 1%Z)
with (length (x)) by word.
replace (int.nat (U64 1)) with (length [U8 2]) by done.
rewrite take_ge; last word.
rename x into eeop_bytes.
iAssert (_) with "Hislow" as "#Hislow2".
iMod (readonly_alloc (own_slice_small eeop_sl byteT 1 eeop_bytes) with "[Hop_sl]") as "#Hop_sl".
wp_apply ("HapplyReadonly_spec" with "[$Hlowstate]").
iIntros (???) "(% & Hlow & Hrep_sl & _)".
rewrite compute_state_snoc.
replace (compute_state ops) with st by done.
iSplitR; first by iPureIntro.
iMod (ghost_no_low_changes with "Hghost") as "$".
rewrite compute_state_snoc.
iExactEq "HesmNextIndex".
replace (compute_state ops) with (st) by done.
Lemma ghost_low_setstate ops :
length ops = int.nat (length ops) →
⊢ |==> ∃ γst,
own_ghost_vnums γst (ops) (length ops) ∗
is_state γst (length (ops)) (compute_state ops).(lowops)
.
iMod (ghost_map_alloc_fin []) as (?) "Hmap".
iDestruct (big_sepS_elem_of_acc_impl (U64 (length ops)) with "Hmap") as "[HH Hmap]".
iMod (ghost_map_points_to_update (compute_state ops).(lowops) with "HH") as "HH".
iMod (ghost_map_points_to_persist with "HH") as "#?".
iAssert (
[∗ set] vnum ∈ fin_to_set u64, ( (⌜int.nat vnum ≤ length ops⌝
→ vnum ⤳[γ] []
∨ is_state γ vnum
(compute_state (take (int.nat vnum) ops)).(lowops)) ∗
(⌜int.nat vnum > length ops⌝ → vnum ⤳[γ] [])))%I with "[-]" as "HH".
destruct (decide (int.nat y ≤ length ops)).
iDestruct (big_sepS_sep with "HH") as "[H H2]".
iApply (big_sepS_impl with "[]").
assert (int.nat x = (length ops)).
replace (x) with (U64 (length ops)) by word.
Lemma wp_eStateMachine__setState s :
{{{
True
}}}
eStateMachine__setState #s
{{{
setFn, RET setFn;
⌜val_ty setFn (slice.T byteT -> (arrowT uint64T unitT))%ht⌝ ∗
esm_is_InMemory_setStateFn setFn (own_StateMachine s)
}}}
.
iIntros (????? Φ) "!# Hpre HΦ".
iDestruct "Hpre" as "(%Hsnap & %HnextIndex & #Hsnap_sl & Hown)".
iMod (readonly_load with "Hsnap_sl") as (?) "Hsnap_sl2".
iIntros (enc_ptr) "Henc".
rewrite /esm_has_snap_encoding in Hsnap.
set (st:=compute_state ops) in *.
set (st_old:=compute_state ops_prev) in *.
destruct Hsnap as (lowsnap & enc_lastSeq & enc_lastReply & Hencseq & Hencrep & Hlowsnap & Hsnap).
wp_apply (wp_ReadInt with "[$Hsnap_sl2]").
wp_apply (wp_DecodeMapU64ToU64 with "[Hsnap_sl2]").
iIntros (???) "[HlastSeqMap Hsnap_sl2]".
wp_apply (wp_DecodeMapU64ToBytes with "[Hsnap_sl2]").
iIntros (???) "[HlastReplyMap Hsnap_sl2]".
iAssert (_) with "Hislow" as "#Hislow2".
iMod (readonly_alloc (own_slice_small rest_enc_sl0 byteT 1 lowsnap) with "[Hsnap_sl2]") as "#Hsnap_sl2".
unfold is_Versioned_setStateFn.
assert (nextIndex = length ops) by word; subst.
assert (Hlen: length ops = int.nat (length ops)).
iMod (ghost_low_setstate _) as (?) "[Hghost2 #Hstate]"; first done.
wp_apply ("HsetState_spec" with "[$Hlowstate Hsnap_sl2]").
Lemma wp_eStatemachine__getState (s:loc) :
⊢ esm_is_InMemory_getStateFn (λ: <>, eStateMachine__getState #s) (own_StateMachine s).
iIntros (? Φ) "!# Hpre HΦ".
iDestruct "Hpre" as "Hown".
set (st:=compute_state ops).
iAssert (_) with "Hislow" as "#Hislow2".
wp_apply ("HgetState_spec" with "[$Hlowstate]").
iIntros (??) "(Hlowstate & %Hlowsnap & #Hsnap_sl)".
iMod (readonly_load with "Hsnap_sl") as (?) "Hsnap_sl2".
wp_apply (wp_NewSliceWithCap).
iIntros (enc_ptr) "Henc".
wp_apply (wp_WriteInt with "Henc_sl").
wp_apply (wp_EncodeMapU64ToU64 with "HlastSeq").
iIntros (??) "(Hmap & HlastSeqEnc & %HlastSeqEnc)".
iDestruct (own_slice_to_small with "HlastSeqEnc") as "HlastSeqEnc".
wp_apply (wp_WriteBytes with "[$Henc_sl $HlastSeqEnc]").
iIntros (?) "[Henc_sl _]".
wp_apply (wp_EncodeMapU64ToBytes with "HlastReply").
iIntros (??) "(Hmap2 & HlastReplyEnc & %HlastReplyEnc)".
iDestruct (own_slice_to_small with "HlastReplyEnc") as "HlastReplyEnc".
wp_apply (wp_WriteBytes with "[$Henc_sl $HlastReplyEnc]").
iIntros (?) "[Henc_sl _]".
wp_apply (wp_WriteBytes with "[$Henc_sl $Hsnap_sl2]").
iIntros (?) "[Henc_sl _]".
iDestruct (own_slice_to_small with "Henc_sl") as "Henc_sl".
iMod (readonly_alloc_1 with "Henc_sl") as "Henc_sl".
unfold esm_has_snap_encoding.
replace (compute_state ops) with (st) by done.
repeat rewrite -app_assoc.
Lemma applyreadonly_step γst ops o latestVnum (lastModifiedVnum:u64) :
length ops = int.nat (length ops) →
own_ghost_vnums γst ops latestVnum -∗
(∀ (vnum : u64),
⌜int.nat vnum < int.nat latestVnum⌝
→ ⌜int.nat lastModifiedVnum ≤ int.nat vnum⌝
→ ∃ someOps : list low_OpType, is_state γst vnum someOps ∗
⌜low_compute_reply someOps o =
low_compute_reply (compute_state ops).(lowops) o⌝) -∗
⌜∀ ops' : list esm_record.(Sm.OpType),
ops' `prefix_of` ops
→ int.nat lastModifiedVnum ≤ length ops'
→ esm_record.(Sm.compute_reply) ops (ro_eop o) = esm_record.(Sm.compute_reply) ops' (ro_eop o)⌝
.
iSpecialize ("Hstates" $! (length a)).
assert (int.nat (length a) = (length a)) as HaOverflow.
apply prefix_length in a0.
rewrite HnoOverflow in a0.
destruct (decide (int.nat latestVnum <= length a)).
iDestruct (big_sepS_elem_of_acc _ _ (U64 (length a)) with "HlatestVersion") as "[#HH _]".
iSpecialize ("HH" with "[%] [%]").
apply prefix_length in a0.
iDestruct (big_sepS_elem_of_acc _ _ (U64 (length a)) with "Hversions") as "[H2 _]".
iSpecialize ("H2" with "[%]").
apply prefix_length in a0.
iDestruct "H2" as "[Hbad|H2]".
iDestruct (ghost_map_points_to_valid_2 with "Hbad HH") as %[Hbad _].
iDestruct (ghost_map_points_to_agree with "HH H2") as %?.
replace (take (int.nat (length a)) ops) with a in H.
unfold apply_op_and_get_reply.
by rewrite take_app_length.
iSpecialize ("Hstates" with "[%] [%]").
iDestruct "Hstates" as (?) "[Hstate %]".
iDestruct (big_sepS_elem_of_acc _ _ (U64 (length a)) with "Hversions") as "[H2 _]".
iSpecialize ("H2" with "[%]").
apply prefix_length in a0.
iDestruct "H2" as "[Hbad|H2]".
iDestruct (ghost_map_points_to_valid_2 with "Hbad Hstate") as %[Hbad _].
iDestruct (ghost_map_points_to_agree with "Hstate H2") as %?.
replace (take (int.nat (length a)) ops) with a in H.
unfold apply_op_and_get_reply.
by rewrite take_app_length.
Lemma wp_eStateMachine__applyReadonly s :
{{{
True
}}}
eStateMachine__applyReadonly #s
{{{
applyReadonlyFn, RET applyReadonlyFn;
⌜val_ty applyReadonlyFn (slice.T byteT -> (prodT uint64T (slice.T byteT)))⌝ ∗
esm_is_InMemory_applyReadonlyFn applyReadonlyFn (own_StateMachine s)
}}}
.
iIntros (???? Φ) "!# Hpre HΦ".
iDestruct "Hpre" as "(%Henc & %Hro & #Hsl & Hown)".
destruct Henc as (lowop_bytes & ? & Henc & ?).
iMod (readonly_load with "Hsl") as (?) "Hsl2".
wp_apply (wp_SliceGet with "[$Hsl2]").
wp_apply (wp_SliceGet with "[$Hsl2]").
wp_apply (wp_SliceGet with "[$Hsl2]").
iDestruct (own_slice_small_sz with "Hsl2") as %Hsl_sz.
wp_apply (wp_SliceSubslice_small with "[$Hsl2]").
iIntros (eeop_sl) "Hop_sl".
rewrite -> subslice_drop_take; last first.
rewrite singleton_length.
replace (1 + length lowop_bytes - int.nat 1%Z)
with (length lowop_bytes) by word.
replace (int.nat (U64 1)) with (length [U8 2]) by done.
rewrite take_ge; last word.
iAssert (_) with "Hislow" as "#Hislow2".
iMod (readonly_alloc (own_slice_small eeop_sl byteT 1 lowop_bytes) with "[Hop_sl]") as "#Hop_sl".
wp_apply ("HapplyReadonly_spec" with "[$Hlowstate]").
rewrite /esm_record /= in Hro.
iIntros (???) "(%Hlen & Hlow & Hrep_sl & #Hstates)".
transitivity (int.nat latestVnum).
iDestruct (applyreadonly_step with "Hghost Hstates") as "#H".
Lemma alloc_own_ghost_vnums :
⊢ |==> ∃ γst, own_ghost_vnums γst [] 0 ∗
is_state γst 0 []
.
iMod (ghost_map_alloc_fin []) as (?) "Hmap".
iDestruct (big_sepS_elem_of_acc_impl (U64 0) with "Hmap") as "[HH Hmap]".
iMod (ghost_map_points_to_persist with "HH") as "#?".
replace (int.nat (U64 0)) with (0) in H; word.
iApply (big_sepS_impl with "[]").
replace (x) with (U64 0) by word.
replace (x) with (U64 0) by word.
Lemma wp_MakeExactlyOnceStateMachine own_low lowSm :
{{{
"#Hislow" ∷ low_is_VersionedStateMachine lowSm own_low ∗
"Hlowstate" ∷ (∀ γst, is_state γst 0 [] -∗
own_low γst [] 0)
}}}
MakeExactlyOnceStateMachine #lowSm
{{{
sm own_MemStateMachine, RET #sm;
esm_is_InMemoryStateMachine sm own_MemStateMachine ∗
own_MemStateMachine []
}}}.
wp_apply (wp_allocStruct).
iDestruct (struct_fields_split with "Hl") as "HH".
wp_apply (wp_NewMap u64).
iIntros (lastSeq_ptr) "HlastSeq".
wp_apply (wp_byteMapNew).
iIntros (lastReply_ptr) "HlastReply".
wp_apply wp_eStateMachine__applyReadonly.
iIntros (?) "[% #HisapplyReadonly]".
wp_apply wp_eStateMachine__apply.
iIntros (?) "[% #Hisapply]".
wp_apply wp_eStateMachine__setState.
iIntros (?) "[% #Hissetstae]".
repeat econstructor; done.
iDestruct (struct_fields_split with "HH") as "HH".
iMod (readonly_alloc_1 with "ApplyVolatile") as "#?".
iMod (readonly_alloc_1 with "GetState") as "#?".
iMod (readonly_alloc_1 with "SetState") as "#?".
iMod (readonly_alloc_1 with "ApplyReadonly") as "#?".
iApply wp_eStatemachine__getState.
iMod (alloc_own_ghost_vnums) as (?) "[Hghost #Hstate]".
iSpecialize ("Hlowstate" with "Hstate").
Lemma wp_MakeClerk configHosts_sl configHosts γ γoplog γerpc :
{{{
"#HconfSl" ∷ readonly (own_slice_small configHosts_sl uint64T 1 configHosts) ∗
"#Hconf" ∷ config_protocol_proof.is_pb_config_hosts configHosts γ ∗
"#Hesm_inv" ∷ is_esm_inv γ γoplog γerpc ∗
"#Herpc_inv" ∷ is_eRPCServer γerpc
}}}
exactlyonce.MakeClerk (slice_val configHosts_sl)
{{{
ck, RET #ck; own_Clerk ck γoplog
}}}
.
wp_apply (wp_allocStruct).
iDestruct (struct_fields_split with "Hl") as "HH".
wp_apply clerk_proof.wp_MakeClerk.
iDestruct (own_slice_to_small with "Hsl") as "Hsl".
wp_apply (wp_SliceSet with "[$Hsl]").
wp_bind (Clerk__Apply _ _).
wp_apply (wp_frame_wand with "[-Hsl Hck]").
wp_apply (wp_Clerk__Apply with "Hck [$Hsl]").
iInv "Hesm_inv" as "Hi" "Hclose".
iDestruct "Hi" as (?) "[>Hpblog Hee]".
iDestruct "Hee" as ">Hee".
iDestruct (big_sepS_elem_of_acc_impl (compute_state ops).(nextCID) with "Hcids") as "[Hcid Hcids]".
iDestruct "Hcid" as "[%Hbad | Hcid]".
iMod ("Hclose" with "[HerpcServer Hoplog Hlog Hcids]").
iExists _; iFrame "Hoplog".
rewrite compute_state_snoc.
iIntros (???) "[%Hineq|$]".
rewrite /esm_record /= in Hpost.
rewrite /esm_record /= in Hpost.
iIntros (?) "Hrep_sl _ Hpbck".
wp_apply (wp_ReadInt with "[Hrep_sl]").
iMod (readonly_alloc_1 with "ck") as "#?".