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
open Protocol
open Alpha_context
module Block_services = Block_services.Make (Protocol) (Protocol)
module Events = Baking_events.Node_rpc
let inject_block cctxt ?(force = false) ~chain operations =
let =
Data_encoding.Binary.to_bytes_exn Block_header.encoding signed_block_header
in
Shell_services.Injection.block
cctxt
~chain
~force
signed_shell_header_bytes
operations
let preapply_block cctxt ~chain ~head ~timestamp ~protocol_data operations =
Block_services.Helpers.Preapply.block
cctxt
~chain
~timestamp
~block:(`Hash (head, 0))
operations
~protocol_data
let preendorsements =
match preendorsements with
| h :: _ as l ->
let ({protocol_data = {contents = Single (Preendorsement content); _}; _})
=
(h : Kind.preendorsement Operation.t)
in
Some
{
Baking_state.level = Raw_level.to_int32 content.level;
round = content.round;
block_payload_hash = content.block_payload_hash;
preendorsements = l;
}
| _ -> None
let raw_info cctxt ~chain ~block_hash shell payload_hash payload_round
current_protocol next_protocol live_blocks =
Events.(emit raw_info (block_hash, shell.Tezos_base.Block_header.level))
>>= fun () ->
let open Protocol_client_context in
let block = `Hash (block_hash, 0) in
let is_in_protocol = Protocol_hash.(current_protocol = Protocol.hash) in
(if is_in_protocol then
Alpha_block_services.Operations.operations cctxt ~chain ~block ()
>>=? fun operations ->
let operations =
List.map
(fun l ->
List.map
(fun {Alpha_block_services.shell; protocol_data; _} ->
{Alpha_context.shell; protocol_data})
l)
operations
in
match Operation_pool.extract_operations_of_list_list operations with
| None -> failwith "Unexpected operation list size"
| Some operations -> return operations
else
return (None, [], Operation_pool.empty_payload))
>>=? fun (preendorsements, quorum, payload) ->
(match Baking_state.round_of_shell_header shell with
| Ok round -> ok round
| _ ->
ok Round.zero)
>>?= fun round ->
let prequorum = Option.bind preendorsements extract_prequorum in
return
{
Baking_state.hash = block_hash;
shell;
payload_hash;
payload_round;
round;
protocol = current_protocol;
next_protocol;
prequorum;
quorum;
payload;
live_blocks;
}
let dummy_payload_hash = Block_payload_hash.zero
let info cctxt ~chain ~block () =
let open Protocol_client_context in
Shell_services.Blocks.protocols cctxt ~chain ~block ()
>>=? fun {current_protocol; next_protocol} ->
(if Protocol_hash.(current_protocol <> Protocol.hash) then
Block_services.Header.shell_header cctxt ~chain ~block () >>=? fun shell ->
Chain_services.Blocks.Header.raw_protocol_data cctxt ~chain ~block ()
>>=? fun protocol_data ->
let hash =
Tezos_base.Block_header.hash {Tezos_base.Block_header.shell; protocol_data}
in
let payload_hash, payload_round =
match
Data_encoding.Binary.of_bytes_opt
Protocol.block_header_data_encoding
protocol_data
with
| Some {contents = {payload_hash; payload_round; _}; _} ->
(payload_hash, payload_round)
| None -> (dummy_payload_hash, Round.zero)
in
return (hash, shell, payload_hash, payload_round)
else
Alpha_block_services.header cctxt ~chain ~block ()
>>=? fun {hash; shell; protocol_data; _} ->
return
( hash,
shell,
protocol_data.contents.payload_hash,
protocol_data.contents.payload_round ))
>>=? fun (hash, shell, payload_hash, payload_round) ->
(Chain_services.Blocks.live_blocks cctxt ~chain ~block () >>= function
| Error _ ->
Lwt.return Block_hash.Set.empty
| Ok live_blocks -> Lwt.return live_blocks)
>>= fun live_blocks ->
raw_info
cctxt
~chain
~block_hash:hash
shell
payload_hash
payload_round
current_protocol
next_protocol
live_blocks
let find_in_cache_or_fetch cctxt ?cache ~chain block_hash =
let open Baking_cache in
let fetch () = info cctxt ~chain ~block:(`Hash (block_hash, 0)) () in
match cache with
| None -> fetch ()
| Some block_cache -> (
match Block_cache.find_opt block_cache block_hash with
| Some block_info -> return block_info
| None ->
fetch () >>=? fun block_info ->
Block_cache.replace block_cache block_hash block_info ;
return block_info)
let proposal cctxt ?cache ~chain block_hash =
find_in_cache_or_fetch cctxt ~chain ?cache block_hash >>=? fun block ->
let predecessor_hash = block.shell.predecessor in
find_in_cache_or_fetch cctxt ~chain ?cache predecessor_hash
>>=? fun predecessor -> return {Baking_state.block; predecessor}
let monitor_proposals cctxt ~chain () =
let cache = Baking_cache.Block_cache.create 100 in
Monitor_services.heads cctxt ~next_protocols:[Protocol.hash] chain
>>=? fun (block_stream, stopper) ->
return
( Lwt_stream.filter_map_s
(fun (block_hash, _) ->
protect (fun () -> proposal cctxt ~cache ~chain block_hash)
>>= function
| Ok proposal -> Lwt.return_some proposal
| Error err ->
Events.(emit error_while_monitoring_heads err) >>= fun () ->
Lwt.return_none)
block_stream,
stopper )
let await_protocol_activation cctxt ~chain () =
Monitor_services.heads cctxt ~next_protocols:[Protocol.hash] chain
>>=? fun (block_stream, stop) ->
Lwt_stream.get block_stream >>= fun _ ->
stop () ;
return_unit