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],
},
}