2016-09-08 21:13:10 +04:00
|
|
|
(**************************************************************************)
|
|
|
|
(* *)
|
2018-02-06 00:17:03 +04:00
|
|
|
(* Copyright (c) 2014 - 2018. *)
|
2016-09-08 21:13:10 +04:00
|
|
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
|
|
(* *)
|
|
|
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
|
|
|
(* *)
|
|
|
|
(**************************************************************************)
|
|
|
|
|
2017-11-11 06:34:12 +04:00
|
|
|
include Logging.Make(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
|
|
|
|
2017-11-11 06:34:12 +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 ;
|
2018-01-22 20:47:18 +04:00
|
|
|
peer_validator_limits: Peer_validator.limits ;
|
2018-01-26 16:10:20 +04:00
|
|
|
block_validator_limits: Block_validator.limits ;
|
2017-11-29 16:51:06 +04:00
|
|
|
prevalidator_limits: Prevalidator.limits ;
|
2016-09-08 21:13:10 +04:00
|
|
|
|
2017-11-27 09:13:12 +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 ;
|
2017-02-24 20:17:53 +04:00
|
|
|
|
2017-11-11 06:34:12 +04:00
|
|
|
}
|
2016-09-08 21:13:10 +04:00
|
|
|
|
2018-01-22 20:21:23 +04:00
|
|
|
let create state db
|
2018-01-22 20:47:18 +04:00
|
|
|
peer_validator_limits
|
2018-01-26 16:10:20 +04:00
|
|
|
block_validator_limits
|
2018-01-22 20:21:23 +04:00
|
|
|
prevalidator_limits
|
2018-02-16 04:26:24 +04:00
|
|
|
chain_validator_limits =
|
2018-01-26 16:10:20 +04:00
|
|
|
Block_validator.create block_validator_limits db >>= fun block_validator ->
|
2017-11-27 09:13:12 +04:00
|
|
|
let valid_block_input = Lwt_watcher.create_input () in
|
2018-01-26 16:10:20 +04:00
|
|
|
Lwt.return
|
2018-01-22 20:21:23 +04:00
|
|
|
{ state ; db ; block_validator ;
|
|
|
|
block_validator_limits ; prevalidator_limits ;
|
2018-02-16 04:26:24 +04:00
|
|
|
peer_validator_limits ; chain_validator_limits ;
|
2018-01-26 16:10:20 +04:00
|
|
|
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
|
|
|
|
2018-02-16 04:26:24 +04:00
|
|
|
let activate v ?max_child_ttl chain_state =
|
|
|
|
let chain_id = State.Chain.id chain_state in
|
|
|
|
lwt_log_notice "activate chain %a" Chain_id.pp chain_id >>= fun () ->
|
|
|
|
try Chain_id.Table.find v.active_chains chain_id
|
2017-11-11 06:34:12 +04:00
|
|
|
with Not_found ->
|
|
|
|
let nv =
|
2018-02-16 04:26:24 +04:00
|
|
|
Chain_validator.create
|
2017-11-11 06:34:12 +04:00
|
|
|
?max_child_ttl
|
2018-01-22 20:21:23 +04:00
|
|
|
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 ;
|
2017-11-11 06:34:12 +04:00
|
|
|
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
|
|
|
|
2017-11-11 06:34:12 +04:00
|
|
|
type error +=
|
2018-02-16 04:26:24 +04:00
|
|
|
| Inactive_chain of Chain_id.t
|
2017-11-11 06:34:12 +04:00
|
|
|
|
2017-11-15 19:50:13 +04:00
|
|
|
let () =
|
|
|
|
register_error_kind `Branch
|
2018-02-16 04:26:24 +04:00
|
|
|
~id: "node.validator.inactive_chain"
|
|
|
|
~title: "Inactive chain"
|
|
|
|
~description: "Attempted validation of a block from an inactive chain."
|
|
|
|
~pp: (fun ppf chain ->
|
2017-11-15 19:50:13 +04:00
|
|
|
Format.fprintf ppf
|
2018-02-16 04:26:24 +04:00
|
|
|
"Tried to validate a block from chain %a, \
|
2017-11-15 19:50:13 +04:00
|
|
|
that is not currently considered active."
|
2018-02-16 04:26:24 +04:00
|
|
|
Chain_id.pp chain)
|
|
|
|
Data_encoding.(obj1 (req "inactive_chain" Chain_id.encoding))
|
|
|
|
(function Inactive_chain chain -> Some chain | _ -> None)
|
|
|
|
(fun chain -> Inactive_chain chain)
|
2017-11-15 19:50:13 +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 (Inactive_chain chain_id)
|
2017-11-11 06:34:12 +04:00
|
|
|
|
2018-02-16 04:26:24 +04:00
|
|
|
let validate_block v ?(force = false) ?chain_id bytes operations =
|
2017-11-11 06:34:12 +04:00
|
|
|
let hash = Block_hash.hash_bytes [bytes] in
|
|
|
|
match Block_header.of_bytes bytes with
|
|
|
|
| None -> failwith "Cannot parse block header."
|
|
|
|
| Some block ->
|
2017-11-14 06:14:26 +04:00
|
|
|
begin
|
2018-02-16 04:26:24 +04:00
|
|
|
match chain_id with
|
2017-11-14 06:14:26 +04:00
|
|
|
| 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
|
2017-11-14 06:14:26 +04:00
|
|
|
end
|
2018-02-16 04:26:24 +04:00
|
|
|
| Some chain_id ->
|
|
|
|
get v chain_id >>=? fun nv ->
|
2017-11-14 06:14:26 +04:00
|
|
|
if force then
|
|
|
|
return nv
|
|
|
|
else
|
|
|
|
Distributed_db.Block_header.known
|
2018-02-16 04:26:24 +04:00
|
|
|
(Chain_validator.chain_db nv)
|
2017-11-14 06:14:26 +04:00
|
|
|
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 ->
|
2017-11-11 06:34:12 +04:00
|
|
|
let validation =
|
2018-02-16 04:26:24 +04:00
|
|
|
Chain_validator.validate_block nv ~force hash block operations in
|
2017-11-11 06:34:12 +04:00
|
|
|
return (hash, validation)
|
|
|
|
|
2018-02-16 04:26:24 +04:00
|
|
|
let shutdown { active_chains ; block_validator } =
|
2017-11-11 06:34:12 +04:00
|
|
|
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
|
2017-11-11 06:34:12 +04:00
|
|
|
Lwt.join jobs >>= fun () ->
|
|
|
|
Lwt.return_unit
|
|
|
|
|
|
|
|
let watcher { valid_block_input } =
|
2017-11-27 09:13:12 +04:00
|
|
|
Lwt_watcher.create_stream valid_block_input
|
2017-11-14 05:41:37 +04:00
|
|
|
|
2018-02-16 04:26:24 +04:00
|
|
|
let inject_operation v ?chain_id op =
|
2017-11-14 05:41:37 +04:00
|
|
|
begin
|
2018-02-16 04:26:24 +04:00
|
|
|
match chain_id with
|
2017-11-14 05:41:37 +04:00
|
|
|
| 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
|
2017-11-14 05:41:37 +04:00
|
|
|
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
|
2017-11-14 05:41:37 +04:00
|
|
|
end >>=? fun nv ->
|
2018-02-16 04:26:24 +04:00
|
|
|
let pv = Chain_validator.prevalidator nv in
|
2017-11-23 19:39:33 +04:00
|
|
|
Prevalidator.inject_operation pv op
|