Source file environment_context.ml
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
include Environment_context_intf
open Error_monad
let err_implementation_mismatch ~expected ~got =
Format.kasprintf
invalid_arg
"Context implementation mismatch: expecting %s, got %s"
expected
got
module Equality_witness : sig
type (_, _) eq = Refl : ('a, 'a) eq
type 'a t
val make : unit -> 'a t
val eq : 'a t -> 'b t -> ('a, 'b) eq option
val hash : 'a t -> int
end = struct
type (_, _) eq = Refl : ('a, 'a) eq
type _ equality = ..
module type Inst = sig
type t
type _ equality += Eq : t equality
end
type 'a t = (module Inst with type t = 'a)
let make : type a. unit -> a t =
fun () ->
let module Inst = struct
type t = a
type _ equality += Eq : t equality
end in
(module Inst)
let eq : type a b. a t -> b t -> (a, b) eq option =
fun (module A) (module B) -> match A.Eq with B.Eq -> Some Refl | _ -> None
let hash : type a. a t -> int = fun (module A) -> Hashtbl.hash A.Eq
end
module Context = struct
type key = string list
type value = Bytes.t
type ('ctxt, 'tree) ops = (module S with type t = 'ctxt and type tree = 'tree)
type _ kind = ..
type ('a, 'b) equality_witness = 'a Equality_witness.t * 'b Equality_witness.t
let equality_witness () = (Equality_witness.make (), Equality_witness.make ())
let equiv (a, b) (c, d) = (Equality_witness.eq a c, Equality_witness.eq b d)
type cache_value = ..
type delayed_value = unit -> cache_value Lwt.t
let delay e () = Lwt.return e
type cache = delayed_value Environment_cache.t
type t =
| Context : {
kind : 'a kind;
impl_name : string;
ctxt : 'a;
ops : ('a, 'b) ops;
equality_witness : ('a, 'b) equality_witness;
cache : cache;
}
-> t
let make ~kind ~impl_name ~ctxt ~ops ~equality_witness =
Context
{
kind;
impl_name;
ctxt;
ops;
equality_witness;
cache = Environment_cache.uninitialised;
}
let mem (Context {ops = (module Ops); ctxt; _}) key = Ops.mem ctxt key
let add (Context ({ops = (module Ops); ctxt; _} as c)) key value =
let open Lwt_syntax in
let+ ctxt = Ops.add ctxt key value in
Context {c with ctxt}
let find (Context {ops = (module Ops); ctxt; _}) key = Ops.find ctxt key
let remove (Context ({ops = (module Ops); ctxt; _} as c)) key =
let open Lwt_syntax in
let+ ctxt = Ops.remove ctxt key in
Context {c with ctxt}
type tree =
| Tree : {
ops : ('a, 'b) ops;
impl_name : string;
tree : 'b;
equality_witness : ('a, 'b) equality_witness;
}
-> tree
let mem_tree (Context {ops = (module Ops); ctxt; _}) key =
Ops.mem_tree ctxt key
let add_tree (Context ({ops = (module Ops); ctxt; _} as c)) key (Tree t) =
let open Lwt_syntax in
match equiv c.equality_witness t.equality_witness with
| Some Refl, Some Refl ->
let+ ctxt = Ops.add_tree ctxt key t.tree in
Context {c with ctxt}
| _ -> err_implementation_mismatch ~expected:c.impl_name ~got:t.impl_name
let find_tree
(Context
{ops = (module Ops) as ops; ctxt; equality_witness; impl_name; _}) key =
let open Lwt_syntax in
let+ t = Ops.find_tree ctxt key in
Option.map (fun tree -> Tree {ops; tree; equality_witness; impl_name}) t
let list
(Context
{ops = (module Ops) as ops; ctxt; equality_witness; impl_name; _})
?offset ?length key =
let open Lwt_syntax in
let+ ls = Ops.list ctxt ?offset ?length key in
List.fold_left
(fun acc (k, tree) ->
let v = Tree {ops; tree; equality_witness; impl_name} in
(k, v) :: acc)
[]
(List.rev ls)
let length (Context {ops = (module Ops); ctxt; _}) key = Ops.length ctxt key
let fold ?depth
(Context
{ops = (module Ops) as ops; ctxt; equality_witness; impl_name; _}) key
~order ~init ~f =
Ops.fold ?depth ctxt key ~order ~init ~f:(fun k v acc ->
let v = Tree {ops; tree = v; equality_witness; impl_name} in
f k v acc)
module Tree = struct
let pp ppf (Tree {ops = (module Ops); tree; _}) = Ops.Tree.pp ppf tree
let hash (Tree {ops = (module Ops); tree; _}) = Ops.Tree.hash tree
let kind (Tree {ops = (module Ops); tree; _}) = Ops.Tree.kind tree
let to_value (Tree {ops = (module Ops); tree; _}) = Ops.Tree.to_value tree
let of_value
(Context
{ops = (module Ops) as ops; ctxt; equality_witness; impl_name; _}) v =
let open Lwt_syntax in
let+ tree = Ops.Tree.of_value ctxt v in
Tree {ops; tree; equality_witness; impl_name}
let equal (Tree {ops = (module Ops); tree; equality_witness; _}) (Tree t) =
match equiv equality_witness t.equality_witness with
| Some Refl, Some Refl -> Ops.Tree.equal tree t.tree
| _ -> false
let empty
(Context
{ops = (module Ops) as ops; equality_witness; ctxt; impl_name; _}) =
let empty = Ops.Tree.empty ctxt in
Tree {ops; equality_witness; tree = empty; impl_name}
let is_empty (Tree {ops = (module Ops); tree; _}) = Ops.Tree.is_empty tree
let mem (Tree {ops = (module Ops); tree; _}) key = Ops.Tree.mem tree key
let add (Tree ({ops = (module Ops); tree; _} as c)) key value =
let open Lwt_syntax in
let+ tree = Ops.Tree.add tree key value in
Tree {c with tree}
let find (Tree {ops = (module Ops); tree; _}) key = Ops.Tree.find tree key
let mem_tree (Tree {ops = (module Ops); tree; _}) key =
Ops.Tree.mem_tree tree key
let add_tree (Tree ({ops = (module Ops); _} as c)) key (Tree t) =
let open Lwt_syntax in
match equiv c.equality_witness t.equality_witness with
| Some Refl, Some Refl ->
let+ tree = Ops.Tree.add_tree c.tree key t.tree in
Tree {c with tree}
| _ -> err_implementation_mismatch ~expected:c.impl_name ~got:t.impl_name
let find_tree (Tree ({ops = (module Ops); tree; _} as c)) key =
let open Lwt_syntax in
let+ t = Ops.Tree.find_tree tree key in
Option.map (fun tree -> Tree {c with tree}) t
let remove (Tree ({ops = (module Ops); tree; _} as c)) key =
let open Lwt_syntax in
let+ tree = Ops.Tree.remove tree key in
Tree {c with tree}
let list
(Tree {ops = (module Ops) as ops; tree; equality_witness; impl_name})
?offset ?length key =
let open Lwt_syntax in
let+ ls = Ops.Tree.list tree ?offset ?length key in
List.fold_left
(fun acc (k, tree) ->
let v = Tree {ops; tree; equality_witness; impl_name} in
(k, v) :: acc)
[]
(List.rev ls)
let length (Tree {ops = (module Ops); tree; _}) key =
Ops.Tree.length tree key
let fold ?depth
(Tree
{ops = (module Ops) as ops; tree = t; equality_witness; impl_name})
key ~order ~init ~f =
Ops.Tree.fold ?depth t key ~order ~init ~f:(fun k v acc ->
let v = Tree {ops; tree = v; equality_witness; impl_name} in
f k v acc)
let clear ?depth (Tree {ops = (module Ops); tree; _}) =
Ops.Tree.clear ?depth tree
let config (Tree {ops = (module Ops); tree; _}) = Ops.Tree.config tree
end
let config (Context {ops = (module Ops); ctxt; _}) = Ops.config ctxt
module Proof = Tezos_context_sigs.Context.Proof_types
module Proof_context = struct
module M = struct
include Tezos_context_memory.Context
let set_protocol = add_protocol
let fork_test_chain c ~protocol:_ ~expiration:_ = Lwt.return c
end
let equality_witness : (M.t, M.tree) equality_witness = equality_witness ()
let ops = (module M : S with type t = 'ctxt and type tree = 'tree)
let impl_name = "proof"
let inject : M.tree -> tree =
fun tree -> Tree {ops; tree; equality_witness; impl_name}
let project : tree -> M.tree =
fun (Tree t) ->
match equiv t.equality_witness equality_witness with
| Some Refl, Some Refl -> t.tree
| _ -> err_implementation_mismatch ~expected:impl_name ~got:t.impl_name
end
module Proof_context_binary = struct
module M = struct
include Tezos_context_memory.Context_binary
let set_protocol = add_protocol
let fork_test_chain c ~protocol:_ ~expiration:_ = Lwt.return c
end
let equality_witness : (M.t, M.tree) equality_witness = equality_witness ()
let ops = (module M : S with type t = 'ctxt and type tree = 'tree)
let impl_name = "proof_binary"
let inject : M.tree -> tree =
fun tree -> Tree {ops; tree; equality_witness; impl_name}
let project : tree -> M.tree =
fun (Tree t) ->
match equiv t.equality_witness equality_witness with
| Some Refl, Some Refl -> t.tree
| _ -> err_implementation_mismatch ~expected:impl_name ~got:t.impl_name
end
module type Proof_context = sig
module M : S
val inject : M.tree -> tree
val project : tree -> M.tree
end
type proof_version_expanded =
Tezos_context_helpers.Context.proof_version_expanded
let decode_proof_version = Tezos_context_helpers.Context.decode_proof_version
let proof_context_of_proof_version_expanded :
proof_version_expanded -> (module Proof_context) = function
| {is_binary = true; _} -> (module Proof_context_binary)
| {is_binary = false; _} -> (module Proof_context)
let proof_context ~kind proof =
match decode_proof_version proof.Proof.version with
| Error `Invalid_proof_version ->
Lwt.fail_with "Environment_context.verify_tree_proof: Invalid version"
| Ok v ->
if kind = `Tree && v.is_stream then
Lwt.fail_with
"Environment_context.verify_tree_proof: Received stream proof"
else if kind = `Stream && not v.is_stream then
Lwt.fail_with
"Environment_context.verify_stream_proof: Received tree proof"
else Lwt.return_ok (proof_context_of_proof_version_expanded v)
let verify_tree_proof proof (f : tree -> (tree * 'a) Lwt.t) =
let open Lwt_result_syntax in
let* (module Proof_context) = proof_context ~kind:`Tree proof in
let* tree, r =
Proof_context.M.verify_tree_proof proof (fun tree ->
let tree = Proof_context.inject tree in
let*! tree, r = f tree in
Lwt.return (Proof_context.project tree, r))
in
return (Proof_context.inject tree, r)
let verify_stream_proof proof (f : tree -> (tree * 'a) Lwt.t) =
let open Lwt_result_syntax in
let* (module Proof_context) = proof_context ~kind:`Stream proof in
let* tree, r =
Proof_context.M.verify_stream_proof proof (fun tree ->
let tree = Proof_context.inject tree in
let*! tree, r = f tree in
Lwt.return (Proof_context.project tree, r))
in
return (Proof_context.inject tree, r)
let equal_config = Tezos_context_sigs.Config.equal
type cache_key = Environment_cache.key
type block_cache = {
context_hash : Tezos_crypto.Hashed.Context_hash.t;
cache : cache;
}
type source_of_cache =
[ `Force_load
| `Load
| `Lazy
| `Inherited of block_cache * Tezos_crypto.Hashed.Context_hash.t ]
type builder = Environment_cache.key -> cache_value tzresult Lwt.t
module Cache = struct
type key = Environment_cache.key
type value = cache_value = ..
type identifier = Environment_cache.identifier
type size = Environment_cache.size
type index = Environment_cache.index
module Events = struct
open Internal_event.Simple
let section = ["protocol_cache"]
let start_loading_cache =
declare_0
~section
~level:Info
~name:"start_loading_cache"
~msg:"start loading cache now"
()
let stop_loading_cache =
declare_0
~section
~level:Info
~name:"stop_loading_cache"
~msg:"stop loading cache now"
()
let start_loading_cache_lazily =
declare_0
~section
~level:Debug
~name:"start_loading_cache_lazily"
~msg:"start loading cache lazily"
()
let stop_loading_cache_lazily =
declare_0
~section
~level:Debug
~name:"stop_loading_cache_lazily"
~msg:"stop loading cache lazily"
()
let emit = Internal_event.Simple.emit
let observe start_event stop_event f =
let open Lwt_result_syntax in
let*! () = emit start_event () in
let* ret = f () in
let*! () = emit stop_event () in
return ret
end
let key_of_identifier = Environment_cache.key_of_identifier
let identifier_of_key = Environment_cache.identifier_of_key
let pp fmt (Context {cache; _}) = Environment_cache.pp fmt cache
let cache_number_path = ["number_of_caches"]
let cache_path cache_index = ["cache"; string_of_int cache_index]
let cache_limit_path cache = cache_path cache @ ["limit"]
let get_cache_number ctxt =
let open Lwt_syntax in
let+ cn = find ctxt cache_number_path in
match cn with
| None -> 0
| Some v -> Data_encoding.(Binary.of_bytes_exn int31 v)
let set_cache_number ctxt cache_number =
if cache_number = 0 then Lwt.return ctxt
else
let bytes = Data_encoding.(Binary.to_bytes_exn int31) cache_number in
add ctxt cache_number_path bytes
let get_cache_limit ctxt cache_handle =
let open Lwt_syntax in
let+ c = find ctxt (cache_limit_path cache_handle) in
Option.map Data_encoding.(Binary.of_bytes_exn int31) c
let set_cache_limit ctxt cache_handle limit =
let path = cache_limit_path cache_handle in
let bytes = Data_encoding.(Binary.to_bytes_exn int31) limit in
add ctxt path bytes
let set_cache_layout (Context ctxt) layout =
let open Lwt_syntax in
let cache = Environment_cache.from_layout layout in
let ctxt = Context {ctxt with cache} in
let cache_number = List.length layout in
let* ctxt = set_cache_number ctxt cache_number in
List.fold_left_i_s
(fun i ctxt limit -> set_cache_limit ctxt i limit)
ctxt
layout
let get_cache_layout ctxt =
let open Lwt_syntax in
let* n = get_cache_number ctxt in
List.map_s
(fun index ->
let* o = get_cache_limit ctxt index in
match o with
| None ->
assert false
| Some limit -> Lwt.return limit)
(0 -- (n - 1))
let update (Context ctxt) key value =
let delayed_value =
Option.map (fun (value, index) -> (delay value, index)) value
in
let cache = Environment_cache.update ctxt.cache key delayed_value in
Context {ctxt with cache}
let cache_domain_path = ["domain"]
let sync (Context ctxt) ~cache_nonce =
let open Environment_cache in
let open Data_encoding in
let cache, domain = sync ctxt.cache ~cache_nonce in
let bytes = Binary.to_bytes_exn domain_encoding domain in
let ctxt = Context {ctxt with cache} in
add ctxt cache_domain_path bytes
let clear (Context ctxt) =
Context {ctxt with cache = Environment_cache.clear ctxt.cache}
let list_keys (Context {cache; _}) = Environment_cache.list_keys cache
let future_cache_expectation (Context ctxt) ~time_in_blocks =
let open Environment_cache in
let cache = future_cache_expectation ctxt.cache ~time_in_blocks in
Context {ctxt with cache}
let find_domain ctxt =
let open Lwt_syntax in
let+ v = find ctxt cache_domain_path in
Option.map
(Data_encoding.Binary.of_bytes_exn Environment_cache.domain_encoding)
v
let find (Context {cache; _}) key =
Option.map_s (fun value -> value ()) (Environment_cache.find cache key)
let load ctxt inherited ~value_of_key =
let open Lwt_syntax in
let open Environment_cache in
let* o = find_domain ctxt in
match o with
| None ->
return_ok @@ clear inherited
| Some domain -> from_cache inherited domain ~value_of_key
let load_now ctxt cache builder =
let open Lwt_result_syntax in
load ctxt cache ~value_of_key:(fun key ->
let* value = builder key in
return (delay value))
let load_on_demand ctxt cache builder =
let open Lwt_syntax in
let builder key =
let* r = builder key in
match r with
| Error _ ->
Lwt.fail_with
"Environment_context.load_on_demand: Unable to load value"
| Ok value -> Lwt.return value
in
load ctxt cache ~value_of_key:(fun key ->
let lazy_value =
let cache = ref None in
fun () ->
match !cache with
| Some value -> return value
| None ->
let+ r = builder key in
cache := Some r ;
r
in
return_ok lazy_value)
let load_cache ctxt cache mode builder =
Events.(
match mode with
| `Load ->
observe start_loading_cache stop_loading_cache @@ fun () ->
load_now ctxt cache builder
| `Lazy ->
observe start_loading_cache_lazily stop_loading_cache_lazily
@@ fun () -> load_on_demand ctxt cache builder)
let ensure_valid_recycling (Context ctxt) cache =
let open Lwt_syntax in
let* layout = get_cache_layout (Context ctxt) in
if Environment_cache.compatible_layout cache layout then Lwt.return cache
else Lwt.return (Environment_cache.from_layout layout)
let key_rank (Context ctxt) key = Environment_cache.key_rank ctxt.cache key
let cache_size (Context ctxt) ~cache_index =
Environment_cache.cache_size ctxt.cache ~cache_index
let cache_size_limit (Context ctxt) ~cache_index =
Environment_cache.cache_size_limit ctxt.cache ~cache_index
module Internal_for_tests = struct
let same_cache_domains ctxt ctxt' =
let open Lwt_syntax in
let* domain = find_domain ctxt in
let* domain' = find_domain ctxt' in
return_ok
@@ Option.equal
Environment_cache.Internal_for_tests.equal_domain
domain
domain'
end
end
let load_cache (Context ctxt) mode builder =
let open Lwt_syntax in
match mode with
| `Inherited ({context_hash; cache}, predecessor_context_hash) ->
if
Tezos_crypto.Hashed.Context_hash.equal
context_hash
predecessor_context_hash
then
return_ok cache
else
let* cache = Cache.ensure_valid_recycling (Context ctxt) cache in
Cache.load_cache (Context ctxt) cache `Load builder
| (`Load | `Lazy) as mode ->
let* layout = Cache.get_cache_layout (Context ctxt) in
let cache = Environment_cache.from_layout layout in
Cache.load_cache (Context ctxt) cache mode builder
(**
The following cache is for the cache to avoid reloading the cache from the
context when it has been used in the last cache-related operations.
The cache is indexed by the block hash that has produced it.
Notice that there is no guarantee that, after a call to [load_cache b], the
[cache_cache] holds the cache of the block [b]. Indeed, a subsequent call
to [load_cache bb] will take precedence. This is true even if the promise
for [b] has not resolved yet. Either way, whatever the pattern of
concurrent calls, the cache is safe in that:
- The cache that is returned by [load_cache b] is always the cache for the
block [b].
- If an error occurs during the loading of a cache, then the cache-cache
simply becomes empty.
*)
module Cache_cache =
Aches_lwt.Lache.Make_result (Aches.Rache.SingletonTransferMap (Block_hash))
let cache_cache : (cache, error trace) Cache_cache.t =
Cache_cache.create (-1)
let load_cache block_hash (Context ctxt) mode builder =
let open Lwt_result_syntax in
let* cache =
match mode with
| `Force_load ->
let p = load_cache (Context ctxt) `Load builder in
Cache_cache.put cache_cache block_hash p ;
p
| (`Load | `Lazy | `Inherited _) as mode ->
Cache_cache.bind_or_put
cache_cache
block_hash
(fun _block_hash -> load_cache (Context ctxt) mode builder)
(fun p -> Lwt.return p)
in
return (Context {ctxt with cache})
let set_protocol (Context ({ops = (module Ops); ctxt; _} as c)) protocol_hash
=
let open Lwt_syntax in
let+ ctxt = Ops.set_protocol ctxt protocol_hash in
Context {c with ctxt}
let get_protocol (Context {ops = (module Ops); ctxt; _}) =
Ops.get_protocol ctxt
let fork_test_chain (Context ({ops = (module Ops); ctxt; _} as c)) ~protocol
~expiration =
let open Lwt_syntax in
let+ ctxt = Ops.fork_test_chain ctxt ~protocol ~expiration in
Context {c with ctxt}
let get_hash_version (Context {ops = (module Ops); ctxt; _}) =
Ops.get_hash_version ctxt
let set_hash_version (Context ({ops = (module Ops); ctxt; _} as c)) v =
let open Lwt_result_syntax in
let+ ctxt = Ops.set_hash_version ctxt v in
Context {c with ctxt}
end
module Register (C : S) = struct
type _ Context.kind += Context : C.t Context.kind
let equality_witness : (C.t, C.tree) Context.equality_witness =
Context.equality_witness ()
let ops = (module C : S with type t = 'ctxt and type tree = 'tree)
end
type validation_result = {
context : Context.t;
fitness : Fitness.t;
message : string option;
max_operations_ttl : int;
last_allowed_fork_level : Int32.t;
}
type quota = {max_size : int; max_op : int option}
type rpc_context = {
block_hash : Tezos_crypto.Hashed.Block_hash.t;
block_header : Block_header.shell_header;
context : Context.t;
}