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}