Source file rpc_directory.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
open Rpc_directory_helpers
let get_head_hash_opt node_ctxt =
let open Lwt_result_syntax in
let+ res = Node_context.last_processed_head_opt node_ctxt in
Option.map
(fun Sc_rollup_block.{header = {block_hash; _}; _} -> block_hash)
res
let get_head_level_opt node_ctxt =
let open Lwt_result_syntax in
let+ res = Node_context.last_processed_head_opt node_ctxt in
Option.map (fun Sc_rollup_block.{header = {level; _}; _} -> level) res
let get_proto_plugin_of_level node_ctxt level =
let open Lwt_result_syntax in
let* proto = Node_context.protocol_of_level node_ctxt level in
let*? plugin = Protocol_plugins.proto_plugin_for_protocol proto.protocol in
return plugin
module Global_directory = Make_directory (struct
include Rollup_node_services.Global
type context = Node_context.rw
type subcontext = Node_context.ro
let context_of_prefix node_ctxt () =
Lwt_result.return (Node_context.readonly node_ctxt)
end)
module Local_directory = Make_directory (struct
include Rollup_node_services.Local
type context = Node_context.rw
type subcontext = Node_context.ro
let context_of_prefix node_ctxt () =
Lwt_result.return (Node_context.readonly node_ctxt)
end)
let () =
Global_directory.register0 Rollup_node_services.Global.sc_rollup_address
@@ fun node_ctxt () () -> Lwt_result.return node_ctxt.rollup_address
let () =
Global_directory.register0 Rollup_node_services.Global.current_tezos_head
@@ fun node_ctxt () () -> get_head_hash_opt node_ctxt
let () =
Global_directory.register0 Rollup_node_services.Global.current_tezos_level
@@ fun node_ctxt () () -> get_head_level_opt node_ctxt
let () =
Global_directory.register0 Rollup_node_services.Global.last_stored_commitment
@@ fun node_ctxt () () ->
let open Lwt_result_syntax in
let* head = Node_context.last_processed_head_opt node_ctxt in
match head with
| None -> return_none
| Some head ->
let commitment_hash =
Sc_rollup_block.most_recent_commitment head.header
in
let+ commitment =
Node_context.find_commitment node_ctxt commitment_hash
in
Option.map (fun c -> (c, commitment_hash)) commitment
let () =
Local_directory.register0 Rollup_node_services.Local.last_published_commitment
@@ fun node_ctxt () () ->
let open Lwt_result_syntax in
match Reference.get node_ctxt.lpc with
| None -> return_none
| Some commitment ->
let hash = Octez_smart_rollup.Commitment.hash commitment in
let* published_at_level_info =
Node_context.commitment_published_at_level node_ctxt hash
in
let first_published, published =
match published_at_level_info with
| None -> (None, None)
| Some {first_published_at_level; published_at_level} ->
(Some first_published_at_level, published_at_level)
in
return_some (commitment, hash, first_published, published)
let () =
Local_directory.register0 Rollup_node_services.Local.injection
@@ fun _node_ctxt () messages -> Batcher.register_messages messages
let () =
Local_directory.register0 Rollup_node_services.Local.batcher_queue
@@ fun _node_ctxt () () ->
let open Lwt_result_syntax in
let*? queue = Batcher.get_queue () in
return queue
(** [commitment_level_of_inbox_level node_ctxt inbox_level] returns the level
of the commitment which should include the inbox of level
[inbox_level].
It is computed with the following formula:
{v
commitment_level(inbox_level) =
last_commitment -
((last_commitment - inbox_level) / commitment_period
* commitment_period)
v}
*)
let commitment_level_of_inbox_level (node_ctxt : _ Node_context.t) inbox_level =
let open Option_syntax in
let+ last_published_commitment = Reference.get node_ctxt.lpc in
let commitment_period =
Int32.of_int
node_ctxt.current_protocol.constants.sc_rollup.commitment_period_in_blocks
in
let last_published = last_published_commitment.inbox_level in
let open Int32 in
div (sub last_published inbox_level) commitment_period
|> mul commitment_period |> sub last_published
let inbox_info_of_level (node_ctxt : _ Node_context.t) inbox_level =
let open Lwt_result_syntax in
let+ finalized_level = Node_context.get_finalized_level node_ctxt in
let finalized = Compare.Int32.(inbox_level <= finalized_level) in
let lcc = Reference.get node_ctxt.lcc in
let cemented = Compare.Int32.(inbox_level <= lcc.level) in
(finalized, cemented)
let () =
Local_directory.register1 Rollup_node_services.Local.batcher_message
@@ fun node_ctxt hash () () ->
let open Lwt_result_syntax in
let*? batch_status = Batcher.message_status hash in
let* status =
match batch_status with
| None -> return (None, Rollup_node_services.Unknown)
| Some (batch_status, msg) -> (
let return status = return (Some msg, status) in
match batch_status with
| Pending_batch -> return Rollup_node_services.Pending_batch
| Batched l1_hash -> (
match Injector.operation_status l1_hash with
| None -> return Rollup_node_services.Unknown
| Some (Pending op) ->
return (Rollup_node_services.Pending_injection op)
| Some (Injected {op; oph; op_index}) ->
return
(Rollup_node_services.Injected
{op = op.operation; oph; op_index})
| Some (Included {op; oph; op_index; l1_block; l1_level}) -> (
let* finalized, cemented =
inbox_info_of_level node_ctxt l1_level
in
let commitment_level =
commitment_level_of_inbox_level node_ctxt l1_level
in
match commitment_level with
| None ->
return
(Rollup_node_services.Included
{
op = op.operation;
oph;
op_index;
l1_block;
l1_level;
finalized;
cemented;
})
| Some commitment_level -> (
let* block =
Node_context.find_l2_block_by_level
node_ctxt
commitment_level
in
match block with
| None ->
return
(Rollup_node_services.Included
{
op = op.operation;
oph;
op_index;
l1_block;
l1_level;
finalized;
cemented;
})
| Some block -> (
let commitment_hash =
WithExceptions.Option.get
~loc:__LOC__
block.header.commitment_hash
in
let* published_at =
Node_context.commitment_published_at_level
node_ctxt
commitment_hash
in
match published_at with
| None | Some {published_at_level = None; _} ->
return
(Rollup_node_services.Included
{
op = op.operation;
oph;
op_index;
l1_block;
l1_level;
finalized;
cemented;
})
| Some
{
first_published_at_level;
published_at_level = Some published_at_level;
} ->
let* commitment =
Node_context.get_commitment
node_ctxt
commitment_hash
in
return
(Rollup_node_services.Committed
{
op = op.operation;
oph;
op_index;
l1_block;
l1_level;
finalized;
cemented;
commitment;
commitment_hash;
first_published_at_level;
published_at_level;
}))))))
in
return status
let top_directory (node_ctxt : _ Node_context.t) =
List.fold_left
(fun dir f -> Tezos_rpc.Directory.merge dir (f node_ctxt))
Tezos_rpc.Directory.empty
[Global_directory.build_directory; Local_directory.build_directory]
let directory node_ctxt =
let path =
Tezos_rpc.Path.(
open_root / "global" / "block" /: Rollup_node_services.Arg.block_id)
in
Tezos_rpc.Directory.register_dynamic_directory
~descr:"Dynamic protocol specific RPC directory for the rollup node"
(top_directory node_ctxt)
path
(fun ((), block_id) ->
let open Lwt_syntax in
let+ dir =
let open Lwt_result_syntax in
let* level =
Block_directory_helpers.block_level_of_id node_ctxt block_id
in
let+ (module Plugin) = get_proto_plugin_of_level node_ctxt level in
Plugin.RPC_directory.block_directory node_ctxt
in
match dir with
| Ok dir -> dir
| Error e ->
Format.kasprintf
Stdlib.failwith
"Could not load block directory for block %s: %a"
(Rollup_node_services.Arg.construct_block_id block_id)
pp_print_trace
e)