cfxcore/sync/message/
get_block_headers.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use crate::{
6    message::{Message, RequestId},
7    sync::{
8        message::{
9            Context, GetBlockHeadersResponse, Handleable, Key, KeyContainer,
10        },
11        request_manager::{AsAny, Request},
12        Error, ProtocolConfiguration,
13    },
14};
15use cfx_parameters::sync::MAX_HEADERS_TO_SEND;
16use cfx_types::H256;
17use malloc_size_of_derive::MallocSizeOf as DeriveMallocSizeOf;
18use rlp_derive::{RlpDecodable, RlpEncodable};
19use std::{any::Any, time::Duration};
20
21#[derive(
22    Debug, PartialEq, Clone, RlpDecodable, RlpEncodable, DeriveMallocSizeOf,
23)]
24pub struct GetBlockHeaders {
25    pub request_id: RequestId,
26    pub hashes: Vec<H256>,
27}
28
29impl AsAny for GetBlockHeaders {
30    fn as_any(&self) -> &dyn Any { self }
31
32    fn as_any_mut(&mut self) -> &mut dyn Any { self }
33}
34
35impl Request for GetBlockHeaders {
36    fn timeout(&self, conf: &ProtocolConfiguration) -> Duration {
37        conf.headers_request_timeout
38    }
39
40    fn on_removed(&self, inflight_keys: &KeyContainer) {
41        let mut inflight_keys = inflight_keys.write(self.msg_id());
42        for hash in self.hashes.iter() {
43            inflight_keys.remove(&Key::Hash(*hash));
44        }
45    }
46
47    fn with_inflight(&mut self, inflight_keys: &KeyContainer) {
48        let mut inflight_keys = inflight_keys.write(self.msg_id());
49        self.hashes.retain(|h| inflight_keys.insert(Key::Hash(*h)));
50    }
51
52    fn is_empty(&self) -> bool { self.hashes.is_empty() }
53
54    fn resend(&self) -> Option<Box<dyn Request>> {
55        Some(Box::new(self.clone()))
56    }
57}
58
59impl Handleable for GetBlockHeaders {
60    fn handle(self, ctx: &Context) -> Result<(), Error> {
61        debug!("Received GetBlockHeaders {:?}", self);
62        let headers = self
63            .hashes
64            .iter()
65            .take(MAX_HEADERS_TO_SEND as usize)
66            .filter_map(|hash| {
67                // We should not use `graph.block_header_by_hash` here because
68                // it only returns headers in memory
69                ctx.manager
70                    .graph
71                    .data_man
72                    .block_header_by_hash(&hash)
73                    .map(|header_arc| header_arc.as_ref().clone())
74            })
75            .collect();
76
77        let mut block_headers_resp = GetBlockHeadersResponse::default();
78        block_headers_resp.request_id = self.request_id;
79        block_headers_resp.headers = headers;
80
81        debug!(
82            "Returned {:?} block headers to peer {:?}",
83            block_headers_resp.headers.len(),
84            ctx.node_id,
85        );
86
87        ctx.send_response(&block_headers_resp)
88    }
89}