pathfinder_consensus/internal/
malachite.rs

1use std::fmt::{Debug, Display};
2use std::marker::PhantomData;
3
4use malachite_signing_ed25519::Ed25519;
5use malachite_types::{Height as _, NilOrVal, Round, SignedExtension, ValueId, VoteType};
6use serde::{Deserialize, Serialize};
7
8use crate::{ProposerSelector, PublicKey, VotingPower};
9
10/// A validator address used to identify participants in the consensus protocol.
11#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Copy, Default, Hash, Serialize, Deserialize)]
12pub(super) struct ValidatorAddress<A>(A);
13
14impl<A> ValidatorAddress<A> {
15    pub fn into_inner(self) -> A {
16        self.0
17    }
18}
19
20impl<A: crate::ValidatorAddress> From<A> for ValidatorAddress<A> {
21    fn from(address: A) -> Self {
22        Self(address)
23    }
24}
25
26impl<A: crate::ValidatorAddress> malachite_types::Address for ValidatorAddress<A> {}
27
28impl<A: Display> Display for ValidatorAddress<A> {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        write!(f, "{}", self.0)
31    }
32}
33
34impl<A: Debug> Debug for ValidatorAddress<A> {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        write!(f, "{:?}", self.0)
37    }
38}
39
40/// The height of a block in the consensus protocol.
41#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Copy, Default)]
42pub(super) struct Height(u64);
43
44impl Height {
45    pub fn new(height: impl Into<u64>) -> Self {
46        Self(height.into())
47    }
48}
49
50impl Display for Height {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        write!(f, "{}", self.0)
53    }
54}
55
56impl Debug for Height {
57    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58        write!(f, "{}", self.0)
59    }
60}
61
62impl malachite_types::Height for Height {
63    const ZERO: Self = Self(0);
64    const INITIAL: Self = Self(0);
65
66    fn increment_by(&self, n: u64) -> Self {
67        Self(self.0 + n)
68    }
69
70    fn decrement_by(&self, n: u64) -> Option<Self> {
71        self.0.checked_sub(n).map(Self)
72    }
73
74    fn as_u64(&self) -> u64 {
75        self.0
76    }
77
78    fn increment(&self) -> Self {
79        Self(self.0 + 1)
80    }
81
82    fn decrement(&self) -> Option<Self> {
83        self.0.checked_sub(1).map(Self)
84    }
85}
86
87impl From<Round> for crate::Round {
88    fn from(value: Round) -> Self {
89        match value {
90            Round::Nil => crate::Round::nil(),
91            Round::Some(round) => crate::Round::new(round),
92        }
93    }
94}
95
96impl From<crate::Round> for Round {
97    fn from(value: crate::Round) -> Self {
98        match value.0 {
99            Some(round) => Round::Some(round),
100            None => Round::Nil,
101        }
102    }
103}
104
105/// A proposal for a block value in a consensus round.
106#[derive(Debug, Clone, PartialEq, Eq)]
107pub(super) struct Proposal<V, A> {
108    pub height: Height,
109    pub round: Round,
110    pub value: ConsensusValue<V>,
111    pub pol_round: Round,
112    pub proposer: ValidatorAddress<A>,
113}
114
115impl<V, A> From<crate::Proposal<V, A>> for Proposal<V, A> {
116    fn from(proposal: crate::Proposal<V, A>) -> Self {
117        Self {
118            height: Height::new(proposal.height),
119            round: proposal.round.into(),
120            value: ConsensusValue(proposal.value),
121            pol_round: proposal.pol_round.into(),
122            proposer: ValidatorAddress(proposal.proposer),
123        }
124    }
125}
126
127impl<V, A> From<Proposal<V, A>> for crate::Proposal<V, A> {
128    fn from(proposal: Proposal<V, A>) -> Self {
129        Self {
130            height: proposal.height.as_u64(),
131            round: proposal.round.into(),
132            value: proposal.value.into_inner(),
133            pol_round: proposal.pol_round.into(),
134            proposer: proposal.proposer.into_inner(),
135        }
136    }
137}
138
139impl<
140        A: crate::ValidatorAddress + 'static,
141        V: crate::ValuePayload + 'static,
142        P: ProposerSelector<A> + Send + Sync + 'static,
143    > malachite_types::Proposal<MalachiteContext<V, A, P>> for Proposal<V, A>
144{
145    fn height(&self) -> Height {
146        self.height
147    }
148
149    fn round(&self) -> malachite_types::Round {
150        self.round
151    }
152
153    fn value(&self) -> &ConsensusValue<V> {
154        &self.value
155    }
156
157    fn take_value(self) -> ConsensusValue<V> {
158        self.value
159    }
160
161    fn pol_round(&self) -> malachite_types::Round {
162        self.pol_round
163    }
164
165    fn validator_address(&self) -> &ValidatorAddress<A> {
166        &self.proposer
167    }
168}
169
170/// A proposal part for a block value in a consensus round.
171/// Note: This is not used anywhere, hence the empty struct.
172#[derive(Debug, Clone, Eq, PartialEq)]
173pub(super) struct ProposalPart;
174
175impl<
176        V: crate::ValuePayload + 'static,
177        A: crate::ValidatorAddress + 'static,
178        P: ProposerSelector<A> + Send + Sync + 'static,
179    > malachite_types::ProposalPart<MalachiteContext<V, A, P>> for ProposalPart
180{
181    fn is_first(&self) -> bool {
182        false
183    }
184
185    fn is_last(&self) -> bool {
186        false
187    }
188}
189
190/// A validator in the consensus protocol.
191#[derive(Debug, Clone, PartialEq, Eq)]
192pub(super) struct Validator<A> {
193    pub address: ValidatorAddress<A>,
194    pub public_key: PublicKey,
195    pub voting_power: VotingPower,
196}
197
198impl<A> From<crate::Validator<A>> for Validator<A> {
199    fn from(validator: crate::Validator<A>) -> Self {
200        Self {
201            address: ValidatorAddress(validator.address),
202            public_key: validator.public_key,
203            voting_power: validator.voting_power,
204        }
205    }
206}
207
208impl<
209        V: crate::ValuePayload + 'static,
210        A: crate::ValidatorAddress + 'static,
211        P: ProposerSelector<A> + Send + Sync + 'static,
212    > malachite_types::Validator<MalachiteContext<V, A, P>> for Validator<A>
213{
214    fn address(&self) -> &ValidatorAddress<A> {
215        &self.address
216    }
217
218    fn public_key(&self) -> &PublicKey {
219        &self.public_key
220    }
221
222    fn voting_power(&self) -> malachite_types::VotingPower {
223        self.voting_power
224    }
225}
226
227/// A validator set for the consensus protocol.
228#[derive(Debug, Clone, PartialEq, Eq)]
229pub(super) struct ValidatorSet<V, A> {
230    pub validators: Vec<Validator<A>>,
231    _phantom_v: PhantomData<V>,
232}
233
234impl<V, A> From<crate::ValidatorSet<A>> for ValidatorSet<V, A> {
235    fn from(validator_set: crate::ValidatorSet<A>) -> Self {
236        Self {
237            validators: validator_set
238                .validators
239                .into_iter()
240                .map(Into::into)
241                .collect(),
242            _phantom_v: PhantomData,
243        }
244    }
245}
246
247impl<
248        V: crate::ValuePayload + 'static,
249        A: crate::ValidatorAddress + 'static,
250        P: ProposerSelector<A> + Send + Sync + 'static,
251    > malachite_types::ValidatorSet<MalachiteContext<V, A, P>> for ValidatorSet<V, A>
252{
253    fn count(&self) -> usize {
254        self.validators.len()
255    }
256
257    fn total_voting_power(&self) -> malachite_types::VotingPower {
258        self.validators.iter().map(|v| v.voting_power).sum()
259    }
260
261    fn get_by_address(&self, address: &ValidatorAddress<A>) -> Option<&Validator<A>> {
262        self.validators.iter().find(|v| &v.address == address)
263    }
264
265    fn get_by_index(&self, index: usize) -> Option<&Validator<A>> {
266        self.validators.get(index)
267    }
268}
269
270/// The value for the consensus protocol.
271#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
272pub(super) struct ConsensusValue<V>(V);
273
274impl<V> ConsensusValue<V> {
275    pub fn into_inner(self) -> V {
276        self.0
277    }
278}
279
280impl<V> From<V> for ConsensusValue<V> {
281    fn from(value: V) -> Self {
282        Self(value)
283    }
284}
285
286impl<V: crate::ValuePayload + 'static> malachite_types::Value for ConsensusValue<V> {
287    type Id = V;
288
289    fn id(&self) -> Self::Id {
290        self.0.clone()
291    }
292}
293
294/// A vote for a block value in a consensus round.
295#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
296pub(super) struct Vote<V, A> {
297    pub r#type: VoteType,
298    pub height: Height,
299    pub round: Round,
300    pub value: NilOrVal<V>,
301    pub validator_address: ValidatorAddress<A>,
302}
303
304impl<V, A> From<crate::Vote<V, A>> for Vote<V, A> {
305    fn from(vote: crate::Vote<V, A>) -> Self {
306        Self {
307            r#type: match vote.r#type {
308                crate::VoteType::Prevote => VoteType::Prevote,
309                crate::VoteType::Precommit => VoteType::Precommit,
310            },
311            height: Height::new(vote.height),
312            round: vote.round.into(),
313            value: match vote.value {
314                Some(value) => NilOrVal::Val(value),
315                None => NilOrVal::Nil,
316            },
317            validator_address: ValidatorAddress(vote.validator_address),
318        }
319    }
320}
321
322impl<V, A> From<Vote<V, A>> for crate::Vote<V, A> {
323    fn from(vote: Vote<V, A>) -> Self {
324        Self {
325            r#type: match vote.r#type {
326                VoteType::Prevote => crate::VoteType::Prevote,
327                VoteType::Precommit => crate::VoteType::Precommit,
328            },
329            height: vote.height.as_u64(),
330            round: vote.round.into(),
331            value: match vote.value {
332                NilOrVal::Val(value) => Some(value),
333                NilOrVal::Nil => None,
334            },
335            validator_address: vote.validator_address.into_inner(),
336        }
337    }
338}
339
340impl<
341        V: crate::ValuePayload + 'static,
342        A: crate::ValidatorAddress + 'static,
343        P: ProposerSelector<A> + Send + Sync + 'static,
344    > malachite_types::Vote<MalachiteContext<V, A, P>> for Vote<V, A>
345{
346    fn height(&self) -> Height {
347        self.height
348    }
349
350    fn round(&self) -> Round {
351        self.round
352    }
353
354    fn value(&self) -> &NilOrVal<V> {
355        &self.value
356    }
357
358    fn take_value(self) -> NilOrVal<V> {
359        self.value
360    }
361
362    fn vote_type(&self) -> VoteType {
363        self.r#type
364    }
365
366    fn validator_address(&self) -> &ValidatorAddress<A> {
367        &self.validator_address
368    }
369
370    fn extension(&self) -> Option<&SignedExtension<MalachiteContext<V, A, P>>> {
371        None
372    }
373
374    fn take_extension(&mut self) -> Option<SignedExtension<MalachiteContext<V, A, P>>> {
375        None
376    }
377
378    fn extend(self, _extension: SignedExtension<MalachiteContext<V, A, P>>) -> Self {
379        self
380    }
381}
382
383/// The malachite context for the consensus logic.
384pub(super) struct MalachiteContext<
385    V: Send + Sync + 'static,
386    A: crate::ValidatorAddress + Send + Sync + 'static,
387    P: ProposerSelector<A> + Send + Sync + 'static,
388> {
389    proposer_selector: P,
390    _phantom_a: PhantomData<A>,
391    _phantom_v: PhantomData<V>,
392}
393
394impl<
395        V: Send + Sync + 'static,
396        A: crate::ValidatorAddress + Send + Sync + 'static,
397        P: ProposerSelector<A> + Send + Sync + 'static,
398    > MalachiteContext<V, A, P>
399{
400    pub fn new(proposer_selector: P) -> Self {
401        Self {
402            proposer_selector,
403            _phantom_a: PhantomData,
404            _phantom_v: PhantomData,
405        }
406    }
407}
408
409impl<
410        V: Send + Sync + 'static,
411        A: crate::ValidatorAddress + Send + Sync + 'static,
412        P: ProposerSelector<A> + Send + Sync + 'static,
413    > Clone for MalachiteContext<V, A, P>
414where
415    P: Clone,
416{
417    fn clone(&self) -> Self {
418        Self {
419            proposer_selector: self.proposer_selector.clone(),
420            _phantom_a: PhantomData,
421            _phantom_v: PhantomData,
422        }
423    }
424}
425
426impl<
427        V: crate::ValuePayload + 'static,
428        A: crate::ValidatorAddress + 'static,
429        P: ProposerSelector<A> + Send + Sync + 'static,
430    > malachite_types::Context for MalachiteContext<V, A, P>
431{
432    type Address = ValidatorAddress<A>;
433    type Height = Height;
434
435    type ProposalPart = ProposalPart;
436    type Proposal = Proposal<V, A>;
437
438    type Validator = Validator<A>;
439    type ValidatorSet = ValidatorSet<V, A>;
440
441    type Value = ConsensusValue<V>;
442
443    type Vote = Vote<V, A>;
444
445    type Extension = Vec<u8>;
446
447    type SigningScheme = Ed25519;
448
449    fn select_proposer<'a>(
450        &self,
451        validator_set: &'a Self::ValidatorSet,
452        height: Self::Height,
453        round: Round,
454    ) -> &'a Self::Validator {
455        let round = round.as_u32().expect("round is not nil");
456
457        // Convert the malachite validator set to our public API validator set
458        let public_validator_set = crate::ValidatorSet {
459            validators: validator_set
460                .validators
461                .iter()
462                .map(|v| crate::Validator {
463                    address: v.address.clone().into_inner(),
464                    public_key: v.public_key,
465                    voting_power: v.voting_power,
466                })
467                .collect(),
468        };
469
470        // Use the proposer selector to select the proposer
471        let selected_validator =
472            self.proposer_selector
473                .select_proposer(&public_validator_set, height.as_u64(), round);
474
475        // Find the corresponding validator in the malachite validator set
476        let proposer = validator_set
477            .validators
478            .iter()
479            .find(|v| v.address.clone().into_inner() == selected_validator.address)
480            .expect("selected validator not found in validator set");
481
482        tracing::debug!(
483            proposer = ?proposer,
484            height = ?height,
485            round = ?round,
486            "Selected proposer for round"
487        );
488        proposer
489    }
490
491    fn new_proposal(
492        &self,
493        height: Self::Height,
494        round: Round,
495        value: Self::Value,
496        pol_round: Round,
497        address: Self::Address,
498    ) -> Self::Proposal {
499        tracing::debug!(
500            validator = %address,
501            value = ?value,
502            height = %height,
503            round = %round,
504            pol_round = %pol_round,
505            "Creating new proposal"
506        );
507        Proposal {
508            height,
509            round,
510            value,
511            proposer: address,
512            pol_round,
513        }
514    }
515
516    fn new_prevote(
517        &self,
518        height: Self::Height,
519        round: Round,
520        value_id: NilOrVal<ValueId<Self>>,
521        address: Self::Address,
522    ) -> Self::Vote {
523        tracing::debug!(
524            validator = %address,
525            value = ?value_id,
526            height = %height,
527            round = %round,
528            "Creating new prevote"
529        );
530        Vote {
531            r#type: VoteType::Prevote,
532            height,
533            round,
534            validator_address: address,
535            value: value_id,
536        }
537    }
538
539    fn new_precommit(
540        &self,
541        height: Self::Height,
542        round: Round,
543        value_id: NilOrVal<ValueId<Self>>,
544        address: Self::Address,
545    ) -> Self::Vote {
546        tracing::debug!(
547            validator = %address,
548            value = ?value_id,
549            height = %height,
550            round = %round,
551            "Creating new precommit"
552        );
553        Vote {
554            r#type: VoteType::Precommit,
555            height,
556            round,
557            validator_address: address,
558            value: value_id,
559        }
560    }
561}