casper_client/validation.rs
1use thiserror::Error;
2
3use casper_types::{bytesrepr, Block, BlockHash, Digest};
4
5use crate::rpcs::{common::BlockIdentifier, results::GetBlockResult};
6
7/// Error that can be returned when validating data returned from a JSON-RPC method.
8#[derive(Error, Debug)]
9pub enum ValidateResponseError {
10 /// Failed to marshall value.
11 #[error("failed to marshall value {0}")]
12 BytesRepr(bytesrepr::Error),
13
14 /// Error from serde.
15 #[error(transparent)]
16 Serde(#[from] serde_json::Error),
17
18 /// Failed to parse JSON.
19 #[error("validate response failed to parse")]
20 ValidateResponseFailedToParse,
21
22 /// The body hash in the header is not the same as the hash of the body of the block.
23 #[error(
24 "block header has incorrect body hash. \
25 actual block body hash: {actual_block_body_hash}, \
26 block: {block}"
27 )]
28 BodyHashMismatch {
29 /// The `Block` with the `BlockHeader` with the incorrect block body hash.
30 block: Box<Block>,
31 /// The actual hash of the block's `BlockBody`.
32 actual_block_body_hash: Digest,
33 },
34
35 /// The block's hash is not the same as the header's hash.
36 #[error(
37 "block has incorrect block hash. \
38 actual block body hash: {actual_block_header_hash}, \
39 block: {block}"
40 )]
41 BlockHashMismatch {
42 /// The `Block` with the incorrect `BlockHeaderHash`
43 block: Box<Block>,
44 /// The actual hash of the block's `BlockHeader`
45 actual_block_header_hash: BlockHash,
46 },
47
48 /// Serialized value not contained in proof.
49 #[error("serialized value not contained in proof")]
50 SerializedValueNotContainedInProof,
51
52 /// No block in response.
53 #[error("no block in response")]
54 NoBlockInResponse,
55
56 /// Block hash requested does not correspond to response.
57 #[error("block hash requested does not correspond to response")]
58 UnexpectedBlockHash,
59
60 /// Block height was not as requested.
61 #[error("block height was not as requested")]
62 UnexpectedBlockHeight,
63
64 /// An invalid combination of state identifier and block header response
65 #[error("invalid combination of state identifier and block header in response")]
66 InvalidGlobalStateResponse,
67}
68
69impl From<bytesrepr::Error> for ValidateResponseError {
70 fn from(e: bytesrepr::Error) -> Self {
71 ValidateResponseError::BytesRepr(e)
72 }
73}
74
75pub(crate) fn validate_get_block_result(
76 _maybe_block_identifier: Option<BlockIdentifier>,
77 _result: &GetBlockResult,
78) -> Result<(), ValidateResponseError> {
79 // TODO: There will likely be a further change made in `casper-types` which will allow the
80 // `JsonBlock` type to be removed in favour of the actual `Block` type. `Block` provides
81 // a public `verify()` method which will be suitable for usage here, meaning the
82 // commented code below can be removed. In case this doesn't happen, the code below
83 // should be reinstated.
84 //
85 // let block = if let Some(block) = result.block.as_ref() {
86 // block
87 // } else {
88 // return Ok(());
89 // };
90 //
91 // match types::validate_block_hashes_v1(block) {
92 // Ok(()) => {}
93 // Err(v1_error) => match types::validate_block_hashes_v2(block) {
94 // Ok(()) => {}
95 // Err(_v2_error) => return Err(v1_error),
96 // },
97 // }
98 //
99 // match maybe_block_identifier {
100 // Some(BlockIdentifier::Hash(block_hash)) => {
101 // if block_hash.inner() != block.hash().inner() {
102 // return Err(ValidateResponseError::UnexpectedBlockHash);
103 // }
104 // }
105 // Some(BlockIdentifier::Height(height)) => {
106 // // More is necessary here to mitigate a MITM attack
107 // if height != block.header().height() {
108 // return Err(ValidateResponseError::UnexpectedBlockHeight);
109 // }
110 // }
111 // // More is necessary here to mitigate a MITM attack. In this case we would want to validate
112 // // `block.proofs()` to make sure that 1/3 of the validator weight signed the block, and we
113 // // would have to know the latest validators through some trustworthy means
114 // None => (),
115 // }
116 Ok(())
117}