cfxcore/sync/message/
get_compact_blocks.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::RequestId,
7    sync::{
8        message::{
9            msgid, Context, GetBlocks, GetCompactBlocksResponse, Handleable,
10            Key, KeyContainer,
11        },
12        request_manager::{AsAny, Request},
13        Error, ProtocolConfiguration,
14    },
15};
16use cfx_parameters::sync::{MAX_BLOCKS_TO_SEND, MAX_HEADERS_TO_SEND};
17use cfx_types::H256;
18use malloc_size_of_derive::MallocSizeOf as DeriveMallocSizeOf;
19use rlp_derive::{RlpDecodable, RlpEncodable};
20use std::{any::Any, time::Duration};
21
22#[derive(
23    Debug, PartialEq, Default, RlpDecodable, RlpEncodable, DeriveMallocSizeOf,
24)]
25pub struct GetCompactBlocks {
26    pub request_id: RequestId,
27    pub hashes: Vec<H256>,
28}
29
30impl AsAny for GetCompactBlocks {
31    fn as_any(&self) -> &dyn Any { self }
32
33    fn as_any_mut(&mut self) -> &mut dyn Any { self }
34}
35
36impl Request for GetCompactBlocks {
37    fn timeout(&self, conf: &ProtocolConfiguration) -> Duration {
38        conf.blocks_request_timeout
39    }
40
41    fn on_removed(&self, inflight_keys: &KeyContainer) {
42        let mut inflight_blocks = inflight_keys.write(msgid::GET_BLOCKS);
43        let mut net_inflight_blocks =
44            inflight_keys.write(msgid::NET_INFLIGHT_BLOCKS);
45        for hash in self.hashes.iter() {
46            inflight_blocks.remove(&Key::Hash(*hash));
47            net_inflight_blocks.remove(&Key::Hash(*hash));
48        }
49    }
50
51    fn with_inflight(&mut self, inflight_keys: &KeyContainer) {
52        let mut inflight_keys = inflight_keys.write(msgid::GET_BLOCKS);
53        self.hashes.retain(|h| inflight_keys.insert(Key::Hash(*h)));
54    }
55
56    fn is_empty(&self) -> bool { self.hashes.is_empty() }
57
58    fn resend(&self) -> Option<Box<dyn Request>> {
59        Some(Box::new(GetBlocks {
60            request_id: 0,
61            with_public: true,
62            hashes: self.hashes.iter().cloned().collect(),
63            preferred_node_type: None,
64        }))
65    }
66}
67
68impl Handleable for GetCompactBlocks {
69    fn handle(self, ctx: &Context) -> Result<(), Error> {
70        let mut compact_blocks = Vec::with_capacity(self.hashes.len());
71        let mut blocks = Vec::new();
72
73        for hash in self.hashes.iter() {
74            if let Some(compact_block) =
75                ctx.manager.graph.data_man.compact_block_by_hash(hash)
76            {
77                if (compact_blocks.len() as u64) < MAX_HEADERS_TO_SEND {
78                    compact_blocks.push(compact_block);
79                }
80            } else if let Some(block) = ctx.manager.graph.block_by_hash(hash) {
81                debug!("Have complete block but no compact block, return complete block instead");
82                if (blocks.len() as u64) < MAX_BLOCKS_TO_SEND {
83                    blocks.push(block.as_ref().clone());
84                }
85            } else {
86                debug!(
87                    "Peer {} requested non-existent compact block {}",
88                    ctx.node_id, hash
89                );
90            }
91        }
92
93        let response = GetCompactBlocksResponse {
94            request_id: self.request_id,
95            compact_blocks,
96            blocks,
97        };
98
99        ctx.send_response(&response)
100    }
101}