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 std::fmt;
14
15pub const MAX_BLOCKS_PER_REQUEST: u64 = 10;
16
17/// RPC to get a chain of block of the given length starting from the given
18/// block id.
19#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
20pub struct BlockRetrievalRequest {
21    block_id: HashValue,
22    num_blocks: u64,
23}
24
25impl BlockRetrievalRequest {
26    pub fn new(block_id: HashValue, num_blocks: u64) -> Self {
27        Self {
28            block_id,
29            num_blocks,
30        }
31    }
32
33    pub fn block_id(&self) -> HashValue { self.block_id }
34
35    pub fn num_blocks(&self) -> u64 { self.num_blocks }
36}
37
38impl fmt::Display for BlockRetrievalRequest {
39    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40        write!(
41            f,
42            "[BlockRetrievalRequest starting from id {} with {} blocks]",
43            self.block_id, self.num_blocks
44        )
45    }
46}
47
48#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
49pub enum BlockRetrievalStatus {
50    // Successfully fill in the request.
51    Succeeded,
52    // Can not find the block corresponding to block_id.
53    IdNotFound,
54    // Can not find enough blocks but find some.
55    NotEnoughBlocks,
56}
57
58/// Carries the returned blocks and the retrieval status.
59#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
60pub struct BlockRetrievalResponse {
61    status: BlockRetrievalStatus,
62    blocks: Vec<Block>,
63}
64
65impl BlockRetrievalResponse {
66    pub fn new(status: BlockRetrievalStatus, blocks: Vec<Block>) -> Self {
67        Self { status, blocks }
68    }
69
70    pub fn status(&self) -> BlockRetrievalStatus { self.status.clone() }
71
72    pub fn blocks(&self) -> &Vec<Block> { &self.blocks }
73
74    pub fn verify(
75        &self, block_id: HashValue, num_blocks: u64,
76        sig_verifier: &ValidatorVerifier,
77    ) -> anyhow::Result<()> {
78        ensure!(
79            self.status != BlockRetrievalStatus::Succeeded
80                || (self.blocks.len() as u64 <= num_blocks
81                    && !self.blocks.is_empty()),
82            "not enough blocks returned, expect {}, get {}",
83            num_blocks,
84            self.blocks.len(),
85        );
86        self.blocks
87            .iter()
88            .try_fold(block_id, |expected_id, block| {
89                block.validate_signature(sig_verifier)?;
90                block.verify_well_formed()?;
91                ensure!(
92                    block.id() == expected_id,
93                    "blocks doesn't form a chain: expect {}, get {}",
94                    expected_id,
95                    block.id()
96                );
97                Ok(block.parent_id())
98            })
99            .map(|_| ())
100    }
101}
102
103impl fmt::Display for BlockRetrievalResponse {
104    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105        match self.status() {
106            BlockRetrievalStatus::Succeeded => {
107                write!(
108                    f,
109                    "[BlockRetrievalResponse: status: {:?}, num_blocks: {}, block_ids: ",
110                    self.status(),
111                    self.blocks().len(),
112                )?;
113
114                f.debug_list()
115                    .entries(
116                        self.blocks
117                            .iter()
118                            .map(|b| hex::encode(&b.id().as_ref()[..4])),
119                    )
120                    .finish()?;
121
122                write!(f, "]")
123            }
124            _ => write!(
125                f,
126                "[BlockRetrievalResponse: status: {:?}]",
127                self.status()
128            ),
129        }
130    }
131}