aneris.examples.counter_with_contributions.proof
From iris Require Import invariants.
From iris.algebra Require Import gmap frac agree frac_auth.
From iris.base_logic Require Export gen_heap.
From iris.base_logic.lib Require Export own saved_prop.
From iris.program_logic Require Export weakestpre.
From iris.proofmode Require Import tactics.
From stdpp Require Import base.
From aneris Require Import tactics proofmode notation adequacy.
From aneris.examples.library Require Import frac_auth.
From aneris.examples.counter_with_contributions Require Import counter.
Set Default Proof Using "Type".
Import Network.
Import String.
Import uPred.
Class ccounterG Σ := MCounterG {
ccounter_inG :> inG Σ (frac_authR (mnatUR));
ccounter_name : gname
}.
Definition ccounterΣ : gFunctors := #[GFunctor (frac_authR mnatUR)].
Instance subG_inG_ccounterΣ {Σ} :
subG ccounterΣ Σ → inG Σ (frac_authR (mnatUR)) .
Proof.
solve_inG.
Qed.
Section ccounter_server.
Context `{cG : ccounterG Σ}
`{dG : distG Σ}
`{node : Network.node}.
Definition ownC := own (A:=frac_authR mnatUR) ccounter_name.
Definition ccounter_si : socket_interp Σ :=
λ msg,
match ms_body msg with
| "INC" =>
(∃ (n : mnat) π φ, ms_sender msg ⤇ φ ∗ ownC (◯F{π} n) ∗
▷ (∀ m (k : nat),
⌜ms_body m = StringOfZ((n + k + 1 : mnat)%nat)⌝ ∗
ownC (◯F{π} (n + k + 1 : mnat)%nat) -∗ φ m))
| _ => ⌜True⌝
end%I.
Arguments ccounter_si : simpl never.
Definition handlerR l :=
(∃ (v : mnat), ownC (●F v) ∗ l ↦[node] #v)%I.
Lemma server_s A address:
address ∈ A ->
{{{ address ⤇ ccounter_si ∗
Fixed A ∗ FreePorts (ip_of_address address) {[port_of_address address]} ∗
ownC (●F (0%nat : mnat)) ∗ IsNode node }}}
⟨node; ccounter_server #address⟩
{{{ v, RET 〈node;v〉; True }}}.
Proof.
iIntros (Haddress Φ) "(#Hsi & #Hfixed & Hip & Hauth & Hn) HΦ".
rewrite /ccounter_server. wp_pures.
wp_alloc l as "Hl". wp_let.
wp_socket h as "Hsocket". wp_pures.
destruct address; simpl.
wp_apply (wp_socketbind_static with "[$Hfixed Hip $Hsocket]"); try done.
iDestruct 1 as (g) "(Hip & Hsocket & Hbind)". wp_seq.
wp_apply (listen_spec (handlerR l) with "[] [-HΦ] [$HΦ]"); last first.
- iFrame; iFrame "#". iExists 0%nat; iFrame.
- simpl. iLöb as "IH" forall (g).
iIntros (m rm' Φ') "!# (HP & Hs & Hrm & Hm & _ & Hsipred) HΦ'".
iDestruct "HP" as (v) "(Hca & Hl)".
wp_rec. wp_let. wp_op. case_bool_decide; wp_if; simplify_eq.
+ rewrite {3}/ccounter_si /=. rewrite H.
iDestruct "Hsipred" as (v' π' φa) "(Hsia & Hc & Hvs)".
wp_load. wp_op. wp_let. wp_store.
iDestruct (own_valid_2 with "Hca Hc") as %Hvalid.
apply frac_auth_mnat_valid in Hvalid.
iMod (frac_auth_mnat_own_update with "Hca Hc") as "[Hca Hc]". wp_seq. wp_op.
wp_apply (wp_send_to_bound with "[$Hs $Hsia Hc Hvs]"); eauto.
{ apply nat_le_sum in Hvalid. destruct Hvalid as [z Hvalid].
iApply ("Hvs" $! _ z).
rewrite Hvalid Nat.add_1_r. iFrame. iPureIntro; auto.
cbn; f_equal; lia. }
iIntros "[Hs _]"; simpl. wp_seq.
wp_apply (listen_spec (handlerR l) (λ v, ⌜True⌝)%I with "[] [-HΦ']"); last first.
* iApply "HΦ'".
* iFrame; iFrame "#". rewrite /handlerR. iExists (S v). iFrame.
{ by rewrite Nat2Z.inj_succ Z.add_1_r. }
* iApply "IH".
* eauto.
+ wp_seq.
wp_apply (listen_spec (handlerR l) (λ v, ⌜True⌝)%I with "[] [-HΦ' $Hsi]");
last first; eauto.
* iFrame; iFrame "#". iExists v. iFrame.
* iApply "IH".
* by [].
- by [].
Qed.
End ccounter_server.
Section ccounter_client.
Context `{cG : ccounterG Σ}
`{dG : distG Σ}.
Definition client_si π n : socket_interp Σ :=
(λ msg, ∃ k : mnat,
⌜ms_body msg = StringOfZ (n + k + 1)%nat⌝ ∗
ownC (◯F{π} (n + k + 1 : mnat)%nat))%I.
Definition handlerR' π v ip port := SocketAddressInet ip port ⤇ client_si π v.
Lemma client_s (n : node) A ip port π v (server : socket_address) :
SocketAddressInet ip port ∉ A →
{{{ Fixed A ∗ server ⤇ ccounter_si ∗
FreePorts ip {[port]} ∗ IsNode n ∗ ownC (◯F{π} v) }}}
⟨n;ccounter_client #ip #(Z.pos port) #server⟩
{{{ r, RET 〈n;r〉; ∃ (v' : mnat) π', ⌜r = #(StringOfZ v')⌝ ∗
⌜v < v'⌝ ∗ ownC (◯F{π'} (v' : mnat))
}}}.
Proof.
iIntros (Hfree Φ) "(#Hnetwork & #Hserver & Hip & Hn & Hc) HΦ".
wp_lam. do 2 wp_let.
wp_socket h as "Hsocket". wp_let.
wp_makeaddress. wp_let.
wp_apply (wp_socketbind_dynamic _ _ _ _ _ {|
sfamily := PF_INET;
stype := SOCK_DGRAM;
sprotocol := IPPROTO_UDP;
saddress := None |} _ (client_si π v)
with "[Hip Hsocket]"); simpl; try done. iFrame; iFrame "#".
iDestruct 1 as (g) "(Hsocket & Hrecs & #Hsi)".
wp_seq.
wp_apply (wp_send_to_bound
with "[$Hsocket Hc]"); eauto; iFrame "#".
{ rewrite /message_stable_from_message /ccounter_si /=.
iExists v,π,(client_si π v). iSplitR; eauto.
iFrame; iFrame "#". iNext.
iIntros (m k) "(% & H')".
iExists k. iFrame. eauto. }
iIntros "[Hsocket _]". wp_seq.
wp_apply (listen_spec (handlerR' π v ip port)
(λ r, ∃ π (v' : mnat),
⌜v < v'⌝ ∗ ⌜r = #(StringOfZ v')⌝ ∗
ownC (◯F{π} (v' : mnat)))%I
_ with "[] [-HΦ]"); eauto; last first.
- iIntros (v') "H'". iApply "HΦ". iDestruct "H'" as (π' m Hlt Heq) "H'".
iExists m. iFrame; iFrame "#". rewrite Heq. auto.
- iFrame; iFrame "#".
- iIntros (m ? Φ') "!# (_ & _ & _ & _ & _ & Hsipred) HΦ'".
wp_pures.
iApply "HΦ'". iDestruct "Hsipred" as (k) "(% & HP)".
iExists π,((v + k + 1)%nat : mnat).
destruct m. simpl in *. subst. iFrame. iSplitR; iPureIntro; auto. lia.
- done.
Qed.
End ccounter_client.
Lemma make_ccounterG `{inG Σ (frac_authR (mnatUR))} :
(|==> ∃ _ : ccounterG Σ, ownC (●F (0%nat : mnat)) ∗ ownC (◯F (0%nat : mnat)))%I.
Proof.
iMod (own_alloc (●F (0%nat : mnat) ⋅ ◯F (0%nat : mnat))) as (γ) "[Hγ Hγ']"; first by apply frac_auth_valid.
by iExists {|ccounter_name := γ |}; iFrame.
Qed.
Section ccounter_runner.
Context `{dG : distG Σ, ccounterG Σ}.
Definition ips : gset string := {[ "0.0.0.0" ; "127.0.0.1" ; "localhost" ]}.
Definition server := SocketAddressInet "127.0.0.1" 1337.
Lemma ccounter_runner_s A :
server ∈ A ->
SocketAddressInet "localhost" 1338 ∉ A →
SocketAddressInet "0.0.0.0" 1339 ∉ A →
{{{ ownC (●F (0%nat : mnat)) ∗ ownC (◯F (0%nat : mnat)) ∗ Fixed A ∗
server ⤇ ccounter_si ∗ [∗ set] ip ∈ ips, FreeIP ip }}}
ccounter_runner
{{{ v, RET v; True }}}.
Proof.
iIntros (? ? ? Φ) "(Hs & Hc & #Hfix & #Hsi & Hips) HΦ".
rewrite /ccounter_runner.
iDestruct (big_sepS_delete _ _ "127.0.0.1" with "Hips") as "(Hserver & Hips)";
first set_solver.
iDestruct (big_sepS_delete _ _ "0.0.0.0" with "Hips") as "(Hc1 & Hips)";
first set_solver.
iDestruct (big_sepS_delete _ _ "localhost" with "Hips") as "(Hc2 & _)";
first set_solver.
wp_makeaddress. wp_let. rewrite /server.
wp_apply (wp_start with "[-]"); first auto. iFrame. simpl.
iSplitL "Hc Hc1 Hc2 HΦ"; last first.
{ iNext. iIntros "Hn Hip".
iApply (server_s with "[Hn Hip $Hs] []");
try iFrame "#"; simpl;
eauto; try done. }
iDestruct "Hc" as "(Hc1' & Hc2')". iNext. wp_seq.
wp_apply (wp_start with "[-]"); first auto. iFrame.
iSplitL "Hc1 Hc1' HΦ"; last first.
{ iNext. iIntros "Hn Hip".
iApply (client_s with "[Hn Hip Hc2'] []"); eauto;
last by iFrame; iFrame "#". }
iNext. wp_seq.
wp_apply (wp_start with "[-]"); first auto. iFrame.
iSplitL "HΦ". by iApply "HΦ".
{ iNext. iIntros "Hn Hip".
iApply (client_s with "[-] []"); eauto;
last by iFrame; iFrame "#". }
Qed.
End ccounter_runner.
Definition counter_is :=
{|
state_heaps := ∅;
state_sockets := ∅;
state_ports_in_use :=
<["0.0.0.0" := ∅ ]> $ <["127.0.0.1" := ∅ ]> $ <["localhost" := ∅ ]> $ ∅;
state_ms := ∅;
|}.
Definition socket_interp `{distG, ccounterG Σ} sa : socket_interp Σ :=
(match sa with
| SocketAddressInet "127.0.0.1" 1337 => ccounter_si
| _ => λ msg, ⌜True⌝
end)%I.
Definition fixed_dom : gset socket_address := {[ server ]}.
Theorem ccounter_safe : adequate NotStuck ccounter_runner counter_is (λ v _, True).
Proof.
set (Σ := #[distΣ; ccounterΣ]).
eapply (@dist_adequacy Σ _ ips fixed_dom); try done; last first.
{ set_solver. }
{ intros i.
rewrite /ips !elem_of_union !elem_of_singleton.
intros [[]|]; subst; set_solver. }
{ rewrite /ips /= !dom_insert_L dom_empty_L right_id_L !assoc_L //. }
iIntros (dinvG).
iMod (@make_ccounterG Σ) as (?) "[? ?]".
iModIntro.
iExists socket_interp.
iIntros "Hsi #Hsc Hips".
iApply (@ccounter_runner_s with "[-] []"); eauto;
rewrite /fixed_dom /server; try iFrame; try set_solver.
rewrite big_sepS_singleton. rewrite /socket_interp. iFrame "#".
Qed.
From iris.algebra Require Import gmap frac agree frac_auth.
From iris.base_logic Require Export gen_heap.
From iris.base_logic.lib Require Export own saved_prop.
From iris.program_logic Require Export weakestpre.
From iris.proofmode Require Import tactics.
From stdpp Require Import base.
From aneris Require Import tactics proofmode notation adequacy.
From aneris.examples.library Require Import frac_auth.
From aneris.examples.counter_with_contributions Require Import counter.
Set Default Proof Using "Type".
Import Network.
Import String.
Import uPred.
Class ccounterG Σ := MCounterG {
ccounter_inG :> inG Σ (frac_authR (mnatUR));
ccounter_name : gname
}.
Definition ccounterΣ : gFunctors := #[GFunctor (frac_authR mnatUR)].
Instance subG_inG_ccounterΣ {Σ} :
subG ccounterΣ Σ → inG Σ (frac_authR (mnatUR)) .
Proof.
solve_inG.
Qed.
Section ccounter_server.
Context `{cG : ccounterG Σ}
`{dG : distG Σ}
`{node : Network.node}.
Definition ownC := own (A:=frac_authR mnatUR) ccounter_name.
Definition ccounter_si : socket_interp Σ :=
λ msg,
match ms_body msg with
| "INC" =>
(∃ (n : mnat) π φ, ms_sender msg ⤇ φ ∗ ownC (◯F{π} n) ∗
▷ (∀ m (k : nat),
⌜ms_body m = StringOfZ((n + k + 1 : mnat)%nat)⌝ ∗
ownC (◯F{π} (n + k + 1 : mnat)%nat) -∗ φ m))
| _ => ⌜True⌝
end%I.
Arguments ccounter_si : simpl never.
Definition handlerR l :=
(∃ (v : mnat), ownC (●F v) ∗ l ↦[node] #v)%I.
Lemma server_s A address:
address ∈ A ->
{{{ address ⤇ ccounter_si ∗
Fixed A ∗ FreePorts (ip_of_address address) {[port_of_address address]} ∗
ownC (●F (0%nat : mnat)) ∗ IsNode node }}}
⟨node; ccounter_server #address⟩
{{{ v, RET 〈node;v〉; True }}}.
Proof.
iIntros (Haddress Φ) "(#Hsi & #Hfixed & Hip & Hauth & Hn) HΦ".
rewrite /ccounter_server. wp_pures.
wp_alloc l as "Hl". wp_let.
wp_socket h as "Hsocket". wp_pures.
destruct address; simpl.
wp_apply (wp_socketbind_static with "[$Hfixed Hip $Hsocket]"); try done.
iDestruct 1 as (g) "(Hip & Hsocket & Hbind)". wp_seq.
wp_apply (listen_spec (handlerR l) with "[] [-HΦ] [$HΦ]"); last first.
- iFrame; iFrame "#". iExists 0%nat; iFrame.
- simpl. iLöb as "IH" forall (g).
iIntros (m rm' Φ') "!# (HP & Hs & Hrm & Hm & _ & Hsipred) HΦ'".
iDestruct "HP" as (v) "(Hca & Hl)".
wp_rec. wp_let. wp_op. case_bool_decide; wp_if; simplify_eq.
+ rewrite {3}/ccounter_si /=. rewrite H.
iDestruct "Hsipred" as (v' π' φa) "(Hsia & Hc & Hvs)".
wp_load. wp_op. wp_let. wp_store.
iDestruct (own_valid_2 with "Hca Hc") as %Hvalid.
apply frac_auth_mnat_valid in Hvalid.
iMod (frac_auth_mnat_own_update with "Hca Hc") as "[Hca Hc]". wp_seq. wp_op.
wp_apply (wp_send_to_bound with "[$Hs $Hsia Hc Hvs]"); eauto.
{ apply nat_le_sum in Hvalid. destruct Hvalid as [z Hvalid].
iApply ("Hvs" $! _ z).
rewrite Hvalid Nat.add_1_r. iFrame. iPureIntro; auto.
cbn; f_equal; lia. }
iIntros "[Hs _]"; simpl. wp_seq.
wp_apply (listen_spec (handlerR l) (λ v, ⌜True⌝)%I with "[] [-HΦ']"); last first.
* iApply "HΦ'".
* iFrame; iFrame "#". rewrite /handlerR. iExists (S v). iFrame.
{ by rewrite Nat2Z.inj_succ Z.add_1_r. }
* iApply "IH".
* eauto.
+ wp_seq.
wp_apply (listen_spec (handlerR l) (λ v, ⌜True⌝)%I with "[] [-HΦ' $Hsi]");
last first; eauto.
* iFrame; iFrame "#". iExists v. iFrame.
* iApply "IH".
* by [].
- by [].
Qed.
End ccounter_server.
Section ccounter_client.
Context `{cG : ccounterG Σ}
`{dG : distG Σ}.
Definition client_si π n : socket_interp Σ :=
(λ msg, ∃ k : mnat,
⌜ms_body msg = StringOfZ (n + k + 1)%nat⌝ ∗
ownC (◯F{π} (n + k + 1 : mnat)%nat))%I.
Definition handlerR' π v ip port := SocketAddressInet ip port ⤇ client_si π v.
Lemma client_s (n : node) A ip port π v (server : socket_address) :
SocketAddressInet ip port ∉ A →
{{{ Fixed A ∗ server ⤇ ccounter_si ∗
FreePorts ip {[port]} ∗ IsNode n ∗ ownC (◯F{π} v) }}}
⟨n;ccounter_client #ip #(Z.pos port) #server⟩
{{{ r, RET 〈n;r〉; ∃ (v' : mnat) π', ⌜r = #(StringOfZ v')⌝ ∗
⌜v < v'⌝ ∗ ownC (◯F{π'} (v' : mnat))
}}}.
Proof.
iIntros (Hfree Φ) "(#Hnetwork & #Hserver & Hip & Hn & Hc) HΦ".
wp_lam. do 2 wp_let.
wp_socket h as "Hsocket". wp_let.
wp_makeaddress. wp_let.
wp_apply (wp_socketbind_dynamic _ _ _ _ _ {|
sfamily := PF_INET;
stype := SOCK_DGRAM;
sprotocol := IPPROTO_UDP;
saddress := None |} _ (client_si π v)
with "[Hip Hsocket]"); simpl; try done. iFrame; iFrame "#".
iDestruct 1 as (g) "(Hsocket & Hrecs & #Hsi)".
wp_seq.
wp_apply (wp_send_to_bound
with "[$Hsocket Hc]"); eauto; iFrame "#".
{ rewrite /message_stable_from_message /ccounter_si /=.
iExists v,π,(client_si π v). iSplitR; eauto.
iFrame; iFrame "#". iNext.
iIntros (m k) "(% & H')".
iExists k. iFrame. eauto. }
iIntros "[Hsocket _]". wp_seq.
wp_apply (listen_spec (handlerR' π v ip port)
(λ r, ∃ π (v' : mnat),
⌜v < v'⌝ ∗ ⌜r = #(StringOfZ v')⌝ ∗
ownC (◯F{π} (v' : mnat)))%I
_ with "[] [-HΦ]"); eauto; last first.
- iIntros (v') "H'". iApply "HΦ". iDestruct "H'" as (π' m Hlt Heq) "H'".
iExists m. iFrame; iFrame "#". rewrite Heq. auto.
- iFrame; iFrame "#".
- iIntros (m ? Φ') "!# (_ & _ & _ & _ & _ & Hsipred) HΦ'".
wp_pures.
iApply "HΦ'". iDestruct "Hsipred" as (k) "(% & HP)".
iExists π,((v + k + 1)%nat : mnat).
destruct m. simpl in *. subst. iFrame. iSplitR; iPureIntro; auto. lia.
- done.
Qed.
End ccounter_client.
Lemma make_ccounterG `{inG Σ (frac_authR (mnatUR))} :
(|==> ∃ _ : ccounterG Σ, ownC (●F (0%nat : mnat)) ∗ ownC (◯F (0%nat : mnat)))%I.
Proof.
iMod (own_alloc (●F (0%nat : mnat) ⋅ ◯F (0%nat : mnat))) as (γ) "[Hγ Hγ']"; first by apply frac_auth_valid.
by iExists {|ccounter_name := γ |}; iFrame.
Qed.
Section ccounter_runner.
Context `{dG : distG Σ, ccounterG Σ}.
Definition ips : gset string := {[ "0.0.0.0" ; "127.0.0.1" ; "localhost" ]}.
Definition server := SocketAddressInet "127.0.0.1" 1337.
Lemma ccounter_runner_s A :
server ∈ A ->
SocketAddressInet "localhost" 1338 ∉ A →
SocketAddressInet "0.0.0.0" 1339 ∉ A →
{{{ ownC (●F (0%nat : mnat)) ∗ ownC (◯F (0%nat : mnat)) ∗ Fixed A ∗
server ⤇ ccounter_si ∗ [∗ set] ip ∈ ips, FreeIP ip }}}
ccounter_runner
{{{ v, RET v; True }}}.
Proof.
iIntros (? ? ? Φ) "(Hs & Hc & #Hfix & #Hsi & Hips) HΦ".
rewrite /ccounter_runner.
iDestruct (big_sepS_delete _ _ "127.0.0.1" with "Hips") as "(Hserver & Hips)";
first set_solver.
iDestruct (big_sepS_delete _ _ "0.0.0.0" with "Hips") as "(Hc1 & Hips)";
first set_solver.
iDestruct (big_sepS_delete _ _ "localhost" with "Hips") as "(Hc2 & _)";
first set_solver.
wp_makeaddress. wp_let. rewrite /server.
wp_apply (wp_start with "[-]"); first auto. iFrame. simpl.
iSplitL "Hc Hc1 Hc2 HΦ"; last first.
{ iNext. iIntros "Hn Hip".
iApply (server_s with "[Hn Hip $Hs] []");
try iFrame "#"; simpl;
eauto; try done. }
iDestruct "Hc" as "(Hc1' & Hc2')". iNext. wp_seq.
wp_apply (wp_start with "[-]"); first auto. iFrame.
iSplitL "Hc1 Hc1' HΦ"; last first.
{ iNext. iIntros "Hn Hip".
iApply (client_s with "[Hn Hip Hc2'] []"); eauto;
last by iFrame; iFrame "#". }
iNext. wp_seq.
wp_apply (wp_start with "[-]"); first auto. iFrame.
iSplitL "HΦ". by iApply "HΦ".
{ iNext. iIntros "Hn Hip".
iApply (client_s with "[-] []"); eauto;
last by iFrame; iFrame "#". }
Qed.
End ccounter_runner.
Definition counter_is :=
{|
state_heaps := ∅;
state_sockets := ∅;
state_ports_in_use :=
<["0.0.0.0" := ∅ ]> $ <["127.0.0.1" := ∅ ]> $ <["localhost" := ∅ ]> $ ∅;
state_ms := ∅;
|}.
Definition socket_interp `{distG, ccounterG Σ} sa : socket_interp Σ :=
(match sa with
| SocketAddressInet "127.0.0.1" 1337 => ccounter_si
| _ => λ msg, ⌜True⌝
end)%I.
Definition fixed_dom : gset socket_address := {[ server ]}.
Theorem ccounter_safe : adequate NotStuck ccounter_runner counter_is (λ v _, True).
Proof.
set (Σ := #[distΣ; ccounterΣ]).
eapply (@dist_adequacy Σ _ ips fixed_dom); try done; last first.
{ set_solver. }
{ intros i.
rewrite /ips !elem_of_union !elem_of_singleton.
intros [[]|]; subst; set_solver. }
{ rewrite /ips /= !dom_insert_L dom_empty_L right_id_L !assoc_L //. }
iIntros (dinvG).
iMod (@make_ccounterG Σ) as (?) "[? ?]".
iModIntro.
iExists socket_interp.
iIntros "Hsi #Hsc Hips".
iApply (@ccounter_runner_s with "[-] []"); eauto;
rewrite /fixed_dom /server; try iFrame; try set_solver.
rewrite big_sepS_singleton. rewrite /socket_interp. iFrame "#".
Qed.