1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use std::fmt::Display;
use datasize::DataSize;
use serde::{Deserialize, Serialize};
use crate::types::{Block, BlockHash, BlockHeader};
#[derive(Clone, DataSize, Debug, Serialize, Deserialize)]
pub enum State {
/// No syncing of the linear chain configured.
None,
/// Synchronizing the linear chain up until trusted hash.
SyncingTrustedHash {
/// Linear chain block to start sync from.
trusted_hash: BlockHash,
/// The header of the highest block we have in storage (if any).
highest_block_header: Option<Box<BlockHeader>>,
/// During synchronization we might see new eras being created.
/// Track the highest height and wait until it's handled by consensus.
highest_block_seen: u64,
/// Chain of downloaded blocks from the linear chain.
/// We will `pop()` when executing blocks.
linear_chain: Vec<Block>,
/// The most recent block we started to execute. This is updated whenever we start
/// downloading deploys for the next block to be executed.
latest_block: Box<Option<Block>>,
/// The block height of the last seen switch block.
last_switch_block_height: Option<u64>,
},
/// Synchronizing the descendants of the trusted hash.
SyncingDescendants {
trusted_hash: BlockHash,
/// The most recent block we started to execute. This is updated whenever we start
/// downloading deploys for the next block to be executed.
latest_block: Box<Block>,
/// During synchronization we might see new eras being created.
/// Track the highest height and wait until it's handled by consensus.
highest_block_seen: u64,
/// The block height of the last seen switch block.
last_switch_block_height: Option<u64>,
},
/// Synchronizing done. The single field contains the highest block seen during the
/// synchronization process.
Done(Option<Box<Block>>),
}
impl Display for State {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
State::None => write!(f, "None"),
State::Done(latest_block) => write!(f, "Done(latest_block={})",
if let Some(block) = latest_block {
format!("{{ hash={}, height={} }}", block.hash(), block.height())
} else {
"None".to_string()
}),
State::SyncingTrustedHash { trusted_hash, highest_block_seen, .. } => {
write!(f, "SyncingTrustedHash(trusted_hash={}, highest_block_seen={})", trusted_hash, highest_block_seen)
},
State::SyncingDescendants {
trusted_hash,
latest_block,
..
} => write!(
f,
"SyncingDescendants(trusted_hash={}, latest_block_hash={}, latest_block_height={}, latest_block_era={})",
trusted_hash,
latest_block.header().hash(),
latest_block.header().height(),
latest_block.header().era_id(),
),
}
}
}
impl State {
pub fn sync_trusted_hash(
trusted_hash: BlockHash,
highest_block_header: Option<BlockHeader>,
) -> Self {
State::SyncingTrustedHash {
trusted_hash,
highest_block_header: highest_block_header.map(Box::new),
highest_block_seen: 0,
linear_chain: Vec::new(),
latest_block: Box::new(None),
last_switch_block_height: None,
}
}
pub fn sync_descendants(
trusted_hash: BlockHash,
latest_block: Block,
last_switch_block_height: Option<u64>,
) -> Self {
State::SyncingDescendants {
trusted_hash,
latest_block: Box::new(latest_block),
highest_block_seen: 0,
last_switch_block_height,
}
}
pub fn block_downloaded(&mut self, block: &Block) {
match self {
State::None | State::Done(_) => {}
State::SyncingTrustedHash {
highest_block_seen, ..
}
| State::SyncingDescendants {
highest_block_seen, ..
} => {
let curr_height = block.height();
if curr_height > *highest_block_seen {
*highest_block_seen = curr_height;
}
}
};
}
/// Returns whether in `Done` state.
pub(crate) fn is_done(&self) -> bool {
matches!(self, State::Done(_))
}
/// Returns whether in `None` state.
pub(crate) fn is_none(&self) -> bool {
matches!(self, State::None)
}
/// Sets the last seen switch block height.
pub(crate) fn set_last_switch_block_height(&mut self, height: u64) {
match self {
State::None | State::Done(_) => (),
State::SyncingTrustedHash {
last_switch_block_height,
..
}
| State::SyncingDescendants {
last_switch_block_height,
..
} => {
*last_switch_block_height = Some(height);
}
}
}
}