validation_errors.ml
(*****************************************************************************)
(* *)
(* Open Source License *)
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* Copyright (c) 2020 Metastate AG <hello@metastate.dev> *)
(* *)
(* 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. *)
(* *)
(*****************************************************************************)
(***************** Prevalidation errors ***********************************)
type error += Parse_error
type error += Too_many_operations
type error += Oversized_operation of {size : int; max : int}
type error +=
| Future_block_header of {
block : Block_hash.t;
block_time : Time.Protocol.t;
time : Time.System.t;
}
type error += Cannot_serialize_operation_metadata
let () =
(* Parse error *)
register_error_kind
`Permanent
~id:"node.prevalidation.parse_error"
~title:"Parsing error in prevalidation"
~description:
"Raised when an operation has not been parsed correctly during \
prevalidation."
~pp:(fun ppf () ->
Format.fprintf ppf "Operation parsing error in prevalidation.")
Data_encoding.empty
(function Parse_error -> Some () | _ -> None)
(fun () -> Parse_error) ;
(* Too many operations *)
register_error_kind
`Temporary
~id:"node.prevalidation.too_many_operations"
~title:"Too many pending operations in prevalidation"
~description:"The prevalidation context is full."
~pp:(fun ppf () ->
Format.fprintf ppf "Too many operations in prevalidation context.")
Data_encoding.empty
(function Too_many_operations -> Some () | _ -> None)
(fun () -> Too_many_operations) ;
(* Oversized operation *)
register_error_kind
`Permanent
~id:"node.prevalidation.oversized_operation"
~title:"Oversized operation"
~description:"The operation size is bigger than allowed."
~pp:(fun ppf (size, max) ->
Format.fprintf ppf "Oversized operation (size: %d, max: %d)" size max)
Data_encoding.(obj2 (req "size" int31) (req "max_size" int31))
(function Oversized_operation {size; max} -> Some (size, max) | _ -> None)
(fun (size, max) -> Oversized_operation {size; max}) ;
(* Block from the future *)
register_error_kind
`Temporary
~id:"node.prevalidation.future_block_header"
~title:"Future block header"
~description:"The block was annotated with a time too far in the future."
~pp:(fun ppf (block, block_time, time) ->
Format.fprintf
ppf
"Future block header (block: %a, block_time: %a, time: %a)"
Block_hash.pp
block
Time.System.pp_hum
(Time.System.of_protocol_exn block_time)
Time.System.pp_hum
time)
Data_encoding.(
obj3
(req "block" Block_hash.encoding)
(req "block_time" Time.Protocol.encoding)
(req "time" Time.System.encoding))
(function
| Future_block_header {block; block_time; time} ->
Some (block, block_time, time)
| _ -> None)
(fun (block, block_time, time) ->
Future_block_header {block; block_time; time}) ;
Error_monad.register_error_kind
`Permanent
~id:"block_validation.cannot_serialize_metadata"
~title:"Cannot serialize metadata"
~description:"Unable to serialize metadata"
~pp:(fun ppf () ->
Format.fprintf ppf "Unable to serialize the metadata for an operation.")
Data_encoding.empty
(function Cannot_serialize_operation_metadata -> Some () | _ -> None)
(fun () -> Cannot_serialize_operation_metadata)
(************************* State errors ***********************************)
type error += Unknown_chain of Chain_id.t
type error += Bad_data_dir
type error += Block_not_invalid of Block_hash.t
let () =
(* Unknown network *)
register_error_kind
`Permanent
~id:"node.state.unknown_chain"
~title:"Unknown chain"
~description:
"The chain identifier could not be found in the chain identifiers table."
~pp:(fun ppf id -> Format.fprintf ppf "Unknown chain %a" Chain_id.pp id)
Data_encoding.(obj1 (req "chain" Chain_id.encoding))
(function Unknown_chain x -> Some x | _ -> None)
(fun x -> Unknown_chain x) ;
register_error_kind
`Permanent
~id:"node.state.bad_data_dir"
~title:"Bad data directory"
~description:
"The data directory could not be read. This could be because it was \
generated with an old version of the tezos-node program. Deleting and \
regenerating this directory may fix the problem."
~pp:(fun ppf () -> Format.fprintf ppf "Bad data directory.")
Data_encoding.empty
(function Bad_data_dir -> Some () | _ -> None)
(fun () -> Bad_data_dir) ;
(* Block not invalid *)
register_error_kind
`Permanent
~id:"node.state.block_not_invalid"
~title:"Block not invalid"
~description:"The invalid block to be unmarked was not actually invalid."
~pp:(fun ppf block ->
Format.fprintf
ppf
"Block %a was expected to be invalid, but was not actually invalid."
Block_hash.pp
block)
Data_encoding.(obj1 (req "block" Block_hash.encoding))
(function Block_not_invalid block -> Some block | _ -> None)
(fun block -> Block_not_invalid block)
(* Block database error *)
type error += Inconsistent_hash of Context_hash.t * Context_hash.t
type error += Missing_block_metadata_hash of Block_hash.t
type error += Missing_operation_metadata_hashes of Block_hash.t
let () =
(* Inconsistent hash *)
register_error_kind
`Permanent
~id:"node.state.block.inconsistent_context_hash"
~title:"Inconsistent commit hash"
~description:
"When committing the context of a block, the announced context hash was \
not the one computed at commit time."
~pp:(fun ppf (got, exp) ->
Format.fprintf
ppf
"@[<v 2>Inconsistent hash:@ got: %a@ expected: %a"
Context_hash.pp
got
Context_hash.pp
exp)
Data_encoding.(
obj2
(req "wrong_context_hash" Context_hash.encoding)
(req "expected_context_hash" Context_hash.encoding))
(function Inconsistent_hash (got, exp) -> Some (got, exp) | _ -> None)
(fun (got, exp) -> Inconsistent_hash (got, exp)) ;
register_error_kind
`Permanent
~id:"node.state.block.missing_block_metadata_hash"
~title:"Missing block metadata hash"
~description:
"A block was expected to commit to a block metadata hash, however none \
was given."
~pp:(fun ppf block ->
Format.fprintf
ppf
"@[<v 2>Missing block metadata hash at block: %a"
Block_hash.pp
block)
Data_encoding.(obj1 (req "block" Block_hash.encoding))
(function Missing_block_metadata_hash block -> Some block | _ -> None)
(fun block -> Missing_block_metadata_hash block) ;
register_error_kind
`Permanent
~id:"node.state.block.missing_operation_metadata_hashes"
~title:"Missing operation metadata hashes"
~description:
"A block was expected to commit to operation metadata hashes, however \
none were given."
~pp:(fun ppf block ->
Format.fprintf
ppf
"@[<v 2>Missing operation metadata hashes at block: %a"
Block_hash.pp
block)
Data_encoding.(obj1 (req "block" Block_hash.encoding))
(function
| Missing_operation_metadata_hashes block -> Some block | _ -> None)
(fun block -> Missing_operation_metadata_hashes block)
(******************* Bootstrap pipeline errors ****************************)
type error += Invalid_locator of P2p_peer.Id.t * Block_locator.t
type error += Too_short_locator of P2p_peer.Id.t * Block_locator.t
let () =
(* Invalid locator *)
register_error_kind
`Permanent
~id:"node.bootstrap_pipeline.invalid_locator"
~title:"Invalid block locator"
~description:"Block locator is invalid."
~pp:(fun ppf (id, locator) ->
Format.fprintf
ppf
"Invalid block locator on peer %a:\n%a"
P2p_peer.Id.pp
id
Block_locator.pp
locator)
Data_encoding.(
obj2
(req "id" P2p_peer.Id.encoding)
(req "locator" Block_locator.encoding))
(function Invalid_locator (id, loc) -> Some (id, loc) | _ -> None)
(fun (id, loc) -> Invalid_locator (id, loc)) ;
(* Too short locator *)
register_error_kind
`Permanent
~id:"node.bootstrap_pipeline.too_short_locator"
~title:"Too short locator"
~description:"Block locator is too short."
~pp:(fun ppf (id, locator) ->
Format.fprintf
ppf
"Too short locator on peer %a:\n%a"
P2p_peer.Id.pp
id
Block_locator.pp
locator)
Data_encoding.(
obj2
(req "id" P2p_peer.Id.encoding)
(req "locator" Block_locator.encoding))
(function Too_short_locator (id, loc) -> Some (id, loc) | _ -> None)
(fun (id, loc) -> Too_short_locator (id, loc))
(******************* Protocol validator errors ****************************)
type protocol_error = Compilation_failed | Dynlinking_failed
type error +=
| Invalid_protocol of {hash : Protocol_hash.t; error : protocol_error}
let protocol_error_encoding =
let open Data_encoding in
union
[
case
(Tag 0)
~title:"Compilation failed"
(obj1 (req "error" (constant "compilation_failed")))
(function Compilation_failed -> Some () | _ -> None)
(fun () -> Compilation_failed);
case
(Tag 1)
~title:"Dynlinking failed"
(obj1 (req "error" (constant "dynlinking_failed")))
(function Dynlinking_failed -> Some () | _ -> None)
(fun () -> Dynlinking_failed);
]
let pp_protocol_error ppf = function
| Compilation_failed -> Format.fprintf ppf "compilation error"
| Dynlinking_failed -> Format.fprintf ppf "dynlinking error"
let () =
(* Invalid protocol *)
register_error_kind
`Permanent
~id:"node.protocol_validator.invalid_protocol"
~title:"Invalid protocol"
~description:"Invalid protocol."
~pp:(fun ppf (protocol, error) ->
Format.fprintf
ppf
"@[<v 2>Invalid protocol %a@ %a@]"
Protocol_hash.pp_short
protocol
pp_protocol_error
error)
Data_encoding.(
merge_objs
(obj1 (req "invalid_protocol" Protocol_hash.encoding))
protocol_error_encoding)
(function
| Invalid_protocol {hash; error} -> Some (hash, error) | _ -> None)
(fun (hash, error) -> Invalid_protocol {hash; error})
type error += Cannot_load_protocol of Protocol_hash.t
let () =
register_error_kind
`Permanent
~id:"node.protocol_validator.cannot_load_protocol"
~title:"Cannot load protocol"
~description:"Cannot load protocol from disk"
~pp:(fun ppf protocol ->
Format.fprintf
ppf
"Failed to load the protocol %a from disk: the corresponding files \
might be missing or corrupted."
Protocol_hash.pp
protocol)
Data_encoding.(obj1 (req "protocol" Protocol_hash.encoding))
(function Cannot_load_protocol protocol -> Some protocol | _ -> None)
(fun protocol -> Cannot_load_protocol protocol)
(********************* Peer validator errors ******************************)
type error += Unknown_ancestor | Known_invalid
let () =
(* Unknown ancestor *)
register_error_kind
`Permanent
~id:"node.peer_validator.unknown_ancestor"
~title:"Unknown ancestor"
~description:"Unknown ancestor block found in the peer's chain"
~pp:(fun ppf () -> Format.fprintf ppf "Unknown ancestor")
Data_encoding.empty
(function Unknown_ancestor -> Some () | _ -> None)
(fun () -> Unknown_ancestor) ;
(* Known invalid *)
register_error_kind
`Permanent
~id:"node.peer_validator.known_invalid"
~title:"Known invalid"
~description:"Known invalid block found in the peer's chain"
~pp:(fun ppf () -> Format.fprintf ppf "Known invalid")
Data_encoding.empty
(function Known_invalid -> Some () | _ -> None)
(fun () -> Known_invalid)
(************************ Validator errors ********************************)
type error += Inactive_chain of Chain_id.t
type error += Checkpoint_error of Block_hash.t * P2p_peer.Id.t option
let () =
(* Inactive network *)
register_error_kind
`Branch
~id:"node.validator.inactive_chain"
~title:"Inactive chain"
~description:"Attempted validation of a block from an inactive chain."
~pp:(fun ppf chain ->
Format.fprintf
ppf
"Tried to validate a block from chain %a, that is not currently \
considered active."
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) ;
register_error_kind
`Branch
~id:"node.validator.checkpoint_error"
~title:"Block incompatible with the current checkpoint."
~description:
"The block belongs to a branch that is not compatible with the current \
checkpoint."
~pp:(fun ppf (block, peer) ->
match peer with
| None ->
Format.fprintf
ppf
"The block %a is incompatible with the current checkpoint."
Block_hash.pp_short
block
| Some peer ->
Format.fprintf
ppf
"The peer %a send us a block which is a sibling of the configured \
checkpoint (%a)."
P2p_peer.Id.pp
peer
Block_hash.pp_short
block)
Data_encoding.(
obj2 (req "block" Block_hash.encoding) (opt "peer" P2p_peer.Id.encoding))
(function
| Checkpoint_error (block, peer) -> Some (block, peer) | _ -> None)
(fun (block, peer) -> Checkpoint_error (block, peer))