pathfinder_consensus/internal/
malachite.rs

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