ligo/src/lib_shell/validator.ml

155 lines
6.3 KiB
OCaml
Raw Normal View History

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. *)
(* *)
(*****************************************************************************)
2016-09-08 21:13:10 +04:00
include Logging.Make_semantic(struct let name = "node.validator" end)
2016-09-08 21:13:10 +04:00
2017-09-29 20:43:13 +04:00
type t = {
2016-09-08 21:13:10 +04:00
state: State.t ;
db: Distributed_db.t ;
block_validator: Block_validator.t ;
2018-02-16 04:26:24 +04:00
chain_validator_limits: Chain_validator.limits ;
peer_validator_limits: Peer_validator.limits ;
block_validator_limits: Block_validator.limits ;
prevalidator_limits: Prevalidator.limits ;
2016-09-08 21:13:10 +04:00
valid_block_input: State.Block.t Lwt_watcher.input ;
2018-02-16 04:26:24 +04:00
active_chains: Chain_validator.t Lwt.t Chain_id.Table.t ;
}
2016-09-08 21:13:10 +04:00
let create state db
peer_validator_limits
block_validator_limits
prevalidator_limits
2018-02-16 04:26:24 +04:00
chain_validator_limits =
Block_validator.create block_validator_limits db >>= fun block_validator ->
let valid_block_input = Lwt_watcher.create_input () in
Lwt.return
{ state ; db ; block_validator ;
block_validator_limits ; prevalidator_limits ;
2018-02-16 04:26:24 +04:00
peer_validator_limits ; chain_validator_limits ;
valid_block_input ;
2018-02-16 04:26:24 +04:00
active_chains = Chain_id.Table.create 7 }
2016-09-08 21:13:10 +04:00
let activate v ?max_child_ttl ~start_prevalidator chain_state =
2018-02-16 04:26:24 +04:00
let chain_id = State.Chain.id chain_state in
lwt_log_notice Tag.DSL.(fun f ->
f "activate chain %a"
-% t event "active_chain"
-% a State_logging.chain_id chain_id) >>= fun () ->
2018-02-16 04:26:24 +04:00
try Chain_id.Table.find v.active_chains chain_id
with Not_found ->
let nv =
2018-02-16 04:26:24 +04:00
Chain_validator.create
?max_child_ttl
~start_prevalidator
v.peer_validator_limits v.prevalidator_limits
2018-02-16 04:26:24 +04:00
v.block_validator v.valid_block_input v.db chain_state
v.chain_validator_limits in
Chain_id.Table.add v.active_chains chain_id nv ;
nv
2018-02-16 04:26:24 +04:00
let get_exn { active_chains } chain_id =
Chain_id.Table.find active_chains chain_id
2016-09-08 21:13:10 +04:00
2018-02-16 04:26:24 +04:00
let get v chain_id =
try get_exn v chain_id >>= fun nv -> return nv
with Not_found -> fail (Validation_errors.Inactive_chain chain_id)
2018-02-16 04:26:24 +04:00
let validate_block v ?(force = false) ?chain_id bytes operations =
let hash = Block_hash.hash_bytes [bytes] in
match Block_header.of_bytes bytes with
| None -> failwith "Cannot parse block header."
| Some block ->
begin
2018-02-16 04:26:24 +04:00
match chain_id with
| None -> begin
Distributed_db.read_block_header
v.db block.shell.predecessor >>= function
| None ->
failwith "Unknown predecessor (%a), cannot inject the block."
Block_hash.pp_short block.shell.predecessor
2018-02-16 04:26:24 +04:00
| Some (chain_id, _bh) -> get v chain_id
end
2018-02-16 04:26:24 +04:00
| Some chain_id ->
get v chain_id >>=? fun nv ->
if force then
return nv
else
Distributed_db.Block_header.known
2018-02-16 04:26:24 +04:00
(Chain_validator.chain_db nv)
block.shell.predecessor >>= function
| true ->
return nv
| false ->
failwith "Unknown predecessor (%a), cannot inject the block."
Block_hash.pp_short block.shell.predecessor
end >>=? fun nv ->
let validation =
2018-02-16 04:26:24 +04:00
Chain_validator.validate_block nv ~force hash block operations in
return (hash, validation)
2018-02-16 04:26:24 +04:00
let shutdown { active_chains ; block_validator } =
let jobs =
Block_validator.shutdown block_validator ::
2018-02-16 04:26:24 +04:00
Chain_id.Table.fold
(fun _ nv acc -> (nv >>= Chain_validator.shutdown) :: acc)
active_chains [] in
Lwt.join jobs >>= fun () ->
Lwt.return_unit
let watcher { valid_block_input } =
Lwt_watcher.create_stream valid_block_input
2018-02-16 04:26:24 +04:00
let inject_operation v ?chain_id op =
begin
2018-02-16 04:26:24 +04:00
match chain_id with
| None -> begin
Distributed_db.read_block_header
v.db op.Operation.shell.branch >>= function
| None ->
failwith "Unknown branch (%a), cannot inject the operation."
Block_hash.pp_short op.shell.branch
2018-02-16 04:26:24 +04:00
| Some (chain_id, _bh) -> get v chain_id
end
2018-02-16 04:26:24 +04:00
| Some chain_id ->
get v chain_id >>=? fun nv ->
2017-11-23 19:39:33 +04:00
Distributed_db.Block_header.known
2018-02-16 04:26:24 +04:00
(Chain_validator.chain_db nv)
2017-11-23 19:39:33 +04:00
op.shell.branch >>= function
| true ->
return nv
| false ->
failwith "Unknown branch (%a), cannot inject the operation."
Block_hash.pp_short op.shell.branch
end >>=? fun nv ->
let pv_opt = Chain_validator.prevalidator nv in
match pv_opt with
| Some pv -> Prevalidator.inject_operation pv op
| None -> failwith "Prevalidator is not running, cannot inject the operation."
let distributed_db { db } = db