consensus_types/
block_retrieval.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8use crate::block::Block;
9use anyhow::ensure;
10use diem_crypto::hash::HashValue;
11use diem_types::validator_verifier::ValidatorVerifier;
12use serde::{Deserialize, Serialize};
13use short_hex_str::AsShortHexStr;
14use std::fmt;
15
16pub const MAX_BLOCKS_PER_REQUEST: u64 = 10;
17
18/// RPC to get a chain of block of the given length starting from the given
19/// block id.
20#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
21pub struct BlockRetrievalRequest {
22    block_id: HashValue,
23    num_blocks: u64,
24}
25
26impl BlockRetrievalRequest {
27    pub fn new(block_id: HashValue, num_blocks: u64) -> Self {
28        Self {
29            block_id,
30            num_blocks,
31        }
32    }
33
34    pub fn block_id(&self) -> HashValue { self.block_id }
35
36    pub fn num_blocks(&self) -> u64 { self.num_blocks }
37}
38
39impl fmt::Display for BlockRetrievalRequest {
40    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41        write!(
42            f,
43            "[BlockRetrievalRequest starting from id {} with {} blocks]",
44            self.block_id, self.num_blocks
45        )
46    }
47}
48
49#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
50pub enum BlockRetrievalStatus {
51    // Successfully fill in the request.
52    Succeeded,
53    // Can not find the block corresponding to block_id.
54    IdNotFound,
55    // Can not find enough blocks but find some.
56    NotEnoughBlocks,
57}
58
59/// Carries the returned blocks and the retrieval status.
60#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
61pub struct BlockRetrievalResponse {
62    status: BlockRetrievalStatus,
63    blocks: Vec<Block>,
64}
65
66impl BlockRetrievalResponse {
67    pub fn new(status: BlockRetrievalStatus, blocks: Vec<Block>) -> Self {
68        Self { status, blocks }
69    }
70
71    pub fn status(&self) -> BlockRetrievalStatus { self.status.clone() }
72
73    pub fn blocks(&self) -> &Vec<Block> { &self.blocks }
74
75    pub fn verify(
76        &self, block_id: HashValue, num_blocks: u64,
77        sig_verifier: &ValidatorVerifier,
78    ) -> anyhow::Result<()> {
79        ensure!(
80            self.status != BlockRetrievalStatus::Succeeded
81                || (self.blocks.len() as u64 <= num_blocks
82                    && !self.blocks.is_empty()),
83            "not enough blocks returned, expect {}, get {}",
84            num_blocks,
85            self.blocks.len(),
86        );
87        self.blocks
88            .iter()
89            .try_fold(block_id, |expected_id, block| {
90                block.validate_signature(sig_verifier)?;
91                block.verify_well_formed()?;
92                ensure!(
93                    block.id() == expected_id,
94                    "blocks doesn't form a chain: expect {}, get {}",
95                    expected_id,
96                    block.id()
97                );
98                Ok(block.parent_id())
99            })
100            .map(|_| ())
101    }
102}
103
104impl fmt::Display for BlockRetrievalResponse {
105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106        match self.status() {
107            BlockRetrievalStatus::Succeeded => {
108                write!(
109                    f,
110                    "[BlockRetrievalResponse: status: {:?}, num_blocks: {}, block_ids: ",
111                    self.status(),
112                    self.blocks().len(),
113                )?;
114
115                f.debug_list()
116                    .entries(self.blocks.iter().map(|b| b.id().short_str()))
117                    .finish()?;
118
119                write!(f, "]")
120            }
121            _ => write!(
122                f,
123                "[BlockRetrievalResponse: status: {:?}]",
124                self.status()
125            ),
126        }
127    }
128}