cfxcore/pos/state_sync/
chunk_response.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::{
9    ledger_info::LedgerInfoWithSignatures,
10    transaction::{TransactionListWithProof, Version},
11};
12use serde::{Deserialize, Serialize};
13use std::fmt;
14
15/// The response can carry different LedgerInfo types depending on whether the
16/// verification is done via the local trusted validator set or a local
17/// waypoint.
18#[allow(clippy::large_enum_variant)]
19#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
20pub enum ResponseLedgerInfo {
21    /// A typical response carries a LedgerInfo with signatures that should be
22    /// verified using the local trusted validator set.
23    /// **DEPRECATED**: `VerifiableLedgerInfo` is only required for backward
24    /// compatibility. State sync avoids sending these response types and
25    /// instead uses `ProgressiveLedgerInfo` below. This message will be removed on the next breaking release: <https://github.com/diem/diem/issues/8013>
26    VerifiableLedgerInfo(LedgerInfoWithSignatures),
27    /// A response to `TargetType::HighestAvailable` chunk request type.
28    ProgressiveLedgerInfo {
29        // LedgerInfo that the corresponding GetChunkResponse is built relative
30        // to.
31        target_li: LedgerInfoWithSignatures,
32        // LedgerInfo for a version later than that of `target_li`
33        // If `None`, this is the same as `target_li`
34        highest_li: Option<LedgerInfoWithSignatures>,
35    },
36    /// During the initial catchup upon startup the chunks carry LedgerInfo
37    /// that is verified using the local waypoint.
38    LedgerInfoForWaypoint {
39        // LedgerInfo corresponding to the waypoint version.
40        waypoint_li: LedgerInfoWithSignatures,
41        // In case a chunk terminates an epoch, the LedgerInfo corresponding to
42        // the epoch boundary.
43        end_of_epoch_li: Option<LedgerInfoWithSignatures>,
44    },
45}
46
47impl ResponseLedgerInfo {
48    /// The version of the LedgerInfo relative to which the transactions proofs
49    /// are built.
50    pub fn version(&self) -> Version {
51        match self {
52            ResponseLedgerInfo::VerifiableLedgerInfo(li) => {
53                li.ledger_info().version()
54            }
55            ResponseLedgerInfo::ProgressiveLedgerInfo { target_li, .. } => {
56                target_li.ledger_info().version()
57            }
58            ResponseLedgerInfo::LedgerInfoForWaypoint {
59                waypoint_li, ..
60            } => waypoint_li.ledger_info().version(),
61        }
62    }
63}
64
65/// The returned chunk is bounded by the end of the known_epoch of the requester
66/// (i.e., a chunk never crosses epoch boundaries).
67#[derive(Clone, Deserialize, Eq, PartialEq, Serialize)]
68pub struct GetChunkResponse {
69    /// The proofs are built relative to the LedgerInfo in `response_li`.
70    /// The specifics of ledger info verification depend on its type.
71    pub response_li: ResponseLedgerInfo,
72    /// Chunk of transactions with proof corresponding to the ledger info
73    /// carried by the response.
74    pub txn_list_with_proof: TransactionListWithProof,
75}
76
77impl GetChunkResponse {
78    pub fn new(
79        response_li: ResponseLedgerInfo,
80        txn_list_with_proof: TransactionListWithProof,
81    ) -> Self {
82        Self {
83            response_li,
84            txn_list_with_proof,
85        }
86    }
87}
88
89impl fmt::Debug for GetChunkResponse {
90    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91        write!(f, "{}", self)
92    }
93}
94
95impl fmt::Display for GetChunkResponse {
96    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97        let txns_repr = match self.txn_list_with_proof.first_transaction_version
98        {
99            None => "empty".to_string(),
100            Some(first_version) => {
101                let last_version = first_version
102                    .checked_add(self.txn_list_with_proof.len() as u64)
103                    .and_then(|v| v.checked_sub(1)) // last_version = first_version + txns.len() - 1
104                    .map(|v| v.to_string())
105                    .unwrap_or_else(|| "Last version has overflown!".into());
106                format!("versions [{} - {}]", first_version, last_version)
107            }
108        };
109        let response_li_repr = match &self.response_li {
110            ResponseLedgerInfo::VerifiableLedgerInfo(li) => {
111                format!("[verifiable LI {}]", li.ledger_info())
112            }
113            ResponseLedgerInfo::ProgressiveLedgerInfo {
114                target_li,
115                highest_li,
116            } => format!(
117                "[progressive LI: target LI {}, highest LI {}]",
118                target_li.ledger_info(),
119                highest_li.as_ref().unwrap_or(target_li).ledger_info(),
120            ),
121            ResponseLedgerInfo::LedgerInfoForWaypoint {
122                waypoint_li,
123                end_of_epoch_li,
124            } => format!(
125                "[waypoint LI {}, end of epoch LI {}]",
126                waypoint_li.ledger_info(),
127                end_of_epoch_li.as_ref().map_or("None".to_string(), |li| li
128                    .ledger_info()
129                    .to_string())
130            ),
131        };
132        write!(
133            f,
134            "[ChunkResponse: response li: {}, txns: {}]",
135            response_li_repr, txns_repr,
136        )
137    }
138}