cfxcore/pos/state_sync/
chunk_request.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 diem_types::{ledger_info::LedgerInfoWithSignatures, transaction::Version};
9use serde::{Deserialize, Serialize};
10use std::fmt;
11
12#[derive(Clone, Deserialize, Eq, PartialEq, Serialize)]
13/// We're currently considering several types of chunk requests depending on the
14/// information available on the requesting side.
15pub enum TargetType {
16    /// The response is built relative to the target (or end of epoch).
17    /// **DEPRECATED**: `TargetLedgerInfo` is only required for backward
18    /// compatibility. State sync avoids sending these target types and
19    /// instead uses `HighestAvailable` below. This message will be removed on the next breaking release: <https://github.com/diem/diem/issues/8013>
20    TargetLedgerInfo(LedgerInfoWithSignatures),
21    /// The response is built relative to the highest available LedgerInfo (or
22    /// end of epoch). The value specifies the timeout in ms to wait for an
23    /// available response. This "long poll" approach allows a responding
24    /// node to add the request to the list of its subscriptions for the
25    /// duration of a timeout until some new information becomes available.
26    ///
27    /// `target_li`: While asking for the highest available ledger info, this
28    /// request also provides the option to the sync requester to specify a
29    /// target LI. This is to support the scenario where the sync requester
30    /// is lagging too much behind the responding node in the sync process.
31    /// If the highest ledger info version keeps advancing on the responding
32    /// node, even though the sync requester continues to receive and sync
33    /// txns, those txns will never be backed an LI, since a LI can only be
34    /// committed once all the transactions up to the LI's version has been
35    /// received. (It is important for a transaction to be backed by an LI,
36    /// because transactions need to be backed by an LI to be shown as
37    /// committed upon storage query) To prevent the above problem where
38    /// the transactions are never backed by a LI during sync catch-up
39    /// (or the difference between synced version and committed LI version
40    /// keeps growing on sync requester), this `TargetType` can
41    /// simultaneously (1) ask for the highest ledger info, and (2) specify a
42    /// target to build the requested transactions w.r.t.. With (1), the
43    /// sync requester can store the LI later to target-sync once it is
44    /// ready for that LI after syncing to an earlier target LI via (2).
45    ///
46    /// If `target_li` is not specified, the responding node will build the
47    /// responses against its highest LI
48    HighestAvailable {
49        target_li: Option<LedgerInfoWithSignatures>,
50        timeout_ms: u64,
51    },
52    /// The response is built relative to a LedgerInfo at a given version.
53    Waypoint(Version),
54}
55
56impl TargetType {
57    pub fn epoch(&self) -> Option<u64> {
58        match self {
59            TargetType::TargetLedgerInfo(li) => Some(li.ledger_info().epoch()),
60            TargetType::HighestAvailable { target_li, .. } => {
61                target_li.as_ref().map(|li| li.ledger_info().epoch())
62            }
63            TargetType::Waypoint(_) => None,
64        }
65    }
66
67    pub fn version(&self) -> Option<u64> {
68        match self {
69            TargetType::TargetLedgerInfo(li) => {
70                Some(li.ledger_info().version())
71            }
72            TargetType::HighestAvailable { target_li, .. } => {
73                target_li.as_ref().map(|li| li.ledger_info().version())
74            }
75            TargetType::Waypoint(version) => Some(*version),
76        }
77    }
78}
79
80impl fmt::Debug for TargetType {
81    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        write!(f, "{}", self)
83    }
84}
85
86impl fmt::Display for TargetType {
87    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88        match self {
89            TargetType::TargetLedgerInfo(ledger_info) => {
90                write!(f, "TargetLedgerInfo({})", ledger_info)
91            }
92            TargetType::HighestAvailable {
93                target_li,
94                timeout_ms,
95            } => write!(
96                f,
97                "HighestAvailable(timeout:{}, target_li:{})",
98                timeout_ms,
99                target_li
100                    .as_ref()
101                    .map_or_else(|| String::from("None"), |li| li.to_string())
102            ),
103            TargetType::Waypoint(version) => write!(f, "Waypoint({})", version),
104        }
105    }
106}
107
108#[derive(Clone, Deserialize, Eq, PartialEq, Serialize)]
109pub struct GetChunkRequest {
110    /// The response should start with `known_version + 1`.
111    pub known_version: Version,
112    /// Epoch the chunk response is supposed to belong to (i.e., epoch of
113    /// known_version + 1).
114    pub current_epoch: u64,
115    /// Max size of a chunk response.
116    pub limit: u64,
117    /// The target of the given request.
118    pub target: TargetType,
119}
120
121impl GetChunkRequest {
122    pub fn new(
123        known_version: Version, current_epoch: u64, limit: u64,
124        target: TargetType,
125    ) -> Self {
126        Self {
127            known_version,
128            current_epoch,
129            limit,
130            target,
131        }
132    }
133}
134
135impl fmt::Debug for GetChunkRequest {
136    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137        write!(f, "{}", self)
138    }
139}
140
141impl fmt::Display for GetChunkRequest {
142    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143        write!(
144            f,
145            "[ChunkRequest: known version: {}, epoch: {}, limit: {}, target: {}]",
146            self.known_version, self.current_epoch, self.limit, self.target,
147        )
148    }
149}