polkadot_node_core_chain_selection/
backend.rs1use polkadot_primitives::{BlockNumber, Hash};
25
26use std::collections::HashMap;
27
28use crate::{BlockEntry, Error, LeafEntrySet, Timestamp};
29
30pub(super) enum BackendWriteOp {
31 WriteBlockEntry(BlockEntry),
32 WriteBlocksByNumber(BlockNumber, Vec<Hash>),
33 WriteViableLeaves(LeafEntrySet),
34 WriteStagnantAt(Timestamp, Vec<Hash>),
35 DeleteBlocksByNumber(BlockNumber),
36 DeleteBlockEntry(Hash),
37 DeleteStagnantAt(Timestamp),
38}
39
40pub(super) trait Backend {
42 fn load_block_entry(&self, hash: &Hash) -> Result<Option<BlockEntry>, Error>;
44 fn load_leaves(&self) -> Result<LeafEntrySet, Error>;
46 fn load_stagnant_at(&self, timestamp: Timestamp) -> Result<Vec<Hash>, Error>;
48 fn load_stagnant_at_up_to(
51 &self,
52 up_to: Timestamp,
53 max_elements: usize,
54 ) -> Result<Vec<(Timestamp, Vec<Hash>)>, Error>;
55 fn load_first_block_number(&self) -> Result<Option<BlockNumber>, Error>;
57 fn load_blocks_by_number(&self, number: BlockNumber) -> Result<Vec<Hash>, Error>;
59
60 fn write<I>(&mut self, ops: I) -> Result<(), Error>
62 where
63 I: IntoIterator<Item = BackendWriteOp>;
64}
65
66pub(super) struct OverlayedBackend<'a, B: 'a> {
72 inner: &'a B,
73
74 block_entries: HashMap<Hash, Option<BlockEntry>>,
76 blocks_by_number: HashMap<BlockNumber, Option<Vec<Hash>>>,
78 stagnant_at: HashMap<Timestamp, Option<Vec<Hash>>>,
80 leaves: Option<LeafEntrySet>,
82}
83
84impl<'a, B: 'a + Backend> OverlayedBackend<'a, B> {
85 pub(super) fn new(backend: &'a B) -> Self {
86 OverlayedBackend {
87 inner: backend,
88 block_entries: HashMap::new(),
89 blocks_by_number: HashMap::new(),
90 stagnant_at: HashMap::new(),
91 leaves: None,
92 }
93 }
94
95 pub(super) fn load_block_entry(&self, hash: &Hash) -> Result<Option<BlockEntry>, Error> {
96 if let Some(val) = self.block_entries.get(&hash) {
97 return Ok(val.clone())
98 }
99
100 self.inner.load_block_entry(hash)
101 }
102
103 pub(super) fn load_blocks_by_number(&self, number: BlockNumber) -> Result<Vec<Hash>, Error> {
104 if let Some(val) = self.blocks_by_number.get(&number) {
105 return Ok(val.as_ref().map_or(Vec::new(), Clone::clone))
106 }
107
108 self.inner.load_blocks_by_number(number)
109 }
110
111 pub(super) fn load_leaves(&self) -> Result<LeafEntrySet, Error> {
112 if let Some(ref set) = self.leaves {
113 return Ok(set.clone())
114 }
115
116 self.inner.load_leaves()
117 }
118
119 pub(super) fn load_stagnant_at(&self, timestamp: Timestamp) -> Result<Vec<Hash>, Error> {
120 if let Some(val) = self.stagnant_at.get(×tamp) {
121 return Ok(val.as_ref().map_or(Vec::new(), Clone::clone))
122 }
123
124 self.inner.load_stagnant_at(timestamp)
125 }
126
127 pub(super) fn write_block_entry(&mut self, entry: BlockEntry) {
128 self.block_entries.insert(entry.block_hash, Some(entry));
129 }
130
131 pub(super) fn delete_block_entry(&mut self, hash: &Hash) {
132 self.block_entries.insert(*hash, None);
133 }
134
135 pub(super) fn write_blocks_by_number(&mut self, number: BlockNumber, blocks: Vec<Hash>) {
136 if blocks.is_empty() {
137 self.blocks_by_number.insert(number, None);
138 } else {
139 self.blocks_by_number.insert(number, Some(blocks));
140 }
141 }
142
143 pub(super) fn delete_blocks_by_number(&mut self, number: BlockNumber) {
144 self.blocks_by_number.insert(number, None);
145 }
146
147 pub(super) fn write_leaves(&mut self, leaves: LeafEntrySet) {
148 self.leaves = Some(leaves);
149 }
150
151 pub(super) fn write_stagnant_at(&mut self, timestamp: Timestamp, hashes: Vec<Hash>) {
152 self.stagnant_at.insert(timestamp, Some(hashes));
153 }
154
155 pub(super) fn delete_stagnant_at(&mut self, timestamp: Timestamp) {
156 self.stagnant_at.insert(timestamp, None);
157 }
158
159 pub(super) fn into_write_ops(self) -> impl Iterator<Item = BackendWriteOp> {
162 let block_entry_ops = self.block_entries.into_iter().map(|(h, v)| match v {
163 Some(v) => BackendWriteOp::WriteBlockEntry(v),
164 None => BackendWriteOp::DeleteBlockEntry(h),
165 });
166
167 let blocks_by_number_ops = self.blocks_by_number.into_iter().map(|(n, v)| match v {
168 Some(v) => BackendWriteOp::WriteBlocksByNumber(n, v),
169 None => BackendWriteOp::DeleteBlocksByNumber(n),
170 });
171
172 let leaf_ops = self.leaves.into_iter().map(BackendWriteOp::WriteViableLeaves);
173
174 let stagnant_at_ops = self.stagnant_at.into_iter().map(|(n, v)| match v {
175 Some(v) => BackendWriteOp::WriteStagnantAt(n, v),
176 None => BackendWriteOp::DeleteStagnantAt(n),
177 });
178
179 block_entry_ops
180 .chain(blocks_by_number_ops)
181 .chain(leaf_ops)
182 .chain(stagnant_at_ops)
183 }
184}
185
186fn contains_ancestor(backend: &impl Backend, head: Hash, ancestor: Hash) -> Result<bool, Error> {
196 let mut current_hash = head;
197 loop {
198 if current_hash == ancestor {
199 return Ok(true)
200 }
201 match backend.load_block_entry(¤t_hash)? {
202 Some(e) => current_hash = e.parent_hash,
203 None => break,
204 }
205 }
206
207 Ok(false)
208}
209
210pub(super) fn find_best_leaf_containing(
225 backend: &impl Backend,
226 required: Hash,
227) -> Result<Option<Hash>, Error> {
228 let leaves = backend.load_leaves()?;
229 for leaf in leaves.into_hashes_descending() {
230 if contains_ancestor(backend, leaf, required)? {
231 return Ok(Some(leaf))
232 }
233 }
234
235 Ok(None)
237}