Skip to main content

espresso_types/v0/
traits.rs

1//! This module contains all the traits used for building the sequencer types.
2//! It also includes some trait implementations that cannot be implemented in an external crate.
3#[cfg(feature = "node")]
4use std::{cmp::max, collections::BTreeMap};
5use std::{fmt::Debug, ops::Range, sync::Arc};
6
7use alloy::primitives::Address;
8#[cfg(feature = "node")]
9use anyhow::{Context, bail, ensure};
10use async_trait::async_trait;
11use committable::Commitment;
12use futures::{FutureExt, TryFutureExt};
13#[cfg(feature = "node")]
14use hotshot::{HotShotInitializer, InitializerEpochInfo, types::EventType};
15#[cfg(feature = "node")]
16use hotshot_libp2p_networking::network::behaviours::dht::store::persistent::DhtPersistentStorage;
17#[cfg(feature = "node")]
18use hotshot_new_protocol::storage::NewProtocolStorage;
19#[cfg(feature = "node")]
20use hotshot_types::simple_certificate::{Certificate1, Certificate2};
21#[cfg(feature = "node")]
22use hotshot_types::{
23    data::{
24        DaProposal, DaProposal2, QuorumProposal, QuorumProposal2, QuorumProposalWrapper,
25        VidCommitment, VidDisperseShare,
26    },
27    drb::{DrbInput, DrbResult},
28    event::{HotShotAction, LeafInfo},
29    message::{Proposal, convert_proposal},
30    simple_certificate::{
31        CertificatePair, NextEpochQuorumCertificate2, QuorumCertificate, QuorumCertificate2,
32        UpgradeCertificate,
33    },
34    traits::{
35        ValidatedState as HotShotState, metrics::Metrics, node_implementation::NodeType,
36        storage::Storage,
37    },
38    utils::genesis_epoch_from_version,
39    vote::HasViewNumber,
40};
41use hotshot_types::{
42    data::{EpochNumber, ViewNumber},
43    epoch_membership::EpochMembershipCoordinator,
44    new_protocol::CoordinatorEvent,
45    simple_certificate::LightClientStateUpdateCertificateV2,
46};
47use indexmap::IndexMap;
48use serde::{Serialize, de::DeserializeOwned};
49#[cfg(feature = "node")]
50use versions::{NEW_PROTOCOL_VERSION, Upgrade};
51
52use super::{
53    impls::NodeState,
54    utils::BackoffParams,
55    v0_3::{EventKey, IndexedStake, StakeTableEvent},
56};
57use crate::{
58    AuthenticatedValidatorMap, BlockMerkleTree, FeeAccount, FeeAccountProof, FeeMerkleCommitment,
59    Leaf2, PubKey, SeqTypes,
60    v0::impls::StakeTableHash,
61    v0_3::{
62        ChainConfig, RegisteredValidator, RewardAccountProofV1, RewardAccountV1, RewardAmount,
63        RewardMerkleCommitmentV1,
64    },
65    v0_4::{PermittedRewardMerkleTreeV2, RewardAccountV2, RewardMerkleCommitmentV2},
66};
67#[cfg(feature = "node")]
68use crate::{NetworkConfig, v0::impls::ValidatedState};
69
70#[async_trait]
71pub trait StateCatchup: Send + Sync {
72    /// Fetch the leaf at the given height without retrying on transient errors.
73    ///
74    /// `coordinator` resolves the stake tables used to verify the fetched leaf
75    /// chain, triggering catchup for epochs whose stake table is not yet
76    /// available.
77    async fn try_fetch_leaf(
78        &self,
79        retry: usize,
80        coordinator: EpochMembershipCoordinator<SeqTypes>,
81        height: u64,
82    ) -> anyhow::Result<Leaf2>;
83
84    /// Fetch the leaf at the given height, retrying on transient errors.
85    async fn fetch_leaf(
86        &self,
87        coordinator: EpochMembershipCoordinator<SeqTypes>,
88        height: u64,
89    ) -> anyhow::Result<Leaf2> {
90        self.backoff()
91            .retry(self, |provider, retry| {
92                let coordinator = coordinator.clone();
93                async move { provider.try_fetch_leaf(retry, coordinator, height).await }.boxed()
94            })
95            .await
96    }
97
98    /// Fetch the given list of accounts without retrying on transient errors.
99    async fn try_fetch_accounts(
100        &self,
101        retry: usize,
102        instance: &NodeState,
103        height: u64,
104        view: ViewNumber,
105        fee_merkle_tree_root: FeeMerkleCommitment,
106        accounts: &[FeeAccount],
107    ) -> anyhow::Result<Vec<FeeAccountProof>>;
108
109    /// Fetch the given list of accounts, retrying on transient errors.
110    async fn fetch_accounts(
111        &self,
112        instance: &NodeState,
113        height: u64,
114        view: ViewNumber,
115        fee_merkle_tree_root: FeeMerkleCommitment,
116        accounts: Vec<FeeAccount>,
117    ) -> anyhow::Result<Vec<FeeAccountProof>> {
118        self.backoff()
119            .retry(self, |provider, retry| {
120                let accounts = &accounts;
121                async move {
122                    provider
123                        .try_fetch_accounts(
124                            retry,
125                            instance,
126                            height,
127                            view,
128                            fee_merkle_tree_root,
129                            accounts,
130                        )
131                        .await
132                        .map_err(|err| {
133                            err.context(format!(
134                                "fetching accounts {accounts:?}, height {height}, view {view}"
135                            ))
136                        })
137                }
138                .boxed()
139            })
140            .await
141    }
142
143    /// Fetch and remember the blocks frontier without retrying on transient errors.
144    async fn try_remember_blocks_merkle_tree(
145        &self,
146        retry: usize,
147        instance: &NodeState,
148        height: u64,
149        view: ViewNumber,
150        mt: &mut BlockMerkleTree,
151    ) -> anyhow::Result<()>;
152
153    /// Fetch and remember the blocks frontier, retrying on transient errors.
154    async fn remember_blocks_merkle_tree(
155        &self,
156        instance: &NodeState,
157        height: u64,
158        view: ViewNumber,
159        mt: &mut BlockMerkleTree,
160    ) -> anyhow::Result<()> {
161        self.backoff()
162            .retry(mt, |mt, retry| {
163                self.try_remember_blocks_merkle_tree(retry, instance, height, view, mt)
164                    .map_err(|err| err.context(format!("fetching frontier using {}", self.name())))
165                    .boxed()
166            })
167            .await
168    }
169
170    /// Fetch the chain config without retrying on transient errors.
171    async fn try_fetch_chain_config(
172        &self,
173        retry: usize,
174        commitment: Commitment<ChainConfig>,
175    ) -> anyhow::Result<ChainConfig>;
176
177    /// Fetch the chain config, retrying on transient errors.
178    async fn fetch_chain_config(
179        &self,
180        commitment: Commitment<ChainConfig>,
181    ) -> anyhow::Result<ChainConfig> {
182        self.backoff()
183            .retry(self, |provider, retry| {
184                provider
185                    .try_fetch_chain_config(retry, commitment)
186                    .map_err(|err| err.context("fetching chain config"))
187                    .boxed()
188            })
189            .await
190    }
191
192    /// Fetch the given reward merkle tree without retrying on transient errors.
193    async fn try_fetch_reward_merkle_tree_v2(
194        &self,
195        retry: usize,
196        height: u64,
197        view: ViewNumber,
198        reward_merkle_tree_root: RewardMerkleCommitmentV2,
199        accounts: Arc<Vec<RewardAccountV2>>,
200    ) -> anyhow::Result<PermittedRewardMerkleTreeV2>;
201
202    async fn fetch_reward_merkle_tree_v2(
203        &self,
204        height: u64,
205        view: ViewNumber,
206        reward_merkle_tree_root: RewardMerkleCommitmentV2,
207        accounts: Arc<Vec<RewardAccountV2>>,
208    ) -> anyhow::Result<PermittedRewardMerkleTreeV2> {
209        self.backoff()
210            .retry(self, |provider, retry| {
211                let accounts = accounts.clone();
212                async move {
213                    provider
214                        .try_fetch_reward_merkle_tree_v2(
215                            retry,
216                            height,
217                            view,
218                            reward_merkle_tree_root,
219                            accounts,
220                        )
221                        .await
222                        .map_err(|err| {
223                            err.context(format!("fetching reward merkle tree for height {height}"))
224                        })
225                }
226                .boxed()
227            })
228            .await
229    }
230
231    /// Fetch the given list of reward accounts without retrying on transient errors.
232    async fn try_fetch_reward_accounts_v1(
233        &self,
234        retry: usize,
235        instance: &NodeState,
236        height: u64,
237        view: ViewNumber,
238        reward_merkle_tree_root: RewardMerkleCommitmentV1,
239        accounts: &[RewardAccountV1],
240    ) -> anyhow::Result<Vec<RewardAccountProofV1>>;
241
242    /// Fetch the given list of reward accounts, retrying on transient errors.
243    async fn fetch_reward_accounts_v1(
244        &self,
245        instance: &NodeState,
246        height: u64,
247        view: ViewNumber,
248        reward_merkle_tree_root: RewardMerkleCommitmentV1,
249        accounts: Vec<RewardAccountV1>,
250    ) -> anyhow::Result<Vec<RewardAccountProofV1>> {
251        self.backoff()
252            .retry(self, |provider, retry| {
253                let accounts = &accounts;
254                async move {
255                    provider
256                        .try_fetch_reward_accounts_v1(
257                            retry,
258                            instance,
259                            height,
260                            view,
261                            reward_merkle_tree_root,
262                            accounts,
263                        )
264                        .await
265                        .map_err(|err| {
266                            err.context(format!(
267                                "fetching v1 reward accounts {accounts:?}, height {height}, view \
268                                 {view}"
269                            ))
270                        })
271                }
272                .boxed()
273            })
274            .await
275    }
276
277    /// Fetch the state certificate for a given epoch without retrying on transient errors.
278    async fn try_fetch_state_cert(
279        &self,
280        retry: usize,
281        epoch: u64,
282    ) -> anyhow::Result<LightClientStateUpdateCertificateV2<SeqTypes>>;
283
284    /// Fetch the state certificate for a given epoch, retrying on transient errors.
285    async fn fetch_state_cert(
286        &self,
287        epoch: u64,
288    ) -> anyhow::Result<LightClientStateUpdateCertificateV2<SeqTypes>> {
289        self.backoff()
290            .retry(self, |provider, retry| {
291                provider
292                    .try_fetch_state_cert(retry, epoch)
293                    .map_err(|err| err.context(format!("fetching state cert for epoch {epoch}")))
294                    .boxed()
295            })
296            .await
297    }
298
299    /// Returns true if the catchup provider is local (e.g. does not make calls to remote resources).
300    fn is_local(&self) -> bool;
301
302    /// Returns the backoff parameters for the catchup provider.
303    fn backoff(&self) -> &BackoffParams;
304
305    /// Returns the name of the catchup provider.
306    fn name(&self) -> String;
307}
308
309#[async_trait]
310impl<T: StateCatchup + ?Sized> StateCatchup for Arc<T> {
311    async fn try_fetch_leaf(
312        &self,
313        retry: usize,
314        coordinator: EpochMembershipCoordinator<SeqTypes>,
315        height: u64,
316    ) -> anyhow::Result<Leaf2> {
317        (**self).try_fetch_leaf(retry, coordinator, height).await
318    }
319
320    async fn fetch_leaf(
321        &self,
322        coordinator: EpochMembershipCoordinator<SeqTypes>,
323        height: u64,
324    ) -> anyhow::Result<Leaf2> {
325        (**self).fetch_leaf(coordinator, height).await
326    }
327
328    async fn try_fetch_accounts(
329        &self,
330        retry: usize,
331        instance: &NodeState,
332        height: u64,
333        view: ViewNumber,
334        fee_merkle_tree_root: FeeMerkleCommitment,
335        accounts: &[FeeAccount],
336    ) -> anyhow::Result<Vec<FeeAccountProof>> {
337        (**self)
338            .try_fetch_accounts(
339                retry,
340                instance,
341                height,
342                view,
343                fee_merkle_tree_root,
344                accounts,
345            )
346            .await
347    }
348
349    async fn fetch_accounts(
350        &self,
351        instance: &NodeState,
352        height: u64,
353        view: ViewNumber,
354        fee_merkle_tree_root: FeeMerkleCommitment,
355        accounts: Vec<FeeAccount>,
356    ) -> anyhow::Result<Vec<FeeAccountProof>> {
357        (**self)
358            .fetch_accounts(instance, height, view, fee_merkle_tree_root, accounts)
359            .await
360    }
361
362    async fn try_remember_blocks_merkle_tree(
363        &self,
364        retry: usize,
365        instance: &NodeState,
366        height: u64,
367        view: ViewNumber,
368        mt: &mut BlockMerkleTree,
369    ) -> anyhow::Result<()> {
370        (**self)
371            .try_remember_blocks_merkle_tree(retry, instance, height, view, mt)
372            .await
373    }
374
375    async fn remember_blocks_merkle_tree(
376        &self,
377        instance: &NodeState,
378        height: u64,
379        view: ViewNumber,
380        mt: &mut BlockMerkleTree,
381    ) -> anyhow::Result<()> {
382        (**self)
383            .remember_blocks_merkle_tree(instance, height, view, mt)
384            .await
385    }
386
387    async fn try_fetch_chain_config(
388        &self,
389        retry: usize,
390        commitment: Commitment<ChainConfig>,
391    ) -> anyhow::Result<ChainConfig> {
392        (**self).try_fetch_chain_config(retry, commitment).await
393    }
394
395    async fn fetch_chain_config(
396        &self,
397        commitment: Commitment<ChainConfig>,
398    ) -> anyhow::Result<ChainConfig> {
399        (**self).fetch_chain_config(commitment).await
400    }
401
402    async fn try_fetch_reward_merkle_tree_v2(
403        &self,
404        retry: usize,
405        height: u64,
406        view: ViewNumber,
407        reward_merkle_tree_root: RewardMerkleCommitmentV2,
408        accounts: Arc<Vec<RewardAccountV2>>,
409    ) -> anyhow::Result<PermittedRewardMerkleTreeV2> {
410        (**self)
411            .try_fetch_reward_merkle_tree_v2(retry, height, view, reward_merkle_tree_root, accounts)
412            .await
413    }
414
415    async fn fetch_reward_merkle_tree_v2(
416        &self,
417        height: u64,
418        view: ViewNumber,
419        reward_merkle_tree_root: RewardMerkleCommitmentV2,
420        accounts: Arc<Vec<RewardAccountV2>>,
421    ) -> anyhow::Result<PermittedRewardMerkleTreeV2> {
422        (**self)
423            .fetch_reward_merkle_tree_v2(height, view, reward_merkle_tree_root, accounts)
424            .await
425    }
426
427    async fn try_fetch_reward_accounts_v1(
428        &self,
429        retry: usize,
430        instance: &NodeState,
431        height: u64,
432        view: ViewNumber,
433        reward_merkle_tree_root: RewardMerkleCommitmentV1,
434        accounts: &[RewardAccountV1],
435    ) -> anyhow::Result<Vec<RewardAccountProofV1>> {
436        (**self)
437            .try_fetch_reward_accounts_v1(
438                retry,
439                instance,
440                height,
441                view,
442                reward_merkle_tree_root,
443                accounts,
444            )
445            .await
446    }
447
448    async fn fetch_reward_accounts_v1(
449        &self,
450        instance: &NodeState,
451        height: u64,
452        view: ViewNumber,
453        reward_merkle_tree_root: RewardMerkleCommitmentV1,
454        accounts: Vec<RewardAccountV1>,
455    ) -> anyhow::Result<Vec<RewardAccountProofV1>> {
456        (**self)
457            .fetch_reward_accounts_v1(instance, height, view, reward_merkle_tree_root, accounts)
458            .await
459    }
460
461    async fn try_fetch_state_cert(
462        &self,
463        retry: usize,
464        epoch: u64,
465    ) -> anyhow::Result<LightClientStateUpdateCertificateV2<SeqTypes>> {
466        (**self).try_fetch_state_cert(retry, epoch).await
467    }
468
469    async fn fetch_state_cert(
470        &self,
471        epoch: u64,
472    ) -> anyhow::Result<LightClientStateUpdateCertificateV2<SeqTypes>> {
473        (**self).fetch_state_cert(epoch).await
474    }
475
476    fn backoff(&self) -> &BackoffParams {
477        (**self).backoff()
478    }
479
480    fn name(&self) -> String {
481        (**self).name()
482    }
483
484    fn is_local(&self) -> bool {
485        (**self).is_local()
486    }
487}
488
489#[cfg(feature = "node")]
490#[async_trait]
491pub trait PersistenceOptions: Clone + Send + Sync + Debug + 'static {
492    type Persistence: SequencerPersistence + MembershipPersistence;
493
494    fn set_view_retention(&mut self, view_retention: u64);
495    async fn create(&mut self) -> anyhow::Result<Self::Persistence>;
496    async fn reset(self) -> anyhow::Result<()>;
497}
498
499/// Determine the read state based on the queried block range.
500// - If the persistence returned events up to the requested block, the read is complete.
501/// - Otherwise, indicate that the read is up to the last processed block.
502#[derive(Clone, Copy, Debug, PartialEq, Eq)]
503pub enum EventsPersistenceRead {
504    Complete,
505    UntilL1Block(u64),
506}
507
508/// Tuple type for stake table data: (validators, block_reward, stake_table_hash)
509pub type StakeTuple = (
510    AuthenticatedValidatorMap,
511    Option<RewardAmount>,
512    Option<StakeTableHash>,
513);
514
515#[async_trait]
516/// Trait used by `Memberships` implementations to interact with persistence layer.
517pub trait MembershipPersistence: Send + Sync + 'static {
518    /// Load stake table for epoch from storage
519    async fn load_stake(&self, epoch: EpochNumber) -> anyhow::Result<Option<StakeTuple>>;
520
521    /// Load stake tables for storage for latest `n` known epochs
522    async fn load_latest_stake(&self, limit: u64) -> anyhow::Result<Option<Vec<IndexedStake>>>;
523
524    /// Store stake table at `epoch` in the persistence layer
525    async fn store_stake(
526        &self,
527        epoch: EpochNumber,
528        stake: AuthenticatedValidatorMap,
529        block_reward: Option<RewardAmount>,
530        stake_table_hash: Option<StakeTableHash>,
531    ) -> anyhow::Result<()>;
532
533    async fn store_events(
534        &self,
535        l1_finalized: u64,
536        events: Vec<(EventKey, StakeTableEvent)>,
537    ) -> anyhow::Result<()>;
538    async fn load_events(
539        &self,
540        from_l1_block: u64,
541        l1_finalized: u64,
542    ) -> anyhow::Result<(
543        Option<EventsPersistenceRead>,
544        Vec<(EventKey, StakeTableEvent)>,
545    )>;
546
547    /// Delete all stake table events, the L1 block tracker, and the epoch DRB and root data.
548    async fn delete_stake_tables(&self) -> anyhow::Result<()>;
549
550    async fn store_all_validators(
551        &self,
552        epoch: EpochNumber,
553        all_validators: IndexMap<Address, RegisteredValidator<PubKey>>,
554    ) -> anyhow::Result<()>;
555
556    async fn load_all_validators(
557        &self,
558        epoch: EpochNumber,
559        offset: u64,
560        limit: u64,
561    ) -> anyhow::Result<Vec<RegisteredValidator<PubKey>>>;
562}
563
564#[cfg(feature = "node")]
565#[async_trait]
566pub trait SequencerPersistence:
567    Sized + Send + Sync + Clone + 'static + DhtPersistentStorage + MembershipPersistence
568{
569    /// Use this storage as a state catchup backend, if supported.
570    fn into_catchup_provider(
571        self,
572        _backoff: BackoffParams,
573    ) -> anyhow::Result<Arc<dyn StateCatchup>> {
574        bail!("state catchup is not implemented for this persistence type");
575    }
576
577    /// Load the orchestrator config from storage.
578    ///
579    /// Returns `None` if no config exists (we are joining a network for the first time). Fails with
580    /// `Err` if it could not be determined whether a config exists or not.
581    async fn load_config(&self) -> anyhow::Result<Option<NetworkConfig>>;
582
583    /// Save the orchestrator config to storage.
584    async fn save_config(&self, cfg: &NetworkConfig) -> anyhow::Result<()>;
585
586    /// Load the highest view saved with [`save_voted_view`](Self::save_voted_view).
587    async fn load_latest_acted_view(&self) -> anyhow::Result<Option<ViewNumber>>;
588
589    /// Load the view to restart from.
590    async fn load_restart_view(&self) -> anyhow::Result<Option<ViewNumber>>;
591
592    /// Load the proposals saved by consensus
593    async fn load_quorum_proposals(
594        &self,
595    ) -> anyhow::Result<BTreeMap<ViewNumber, Proposal<SeqTypes, QuorumProposalWrapper<SeqTypes>>>>;
596
597    async fn load_quorum_proposal(
598        &self,
599        view: ViewNumber,
600    ) -> anyhow::Result<Proposal<SeqTypes, QuorumProposalWrapper<SeqTypes>>>;
601
602    async fn load_vid_share(
603        &self,
604        view: ViewNumber,
605    ) -> anyhow::Result<Option<Proposal<SeqTypes, VidDisperseShare<SeqTypes>>>>;
606    async fn load_da_proposal(
607        &self,
608        view: ViewNumber,
609    ) -> anyhow::Result<Option<Proposal<SeqTypes, DaProposal2<SeqTypes>>>>;
610    async fn load_upgrade_certificate(
611        &self,
612    ) -> anyhow::Result<Option<UpgradeCertificate<SeqTypes>>>;
613    async fn load_start_epoch_info(&self) -> anyhow::Result<Vec<InitializerEpochInfo<SeqTypes>>>;
614    async fn load_state_cert(
615        &self,
616    ) -> anyhow::Result<Option<LightClientStateUpdateCertificateV2<SeqTypes>>>;
617
618    /// Get a state certificate for an epoch.
619    async fn get_state_cert_by_epoch(
620        &self,
621        epoch: u64,
622    ) -> anyhow::Result<Option<LightClientStateUpdateCertificateV2<SeqTypes>>>;
623
624    /// Insert a state certificate for a given epoch.
625    async fn insert_state_cert(
626        &self,
627        epoch: u64,
628        cert: LightClientStateUpdateCertificateV2<SeqTypes>,
629    ) -> anyhow::Result<()>;
630
631    /// Load the latest known consensus state.
632    ///
633    /// Returns an initializer to resume HotShot from the latest saved state (or start from genesis,
634    /// if there is no saved state). Also returns the anchor view number, which can be used as a
635    /// reference point to process any events which were not processed before a previous shutdown,
636    /// if applicable,.
637    async fn load_consensus_state(
638        &self,
639        state: NodeState,
640        upgrade: Upgrade,
641    ) -> anyhow::Result<(HotShotInitializer<SeqTypes>, Option<ViewNumber>)> {
642        let genesis_validated_state = ValidatedState::genesis(&state).0;
643        let highest_voted_view = match self
644            .load_latest_acted_view()
645            .await
646            .context("loading last voted view")?
647        {
648            Some(view) => {
649                tracing::info!(?view, "starting with last actioned view");
650                view
651            },
652            None => {
653                tracing::info!("no saved view, starting from genesis");
654                ViewNumber::genesis()
655            },
656        };
657
658        let restart_view = match self
659            .load_restart_view()
660            .await
661            .context("loading restart view")?
662        {
663            Some(view) => {
664                tracing::info!(?view, "starting from saved view");
665                view
666            },
667            None => {
668                tracing::info!("no saved view, starting from genesis");
669                ViewNumber::genesis()
670            },
671        };
672        let config = self.load_config().await.context("loading config")?;
673        // Use epoch height from node state. Node state gets the epoch height from the genesis file.
674        let epoch_height = state.epoch_height.unwrap_or_else(|| {
675            config
676                .as_ref()
677                .map(|c| c.config.epoch_height)
678                .unwrap_or_default()
679        });
680        let (leaf, cert_pair, anchor_view) = match self
681            .load_anchor_leaf()
682            .await
683            .context("loading anchor leaf")?
684        {
685            Some((leaf, cert_pair)) => {
686                tracing::info!(?leaf, ?cert_pair, "starting from saved leaf");
687                let high_qc = cert_pair.qc().clone();
688                let leaf_view = leaf.view_number();
689                ensure!(
690                    leaf_view == high_qc.view_number,
691                    format!(
692                        "loaded anchor leaf from view {}, but high QC is from view {}",
693                        leaf_view, high_qc.view_number
694                    )
695                );
696                if leaf.block_header().version() < NEW_PROTOCOL_VERSION {
697                    ensure!(
698                        epoch_height == 0
699                            || cert_pair.block_number().is_none()
700                            || cert_pair.verify_next_epoch_qc(epoch_height).is_ok(),
701                        format!(
702                            "Next epoch QC is required but it's not present or doesn't match \
703                             primary QC\nPrimary QC: {:?}\nNext epoch QC: {:?}",
704                            cert_pair.qc(),
705                            cert_pair.next_epoch_qc()
706                        )
707                    );
708                }
709
710                let anchor_view = leaf.view_number();
711                (leaf, cert_pair, Some(anchor_view))
712            },
713            None => {
714                tracing::info!("no saved leaf, starting from genesis leaf");
715                let genesis_qc =
716                    QuorumCertificate2::genesis(&genesis_validated_state, &state, upgrade).await;
717                (
718                    hotshot_types::data::Leaf2::genesis(
719                        &genesis_validated_state,
720                        &state,
721                        upgrade.base,
722                    )
723                    .await,
724                    CertificatePair::new(genesis_qc, None),
725                    None,
726                )
727            },
728        };
729
730        let mut high_qc = cert_pair.qc().clone();
731        let mut next_epoch_high_qc = cert_pair.next_epoch_qc().cloned();
732        if let Some((extended_high_qc, extended_next_qc)) = self.load_eqc().await
733            && extended_high_qc.view_number() > high_qc.view_number()
734        {
735            high_qc = extended_high_qc;
736            next_epoch_high_qc = Some(extended_next_qc);
737        }
738
739        let validated_state = if leaf.block_header().height() == 0 {
740            // If we are starting from genesis, we can provide the full state.
741            genesis_validated_state
742        } else {
743            // Otherwise, we will have to construct a sparse state and fetch missing data during
744            // catchup.
745            ValidatedState::from_header(leaf.block_header())
746        };
747
748        // If we are not starting from genesis, we start from the view following the maximum view
749        // between `highest_voted_view` and `leaf.view_number`. This prevents double votes from
750        // starting in a view in which we had already voted before the restart, and prevents
751        // unnecessary catchup from starting in a view earlier than the anchor leaf.
752        let restart_view = max(restart_view, leaf.view_number());
753        // TODO:
754        let epoch = genesis_epoch_from_version(upgrade.base);
755
756        // Use epoch start block from node state. Node state gets it from the genesis file.
757        let epoch_start_block = state.epoch_start_block;
758
759        let saved_proposals = self
760            .load_quorum_proposals()
761            .await
762            .context("loading saved proposals")?;
763
764        let upgrade_certificate = self
765            .load_upgrade_certificate()
766            .await
767            .context("loading upgrade certificate")?;
768
769        let start_epoch_info = self
770            .load_start_epoch_info()
771            .await
772            .context("loading start epoch info")?;
773
774        let state_cert = self
775            .load_state_cert()
776            .await
777            .context("loading light client state update certificate")?;
778
779        tracing::warn!(
780            ?leaf,
781            ?restart_view,
782            ?epoch,
783            ?high_qc,
784            ?validated_state,
785            ?state_cert,
786            "loaded consensus state"
787        );
788
789        Ok((
790            HotShotInitializer {
791                instance_state: state,
792                epoch_height,
793                epoch_start_block,
794                anchor_leaf: leaf,
795                anchor_state: Arc::new(validated_state),
796                anchor_state_delta: None,
797                start_view: restart_view,
798                start_epoch: epoch,
799                last_actioned_view: highest_voted_view,
800                saved_proposals,
801                high_qc,
802                next_epoch_high_qc,
803                decided_upgrade_certificate: upgrade_certificate,
804                undecided_leaves: Default::default(),
805                undecided_state: Default::default(),
806                saved_vid_shares: Default::default(), // TODO: implement saved_vid_shares
807                start_epoch_info,
808                state_cert,
809            },
810            anchor_view,
811        ))
812    }
813
814    /// Decode a consensus decide event and persist its leaves, for the consensus event loop.
815    /// Returns `Some((decided_view, deciding_qc))` on a decide so the caller can wake a background
816    /// task to run [`process_decided_events`](Self::process_decided_events); `None` otherwise.
817    ///
818    /// This is the persist-only half of a decide: query-service ingestion and GC are deferred to
819    /// [`process_decided_events`](Self::process_decided_events). Tests that want the synchronous
820    /// persist-then-process behavior use [`append_decided_leaves`](Self::append_decided_leaves).
821    async fn persist_event(
822        &self,
823        event: &CoordinatorEvent<SeqTypes>,
824        consumer: &(impl EventConsumer + 'static),
825    ) -> Option<(ViewNumber, Option<Arc<CertificatePair<SeqTypes>>>)> {
826        match event {
827            CoordinatorEvent::LegacyEvent(hotshot_event) => {
828                let EventType::Decide {
829                    leaf_chain,
830                    committing_qc,
831                    deciding_qc,
832                    ..
833                } = &hotshot_event.event
834                else {
835                    return None;
836                };
837                let LeafInfo { leaf, .. } = leaf_chain.first()?;
838                let decided_view = leaf.view_number();
839
840                let chain = leaf_chain.iter().zip(
841                    std::iter::once((**committing_qc).clone()).chain(
842                        leaf_chain
843                            .iter()
844                            .map(|leaf| CertificatePair::for_parent(&leaf.leaf)),
845                    ),
846                );
847
848                if let Err(err) = self
849                    .persist_decided_leaves(decided_view, chain, deciding_qc.clone(), consumer)
850                    .await
851                {
852                    tracing::error!(
853                        "failed to save decided leaves, chain may not be up to date: {err:#}"
854                    );
855                    return None;
856                }
857                Some((decided_view, deciding_qc.clone()))
858            },
859            CoordinatorEvent::NewDecide {
860                leaf_infos, cert1, ..
861            } => {
862                let first = leaf_infos.first()?;
863                let decided_view = first.leaf.view_number();
864
865                // `cert1` certifies the newest leaf; each newer leaf's justify_qc certifies the
866                // next older leaf.
867                let certifying_qcs = std::iter::once(cert1.clone())
868                    .chain(leaf_infos.iter().map(|info| info.leaf.justify_qc()))
869                    .take(leaf_infos.len())
870                    .map(CertificatePair::non_epoch_change);
871
872                if let Err(err) = self
873                    .persist_decided_leaves(
874                        decided_view,
875                        leaf_infos.iter().zip(certifying_qcs),
876                        None,
877                        consumer,
878                    )
879                    .await
880                {
881                    tracing::error!(
882                        "failed to save decided leaves from new protocol, chain may not be up to \
883                         date: {err:#}"
884                    );
885                    return None;
886                }
887                Some((decided_view, None))
888            },
889            _ => None,
890        }
891    }
892
893    /// Append decided leaves to persistent storage and emit a corresponding event.
894    ///
895    /// `consumer` will be sent a `Decide` event containing all decided leaves in persistent storage
896    /// up to and including `view`. If available in persistent storage, full block payloads and VID
897    /// info will also be included for each leaf.
898    ///
899    /// Once the new decided leaves have been processed, old data up to `view` will be garbage
900    /// collected The consumer's handling of this event is a prerequisite for the completion of
901    /// garbage collection: if the consumer fails to process the event, no data is deleted. This
902    /// ensures that, if called repeatedly, all decided leaves ever recorded in consensus storage
903    /// will eventually be passed to the consumer.
904    ///
905    /// Note that the converse is not true: if garbage collection fails, it is not guaranteed that
906    /// the consumer hasn't processed the decide event. Thus, in rare cases, some events may be
907    /// processed twice, or the consumer may get two events which share a subset of their data.
908    /// Thus, it is the consumer's responsibility to make sure its handling of each leaf is
909    /// idempotent.
910    ///
911    /// If the consumer fails to handle the new decide event, it may be retried, or simply postponed
912    /// until the next decide, at which point all persisted leaves from the failed GC run will be
913    /// included in the event along with subsequently decided leaves.
914    ///
915    /// This functionality is useful for keeping a separate view of the blockchain in sync with the
916    /// consensus storage. For example, the `consumer` could be used for moving data from consensus
917    /// storage to long-term archival storage.
918    ///
919    /// Convenience combinator: [`persist_decided_leaves`](Self::persist_decided_leaves) then
920    /// [`process_decided_events`](Self::process_decided_events). Production drives the two halves on
921    /// separate tasks; tests and back-compat callers use this synchronous form.
922    async fn append_decided_leaves(
923        &self,
924        decided_view: ViewNumber,
925        leaf_chain: impl IntoIterator<Item = (&LeafInfo<SeqTypes>, CertificatePair<SeqTypes>)> + Send,
926        deciding_qc: Option<Arc<CertificatePair<SeqTypes>>>,
927        consumer: &(impl EventConsumer + 'static),
928    ) -> anyhow::Result<()> {
929        self.persist_decided_leaves(decided_view, leaf_chain, deciding_qc.clone(), consumer)
930            .await?;
931        // Leaves are persisted; processing failures are non-fatal here and retried in production.
932        if let Err(err) = self
933            .process_decided_events(decided_view, deciding_qc, consumer)
934            .await
935        {
936            tracing::warn!(?decided_view, "decide event processing failed: {err:#}");
937        }
938        Ok(())
939    }
940
941    /// Persist decided leaves only (the critical, must-not-lag half of a decide; also the
942    /// anchor for restart recovery). Query-service ingestion and GC are deferred to
943    /// [`process_decided_events`](Self::process_decided_events). Backends with no replayable storage
944    /// (e.g. `NoStorage`) may instead forward decide events to `consumer` here.
945    async fn persist_decided_leaves(
946        &self,
947        decided_view: ViewNumber,
948        leaf_chain: impl IntoIterator<Item = (&LeafInfo<SeqTypes>, CertificatePair<SeqTypes>)> + Send,
949        deciding_qc: Option<Arc<CertificatePair<SeqTypes>>>,
950        consumer: &(impl EventConsumer + 'static),
951    ) -> anyhow::Result<()>;
952
953    /// Generate decide events for `consumer` from persisted leaves, then GC processed data.
954    /// Cursor-driven (e.g. `last_processed_view`): advances only on success, so it may lag
955    /// consensus without losing data.
956    ///
957    /// Returns the highest view confirmed processed (the cursor), or `None` if nothing was
958    /// processed, so the caller can track real progress. Errors are propagated; the failed range
959    /// is retried on the next call.
960    ///
961    /// Default returns `Some(decided_view)`: backends with no replayable storage (e.g. `NoStorage`)
962    /// forward events synchronously in `persist_decided_leaves` and are always caught up here.
963    async fn process_decided_events(
964        &self,
965        decided_view: ViewNumber,
966        _deciding_qc: Option<Arc<CertificatePair<SeqTypes>>>,
967        _consumer: &(impl EventConsumer + 'static),
968    ) -> anyhow::Result<Option<ViewNumber>> {
969        Ok(Some(decided_view))
970    }
971
972    async fn load_anchor_leaf(&self) -> anyhow::Result<Option<(Leaf2, CertificatePair<SeqTypes>)>>;
973    async fn append_vid(
974        &self,
975        proposal: &Proposal<SeqTypes, VidDisperseShare<SeqTypes>>,
976    ) -> anyhow::Result<()>;
977    async fn append_da(
978        &self,
979        proposal: &Proposal<SeqTypes, DaProposal<SeqTypes>>,
980        vid_commit: VidCommitment,
981    ) -> anyhow::Result<()>;
982    async fn record_action(
983        &self,
984        view: ViewNumber,
985        epoch: Option<EpochNumber>,
986        action: HotShotAction,
987    ) -> anyhow::Result<()>;
988
989    async fn append_quorum_proposal2(
990        &self,
991        proposal: &Proposal<SeqTypes, QuorumProposalWrapper<SeqTypes>>,
992    ) -> anyhow::Result<()>;
993
994    /// Persist cert2 for the given view.
995    async fn append_cert2(
996        &self,
997        _view: ViewNumber,
998        _cert2: Certificate2<SeqTypes>,
999    ) -> anyhow::Result<()> {
1000        Ok(())
1001    }
1002
1003    /// Load a persisted cert2 by view, if any.
1004    async fn load_cert2(
1005        &self,
1006        _view: ViewNumber,
1007    ) -> anyhow::Result<Option<Certificate2<SeqTypes>>> {
1008        Ok(None)
1009    }
1010
1011    /// Persist the new protocol's locked QC, written before each phase-2 vote.
1012    ///
1013    /// Implementations must apply this as an atomic monotonic compare-and-set: a
1014    /// write whose view is not newer than the stored one is a no-op. This lets
1015    /// concurrent, retried writes race without ever regressing the persisted lock.
1016    async fn append_high_qc2(&self, _high_qc: QuorumCertificate2<SeqTypes>) -> anyhow::Result<()> {
1017        Ok(())
1018    }
1019
1020    /// Load the persisted locked QC, if any.
1021    async fn load_high_qc2(&self) -> anyhow::Result<Option<QuorumCertificate2<SeqTypes>>> {
1022        Ok(None)
1023    }
1024
1025    /// Update the current eQC in storage.
1026    async fn store_eqc(
1027        &self,
1028        _high_qc: QuorumCertificate2<SeqTypes>,
1029        _next_epoch_high_qc: NextEpochQuorumCertificate2<SeqTypes>,
1030    ) -> anyhow::Result<()>;
1031
1032    /// Load the current eQC from storage.
1033    async fn load_eqc(
1034        &self,
1035    ) -> Option<(
1036        QuorumCertificate2<SeqTypes>,
1037        NextEpochQuorumCertificate2<SeqTypes>,
1038    )>;
1039
1040    async fn store_upgrade_certificate(
1041        &self,
1042        decided_upgrade_certificate: Option<UpgradeCertificate<SeqTypes>>,
1043    ) -> anyhow::Result<()>;
1044
1045    async fn migrate_storage(&self) -> anyhow::Result<()> {
1046        tracing::warn!("migrating consensus data...");
1047
1048        self.migrate_anchor_leaf().await?;
1049        self.migrate_da_proposals().await?;
1050        self.migrate_vid_shares().await?;
1051        self.migrate_quorum_proposals().await?;
1052        self.migrate_quorum_certificates().await?;
1053        self.migrate_x25519_keys().await?;
1054        tracing::warn!("consensus storage has been migrated to new types");
1055
1056        Ok(())
1057    }
1058
1059    async fn migrate_x25519_keys(&self) -> anyhow::Result<()>;
1060
1061    async fn migrate_anchor_leaf(&self) -> anyhow::Result<()>;
1062    async fn migrate_da_proposals(&self) -> anyhow::Result<()>;
1063    async fn migrate_vid_shares(&self) -> anyhow::Result<()>;
1064    async fn migrate_quorum_proposals(&self) -> anyhow::Result<()>;
1065    async fn migrate_quorum_certificates(&self) -> anyhow::Result<()>;
1066
1067    async fn load_anchor_view(&self) -> anyhow::Result<ViewNumber> {
1068        match self.load_anchor_leaf().await? {
1069            Some((leaf, _)) => Ok(leaf.view_number()),
1070            None => Ok(ViewNumber::genesis()),
1071        }
1072    }
1073
1074    async fn store_next_epoch_quorum_certificate(
1075        &self,
1076        high_qc: NextEpochQuorumCertificate2<SeqTypes>,
1077    ) -> anyhow::Result<()>;
1078
1079    async fn load_next_epoch_quorum_certificate(
1080        &self,
1081    ) -> anyhow::Result<Option<NextEpochQuorumCertificate2<SeqTypes>>>;
1082
1083    async fn append_da2(
1084        &self,
1085        proposal: &Proposal<SeqTypes, DaProposal2<SeqTypes>>,
1086        vid_commit: VidCommitment,
1087    ) -> anyhow::Result<()>;
1088
1089    async fn append_proposal2(
1090        &self,
1091        proposal: &Proposal<SeqTypes, QuorumProposalWrapper<SeqTypes>>,
1092    ) -> anyhow::Result<()> {
1093        self.append_quorum_proposal2(proposal).await
1094    }
1095
1096    async fn store_drb_result(
1097        &self,
1098        epoch: EpochNumber,
1099        drb_result: DrbResult,
1100    ) -> anyhow::Result<()>;
1101    async fn store_drb_input(&self, drb_input: DrbInput) -> anyhow::Result<()>;
1102    async fn load_drb_input(&self, epoch: u64) -> anyhow::Result<DrbInput>;
1103    async fn store_epoch_root(
1104        &self,
1105        epoch: EpochNumber,
1106        block_header: <SeqTypes as NodeType>::BlockHeader,
1107    ) -> anyhow::Result<()>;
1108    async fn add_state_cert(
1109        &self,
1110        state_cert: LightClientStateUpdateCertificateV2<SeqTypes>,
1111    ) -> anyhow::Result<()>;
1112
1113    fn enable_metrics(&mut self, metrics: &dyn Metrics);
1114}
1115
1116#[async_trait]
1117pub trait EventConsumer: Debug + Send + Sync {
1118    async fn handle_event(&self, event: &CoordinatorEvent<SeqTypes>) -> anyhow::Result<()>;
1119}
1120
1121#[async_trait]
1122impl<T> EventConsumer for Box<T>
1123where
1124    T: EventConsumer + ?Sized,
1125{
1126    async fn handle_event(&self, event: &CoordinatorEvent<SeqTypes>) -> anyhow::Result<()> {
1127        (**self).handle_event(event).await
1128    }
1129}
1130
1131#[derive(Clone, Copy, Debug)]
1132pub struct NullEventConsumer;
1133
1134#[async_trait]
1135impl EventConsumer for NullEventConsumer {
1136    async fn handle_event(&self, _event: &CoordinatorEvent<SeqTypes>) -> anyhow::Result<()> {
1137        Ok(())
1138    }
1139}
1140
1141#[cfg(feature = "node")]
1142#[async_trait]
1143impl<P: SequencerPersistence> Storage<SeqTypes> for Arc<P> {
1144    async fn append_vid(
1145        &self,
1146        proposal: &Proposal<SeqTypes, VidDisperseShare<SeqTypes>>,
1147    ) -> anyhow::Result<()> {
1148        (**self).append_vid(proposal).await
1149    }
1150
1151    async fn append_da(
1152        &self,
1153        proposal: &Proposal<SeqTypes, DaProposal<SeqTypes>>,
1154        vid_commit: VidCommitment,
1155    ) -> anyhow::Result<()> {
1156        (**self).append_da(proposal, vid_commit).await
1157    }
1158
1159    async fn append_da2(
1160        &self,
1161        proposal: &Proposal<SeqTypes, DaProposal2<SeqTypes>>,
1162        vid_commit: VidCommitment,
1163    ) -> anyhow::Result<()> {
1164        (**self).append_da2(proposal, vid_commit).await
1165    }
1166
1167    async fn record_action(
1168        &self,
1169        view: ViewNumber,
1170        epoch: Option<EpochNumber>,
1171        action: HotShotAction,
1172    ) -> anyhow::Result<()> {
1173        (**self).record_action(view, epoch, action).await
1174    }
1175
1176    async fn update_high_qc(&self, _high_qc: QuorumCertificate<SeqTypes>) -> anyhow::Result<()> {
1177        Ok(())
1178    }
1179
1180    async fn append_proposal(
1181        &self,
1182        proposal: &Proposal<SeqTypes, QuorumProposal<SeqTypes>>,
1183    ) -> anyhow::Result<()> {
1184        (**self)
1185            .append_quorum_proposal2(&convert_proposal(proposal.clone()))
1186            .await
1187    }
1188
1189    async fn append_proposal2(
1190        &self,
1191        proposal: &Proposal<SeqTypes, QuorumProposal2<SeqTypes>>,
1192    ) -> anyhow::Result<()> {
1193        let proposal_qp_wrapper: Proposal<SeqTypes, QuorumProposalWrapper<SeqTypes>> =
1194            convert_proposal(proposal.clone());
1195        (**self).append_quorum_proposal2(&proposal_qp_wrapper).await
1196    }
1197
1198    async fn update_high_qc2(&self, _high_qc: QuorumCertificate2<SeqTypes>) -> anyhow::Result<()> {
1199        Ok(())
1200    }
1201
1202    /// Update the current eQC in storage.
1203    async fn update_eqc(
1204        &self,
1205        high_qc: QuorumCertificate2<SeqTypes>,
1206        next_epoch_high_qc: NextEpochQuorumCertificate2<SeqTypes>,
1207    ) -> anyhow::Result<()> {
1208        if let Some((existing_high_qc, _)) = (**self).load_eqc().await
1209            && high_qc.view_number() < existing_high_qc.view_number()
1210        {
1211            return Ok(());
1212        }
1213
1214        (**self).store_eqc(high_qc, next_epoch_high_qc).await
1215    }
1216
1217    async fn update_next_epoch_high_qc2(
1218        &self,
1219        _next_epoch_high_qc: NextEpochQuorumCertificate2<SeqTypes>,
1220    ) -> anyhow::Result<()> {
1221        Ok(())
1222    }
1223
1224    async fn update_decided_upgrade_certificate(
1225        &self,
1226        decided_upgrade_certificate: Option<UpgradeCertificate<SeqTypes>>,
1227    ) -> anyhow::Result<()> {
1228        (**self)
1229            .store_upgrade_certificate(decided_upgrade_certificate)
1230            .await
1231    }
1232
1233    async fn store_drb_result(
1234        &self,
1235        epoch: EpochNumber,
1236        drb_result: DrbResult,
1237    ) -> anyhow::Result<()> {
1238        (**self).store_drb_result(epoch, drb_result).await
1239    }
1240
1241    async fn store_epoch_root(
1242        &self,
1243        epoch: EpochNumber,
1244        block_header: <SeqTypes as NodeType>::BlockHeader,
1245    ) -> anyhow::Result<()> {
1246        (**self).store_epoch_root(epoch, block_header).await
1247    }
1248
1249    async fn store_drb_input(&self, drb_input: DrbInput) -> anyhow::Result<()> {
1250        (**self).store_drb_input(drb_input).await
1251    }
1252
1253    async fn load_drb_input(&self, epoch: u64) -> anyhow::Result<DrbInput> {
1254        (**self).load_drb_input(epoch).await
1255    }
1256
1257    async fn update_state_cert(
1258        &self,
1259        state_cert: LightClientStateUpdateCertificateV2<SeqTypes>,
1260    ) -> anyhow::Result<()> {
1261        (**self).add_state_cert(state_cert).await
1262    }
1263}
1264
1265#[cfg(feature = "node")]
1266#[async_trait]
1267impl<P: SequencerPersistence> NewProtocolStorage<SeqTypes> for Arc<P> {
1268    async fn append_cert2(
1269        &self,
1270        view: ViewNumber,
1271        cert: Certificate2<SeqTypes>,
1272    ) -> anyhow::Result<()> {
1273        (**self).append_cert2(view, cert).await
1274    }
1275
1276    async fn append_high_qc2(&self, high_qc: Certificate1<SeqTypes>) -> anyhow::Result<()> {
1277        // Writes are spawned concurrently and retried, so a stale write can land
1278        // after a newer one. The backend applies a monotonic compare-and-set
1279        // atomically, so such a stale write is a no-op and never regresses the
1280        // persisted view.
1281        (**self).append_high_qc2(high_qc).await
1282    }
1283
1284    async fn load_high_qc2(&self) -> anyhow::Result<Option<Certificate1<SeqTypes>>> {
1285        (**self).load_high_qc2().await
1286    }
1287}
1288
1289/// Data that can be deserialized from a subslice of namespace payload bytes.
1290///
1291/// Companion trait for [`NsPayloadBytesRange`], which specifies the subslice of
1292/// namespace payload bytes to read.
1293pub trait FromNsPayloadBytes<'a> {
1294    /// Deserialize `Self` from namespace payload bytes.
1295    fn from_payload_bytes(bytes: &'a [u8]) -> Self;
1296}
1297
1298/// Specifies a subslice of namespace payload bytes to read.
1299///
1300/// Companion trait for [`FromNsPayloadBytes`], which holds data that can be
1301/// deserialized from that subslice of bytes.
1302pub trait NsPayloadBytesRange<'a> {
1303    type Output: FromNsPayloadBytes<'a>;
1304
1305    /// Range relative to this ns payload
1306    fn ns_payload_range(&self) -> Range<usize>;
1307}
1308
1309/// Types which can be deserialized from either integers or strings.
1310///
1311/// Some types can be represented as an integer or a string in human-readable formats like JSON or
1312/// TOML. For example, 1 GWEI might be represented by the integer `1000000000` or the string `"1
1313/// gwei"`. Such types can implement `FromStringOrInteger` and then use [`impl_string_or_integer`]
1314/// to derive this user-friendly serialization.
1315///
1316/// These types are assumed to have an efficient representation as an integral type in Rust --
1317/// [`Self::Binary`] -- and will be serialized to and from this type when using a non-human-readable
1318/// encoding. With human readable encodings, serialization is always to a string.
1319pub trait FromStringOrInteger: Sized {
1320    type Binary: Serialize + DeserializeOwned;
1321    type Integer: Serialize + DeserializeOwned;
1322
1323    fn from_binary(b: Self::Binary) -> anyhow::Result<Self>;
1324    fn from_string(s: String) -> anyhow::Result<Self>;
1325    fn from_integer(i: Self::Integer) -> anyhow::Result<Self>;
1326
1327    fn to_binary(&self) -> anyhow::Result<Self::Binary>;
1328    fn to_string(&self) -> anyhow::Result<String>;
1329}