Docs

grants

Source: crates/lvcs-net/src/grants/mod.rs.

/// Which bucket a token comes from (design §15).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum Bucket {
    /// Gossip messages a signer may have forwarded or published.
    Gossip,
    /// Changes the daemon signs for a participant key.
    Sign,
}

/// What a bucket refills at (design §15, decision 146): `per_sec` tokens
/// a second, holding at most `burst` (and always room for one, so a burst
/// of 0 still lets the rate through).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Rate {
    /// Tokens added a second.
    pub per_sec: u32,
    /// The most tokens the bucket holds.
    pub burst: u32,
}

/// What a take is for, echoed by [`GrantsOutput::Taken`].
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum TakeKey {
    /// The gossipsub message id the gossip actor is validating.
    Gossip(#[serde(with = "crate::wire::cbor::bytes")] Vec<u8>),
    /// The daemon's id of the request about to be committed.
    Sign(u64),
}

/// The limits in force (design §15, decision 146).
///
/// They are the limit constants in `docs/generated/vocabulary.md` by
/// default ([`Limits::DEFAULT`]), each replaced by its key in protected
/// `lvcs.toml` `[limits]` (the daemon's `LvcsToml`; a missing key keeps its
/// default), so a participant can't change them by editing the file. The
/// field names are the `[limits]` keys (the constants' names in lower
/// case). They are the defaults for every signer, the owner included: the
/// shell gives each take its [`Rate`] from them ([`Limits::sign_rate`],
/// [`Limits::gossip_rate`]), each per-second rate and the signing burst
/// replaced by the signer's grant terms where they name one (decision 146),
/// and the gossip actor sizes its memory and tolerance by `gossip_burst`. A
/// change quota is never a limit: a grant's terms carry it (decision 70).
/// Owner: `M3.grants`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default)]
pub struct Limits {
    /// `PARTICIPANT_SIGN_PER_SEC` in force.
    pub participant_sign_per_sec: u32,
    /// `PARTICIPANT_SIGN_BURST` in force.
    pub participant_sign_burst: u32,
    /// `PARTICIPANT_GOSSIP_PER_SEC` in force.
    pub participant_gossip_per_sec: u32,
    /// `GOSSIP_BURST` in force.
    pub gossip_burst: u32,
}

impl Limits {
    /// The protocol defaults.
    pub const DEFAULT: Self = Self {
        participant_sign_per_sec: PARTICIPANT_SIGN_PER_SEC,
        participant_sign_burst: PARTICIPANT_SIGN_BURST,
        participant_gossip_per_sec: PARTICIPANT_GOSSIP_PER_SEC,
        gossip_burst: GOSSIP_BURST,
    };

    /// The default signing rate: `participant_sign_per_sec`, holding
    /// `participant_sign_burst`.
    #[must_use]
    pub const fn sign_rate(&self) -> Rate {
        Rate {
            per_sec: self.participant_sign_per_sec,
            burst: self.participant_sign_burst,
        }
    }

    /// The default gossip rate: `participant_gossip_per_sec`, holding
    /// `gossip_burst`.
    #[must_use]
    pub const fn gossip_rate(&self) -> Rate {
        Rate {
            per_sec: self.participant_gossip_per_sec,
            burst: self.gossip_burst,
        }
    }
}

impl Default for Limits {
    fn default() -> Self {
        Self::DEFAULT
    }
}

/// The grants actor's events, generated by its sml table: its mailbox and
/// journal type (decision 286). Owner: `M3.grants`.
///
/// Its events, each the payload type its variant is named for: [`TakeToken`],
/// [`RefillToken`], [`RenewTick`], [`SetRenewable`].
pub use machine::{MeteringEvents, RefillToken, RenewTick, SetRenewable, TakeToken};

/// A grant the issuer's daemon renews (decision 148): its id and its
/// window, in Unix seconds. lvcs-net never names a grant (decision 30),
/// so the id is opaque here: the shell's grant id, 32 bytes.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Renewable {
    /// The shell's grant id, opaque here.
    #[serde(with = "crate::wire::cbor::fixed")]
    pub grant: [u8; 32],
    /// The window's start, in Unix seconds.
    pub not_before_s: i64,
    /// The window's end, in Unix seconds.
    pub not_after_s: i64,
}

/// Outputs of the grants actor. Owner: `M3.grants`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GrantsOutput {
    /// The answer to a [`MeteringEvents::TakeToken`]. When `allowed` is false,
    /// `retry_after_ms` is how long until the bucket holds a token, at
    /// most one hour (3 600 000, for a bucket whose rate is 0 and so never
    /// refills; decision 109): for a gossip take the message is dropped (`rejection` = `rate_limited`),
    /// and for a sign take the daemon answers the request `rate_limited`
    /// with it, uncommitted. A waiting take is never refused: it is
    /// answered allowed, with `retry_after_ms` 0, once its bucket holds a
    /// token.
    Taken {
        /// The take answered.
        key: TakeKey,
        /// Whether a token was taken.
        allowed: bool,
        /// How long until the bucket holds a token, when refused.
        retry_after_ms: u64,
    },
    /// Send [`MeteringEvents::RefillToken`] for the kept take `key` at `at_ms`,
    /// when its bucket should hold a token (at most one hour on, for a
    /// bucket whose rate is 0).
    Wake {
        /// The kept take.
        key: TakeKey,
        /// When, by the shell's clock.
        at_ms: i64,
    },
    /// Renew the listed grant `grant` (decision 148): the shell re-issues
    /// it with the same terms and a window of the same length starting
    /// now, signed by its issuer once the issuer's waiting signing take is
    /// given (decision 185), or drops the renewal when it can't. The
    /// grant is asked again after `GRANT_RENEW_RETRY_MS` while a renewal
    /// hasn't replaced it in [`MeteringEvents::SetRenewable`].
    Renew {
        /// The shell's grant id, opaque here.
        grant: [u8; 32],
    },
}