Skip to main content

poi_rs/
cache.rs

1// Copyright 2020-2026 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use iota_types::committee::{Committee, EpochId};
5use iota_types::digests::ChainIdentifier;
6
7use crate::BoxError;
8
9mod in_memory;
10
11pub use in_memory::MemoryCommitteeCache;
12
13/// Identifies one committee-cache entry by its network and epoch.
14///
15/// The chain identifier is the network's genesis checkpoint digest. Cache
16/// adapters must use the complete key so entries authenticated for different
17/// networks cannot collide.
18#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
19pub struct CommitteeCacheKey {
20    chain_identifier: ChainIdentifier,
21    epoch: EpochId,
22}
23
24impl CommitteeCacheKey {
25    /// Creates a cache key for `epoch` on the identified network.
26    pub const fn new(chain_identifier: ChainIdentifier, epoch: EpochId) -> Self {
27        Self {
28            chain_identifier,
29            epoch,
30        }
31    }
32
33    /// Creates a key for a cache private to one resolver.
34    pub(crate) fn isolated(epoch: EpochId) -> Self {
35        Self::new(ChainIdentifier::default(), epoch)
36    }
37
38    /// Returns the network's genesis checkpoint digest.
39    pub const fn chain_identifier(&self) -> &ChainIdentifier {
40        &self.chain_identifier
41    }
42
43    /// Returns the cached committee epoch.
44    pub const fn epoch(&self) -> EpochId {
45        self.epoch
46    }
47}
48
49/// Error returned by a committee cache.
50#[derive(Debug, thiserror::Error)]
51#[non_exhaustive]
52pub enum CommitteeCacheError {
53    /// A cached committee conflicts with authenticated committee data.
54    #[error("cached committee conflicts at epoch {epoch}")]
55    Conflict {
56        /// Epoch whose cached material conflicts.
57        epoch: EpochId,
58    },
59    /// A cache backend failed to read or write committee material.
60    #[error("committee cache backend failed at epoch {epoch}")]
61    Backend {
62        /// Epoch being accessed when the backend failed.
63        epoch: EpochId,
64        /// Underlying backend error.
65        #[source]
66        source: BoxError,
67    },
68}
69
70/// Stores authenticated committees for anchored resolution.
71///
72/// Implementations must preserve committee integrity after storage and use the
73/// complete [`CommitteeCacheKey`] for every lookup.
74#[async_trait::async_trait]
75pub trait CommitteeCache: Send + Sync {
76    /// Returns the authenticated committee for `key`, when available.
77    async fn committee(&self, key: CommitteeCacheKey) -> Result<Option<Committee>, CommitteeCacheError>;
78
79    /// Stores a committee under `key` after the resolver has authenticated it.
80    async fn store(&self, key: CommitteeCacheKey, committee: &Committee) -> Result<(), CommitteeCacheError>;
81}