cfxcore/sync/message/
get_block_txn.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, GetBlockTxnResponse, GetBlocks, Handleable, Key,
10            KeyContainer,
11        },
12        request_manager::{AsAny, Request},
13        Error, ProtocolConfiguration,
14    },
15};
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,
23    PartialEq,
24    Default,
25    RlpDecodable,
26    RlpEncodable,
27    Clone,
28    DeriveMallocSizeOf,
29)]
30pub struct GetBlockTxn {
31    pub request_id: RequestId,
32    pub block_hash: H256,
33    pub index_skips: Vec<usize>,
34}
35
36impl AsAny for GetBlockTxn {
37    fn as_any(&self) -> &dyn Any { self }
38
39    fn as_any_mut(&mut self) -> &mut dyn Any { self }
40}
41
42impl Request for GetBlockTxn {
43    fn timeout(&self, conf: &ProtocolConfiguration) -> Duration {
44        conf.blocks_request_timeout
45    }
46
47    fn on_removed(&self, inflight_keys: &KeyContainer) {
48        let mut inflight_blocks = inflight_keys.write(msgid::GET_BLOCKS);
49        let mut net_inflight_blocks =
50            inflight_keys.write(msgid::NET_INFLIGHT_BLOCKS);
51        inflight_blocks.remove(&Key::Hash(self.block_hash.clone()));
52        net_inflight_blocks.remove(&Key::Hash(self.block_hash.clone()));
53    }
54
55    fn with_inflight(&mut self, _inflight_keys: &KeyContainer) {
56        // reuse the inflight key of GetCompactBlocks
57    }
58
59    fn is_empty(&self) -> bool { false }
60
61    fn resend(&self) -> Option<Box<dyn Request>> {
62        Some(Box::new(GetBlocks {
63            request_id: 0,
64            // request_block_need_public can only be true in catch_up_mode,
65            // where GetBlockTxn can not be initiated.
66            with_public: false,
67            hashes: vec![self.block_hash.clone()],
68            preferred_node_type: None,
69        }))
70    }
71}
72
73impl Handleable for GetBlockTxn {
74    fn handle(self, ctx: &Context) -> Result<(), Error> {
75        match ctx.manager.graph.block_by_hash(&self.block_hash) {
76            Some(block) => {
77                debug!("Process get_blocktxn hash={:?}", block.hash());
78                let mut tx_resp = Vec::with_capacity(self.index_skips.len());
79                let mut last = 0;
80                for index_skip in self.index_skips.iter() {
81                    last += *index_skip;
82                    if last >= block.transactions.len() {
83                        warn!(
84                            "Request tx index out of bound, peer={}, hash={}",
85                            ctx.node_id,
86                            block.hash()
87                        );
88                        return Err(Error::InvalidGetBlockTxn(
89                            "index out-of-bound".into(),
90                        )
91                        .into());
92                    }
93                    tx_resp.push(block.transactions[last].transaction.clone());
94                    last += 1;
95                }
96                let response = GetBlockTxnResponse {
97                    request_id: self.request_id,
98                    block_hash: self.block_hash,
99                    block_txn: tx_resp,
100                };
101
102                ctx.send_response(&response)
103            }
104            None => {
105                warn!(
106                    "Get blocktxn request of non-existent block, hash={}",
107                    self.block_hash
108                );
109
110                let response = GetBlockTxnResponse {
111                    request_id: self.request_id,
112                    block_hash: H256::default(),
113                    block_txn: Vec::new(),
114                };
115
116                ctx.send_response(&response)
117            }
118        }
119    }
120}