2018-06-29 16:08:08 +04:00
|
|
|
(*****************************************************************************)
|
|
|
|
(* *)
|
|
|
|
(* Open Source License *)
|
|
|
|
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
|
|
(* *)
|
|
|
|
(* Permission is hereby granted, free of charge, to any person obtaining a *)
|
|
|
|
(* copy of this software and associated documentation files (the "Software"),*)
|
|
|
|
(* to deal in the Software without restriction, including without limitation *)
|
|
|
|
(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)
|
|
|
|
(* and/or sell copies of the Software, and to permit persons to whom the *)
|
|
|
|
(* Software is furnished to do so, subject to the following conditions: *)
|
|
|
|
(* *)
|
|
|
|
(* The above copyright notice and this permission notice shall be included *)
|
|
|
|
(* in all copies or substantial portions of the Software. *)
|
|
|
|
(* *)
|
|
|
|
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
|
|
|
|
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)
|
|
|
|
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)
|
|
|
|
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
|
|
|
|
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)
|
|
|
|
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)
|
|
|
|
(* DEALINGS IN THE SOFTWARE. *)
|
|
|
|
(* *)
|
|
|
|
(*****************************************************************************)
|
2017-11-11 06:34:12 +04:00
|
|
|
|
2018-02-13 17:12:09 +04:00
|
|
|
open Validation_errors
|
|
|
|
|
2018-06-12 23:07:50 +04:00
|
|
|
include Logging.Make_semantic(struct let name = "node.validator.block" end)
|
2017-11-11 06:34:12 +04:00
|
|
|
|
|
|
|
type 'a request =
|
|
|
|
| Request_validation: {
|
|
|
|
hash: Protocol_hash.t ;
|
|
|
|
protocol: Protocol.t ;
|
2018-03-15 18:26:52 +04:00
|
|
|
} -> Registered_protocol.t tzresult request
|
2017-11-11 06:34:12 +04:00
|
|
|
|
|
|
|
type message = Message: 'a request * 'a Lwt.u option -> message
|
|
|
|
|
|
|
|
type t = {
|
|
|
|
db: Distributed_db.t ;
|
|
|
|
mutable worker: unit Lwt.t ;
|
|
|
|
messages: message Lwt_pipe.t ;
|
2017-11-27 09:13:12 +04:00
|
|
|
canceler: Lwt_canceler.t ;
|
2017-11-11 06:34:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
(** Block validation *)
|
|
|
|
|
|
|
|
let rec worker_loop bv =
|
|
|
|
begin
|
2018-02-08 13:51:01 +04:00
|
|
|
protect ~canceler:bv.canceler begin fun () ->
|
2017-11-11 06:34:12 +04:00
|
|
|
Lwt_pipe.pop bv.messages >>= return
|
|
|
|
end >>=? function Message (request, wakener) ->
|
|
|
|
match request with
|
|
|
|
| Request_validation { hash ; protocol } ->
|
|
|
|
Updater.compile hash protocol >>= fun valid ->
|
|
|
|
begin
|
|
|
|
if valid then
|
|
|
|
Distributed_db.commit_protocol bv.db hash protocol
|
|
|
|
else
|
|
|
|
(* no need to tag 'invalid' protocol on disk,
|
|
|
|
the economic protocol prevents us from
|
|
|
|
being spammed with protocol validation. *)
|
2018-06-27 06:05:42 +04:00
|
|
|
return_true
|
2017-11-11 06:34:12 +04:00
|
|
|
end >>=? fun _ ->
|
|
|
|
match wakener with
|
|
|
|
| None ->
|
2018-06-26 13:07:12 +04:00
|
|
|
return_unit
|
2017-11-11 06:34:12 +04:00
|
|
|
| Some wakener ->
|
|
|
|
if valid then
|
2018-03-15 18:26:52 +04:00
|
|
|
match Registered_protocol.get hash with
|
2017-11-11 06:34:12 +04:00
|
|
|
| Some protocol ->
|
|
|
|
Lwt.wakeup_later wakener (Ok protocol)
|
|
|
|
| None ->
|
|
|
|
Lwt.wakeup_later wakener
|
|
|
|
(Error
|
|
|
|
[Invalid_protocol { hash ;
|
|
|
|
error = Dynlinking_failed }])
|
|
|
|
else
|
|
|
|
Lwt.wakeup_later wakener
|
|
|
|
(Error
|
|
|
|
[Invalid_protocol { hash ;
|
|
|
|
error = Compilation_failed }]) ;
|
2018-06-26 13:07:12 +04:00
|
|
|
return_unit
|
2017-11-11 06:34:12 +04:00
|
|
|
end >>= function
|
|
|
|
| Ok () ->
|
|
|
|
worker_loop bv
|
2018-02-08 13:51:01 +04:00
|
|
|
| Error [Canceled | Exn Lwt_pipe.Closed] ->
|
2018-06-12 23:07:50 +04:00
|
|
|
lwt_log_notice Tag.DSL.(fun f ->
|
|
|
|
f "terminating" -% t event "terminating") >>= fun () ->
|
2017-11-11 06:34:12 +04:00
|
|
|
Lwt.return_unit
|
|
|
|
| Error err ->
|
2018-06-12 23:07:50 +04:00
|
|
|
lwt_log_error Tag.DSL.(fun f ->
|
|
|
|
f "@[Unexpected error (worker):@ %a@]"
|
|
|
|
-% t event "unexpected_error"
|
|
|
|
-% a errs_tag err) >>= fun () ->
|
2017-11-27 09:13:12 +04:00
|
|
|
Lwt_canceler.cancel bv.canceler >>= fun () ->
|
2017-11-11 06:34:12 +04:00
|
|
|
Lwt.return_unit
|
|
|
|
|
|
|
|
let create db =
|
2017-11-27 09:13:12 +04:00
|
|
|
let canceler = Lwt_canceler.create () in
|
2017-11-11 06:34:12 +04:00
|
|
|
let messages = Lwt_pipe.create () in
|
|
|
|
let bv = {
|
|
|
|
canceler ; messages ; db ;
|
|
|
|
worker = Lwt.return_unit } in
|
2017-11-27 09:13:12 +04:00
|
|
|
Lwt_canceler.on_cancel bv.canceler begin fun () ->
|
2017-11-11 06:34:12 +04:00
|
|
|
Lwt_pipe.close bv.messages ;
|
|
|
|
Lwt.return_unit
|
|
|
|
end ;
|
|
|
|
bv.worker <-
|
|
|
|
Lwt_utils.worker "block_validator"
|
|
|
|
~run:(fun () -> worker_loop bv)
|
2017-11-27 09:13:12 +04:00
|
|
|
~cancel:(fun () -> Lwt_canceler.cancel bv.canceler) ;
|
2017-11-11 06:34:12 +04:00
|
|
|
bv
|
|
|
|
|
|
|
|
let shutdown { canceler ; worker } =
|
2017-11-27 09:13:12 +04:00
|
|
|
Lwt_canceler.cancel canceler >>= fun () ->
|
2017-11-11 06:34:12 +04:00
|
|
|
worker
|
|
|
|
|
|
|
|
let validate { messages } hash protocol =
|
2018-03-15 18:26:52 +04:00
|
|
|
match Registered_protocol.get hash with
|
2017-11-11 06:34:12 +04:00
|
|
|
| Some protocol ->
|
2018-06-12 23:07:50 +04:00
|
|
|
lwt_debug Tag.DSL.(fun f ->
|
|
|
|
f "previously validated protocol %a (before pipe)"
|
|
|
|
-% t event "previously_validated_protocol"
|
|
|
|
-% a Protocol_hash.Logging.tag hash) >>= fun () ->
|
2017-11-11 06:34:12 +04:00
|
|
|
return protocol
|
|
|
|
| None ->
|
|
|
|
let res, wakener = Lwt.task () in
|
2018-06-12 23:07:50 +04:00
|
|
|
lwt_debug Tag.DSL.(fun f ->
|
|
|
|
f "pushing validation request for protocol %a"
|
|
|
|
-% t event "pushing_validation_request"
|
|
|
|
-% a Protocol_hash.Logging.tag hash) >>= fun () ->
|
2017-11-11 06:34:12 +04:00
|
|
|
Lwt_pipe.push messages
|
|
|
|
(Message (Request_validation { hash ; protocol },
|
|
|
|
Some wakener)) >>= fun () ->
|
|
|
|
res
|
|
|
|
|
|
|
|
let fetch_and_compile_protocol pv ?peer ?timeout hash =
|
2018-03-15 18:26:52 +04:00
|
|
|
match Registered_protocol.get hash with
|
2017-11-11 06:34:12 +04:00
|
|
|
| Some proto -> return proto
|
|
|
|
| None ->
|
|
|
|
begin
|
|
|
|
Distributed_db.Protocol.read_opt pv.db hash >>= function
|
|
|
|
| Some protocol -> return protocol
|
|
|
|
| None ->
|
2018-06-12 23:07:50 +04:00
|
|
|
lwt_log_notice Tag.DSL.(fun f ->
|
|
|
|
f "Fetching protocol %a%a"
|
|
|
|
-% t event "fetching_protocol"
|
|
|
|
-% a Protocol_hash.Logging.tag hash
|
|
|
|
-% a P2p_peer.Id.Logging.tag_source peer) >>= fun () ->
|
2017-11-11 06:34:12 +04:00
|
|
|
Distributed_db.Protocol.fetch pv.db ?peer ?timeout hash ()
|
|
|
|
end >>=? fun protocol ->
|
|
|
|
validate pv hash protocol >>=? fun proto ->
|
|
|
|
return proto
|
|
|
|
|
|
|
|
let fetch_and_compile_protocols pv ?peer ?timeout (block: State.Block.t) =
|
|
|
|
State.Block.context block >>= fun context ->
|
|
|
|
let protocol =
|
|
|
|
Context.get_protocol context >>= fun protocol_hash ->
|
|
|
|
fetch_and_compile_protocol pv ?peer ?timeout protocol_hash >>=? fun _ ->
|
2018-06-26 13:07:12 +04:00
|
|
|
return_unit
|
2017-11-11 06:34:12 +04:00
|
|
|
and test_protocol =
|
2018-02-16 04:26:24 +04:00
|
|
|
Context.get_test_chain context >>= function
|
2018-06-26 13:07:12 +04:00
|
|
|
| Not_running -> return_unit
|
2017-11-11 06:34:12 +04:00
|
|
|
| Forking { protocol }
|
|
|
|
| Running { protocol } ->
|
|
|
|
fetch_and_compile_protocol pv ?peer ?timeout protocol >>=? fun _ ->
|
2018-06-26 13:07:12 +04:00
|
|
|
return_unit in
|
2017-11-11 06:34:12 +04:00
|
|
|
protocol >>=? fun () ->
|
|
|
|
test_protocol >>=? fun () ->
|
2018-06-26 13:07:12 +04:00
|
|
|
return_unit
|
2017-11-11 06:34:12 +04:00
|
|
|
|
|
|
|
let prefetch_and_compile_protocols pv ?peer ?timeout block =
|
|
|
|
try ignore (fetch_and_compile_protocols pv ?peer ?timeout block) with _ -> ()
|