Source file wasm_2_0_0_dump.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
(** [get_wasm_pvm_state ~l2_header data_dir] reads the WASM PVM state in
[data_dir] for the given [l2_header].*)
let get_wasm_pvm_state ~( : Sc_rollup_block.header) data_dir =
let open Lwt_result_syntax in
let context_hash = l2_header.context in
let block_hash = l2_header.block_hash in
let* context =
Context.load
~cache_size:0
Tezos_layer2_store.Store_sigs.Read_only
(Configuration.default_context_dir data_dir)
in
let*! ctxt = Context.checkout context context_hash in
let* ctxt =
match ctxt with
| None ->
tzfail
(Rollup_node_errors.Cannot_checkout_context
(block_hash, Some context_hash))
| Some ctxt -> return ctxt
in
let*! state = Context.PVMState.find ctxt in
match state with
| Some s -> return s
| None -> failwith "No PVM state found for block %a" Block_hash.pp block_hash
(** [decode_value tree] decodes a durable storage value from the given tree. *)
let decode_value ~(pvm : (module Pvm_plugin_sig.S)) tree =
let open Lwt_syntax in
let module Pvm : Pvm_plugin_sig.S = (val pvm) in
let* cbv =
Pvm.Wasm_2_0_0.decode_durable_state
Tezos_lazy_containers.Chunked_byte_vector.encoding
tree
in
Tezos_lazy_containers.Chunked_byte_vector.to_string cbv
(** Returns whether the value under the current key should be dumped. *)
let check_dumpable_path key =
match key with
| "readonly" :: _ | "kernel" :: "boot.wasm" :: _ -> `Nothing
| l -> (
match List.rev l with
| "@" :: path -> `Value (List.rev path)
| _ -> `Nothing)
(** [print_set_value] dumps a value in the YAML format of the installer. *)
let set_value_instr ~(pvm : (module Pvm_plugin_sig.S)) key tree =
let open Lwt_syntax in
let full_key = String.concat "/" key in
let+ value = decode_value ~pvm tree in
Installer_config.Set {value; to_ = "/" ^ full_key}
let generate_durable_storage ~(plugin : (module Protocol_plugin_sig.S)) tree =
let open Lwt_syntax in
let durable_path = "durable" :: [] in
let module Plugin : Protocol_plugin_sig.S = (val plugin) in
let* path_exists = Plugin.Pvm.Wasm_2_0_0.proof_mem_tree tree durable_path in
if path_exists then
let* instrs =
Plugin.Pvm.Wasm_2_0_0.proof_fold_tree
tree
durable_path
~order:`Undefined
~init:[]
~f:(fun key tree acc ->
match check_dumpable_path key with
| `Nothing -> return acc
| `Value key ->
let+ instr = set_value_instr ~pvm:(module Plugin.Pvm) key tree in
instr :: acc)
in
return_ok instrs
else failwith "The durable storage is not available in the tree\n%!"
let dump_durable_storage ~block ~data_dir ~file =
let open Lwt_result_syntax in
let* store =
Store.load
Tezos_layer2_store.Store_sigs.Read_only
~index_buffer_size:0
~l2_blocks_cache_size:5
(Configuration.default_storage_dir data_dir)
in
let get name load =
let* value = load () in
match value with
| Some v -> return v
| None -> failwith "%s not found in the rollup node storage" name
in
let hash_from_level l =
get (Format.asprintf "Block hash for level %ld" l) (fun () ->
Store.Levels_to_hashes.find store.levels_to_hashes l)
in
let block_from_hash h =
get (Format.asprintf "Block with hash %a" Block_hash.pp h) (fun () ->
Store.L2_blocks.read store.l2_blocks h)
in
let get_l2_head () =
get "Processed L2 head" (fun () -> Store.L2_head.read store.l2_head)
in
let* block_hash, block_level =
match block with
| `Genesis -> failwith "Genesis not supported"
| `Head 0 ->
let* {header = {block_hash; level; _}; _} = get_l2_head () in
return (block_hash, level)
| `Head offset ->
let* {header = {level; _}; _} = get_l2_head () in
let l = Int32.(sub level (of_int offset)) in
let* h = hash_from_level l in
return (h, l)
| `Alias (_, _) -> failwith "Alias not supported"
| `Hash (h, 0) ->
let* _block, {block_hash; level; _} = block_from_hash h in
return (block_hash, level)
| `Hash (h, offset) ->
let* _block, = block_from_hash h in
let l = Int32.(sub block_header.level (of_int offset)) in
let* h = hash_from_level l in
return (h, l)
| `Level l ->
let* h = hash_from_level l in
return (h, l)
in
let* (plugin : (module Protocol_plugin_sig.S)) =
Protocol_plugins.proto_plugin_for_level_with_store store block_level
in
let* = Store.L2_blocks.header store.l2_blocks block_hash in
let* =
match l2_header with
| None -> tzfail Rollup_node_errors.Cannot_checkout_l2_header
| Some -> return header
in
let* state = get_wasm_pvm_state ~l2_header data_dir in
let* instrs = generate_durable_storage ~plugin state in
let*? contents =
if Filename.check_suffix file ".yaml" then Installer_config.emit_yaml instrs
else
Ok
(Data_encoding.Json.construct Installer_config.encoding instrs
|> Data_encoding.Json.to_string)
in
let*! () =
Lwt_io.with_file ~mode:Lwt_io.Output file (fun oc ->
Lwt_io.write_from_string_exactly oc contents 0 (String.length contents))
in
return_unit