1use std::{
2 collections::{vec_deque::Iter, VecDeque},
3 fmt::Debug,
4};
5
6use serde::{Deserialize, Serialize};
7
8#[cfg(any(test, feature = "fuzzing"))]
9use proptest_derive::Arbitrary;
10
11use diem_logger::prelude::*;
12
13use crate::{
14 block_info::View,
15 term_state::pos_state_config::{PosStateConfigTrait, POS_STATE_CONFIG},
16};
17
18#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
19#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
20pub struct StatusItem {
21 pub view: View,
22 pub votes: u64,
23}
24
25#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
26#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
27pub struct StatusList {
28 inner: VecDeque<StatusItem>,
29 sorted: bool,
30}
31
32impl Default for StatusList {
33 fn default() -> Self {
34 Self {
35 inner: VecDeque::new(),
36 sorted: true,
37 }
38 }
39}
40
41impl StatusList {
42 fn push(
44 &mut self, exit_view: View, votes: u64, update_views: &mut Vec<View>,
45 ) {
46 if self
49 .inner
50 .back()
51 .map_or(false, |item| item.view > exit_view)
52 {
53 self.sorted = false;
54 }
55 self.inner.push_back(StatusItem {
56 view: exit_view,
57 votes,
58 });
59 update_views.push(exit_view);
60 }
61
62 fn pull(&mut self, required_votes: u64) -> Option<StatusItem> {
65 self.sort();
66 if let Some(item) = self.inner.pop_front() {
67 if item.votes <= required_votes {
68 Some(item)
69 } else {
70 let rest_votes = item.votes - required_votes;
71 self.inner.push_front(StatusItem {
72 view: item.view,
73 votes: rest_votes,
74 });
75 Some(StatusItem {
76 view: item.view,
77 votes: required_votes,
78 })
79 }
80 } else {
81 None
82 }
83 }
84
85 fn pop_by_view(&mut self, view: View) -> Option<StatusItem> {
87 self.sort();
88 if let Some(item) = self.inner.pop_front() {
89 if item.view > view {
90 self.inner.push_front(item);
91 None
92 } else {
93 Some(item)
94 }
95 } else {
96 None
97 }
98 }
99
100 fn sort(&mut self) {
101 if !self.sorted {
102 self.inner
103 .make_contiguous()
104 .sort_unstable_by_key(|item| item.view);
105 self.sorted = true;
106 }
107 }
108
109 fn clear(&mut self) {
110 self.inner.clear();
111 self.sorted = true;
112 }
113
114 pub fn len(&self) -> usize { self.inner.len() }
115
116 pub fn is_empty(&self) -> bool { self.inner.is_empty() }
117
118 pub fn iter(&self) -> Iter<'_, StatusItem> { self.inner.iter() }
119}
120
121#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Debug, Default)]
122#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
123pub struct NodeLockStatus {
124 pub in_queue: StatusList,
125 pub locked: u64,
126 pub out_queue: StatusList,
127 unlocked: u64,
128
129 available_votes: u64,
131
132 force_retired: Option<View>,
134 exempt_from_forfeit: Option<u64>,
137}
138
139impl NodeLockStatus {
140 pub fn available_votes(&self) -> u64 {
141 if self.exempt_from_forfeit.is_some() {
142 0
143 } else {
144 self.available_votes
145 }
146 }
147
148 pub fn unlocked_votes(&self) -> u64 {
149 self.exempt_from_forfeit.unwrap_or(self.unlocked)
150 }
151
152 pub fn forfeited(&self) -> u64 { self.unlocked - self.unlocked_votes() }
153
154 pub fn force_retired(&self) -> Option<u64> { self.force_retired }
155
156 pub fn exempt_from_forfeit(&self) -> Option<u64> {
157 self.exempt_from_forfeit
158 }
159}
160
161impl NodeLockStatus {
162 pub(super) fn update(&mut self, view: View) -> bool {
163 let mut new_votes_unlocked = false;
164
165 while let Some(item) = self.in_queue.pop_by_view(view) {
166 self.locked += item.votes;
167 }
168
169 while let Some(item) = self.out_queue.pop_by_view(view) {
170 self.unlocked += item.votes;
171 new_votes_unlocked = true;
172 }
173
174 if self.force_retired.map_or(false, |retire_view| {
175 view >= retire_view
176 + POS_STATE_CONFIG.force_retired_locked_views(view)
177 }) {
178 self.force_retired = None;
179 }
180
181 if self.exempt_from_forfeit.is_some() {
182 new_votes_unlocked = false
183 }
184
185 new_votes_unlocked
186 }
187
188 pub(super) fn new_lock(
189 &mut self, view: View, votes: u64, initialize_mode: bool,
190 update_views: &mut Vec<View>,
191 ) {
192 if votes == 0 {
193 return;
194 }
195
196 if initialize_mode {
197 self.available_votes += votes;
198 self.locked += votes;
199 return;
200 }
201
202 if self.force_retired.is_some() {
205 let exit_view = view
206 + POS_STATE_CONFIG.in_queue_locked_views(view)
207 + POS_STATE_CONFIG.out_queue_locked_views(view);
208 self.out_queue.push(exit_view, votes, update_views);
209 } else {
210 self.available_votes += votes;
211 let exit_view = view + POS_STATE_CONFIG.in_queue_locked_views(view);
212 self.in_queue.push(exit_view, votes, update_views);
213 }
214 }
215
216 pub(super) fn new_unlock(
217 &mut self, view: View, to_unlock_votes: u64,
218 update_views: &mut Vec<View>,
219 ) {
220 if to_unlock_votes == 0 {
221 return;
222 }
223
224 let before_available_votes = self.available_votes;
225 let mut rest_votes = to_unlock_votes;
226
227 let votes = rest_votes.min(self.locked);
229 if votes > 0 {
230 rest_votes -= votes;
231 self.locked -= votes;
232 self.available_votes -= votes;
233
234 let exit_view =
235 view + POS_STATE_CONFIG.out_queue_locked_views(view);
236 self.out_queue.push(exit_view, votes, update_views);
237 }
238
239 while rest_votes > 0 {
241 let maybe_item = self.in_queue.pull(rest_votes);
242
243 if maybe_item.is_none() {
244 diem_warn!(
245 "Not enough votes to unlock: before available votes {}, to unlock votes {}, rest votes {}.",
246 before_available_votes,
247 to_unlock_votes,
248 rest_votes
249 );
250 break;
251 }
252
253 let item = maybe_item.unwrap();
254
255 rest_votes -= item.votes;
256 self.available_votes -= item.votes;
257
258 let exit_view =
259 item.view + POS_STATE_CONFIG.out_queue_locked_views(view);
260 self.out_queue.push(exit_view, item.votes, update_views);
261 }
262 }
263
264 pub(super) fn force_retire(
265 &mut self, view: View, callback_views: &mut Vec<View>,
266 ) {
267 if self.force_retired.is_none() {
268 self.force_retired = Some(view);
269 callback_views
270 .push(view + POS_STATE_CONFIG.force_retired_locked_views(view));
271 self.new_unlock(view, self.available_votes, callback_views);
272 }
273 }
274
275 pub(super) fn forfeit(
276 &mut self, view: View, updated_views: &mut Vec<View>,
277 ) {
278 if self.exempt_from_forfeit.is_some() {
279 return;
280 }
281 match POS_STATE_CONFIG.dispute_locked_views(view) {
282 None => self.exempt_from_forfeit = Some(self.unlocked),
283 Some(dispute_locked_views) => {
284 let relock = self.available_votes > 0
287 || (POS_STATE_CONFIG.dispute_lock_includes_out_queue(view)
288 && !self.out_queue.is_empty());
289 if relock {
290 let mut to_lock_votes = self.available_votes;
293 self.in_queue.clear();
294 self.locked = 0;
295 self.available_votes = 0;
296
297 while let Some(item) = self.out_queue.pop_by_view(u64::MAX)
298 {
299 to_lock_votes += item.votes;
300 }
301 self.force_retired = None;
305
306 self.out_queue.push(
307 view.saturating_add(dispute_locked_views),
308 to_lock_votes,
309 updated_views,
310 );
311 }
312 }
313 }
314 }
315}
316
317#[allow(dead_code)]
318pub mod tests {
319 use super::*;
320 use std::collections::HashSet;
321
322 enum Operation {
323 NewLock(u64),
324 NewUnlock(u64),
325 ForceRetire,
326 Forfeit,
327 AssertAvailable(u64),
328 AssertLocked(u64),
329 AssertUnlocked(u64),
330 }
331
332 use Operation::*;
333
334 fn run_tasks(tasks: Vec<(Operation, View)>) {
335 let mut tasks: VecDeque<(Operation, View)> = tasks.into();
336
337 let mut lock_status = NodeLockStatus::default();
338 let mut hint_views = HashSet::<View>::new();
339 let mut view = 0;
340
341 while !(tasks.is_empty() && hint_views.is_empty()) {
342 if hint_views.contains(&view) {
343 lock_status.update(view);
344 hint_views.remove(&view);
345 }
346
347 let mut update_views = Vec::new();
348
349 while tasks.front().map(|x| x.1) == Some(view) {
350 match tasks.pop_front().unwrap().0 {
351 Operation::NewLock(votes) => {
352 lock_status.new_lock(
353 view,
354 votes,
355 false,
356 &mut update_views,
357 );
358 }
359 Operation::NewUnlock(votes) => {
360 lock_status.new_unlock(view, votes, &mut update_views);
361 }
362 Operation::ForceRetire => {
363 lock_status.force_retire(view, &mut update_views);
364 }
365 Operation::Forfeit => {
366 lock_status.forfeit(view, &mut update_views)
367 }
368 Operation::AssertAvailable(votes) => {
369 if lock_status.available_votes != votes {
370 panic!("View {}\n {:?}", view, lock_status);
371 }
372 }
373 Operation::AssertLocked(votes) => {
374 if lock_status.locked != votes {
375 panic!("View {}\n {:?}", view, lock_status);
376 }
377 }
378 Operation::AssertUnlocked(votes) => {
379 if lock_status.unlocked_votes() != votes {
380 panic!("View {}\n {:?}", view, lock_status);
381 }
382 }
383 }
384 }
385
386 for update_view in update_views {
387 if update_view > view {
388 hint_views.insert(update_view);
389 }
390 }
391 view += 1;
392 }
393 }
394
395 fn basic() {
397 let one_vote = vec![
398 (NewLock(1), 2),
399 (AssertAvailable(1), 3),
400 (AssertLocked(1), 10082),
401 (NewUnlock(1), 20000),
402 (AssertAvailable(0), 20001),
403 (AssertUnlocked(0), 20002),
404 (AssertUnlocked(1), 30080),
405 ];
406
407 let multi_vote = vec![
408 (NewLock(10), 2u64),
409 (AssertAvailable(10), 3),
410 (AssertLocked(10), 10082),
411 (NewUnlock(7), 20000),
412 (AssertAvailable(3), 20001),
413 (AssertUnlocked(0), 20002),
414 (AssertUnlocked(7), 30080),
415 (AssertAvailable(3), 30081),
416 ];
417
418 run_tasks(one_vote);
419 run_tasks(multi_vote);
420 }
421
422 fn increase_during_exit() {
424 let tasks = vec![
425 (NewLock(10), 2),
426 (AssertAvailable(10), 3),
427 (NewLock(5), 4),
428 (AssertAvailable(15), 5),
429 (NewUnlock(7), 20000),
430 (AssertAvailable(8), 20001),
431 (NewLock(5), 20002),
432 (AssertAvailable(13), 20003),
433 (NewUnlock(7), 20004),
434 (AssertAvailable(6), 20005),
435 (AssertUnlocked(0), 20005),
436 (NewUnlock(3), 20006),
437 (AssertUnlocked(7), 30080),
438 (AssertUnlocked(14), 30084),
439 (AssertUnlocked(15), 30086),
440 (AssertUnlocked(15), 40161),
441 (AssertUnlocked(17), 40162),
442 ];
443
444 run_tasks(tasks);
445 }
446
447 fn force_retire() {
449 let tasks = vec![
450 (NewLock(6), 2),
451 (AssertAvailable(6), 3),
452 (NewLock(7), 12),
453 (AssertAvailable(13), 13),
454 (AssertLocked(6), 10090),
455 (ForceRetire, 10090),
456 (NewLock(8), 10092),
457 (AssertAvailable(0), 10093),
458 (AssertLocked(0), 10093),
459 (AssertUnlocked(0), 20169),
460 (AssertUnlocked(6), 20170),
461 (NewLock(9), 20170),
462 (AssertAvailable(9), 20171),
463 (AssertUnlocked(13), 20172),
464 (AssertLocked(0), 30249),
465 (AssertLocked(9), 30250),
466 (AssertUnlocked(13), 30251),
467 (AssertUnlocked(21), 30252),
468 ];
469
470 run_tasks(tasks);
471 }
472
473 fn resolve_retired() {
474 let tasks = vec![
475 (NewLock(6), 2),
476 (AssertAvailable(6), 3),
477 (ForceRetire, 10),
478 (NewLock(8), 10090),
479 (AssertAvailable(8), 10091),
480 ];
481
482 run_tasks(tasks);
483 }
484
485 pub fn run_all() {
486 basic();
487 increase_during_exit();
488 force_retire();
489 resolve_retired();
490 }
491}