Skip to main content

near_client_primitives/
debug.rs

1//! Structs in this module are used for debug purposes, and might change at any time
2//! without backwards compatibility of JSON encoding.
3use near_primitives::congestion_info::CongestionInfo;
4use near_primitives::types::{EpochId, ShardId};
5use near_primitives::views::{
6    CatchupStatusView, ChainProcessingInfo, EpochValidatorInfo, RequestedStatePartsView,
7    SyncStatusView,
8};
9use near_primitives::{
10    block_header::ApprovalInner,
11    hash::CryptoHash,
12    sharding::ChunkHash,
13    types::{AccountId, BlockHeight},
14    views::ValidatorInfo,
15};
16use near_time::Utc;
17use std::collections::HashMap;
18use std::str::FromStr;
19use strum::Display;
20
21#[derive(serde::Serialize, serde::Deserialize, Debug)]
22pub struct TrackedShardsView {
23    pub shards_tracked_this_epoch: Vec<bool>,
24    pub shards_tracked_next_epoch: Vec<bool>,
25}
26
27#[derive(serde::Serialize, serde::Deserialize, Debug)]
28pub struct EpochInfoView {
29    pub epoch_height: u64,
30    pub epoch_id: CryptoHash,
31    pub height: BlockHeight,
32    pub first_block: Option<(CryptoHash, Utc)>,
33    pub block_producers: Vec<ValidatorInfo>,
34    pub chunk_producers: Vec<String>,
35    pub chunk_validators: Vec<String>,
36    pub validator_info: Option<EpochValidatorInfo>,
37    pub protocol_version: u32,
38    pub sync_hash: Option<CryptoHash>,
39    pub shards_size_and_parts: Vec<(u64, u64, bool)>,
40}
41
42#[derive(serde::Serialize, serde::Deserialize, Debug)]
43pub struct DebugChunkStatus {
44    pub shard_id: u64,
45    pub chunk_hash: ChunkHash,
46    pub chunk_producer: Option<AccountId>,
47    pub gas_used: u64,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub processing_time_ms: Option<u64>,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub congestion_level: Option<f64>,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub congestion_info: Option<CongestionInfo>,
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub endorsement_ratio: Option<f64>,
56}
57
58#[derive(serde::Serialize, serde::Deserialize, Debug)]
59pub struct DebugBlockStatus {
60    pub block_hash: CryptoHash,
61    pub prev_block_hash: CryptoHash,
62    pub block_height: u64,
63    pub block_timestamp: u64,
64    pub block_producer: Option<AccountId>,
65    pub full_block_missing: bool, // only header available
66    pub is_on_canonical_chain: bool,
67    pub chunks: Vec<DebugChunkStatus>,
68    // Time that was spent processing a given block.
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub processing_time_ms: Option<u64>,
71    pub gas_price_ratio: f64,
72}
73
74#[derive(serde::Serialize, serde::Deserialize, Debug)]
75pub struct MissedHeightInfo {
76    pub block_height: u64,
77    pub block_producer: Option<AccountId>,
78}
79
80#[derive(serde::Serialize, serde::Deserialize, Debug)]
81pub struct DebugBlockStatusData {
82    pub blocks: Vec<DebugBlockStatus>,
83    pub missed_heights: Vec<MissedHeightInfo>,
84    pub head: CryptoHash,
85    pub header_head: CryptoHash,
86}
87
88// Information about the approval created by this node.
89// Used for debug purposes only.
90#[derive(serde::Serialize, Debug, Clone)]
91pub struct ApprovalHistoryEntry {
92    // If target_height == base_height + 1  - this is endorsement.
93    // Otherwise this is a skip.
94    pub parent_height: BlockHeight,
95    pub target_height: BlockHeight,
96    // Time when we actually created the approval and sent it out.
97    pub approval_creation_time: Utc,
98    // The moment when we were ready to send this approval (or skip)
99    pub timer_started_ago_millis: u64,
100    // But we had to wait at least this long before doing it.
101    pub expected_delay_millis: u64,
102}
103
104// Information about chunk produced by this node.
105// For debug purposes only.
106#[derive(serde::Serialize, Debug, Default, Clone)]
107pub struct ChunkProduction {
108    // Time when we produced the chunk.
109    pub chunk_production_time: Option<Utc>,
110    // How long did the chunk production take (reed solomon encoding, preparing fragments etc.)
111    // Doesn't include network latency.
112    pub chunk_production_duration_millis: Option<u64>,
113}
114// Information about the block produced by this node.
115// For debug purposes only.
116#[derive(serde::Serialize, Debug, Clone, Default)]
117pub struct BlockProduction {
118    // Approvals that we received.
119    pub approvals: ApprovalAtHeightStatus,
120    // Chunk producer and time at which we received chunk for given shard. This field will not be
121    // set if we didn't produce the block.
122    pub chunks_collection_time: Vec<ChunkCollection>,
123    // Time when we produced the block, None if we didn't produce the block.
124    pub block_production_time: Option<Utc>,
125    // Whether this block is included on the canonical chain.
126    pub block_included: bool,
127}
128
129#[derive(serde::Serialize, Debug, Clone)]
130pub struct ChunkCollection {
131    // Chunk producer of the chunk
132    pub chunk_producer: AccountId,
133    // Time when the chunk was received. Note that this field can be filled even if the block doesn't
134    // include a chunk for the shard, if a chunk at this height was received after the block was produced.
135    pub received_time: Option<Utc>,
136    // Whether the block included a chunk for this shard
137    pub chunk_included: bool,
138}
139
140// Information about things related to block/chunk production
141// at given height.
142// For debug purposes only.
143#[derive(serde::Serialize, Debug, Default)]
144pub struct ProductionAtHeight {
145    // Stores information about block production is we are responsible for producing this block,
146    // None if we are not responsible for producing this block.
147    pub block_production: Option<BlockProduction>,
148    // Map from shard_id to chunk that we are responsible to produce at this height
149    pub chunk_production: HashMap<ShardId, ChunkProduction>,
150}
151
152// Information about the approvals that we received.
153#[derive(serde::Serialize, Debug, Default, Clone)]
154pub struct ApprovalAtHeightStatus {
155    // Map from validator id to the type of approval that they sent and timestamp.
156    pub approvals: HashMap<AccountId, (ApprovalInner, Utc)>,
157    // Time at which we received 2/3 approvals (doomslug threshold).
158    pub ready_at: Option<Utc>,
159}
160
161#[derive(serde::Serialize, Debug)]
162pub struct ValidatorStatus {
163    pub validator_name: Option<AccountId>,
164    // Current number of shards
165    pub shards: u64,
166    // Current height.
167    pub head_height: u64,
168    // Current validators with their stake (stake is in NEAR - not yocto near).
169    pub validators: Option<Vec<(AccountId, u64)>>,
170    // All approvals that we've sent.
171    pub approval_history: Vec<ApprovalHistoryEntry>,
172    // Blocks & chunks that we've produced or about to produce.
173    // Sorted by block height inversely (high to low)
174    // The range of heights are controlled by constants in client_actor.rs
175    pub production: Vec<(BlockHeight, ProductionAtHeight)>,
176    // Chunk producers that this node has banned.
177    pub banned_chunk_producers: Vec<(EpochId, Vec<AccountId>)>,
178}
179
180/// Defines the mode for finding the first block to display.
181#[derive(Debug, Display)]
182pub enum DebugBlocksStartingMode {
183    /// Start from the height given in the query.
184    All,
185    /// Jump to the first missing block, since the given height.
186    JumpToBlockMiss,
187    /// Jump to the first block with a missing chunk, since the given height.
188    JumpToChunkMiss,
189    /// Jump to the first produced block, since the given height.
190    JumpToBlockProduced,
191    /// Jump to the first block that has all chunks included, since the given height.
192    JumpToAllChunksIncluded,
193}
194
195impl FromStr for DebugBlocksStartingMode {
196    type Err = String;
197
198    fn from_str(input: &str) -> Result<DebugBlocksStartingMode, Self::Err> {
199        match input {
200            "all" => Ok(DebugBlocksStartingMode::All),
201            "first_block_miss" => Ok(DebugBlocksStartingMode::JumpToBlockMiss),
202            "first_chunk_miss" => Ok(DebugBlocksStartingMode::JumpToChunkMiss),
203            "first_block_produced" => Ok(DebugBlocksStartingMode::JumpToBlockProduced),
204            "all_chunks_included" => Ok(DebugBlocksStartingMode::JumpToAllChunksIncluded),
205            _ => Err(format!("Invalid input: {}", input)),
206        }
207    }
208}
209
210impl<'de> serde::Deserialize<'de> for DebugBlocksStartingMode {
211    fn deserialize<D>(deserializer: D) -> Result<DebugBlocksStartingMode, D::Error>
212    where
213        D: serde::Deserializer<'de>,
214    {
215        let s = String::deserialize(deserializer)?;
216        DebugBlocksStartingMode::from_str(&s).map_err(serde::de::Error::custom)
217    }
218}
219
220#[derive(serde::Deserialize, Debug)]
221pub struct DebugBlockStatusQuery {
222    /// Height to start searching for blocks from.
223    pub starting_height: Option<u64>,
224    /// Mode for the block status query.
225    #[serde(default = "default_block_status_mode")]
226    pub mode: DebugBlocksStartingMode,
227    /// Number of blocks to return.
228    #[serde(default = "default_block_status_num_blocks")]
229    pub num_blocks: u64,
230}
231
232impl Default for DebugBlockStatusQuery {
233    fn default() -> Self {
234        Self {
235            starting_height: None,
236            mode: default_block_status_mode(),
237            num_blocks: default_block_status_num_blocks(),
238        }
239    }
240}
241
242fn default_block_status_mode() -> DebugBlocksStartingMode {
243    DebugBlocksStartingMode::All
244}
245
246fn default_block_status_num_blocks() -> u64 {
247    50
248}
249
250// Different debug requests that can be sent by HTML pages, via GET.
251#[derive(Debug)]
252pub enum DebugStatus {
253    // Request for the current sync status
254    SyncStatus,
255    // Request currently tracked shards
256    TrackedShards,
257    // Detailed information about last couple epochs.
258    EpochInfo(Option<EpochId>),
259    // Same as EpochInfo, but omits the expensive per-validator `validator_info`.
260    // Used by debug-ui views that only need epoch metadata and producer/validator
261    // counts (recent epochs, epoch shards, current peers).
262    EpochInfoLight(Option<EpochId>),
263    // Detailed information about last couple blocks.
264    BlockStatus(DebugBlockStatusQuery),
265    // Consensus related information.
266    ValidatorStatus,
267    // Request for the current catchup status
268    CatchupStatus,
269    // Request for the current state of chain processing (blocks in progress etc).
270    ChainProcessingStatus,
271    // The state parts already requested.
272    RequestedStateParts,
273}
274
275#[derive(serde::Serialize, Debug)]
276pub enum DebugStatusResponse {
277    SyncStatus(SyncStatusView),
278    CatchupStatus(Vec<CatchupStatusView>),
279    TrackedShards(TrackedShardsView),
280    // List of epochs - in descending order (next epoch is first).
281    EpochInfo(Vec<EpochInfoView>),
282    // Detailed information about blocks.
283    BlockStatus(DebugBlockStatusData),
284    // Detailed information about the validator (approvals, block & chunk production etc.)
285    ValidatorStatus(ValidatorStatus),
286    // Detailed information about chain processing (blocks in progress etc).
287    ChainProcessingStatus(ChainProcessingInfo),
288    // The state parts already requested.
289    RequestedStateParts(Vec<RequestedStatePartsView>),
290}