Built with Alectryon, running Coq+SerAPI v8.12.0+0.12.0. Coq sources are in this panel; goals and messages will appear in the other. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+🖱️ to focus.
Require Import POCS. Require Import OneDiskAPI. Require Import BadBlockAPI. Module RemappedDisk (bd : BadBlockAPI) <: OneDiskAPI. Import ListNotations. Definition read (a : addr) : proc block := bs <- bd.getBadBlock; if a == bs then len <- bd.size; r <- bd.read (len-1); Ret r else r <- bd.read a; Ret r. Definition write (a : addr) (b : block) : proc unit := Ret tt. Definition size : proc nat := len <- bd.size; Ret (len - 1). Definition init' : proc InitResult := len <- bd.size; if len == 0 then Ret InitFailed else bs <- bd.getBadBlock; if (lt_dec bs len) then Ret Initialized else Ret InitFailed. Definition init := then_init bd.init init'. Definition recover: proc unit := bd.recover. Inductive remapped_abstraction (bs_state : BadBlockAPI.State) (rd_disk : OneDiskAPI.State) : Prop := | RemappedAbstraction : let bs_disk := stateDisk bs_state in let bs_addr := stateBadBlock bs_state in forall (* Fill in the rest of your abstraction here. *) (* To refer to the contents of disk [d] at address [a], you can write [diskGet a] *) (* To refer to the size of disk [d], you can write [diskSize d] *) (* You can try to prove [read_ok] to discover what you need from this abstraction *) (* Hint 1: What should be true about the non-bad blocks? Replace [True] with what needs to be true *) (Hgoodblocks : True) (* Hint 2: What should be true about the bad block? *) (Hbadblock : True) (* when writing the above, *) (* Hint 3: What if the bad block address is the last address? *) (Hsize : diskSize bs_disk = diskSize rd_disk + 1), remapped_abstraction bs_state rd_disk. Hint Constructors remapped_abstraction : core. Definition abstr : Abstraction OneDiskAPI.State := abstraction_compose bd.abstr {| abstraction := remapped_abstraction |}. (* Note that these examples aren't trivial to prove, even if you have the right abstraction relation. They should help you think about whether your abstraction relation makes sense (although you may need to modify it to actually prove the implementation correct). *)forall Hinbounds : 0 < diskSize [block1; block0; block0], remapped_abstraction {| stateDisk := [block1; block0; block0]; stateBadBlock := 0; stateBadBlockInBounds := Hinbounds |} [block0; block0]constructor; auto. Admitted.forall Hinbounds : 0 < diskSize [block1; block0; block0], remapped_abstraction {| stateDisk := [block1; block0; block0]; stateBadBlock := 0; stateBadBlockInBounds := Hinbounds |} [block0; block0]forall Hinbounds : 0 < diskSize [block1; block0], remapped_abstraction {| stateDisk := [block1; block0]; stateBadBlock := 0; stateBadBlockInBounds := Hinbounds |} [block0]constructor; auto. Admitted.forall Hinbounds : 0 < diskSize [block1; block0], remapped_abstraction {| stateDisk := [block1; block0]; stateBadBlock := 0; stateBadBlockInBounds := Hinbounds |} [block0]forall Hinbounds : 1 < diskSize [block0; block0], remapped_abstraction {| stateDisk := [block0; block0]; stateBadBlock := 1; stateBadBlockInBounds := Hinbounds |} [block0]constructor; auto. Admitted.forall Hinbounds : 1 < diskSize [block0; block0], remapped_abstraction {| stateDisk := [block0; block0]; stateBadBlock := 1; stateBadBlockInBounds := Hinbounds |} [block0]forall Hinbounds : 1 < diskSize [block0; block0], ~ remapped_abstraction {| stateDisk := [block0; block0]; stateBadBlock := 1; stateBadBlockInBounds := Hinbounds |} [block1]forall Hinbounds : 1 < diskSize [block0; block0], ~ remapped_abstraction {| stateDisk := [block0; block0]; stateBadBlock := 1; stateBadBlockInBounds := Hinbounds |} [block1]Hinbounds:1 < diskSize [block0; block0]~ remapped_abstraction {| stateDisk := [block0; block0]; stateBadBlock := 1; stateBadBlockInBounds := Hinbounds |} [block1]Hinbounds:1 < diskSize [block0; block0]H:remapped_abstraction {| stateDisk := [block0; block0]; stateBadBlock := 1; stateBadBlockInBounds := Hinbounds |} [block1]FalseAdmitted.Hinbounds:1 < 2H:remapped_abstraction {| stateDisk := [block0; block0]; stateBadBlock := 1; stateBadBlockInBounds := Hinbounds |} [block1]bs_disk:=[block0; block0]:diskbs_addr:=1:addrHgoodblocks, Hbadblock:TrueHsize:2 = 2Falseforall Hinbounds : 0 < diskSize [block1; block1], ~ remapped_abstraction {| stateDisk := [block1; block1]; stateBadBlock := 0; stateBadBlockInBounds := Hinbounds |} [block0]forall Hinbounds : 0 < diskSize [block1; block1], ~ remapped_abstraction {| stateDisk := [block1; block1]; stateBadBlock := 0; stateBadBlockInBounds := Hinbounds |} [block0]Hinbounds:0 < diskSize [block1; block1]~ remapped_abstraction {| stateDisk := [block1; block1]; stateBadBlock := 0; stateBadBlockInBounds := Hinbounds |} [block0]Hinbounds:0 < diskSize [block1; block1]H:remapped_abstraction {| stateDisk := [block1; block1]; stateBadBlock := 0; stateBadBlockInBounds := Hinbounds |} [block0]FalseAdmitted. (* Due to how remapped_abstraction is defined (as an inductive), it cannot be unfolded. This tactic identifies abstraction relations in the hypotheses and breaks them apart with [inversion], and also does some cleanup. *) Ltac invert_abstraction := match goal with | H : remapped_abstraction _ _ |- _ => inversion H; clear H; subst; subst_var end.Hinbounds:0 < 2H:remapped_abstraction {| stateDisk := [block1; block1]; stateBadBlock := 0; stateBadBlockInBounds := Hinbounds |} [block0]bs_disk:=[block1; block1]:diskbs_addr:=0:addrHgoodblocks, Hbadblock:TrueHsize:2 = 2Falseinit_abstraction init recover abstr inited_anyinit_abstraction init recover abstr inited_anyproc_spec (fun (_ : unit) (state : State) => {| pre := inited_any state; post := fun (r : InitResult) (state' : State) => match r with | Initialized => exists state'' : OneDiskAPI.State, abstraction {| abstraction := remapped_abstraction |} state' state'' /\ inited_any state'' | InitFailed => True end; recovered := fun (_ : unit) (_ : State) => True |}) init' bd.recover bd.abstrAdmitted.a':unitstate:StateH:inited_any stater:natLexec:Marker "after" bd.sizeproc_spec (fun (_ : unit) (state' : State) => {| pre := state' = state /\ r = diskSize (stateDisk state); post := fun (r' : InitResult) (state'' : State) => match r' with | Initialized => exists state''0 : OneDiskAPI.State, remapped_abstraction state'' state''0 /\ inited_any state''0 | InitFailed => True end; recovered := fun (_ : unit) (_ : State) => True |}) (if equal_dec r 0 then Ret InitFailed else bs <- bd.getBadBlock; (if lt_dec bs r then Ret Initialized else Ret InitFailed)) bd.recover bd.abstrforall a : addr, proc_spec (OneDiskAPI.read_spec a) (read a) recover abstrforall a : addr, proc_spec (OneDiskAPI.read_spec a) (read a) recover abstrforall a : addr, proc_spec (OneDiskAPI.read_spec a) (bs <- bd.getBadBlock; (if equal_dec a bs then len <- bd.size; r <- bd.read (len - 1); Ret r else r <- bd.read a; Ret r)) recover abstra:addrproc_spec (OneDiskAPI.read_spec a) (bs <- bd.getBadBlock; (if equal_dec a bs then len <- bd.size; r <- bd.read (len - 1); Ret r else r <- bd.read a; Ret r)) recover abstra:addrproc_spec (fun '(_, state2) (state : State) => {| pre := True /\ remapped_abstraction state state2; post := fun (v : block) (state' : State) => exists state2' : OneDiskAPI.State, (state2' = state2 /\ diskGet state2 a =?= v) /\ remapped_abstraction state' state2'; recovered := fun (_ : unit) (state' : State) => exists state2' : OneDiskAPI.State, state2' = state2 /\ remapped_abstraction state' state2' |}) (bs <- bd.getBadBlock; (if equal_dec a bs then len <- bd.size; r <- bd.read (len - 1); Ret r else r <- bd.read a; Ret r)) recover bd.abstra:addra0:unitstate2:OneDiskAPI.Statestate:StateH:TrueH0:remapped_abstraction state state2r:addrLexec:Marker "after" bd.getBadBlockproc_spec (fun (_ : unit) (state' : State) => {| pre := state' = state /\ r = stateBadBlock state; post := fun (r' : block) (state'' : State) => exists state2' : OneDiskAPI.State, (state2' = state2 /\ diskGet state2 a =?= r') /\ remapped_abstraction state'' state2'; recovered := fun (_ : unit) (state'' : State) => exists state2' : OneDiskAPI.State, state2' = state2 /\ remapped_abstraction state'' state2' |}) (if equal_dec a r then len <- bd.size; r <- bd.read (len - 1); Ret r else r <- bd.read a; Ret r) recover bd.abstra:addra0:unitstate2:OneDiskAPI.Statestate:StateH:TrueH0:remapped_abstraction state state2r:addrLexec:Marker "after" bd.getBadBlocke:a = rproc_spec (fun (_ : unit) (state' : State) => {| pre := state' = state /\ r = stateBadBlock state; post := fun (r' : block) (state'' : State) => exists state2' : OneDiskAPI.State, (state2' = state2 /\ diskGet state2 a =?= r') /\ remapped_abstraction state'' state2'; recovered := fun (_ : unit) (state'' : State) => exists state2' : OneDiskAPI.State, state2' = state2 /\ remapped_abstraction state'' state2' |}) (len <- bd.size; r <- bd.read (len - 1); Ret r) recover bd.abstra:addra0:unitstate2:OneDiskAPI.Statestate:StateH:TrueH0:remapped_abstraction state state2r:addrLexec:Marker "after" bd.getBadBlockn:a <> rproc_spec (fun (_ : unit) (state' : State) => {| pre := state' = state /\ r = stateBadBlock state; post := fun (r' : block) (state'' : State) => exists state2' : OneDiskAPI.State, (state2' = state2 /\ diskGet state2 a =?= r') /\ remapped_abstraction state'' state2'; recovered := fun (_ : unit) (state'' : State) => exists state2' : OneDiskAPI.State, state2' = state2 /\ remapped_abstraction state'' state2' |}) (r <- bd.read a; Ret r) recover bd.abstradmit.a:addra0:unitstate2:OneDiskAPI.Statestate:StateH:TrueH0:remapped_abstraction state state2r:addrLexec:Marker "after" bd.getBadBlocke:a = rproc_spec (fun (_ : unit) (state' : State) => {| pre := state' = state /\ r = stateBadBlock state; post := fun (r' : block) (state'' : State) => exists state2' : OneDiskAPI.State, (state2' = state2 /\ diskGet state2 a =?= r') /\ remapped_abstraction state'' state2'; recovered := fun (_ : unit) (state'' : State) => exists state2' : OneDiskAPI.State, state2' = state2 /\ remapped_abstraction state'' state2' |}) (len <- bd.size; r <- bd.read (len - 1); Ret r) recover bd.abstradmit. Admitted.a:addra0:unitstate2:OneDiskAPI.Statestate:StateH:TrueH0:remapped_abstraction state state2r:addrLexec:Marker "after" bd.getBadBlockn:a <> rproc_spec (fun (_ : unit) (state' : State) => {| pre := state' = state /\ r = stateBadBlock state; post := fun (r' : block) (state'' : State) => exists state2' : OneDiskAPI.State, (state2' = state2 /\ diskGet state2 a =?= r') /\ remapped_abstraction state'' state2'; recovered := fun (_ : unit) (state'' : State) => exists state2' : OneDiskAPI.State, state2' = state2 /\ remapped_abstraction state'' state2' |}) (r <- bd.read a; Ret r) recover bd.abstrforall state : State, stateBadBlock state < diskSize (stateDisk state)forall state : State, stateBadBlock state < diskSize (stateDisk state)state:StatestateBadBlock state < diskSize (stateDisk state)stateDisk:diskstateBadBlock:addrstateBadBlockInBounds:stateBadBlock < diskSize stateDiskBadBlockAPI.stateBadBlock {| stateDisk := stateDisk; stateBadBlock := stateBadBlock; stateBadBlockInBounds := stateBadBlockInBounds |} < diskSize (BadBlockAPI.stateDisk {| stateDisk := stateDisk; stateBadBlock := stateBadBlock; stateBadBlockInBounds := stateBadBlockInBounds |})exact stateBadBlockInBounds. Qed.stateDisk:diskstateBadBlock:addrstateBadBlockInBounds:stateBadBlock < diskSize stateDiskstateBadBlock < diskSize stateDiskforall (state state' : State) (s : OneDiskAPI.State) (v : block), remapped_abstraction state s -> stateBadBlock state' = stateBadBlock state -> stateDisk state' = diskUpd (stateDisk state) (diskSize (stateDisk state) - 1) v -> remapped_abstraction state' (diskUpd s (stateBadBlock state) v)(* Hint: you may find it useful to use the [pose proof (bad_block_inbounds state)] if you need [lia] to make use of the fact that the bad block is in-bounds. *) Admitted.forall (state state' : State) (s : OneDiskAPI.State) (v : block), remapped_abstraction state s -> stateBadBlock state' = stateBadBlock state -> stateDisk state' = diskUpd (stateDisk state) (diskSize (stateDisk state) - 1) v -> remapped_abstraction state' (diskUpd s (stateBadBlock state) v)forall (state state' : State) (s : OneDiskAPI.State) (a : nat) (v : block), remapped_abstraction state s -> a <> diskSize (stateDisk state) - 1 -> a <> stateBadBlock state -> stateBadBlock state' = stateBadBlock state -> stateDisk state' = diskUpd (stateDisk state) a v -> remapped_abstraction state' (diskUpd s a v)Admitted. Hint Resolve remapped_abstraction_diskUpd_remap : core. Hint Resolve remapped_abstraction_diskUpd_noremap : core.forall (state state' : State) (s : OneDiskAPI.State) (a : nat) (v : block), remapped_abstraction state s -> a <> diskSize (stateDisk state) - 1 -> a <> stateBadBlock state -> stateBadBlock state' = stateBadBlock state -> stateDisk state' = diskUpd (stateDisk state) a v -> remapped_abstraction state' (diskUpd s a v)forall (a : addr) (v : block), proc_spec (OneDiskAPI.write_spec a v) (write a v) recover abstrforall (a : addr) (v : block), proc_spec (OneDiskAPI.write_spec a v) (write a v) recover abstrforall (a : addr) (v : block), proc_spec (OneDiskAPI.write_spec a v) (Ret tt) recover abstra:addrv:blockproc_spec (OneDiskAPI.write_spec a v) (Ret tt) recover abstrAdmitted.a:addrv:blockproc_spec (fun '(_, state2) (state : State) => {| pre := True /\ remapped_abstraction state state2; post := fun (v0 : unit) (state' : State) => exists state2' : OneDiskAPI.State, (v0 = tt /\ state2' = diskUpd state2 a v) /\ remapped_abstraction state' state2'; recovered := fun (_ : unit) (state' : State) => exists state2' : OneDiskAPI.State, (state2' = state2 \/ state2' = diskUpd state2 a v) /\ remapped_abstraction state' state2' |}) (Ret tt) recover bd.abstrproc_spec OneDiskAPI.size_spec size recover abstrproc_spec OneDiskAPI.size_spec size recover abstrproc_spec OneDiskAPI.size_spec size recover abstrproc_spec OneDiskAPI.size_spec size recover abstrproc_spec (fun '(_, state2) (state : State) => {| pre := True /\ remapped_abstraction state state2; post := fun (v : nat) (state' : State) => exists state2' : OneDiskAPI.State, (state2' = state2 /\ v = diskSize state2) /\ remapped_abstraction state' state2'; recovered := fun (_ : unit) (state' : State) => exists state2' : OneDiskAPI.State, state2' = state2 /\ remapped_abstraction state' state2' |}) size recover bd.abstrAdmitted. (* This proof proves that recovery corresponds to no_wipe. *)a:unitstate2:OneDiskAPI.Statestate:StateH:TrueH0:remapped_abstraction state state2r:natLexec:Marker "after" bd.sizeproc_spec (fun (_ : unit) (state' : State) => {| pre := state' = state /\ r = diskSize (stateDisk state); post := fun (r' : nat) (state'' : State) => exists state2' : OneDiskAPI.State, (state2' = state2 /\ r' = diskSize state2) /\ remapped_abstraction state'' state2'; recovered := fun (_ : unit) (state'' : State) => exists state2' : OneDiskAPI.State, state2' = state2 /\ remapped_abstraction state'' state2' |}) (Ret (r - 1)) recover bd.abstrrec_wipe recover abstr no_wiperec_wipe recover abstr no_wipeforall (T : Type) (v : T), proc_spec (fun (_ : unit) (state : OneDiskAPI.State) => {| pre := True; post := fun (r : T) (state' : OneDiskAPI.State) => r = v /\ state' = state; recovered := fun (_ : unit) (state' : OneDiskAPI.State) => no_wipe state state' |}) (Ret v) recover abstrT:Typev:Tproc_spec (fun (_ : unit) (state : OneDiskAPI.State) => {| pre := True; post := fun (r : T) (state' : OneDiskAPI.State) => r = v /\ state' = state; recovered := fun (_ : unit) (state' : OneDiskAPI.State) => no_wipe state state' |}) (Ret v) recover abstrstep_proc; eauto. Qed. End RemappedDisk. Require Import BadBlockImpl. Module x := RemappedDisk BadBlockDisk.T:Typev:Tproc_spec (fun '(_, state2) (state : State) => {| pre := True /\ remapped_abstraction state state2; post := fun (v0 : T) (state' : State) => exists state2' : OneDiskAPI.State, (v0 = v /\ state2' = state2) /\ remapped_abstraction state' state2'; recovered := fun (_ : unit) (state' : State) => exists state2' : OneDiskAPI.State, no_wipe state2 state2' /\ remapped_abstraction state' state2' |}) (Ret v) recover bd.abstr