1use std::marker::PhantomData;
26use std::{cmp, iter};
27
28use derivative::Derivative;
29use rand::distributions::{Distribution, Standard};
30use rand::Rng;
31use serde::{de::DeserializeOwned, Serialize};
32use thiserror::Error;
33
34use crate::crypto::{PublicKey, SecretKey};
35use crate::dynamic_honey_badger::{
36 self, Batch as DhbBatch, DynamicHoneyBadger, FaultKind, JoinPlan, Message, Step as DhbStep,
37};
38use crate::transaction_queue::TransactionQueue;
39use crate::{ConsensusProtocol, Contribution, NetworkInfo, NodeIdT};
40
41pub use crate::dynamic_honey_badger::{Change, ChangeState, Input};
42
43#[derive(Debug, Error)]
45pub enum Error {
46 #[error("Input error: {0}")]
48 Input(dynamic_honey_badger::Error),
49 #[error("Handle message error: {0}")]
51 HandleMessage(dynamic_honey_badger::Error),
52 #[error("Propose error: {0}")]
54 Propose(dynamic_honey_badger::Error),
55 #[error("New joining error: {0}")]
57 NewJoining(dynamic_honey_badger::Error),
58}
59
60pub type Result<T> = ::std::result::Result<T, Error>;
62
63pub struct QueueingHoneyBadgerBuilder<T, N, Q>
66where
67 T: Contribution + Serialize + DeserializeOwned + Clone,
68 N: NodeIdT + Serialize + DeserializeOwned,
69{
70 dyn_hb: DynamicHoneyBadger<Vec<T>, N>,
72 batch_size: usize,
74 queue: Q,
76 step: Option<DhbStep<Vec<T>, N>>,
78 _phantom: PhantomData<T>,
79}
80
81type QueueingHoneyBadgerWithStep<T, N, Q> = (QueueingHoneyBadger<T, N, Q>, Step<T, N>);
82
83impl<T, N, Q> QueueingHoneyBadgerBuilder<T, N, Q>
84where
85 T: Contribution + Serialize + DeserializeOwned + Clone,
86 N: NodeIdT + Serialize + DeserializeOwned,
87 Q: TransactionQueue<T>,
88 Standard: Distribution<N>,
89{
90 pub fn new(dyn_hb: DynamicHoneyBadger<Vec<T>, N>) -> Self {
93 QueueingHoneyBadgerBuilder {
95 dyn_hb,
96 batch_size: 100,
97 queue: Default::default(),
98 step: None,
99 _phantom: PhantomData,
100 }
101 }
102
103 pub fn step(mut self, step: DhbStep<Vec<T>, N>) -> Self {
105 self.step = Some(step);
106 self
107 }
108
109 pub fn batch_size(mut self, batch_size: usize) -> Self {
111 self.batch_size = batch_size;
112 self
113 }
114
115 pub fn queue(mut self, queue: Q) -> Self {
117 self.queue = queue;
118 self
119 }
120
121 pub fn build<R: Rng>(self, rng: &mut R) -> Result<QueueingHoneyBadgerWithStep<T, N, Q>> {
123 self.build_with_transactions(None, rng)
124 }
125
126 pub fn build_with_transactions<TI, R>(
129 mut self,
130 txs: TI,
131 rng: &mut R,
132 ) -> Result<QueueingHoneyBadgerWithStep<T, N, Q>>
133 where
134 TI: IntoIterator<Item = T>,
135 R: Rng,
136 {
137 self.queue.extend(txs);
138 let mut qhb = QueueingHoneyBadger {
139 dyn_hb: self.dyn_hb,
140 batch_size: self.batch_size,
141 queue: self.queue,
142 };
143 let mut step = qhb.propose(rng)?;
144 if let Some(dhb_step) = self.step {
145 step.extend(dhb_step);
146 }
147 Ok((qhb, step))
148 }
149}
150
151#[derive(Derivative)]
154#[derivative(Debug)]
155pub struct QueueingHoneyBadger<T, N: Ord, Q> {
156 batch_size: usize,
158 dyn_hb: DynamicHoneyBadger<Vec<T>, N>,
160 queue: Q,
162}
163
164pub type Step<T, N> = crate::Step<Message<N>, Batch<T, N>, N, FaultKind>;
166
167impl<T, N, Q> ConsensusProtocol for QueueingHoneyBadger<T, N, Q>
168where
169 T: Contribution + Serialize + DeserializeOwned + Clone,
170 N: NodeIdT + Serialize + DeserializeOwned,
171 Q: TransactionQueue<T>,
172 Standard: Distribution<N>,
173{
174 type NodeId = N;
175 type Input = Input<T, N>;
176 type Output = Batch<T, N>;
177 type Message = Message<N>;
178 type Error = Error;
179 type FaultKind = FaultKind;
180
181 fn handle_input<R: Rng>(&mut self, input: Self::Input, rng: &mut R) -> Result<Step<T, N>> {
182 match input {
186 Input::User(tx) => self.push_transaction(tx, rng),
187 Input::Change(change) => self.vote_for(change, rng),
188 }
189 }
190
191 fn handle_message<R: Rng>(
192 &mut self,
193 sender_id: &N,
194 message: Self::Message,
195 rng: &mut R,
196 ) -> Result<Step<T, N>> {
197 self.handle_message(sender_id, message, rng)
198 }
199
200 fn terminated(&self) -> bool {
201 false
202 }
203
204 fn our_id(&self) -> &N {
205 self.dyn_hb.our_id()
206 }
207}
208
209impl<T, N, Q> QueueingHoneyBadger<T, N, Q>
210where
211 T: Contribution + Serialize + DeserializeOwned + Clone,
212 N: NodeIdT + Serialize + DeserializeOwned,
213 Q: TransactionQueue<T>,
214 Standard: Distribution<N>,
215{
216 pub fn builder(dyn_hb: DynamicHoneyBadger<Vec<T>, N>) -> QueueingHoneyBadgerBuilder<T, N, Q> {
219 QueueingHoneyBadgerBuilder::new(dyn_hb)
220 }
221
222 pub fn builder_joining<R: Rng>(
228 our_id: N,
229 secret_key: SecretKey,
230 join_plan: JoinPlan<N>,
231 rng: &mut R,
232 ) -> Result<QueueingHoneyBadgerBuilder<T, N, Q>> {
233 let (dhb, step) = DynamicHoneyBadger::new_joining(our_id, secret_key, join_plan, rng)
234 .map_err(Error::NewJoining)?;
235 Ok(QueueingHoneyBadgerBuilder::new(dhb).step(step))
236 }
237
238 pub fn push_transaction<R: Rng>(&mut self, tx: T, rng: &mut R) -> Result<Step<T, N>> {
247 self.queue.extend(iter::once(tx));
248 self.propose(rng)
249 }
250
251 pub fn vote_for<R: Rng>(&mut self, change: Change<N>, rng: &mut R) -> Result<Step<T, N>> {
256 self.apply(|dyn_hb, _| dyn_hb.vote_for(change), rng)
257 }
258
259 pub fn vote_to_add<R: Rng>(
264 &mut self,
265 node_id: N,
266 pub_key: PublicKey,
267 rng: &mut R,
268 ) -> Result<Step<T, N>> {
269 self.apply(|dyn_hb, _| dyn_hb.vote_to_add(node_id, pub_key), rng)
270 }
271
272 pub fn vote_to_remove<R: Rng>(&mut self, node_id: &N, rng: &mut R) -> Result<Step<T, N>> {
277 self.apply(|dyn_hb, _| dyn_hb.vote_to_remove(node_id), rng)
278 }
279
280 pub fn handle_message<R: Rng>(
284 &mut self,
285 sender_id: &N,
286 message: Message<N>,
287 rng: &mut R,
288 ) -> Result<Step<T, N>> {
289 self.apply(
290 |dyn_hb, rng| dyn_hb.handle_message(sender_id, message, rng),
291 rng,
292 )
293 }
294
295 pub fn dyn_hb(&self) -> &DynamicHoneyBadger<Vec<T>, N> {
297 &self.dyn_hb
298 }
299
300 pub fn netinfo(&self) -> &NetworkInfo<N> {
302 self.dyn_hb.netinfo()
303 }
304
305 pub fn queue(&self) -> &Q {
307 &self.queue
308 }
309
310 fn apply<R, F>(&mut self, f: F, rng: &mut R) -> Result<Step<T, N>>
312 where
313 F: FnOnce(
314 &mut DynamicHoneyBadger<Vec<T>, N>,
315 &mut R,
316 ) -> dynamic_honey_badger::Result<Step<T, N>>,
317 R: Rng,
318 {
319 let step = f(&mut self.dyn_hb, rng).map_err(Error::Input)?;
320 self.queue
321 .remove_multiple(step.output.iter().flat_map(Batch::iter));
322 Ok(step.join(self.propose(rng)?))
323 }
324
325 pub fn next_epoch(&self) -> u64 {
327 self.dyn_hb.next_epoch()
328 }
329
330 fn can_propose(&self) -> bool {
334 if self.dyn_hb.has_input() {
335 return false; }
337 !self.queue.is_empty() || self.dyn_hb.should_propose()
338 }
339
340 fn propose<R: Rng>(&mut self, rng: &mut R) -> Result<Step<T, N>> {
342 let mut step = Step::default();
343 while self.can_propose() {
344 let amount = cmp::max(1, self.batch_size / self.dyn_hb.netinfo().num_nodes());
345 let proposal = self.queue.choose(rng, amount, self.batch_size);
346 let propose_step = self
347 .dyn_hb
348 .handle_input(Input::User(proposal), rng)
349 .map_err(Error::Propose)?;
350 self.queue
351 .remove_multiple(propose_step.output.iter().flat_map(Batch::iter));
352 step.extend(propose_step);
353 }
354 Ok(step)
355 }
356}
357
358pub type Batch<T, N> = DhbBatch<Vec<T>, N>;