finality_grandpa/
bridge_state.rs

1// Copyright 2018-2019 Parity Technologies (UK) Ltd
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Bridging round state between rounds.
16
17use crate::round::State as RoundState;
18use futures::task;
19use parking_lot::{RwLock, RwLockReadGuard};
20use std::{sync::Arc, task::Context};
21
22// round state bridged across rounds.
23struct Bridged<H, N> {
24	inner: RwLock<RoundState<H, N>>,
25	waker: task::AtomicWaker,
26}
27
28impl<H, N> Bridged<H, N> {
29	fn new(inner: RwLock<RoundState<H, N>>) -> Self {
30		Bridged { inner, waker: task::AtomicWaker::new() }
31	}
32}
33
34/// A prior view of a round-state.
35pub(crate) struct PriorView<H, N>(Arc<Bridged<H, N>>);
36
37impl<H, N> PriorView<H, N> {
38	/// Push an update to the latter view.
39	pub(crate) fn update(&self, new: RoundState<H, N>) {
40		*self.0.inner.write() = new;
41		self.0.waker.wake();
42	}
43}
44
45/// A latter view of a round-state.
46pub(crate) struct LatterView<H, N>(Arc<Bridged<H, N>>);
47
48impl<H, N> LatterView<H, N> {
49	/// Fetch a handle to the last round-state.
50	pub(crate) fn get(&self, cx: &mut Context) -> RwLockReadGuard<RoundState<H, N>> {
51		self.0.waker.register(cx.waker());
52		self.0.inner.read()
53	}
54}
55
56/// Constructs two views of a bridged round-state.
57///
58/// The prior view is held by a round which produces the state and pushes updates to a latter view.
59/// When updating, the latter view's task is updated.
60///
61/// The latter view is held by the subsequent round, which blocks certain activity
62/// while waiting for events on an older round.
63pub(crate) fn bridge_state<H, N>(initial: RoundState<H, N>) -> (PriorView<H, N>, LatterView<H, N>) {
64	let inner = Arc::new(Bridged::new(RwLock::new(initial)));
65	(PriorView(inner.clone()), LatterView(inner))
66}
67
68#[cfg(test)]
69mod tests {
70	use super::*;
71	use std::{sync::Barrier, task::Poll};
72
73	#[test]
74	fn bridging_state() {
75		let initial =
76			RoundState { prevote_ghost: None, finalized: None, estimate: None, completable: false };
77
78		let (prior, latter) = bridge_state(initial);
79		let waits_for_finality = ::futures::future::poll_fn(move |cx| -> Poll<()> {
80			if latter.get(cx).finalized.is_some() {
81				Poll::Ready(())
82			} else {
83				Poll::Pending
84			}
85		});
86
87		let barrier = Arc::new(Barrier::new(2));
88		let barrier_other = barrier.clone();
89		::std::thread::spawn(move || {
90			barrier_other.wait();
91			prior.update(RoundState {
92				prevote_ghost: Some(("5", 5)),
93				finalized: Some(("1", 1)),
94				estimate: Some(("3", 3)),
95				completable: true,
96			});
97		});
98
99		barrier.wait();
100		futures::executor::block_on(waits_for_finality);
101	}
102}