Source file tx_rollup_inbox_storage.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
open Tx_rollup_errors_repr
let find :
Raw_context.t ->
Tx_rollup_level_repr.t ->
Tx_rollup_repr.t ->
(Raw_context.t * Tx_rollup_inbox_repr.t option) tzresult Lwt.t =
fun ctxt level tx_rollup ->
Storage.Tx_rollup.Inbox.find (ctxt, tx_rollup) level
let get :
Raw_context.t ->
Tx_rollup_level_repr.t ->
Tx_rollup_repr.t ->
(Raw_context.t * Tx_rollup_inbox_repr.t) tzresult Lwt.t =
fun ctxt level tx_rollup ->
find ctxt level tx_rollup >>=? function
| _, None -> tzfail (Inbox_does_not_exist (tx_rollup, level))
| ctxt, Some inbox -> return (ctxt, inbox)
(** [prepare_inbox ctxt rollup state level] prepares the metadata
for an inbox at [level], which may imply creating it if it does
not already exist. *)
let prepare_inbox :
Raw_context.t ->
Tx_rollup_repr.t ->
Tx_rollup_state_repr.t ->
Raw_level_repr.t ->
(Raw_context.t
* Tx_rollup_state_repr.t
* Tx_rollup_level_repr.t
* Tx_rollup_inbox_repr.t
* Z.t)
tzresult
Lwt.t =
fun ctxt rollup state level ->
fail_when
Compare.Int.(
Constants_storage.tx_rollup_max_inboxes_count ctxt
<= Tx_rollup_state_repr.inboxes_count state)
Too_many_inboxes
>>=? fun () ->
let current_levels = Tx_rollup_state_repr.head_levels state in
match current_levels with
| Some (_, tezos_lvl) when Raw_level_repr.(level < tezos_lvl) ->
tzfail (Internal_error "Trying to write into an inbox from the past")
| Some (tx_lvl, tezos_lvl) when Raw_level_repr.(tezos_lvl = level) ->
Storage.Tx_rollup.Inbox.get (ctxt, rollup) tx_lvl
>>=? fun (ctxt, metadata) -> return (ctxt, state, tx_lvl, metadata, Z.zero)
| _ ->
let pred_level_and_tx_level =
Option.bind current_levels (fun (tx_level, tezos_level) ->
Option.map (fun pred -> (pred, tezos_level))
@@ Tx_rollup_level_repr.pred tx_level)
in
(match pred_level_and_tx_level with
| None -> return (ctxt, state)
| Some (tx_level, tezos_level) ->
find ctxt tx_level rollup >>=? fun (ctxt, minbox) ->
let final_size =
match minbox with Some inbox -> inbox.cumulated_size | None -> 0
in
let hard_limit =
Constants_storage.tx_rollup_hard_size_limit_per_inbox ctxt
in
let factor =
Constants_storage.tx_rollup_cost_per_byte_ema_factor ctxt
in
let diff = Raw_level_repr.diff level tezos_level in
let elapsed =
if Compare.Int32.(diff <= Int32.one) then 0 else Int32.to_int diff
in
let state =
Tx_rollup_state_repr.update_burn_per_byte
state
~elapsed
~factor
~final_size
~hard_limit
in
Storage.Tx_rollup.State.add ctxt rollup state >|=? fun (ctxt, _, _) ->
(ctxt, state))
>>=? fun (ctxt, state) ->
Tx_rollup_state_repr.record_inbox_creation state level
>>?= fun (state, tx_level, paid_storage_space_diff) ->
let inbox = Tx_rollup_inbox_repr.empty in
Storage.Tx_rollup.Inbox.init (ctxt, rollup) tx_level inbox
>>=? fun (ctxt, _inbox_size_alloc) ->
return (ctxt, state, tx_level, inbox, paid_storage_space_diff)
(** [update_inbox inbox msg_size] updates [metadata] to account
for a new message of [msg_size] bytes. *)
let update_inbox :
Tx_rollup_inbox_repr.t ->
int ->
Tx_rollup_inbox_repr.Merkle.root ->
Tx_rollup_inbox_repr.t =
fun metadata msg_size merkle_root ->
Tx_rollup_inbox_repr.
{
inbox_length = 1 + metadata.inbox_length;
cumulated_size = msg_size + metadata.cumulated_size;
merkle_root;
}
let append_message :
Raw_context.t ->
Tx_rollup_repr.t ->
Tx_rollup_state_repr.t ->
Tx_rollup_message_repr.t ->
(Raw_context.t * Tx_rollup_state_repr.t * Z.t) tzresult Lwt.t =
fun ctxt rollup state message ->
let level = (Raw_context.current_level ctxt).level in
let message_size = Tx_rollup_message_repr.size message in
prepare_inbox ctxt rollup state level
>>=? fun ( ctxt,
new_state,
tx_level,
inbox,
paid_storage_space_diff_for_init_inbox ) ->
fail_when
Compare.Int.(
inbox.inbox_length
>= Constants_storage.tx_rollup_max_messages_per_inbox ctxt)
(Inbox_count_would_exceed_limit rollup)
>>=? fun () ->
Tx_rollup_hash_builder.message ctxt message >>?= fun (ctxt, message_hash) ->
Tx_rollup_gas.consume_add_message_cost ctxt >>?= fun ctxt ->
let ctxt, inbox_merkle_root =
Raw_context.Tx_rollup.add_message ctxt rollup message_hash
in
let new_inbox = update_inbox inbox message_size inbox_merkle_root in
let new_size = new_inbox.cumulated_size in
let inbox_limit =
Constants_storage.tx_rollup_hard_size_limit_per_inbox ctxt
in
fail_unless
Compare.Int.(new_size <= inbox_limit)
(Inbox_size_would_exceed_limit rollup)
>>=? fun () ->
Storage.Tx_rollup.Inbox.add (ctxt, rollup) tx_level new_inbox
>>=? fun (ctxt, new_inbox_size_alloc, _) ->
Tx_rollup_state_repr.adjust_storage_allocation
new_state
~delta:Z.(of_int new_inbox_size_alloc)
>>?= fun (new_state, paid_storage_space_diff) ->
return
( ctxt,
new_state,
Z.add paid_storage_space_diff_for_init_inbox paid_storage_space_diff )
let remove :
Raw_context.t ->
Tx_rollup_level_repr.t ->
Tx_rollup_repr.t ->
Raw_context.t tzresult Lwt.t =
fun ctxt level rollup ->
Storage.Tx_rollup.Inbox.remove (ctxt, rollup) level
>>=? fun (ctxt, _freed, _) -> return ctxt
let check_message_hash :
Raw_context.t ->
Tx_rollup_level_repr.t ->
Tx_rollup_repr.t ->
position:int ->
Tx_rollup_message_repr.t ->
Tx_rollup_inbox_repr.Merkle.path ->
Raw_context.t tzresult Lwt.t =
fun ctxt level tx_rollup ~position message path ->
Storage.Tx_rollup.Inbox.get (ctxt, tx_rollup) level >>=? fun (ctxt, inbox) ->
Tx_rollup_hash_builder.message ctxt message >>?= fun (ctxt, message_hash) ->
Tx_rollup_gas.consume_check_path_inbox_cost ctxt >>?= fun ctxt ->
Tx_rollup_inbox_repr.Merkle.check_path
path
position
message_hash
inbox.merkle_root
>>?= fun b ->
fail_unless b (Wrong_message_path {expected = inbox.merkle_root})
>>=? fun () -> return ctxt