-
Notifications
You must be signed in to change notification settings - Fork 19
/
CounterDepCertifiedLiquidity.v
253 lines (202 loc) · 9.29 KB
/
CounterDepCertifiedLiquidity.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
(** * Extraction of a counter contract with dependent types (propositions) *)
(** A version of the counter contract that uses propositions to restrict the input.
We also demonstrate how one can use the certifying eta-expansion to make sure
that constants and constructors are applied to all logical arguments *)
From MetaCoq.Common Require Import Kernames.
From MetaCoq.Template Require Import All.
From ConCert.Embedding Require Import Notations.
From ConCert.Embedding.Extraction Require Import PreludeExt.
From ConCert.Execution Require Import Blockchain.
From ConCert.Execution Require Import ResultMonad.
From ConCert.Extraction Require Import LiquidityExtract.
From ConCert.Extraction Require Import LiquidityPretty.
From ConCert.Extraction Require Import Common.
From MetaCoq.Erasure.Typed Require Import CertifyingEta.
From Coq Require Import ZArith.
From Coq Require Import Bool.
From Coq Require Import String.
Import MCMonadNotation.
Local Open Scope string_scope.
Open Scope Z.
Definition PREFIX := "coq_".
Module Counter.
Definition address := nat.
Definition operation := unit.
Definition storage := Z × address.
Definition Error : Type := nat.
Definition default_error : Error := 1%nat.
Definition init (ctx : SimpleCallCtx)
(setup : Z * address)
: result storage Error :=
let ctx' := ctx in (* prevents optimizations from removing unused [ctx] *)
Ok setup.
Inductive msg :=
| Inc (_ : Z)
| Dec (_ : Z).
Definition inc_balance (st : storage) (new_balance : Z)
(p : (0 <=? new_balance) = true) : storage :=
(st.1 + new_balance, st.2).
Definition dec_balance (st : storage) (new_balance : Z)
(p : (0 <=? new_balance) = true) : storage :=
(st.1 - new_balance, st.2).
Definition my_bool_dec := Eval compute in bool_dec.
Definition counter (msg : msg)
(st : storage)
: result (list operation * storage) Error :=
match msg with
| Inc i =>
match (my_bool_dec (0 <=? i) true) with
| left h =>
Ok ([], inc_balance st i h)
| right _ => Err default_error
end
| Dec i =>
match (my_bool_dec (0 <=? i) true) with
| left h => Ok ([], dec_balance st i h)
| right _ => Err default_error
end
end.
(** A version of the counter with [inc_balance] applied only partially.
Requires eta-expansion for deboxing, because the last argument is logical. *)
Definition counter_partially_applied (msg : msg)
(st : storage)
: result (list operation * storage) Error :=
match msg with
| Inc i =>
match (my_bool_dec (0 <=? i) true) with
| left h =>
let f := inc_balance st i in
Ok ([], f h)
| right _ => Err default_error
end
| Dec i =>
match (my_bool_dec (0 <=? i) true) with
| left h => Ok ([], dec_balance st i h)
| right _ => Err default_error
end
end.
End Counter.
Import Counter.
(** A translation table for definitions we want to remap. The corresponding top-level definitions will be *ignored* *)
Definition TT_remap : list (kername * string) :=
[ remap <%% bool %%> "bool"
; remap <%% list %%> "list"
; remap <%% Amount %%> "tez"
; remap <%% address_coq %%> "address"
; remap <%% time_coq %%> "timestamp"
; remap <%% option %%> "option"
; remap <%% result %%> "result"
; remap <%% Z.add %%> "addInt"
; remap <%% Z.sub %%> "subInt"
; remap <%% Z.leb %%> "leInt"
; remap <%% Z %%> "int"
; remap <%% address %%> "key_hash" (* type of account addresses*)
; remap <%% operation %%> "operation"
; remap <%% @fst %%> "fst"
; remap <%% @snd %%> "snd" ].
(** A translation table of constructors and some constants. The corresponding definitions will be extracted and renamed. *)
Definition TT_rename : list (string * string) :=
[ ("Some", "Some")
; ("None", "None")
; ("Ok", "Ok")
; ("Err", "Err")
; ("O", "0")
; ("Z0" ,"0")
; ("nil", "[]")
; ("true", "true")
; (String.to_string (string_of_kername <%% storage %%>), "storage") (* we add [storage] so it is printed without the prefix *) ].
Definition COUNTER_MODULE : LiquidityMod msg _ (Z × address) storage operation Error :=
{| (* a name for the definition with the extracted code *)
lmd_module_name := "liquidity_counter" ;
(* definitions of operations on pairs and ints *)
lmd_prelude := prod_ops ++ nl ++ int_ops ++ nl ++ result_def;
(* initial storage *)
lmd_init := init ;
(* no extra operations in [init] are required *)
lmd_init_prelude := "" ;
(* the main functionality *)
lmd_receive := counter ;
(* code for the entry point *)
lmd_entry_point := printWrapper (PREFIX ++ "counter") ++ nl
++ printMain
|}.
(** We run the extraction procedure inside the [TemplateMonad].
It uses the certified erasure from [MetaCoq] and the certified deboxing procedure
that removes application of boxes to constants and constructors. *)
Time MetaCoq Run
(t <- liquidity_extraction PREFIX TT_remap TT_rename [] COUNTER_MODULE ;;
tmDefinition (String.of_string COUNTER_MODULE.(lmd_module_name)) t
).
(* Print liquidity_counter. *)
(* Now we show how we can also eta expand using MetaCoq.
There is a version of the counter above that it partially applied, and if we
try to extract that extraction fails. *)
Definition COUNTER_PARTIAL_MODULE : LiquidityMod msg _ (Z × address) storage operation Error :=
{| (* a name for the definition with the extracted code *)
lmd_module_name := "liquidity_counter_partially_applied" ;
(* definitions of operations on pairs and ints *)
lmd_prelude := prod_ops ++ nl ++ int_ops;
(* initial storage *)
lmd_init := init ;
(* no extra operations in [init] are required *)
lmd_init_prelude := "" ;
(* the main functionality *)
lmd_receive := counter_partially_applied ;
(* code for the entry point *)
lmd_entry_point := printWrapper (PREFIX ++ "counter") ++ nl
++ printMain |}.
Fail MetaCoq Run
(liquidity_extraction PREFIX TT_remap TT_rename [] COUNTER_PARTIAL_MODULE).
(* The command has indeed failed with message:
Erased environment is not expanded enough for dearging to be provably correct *)
(* However, Coq's metatheory already includes eta conversion as part of its TCB,
so we can systematically eta expand the necessary terms and easily generate
a proof that the new definition is equal to the old (by reflexivity). *)
(** Just a dummy definition to get the current module path *)
Definition anchor := fun x : nat => x.
Definition CURRENT_MODULE := Eval compute in <%% anchor %%>.1.
(** Running our eta-expansion procedure with MetaCoq *)
MetaCoq Run (counter_syn <- quote_recursively_body counter_partially_applied ;;
tmDefinition "counter_partially_applied_syn"%bs counter_syn;;
(* eta-expand dedinitions in the environment *)
Σexpanded <- eta_global_env_template
(fun _ => None)
true true
CURRENT_MODULE
counter_syn.1
(KernameSet.add
<%% inc_balance %%>
(KernameSet.add
<%% counter_partially_applied %%>
KernameSet.empty))
(fun kn => negb (eq_kername kn <%% inc_balance %%>) &&
negb (eq_kername kn <%% counter_partially_applied %%>));;
tmDefinition "Σexpanded"%bs Σexpanded).
(** [Σexpanded] contains expanded definitions *)
(** A proof generated by the eta-expansion procedure. *)
(* Check ConCert_Examples_Counter_extraction_CounterDepCertifiedLiquidity_Counter_counter_partially_applied_expanded_convertible. *)
(* ConCert_Extraction_Tests_CounterDepCertifiedLiquidity_Counter_counter_partially_applied_expanded_convertible
: counter_partially_applied =
ConCert_Extraction_Tests_CounterDepCertifiedLiquidity_Counter_counter_partially_applied_expanded *)
(* Now we can extract this one successfully. *)
Definition COUNTER_PARTIAL_EXPANDED_MODULE : LiquidityMod msg _ (Z × address) storage operation Error :=
{| (* a name for the definition with the extracted code *)
lmd_module_name := "liquidity_counter_partially_applied_expanded" ;
(* definitions of operations on pairs and ints *)
lmd_prelude := prod_ops ++ nl ++ int_ops;
(* initial storage *)
lmd_init := init ;
(* no extra operations in [init] are required *)
lmd_init_prelude := "" ;
(* the main functionality *)
lmd_receive := ConCert_Examples_Counter_extraction_CounterDepCertifiedLiquidity_Counter_counter_partially_applied_expanded;
(* code for the entry point *)
lmd_entry_point := printWrapper (PREFIX ++ "counter") ++ nl
++ printMain |}.
Time MetaCoq Run
(t <- liquidity_extraction PREFIX TT_remap TT_rename [] COUNTER_PARTIAL_EXPANDED_MODULE ;;
tmDefinition (String.of_string COUNTER_PARTIAL_EXPANDED_MODULE.(lmd_module_name)) t
).
(* Print liquidity_counter_partially_applied_expanded. *)
(** We redirect the extraction result for later processing and compiling with the Liquidity compiler *)
Redirect "../extraction/tests/extracted-code/liquidity-extract/CounterDepCertifiedLiquidity.liq" Compute liquidity_counter.