Skip to main content

platform_version/version/fee/document_ttl/
mod.rs

1use bincode::{Decode, Encode};
2
3pub mod v1;
4
5/// One price tier of short-lived document storage.
6#[derive(Clone, Copy, Debug, Encode, Decode, Default, PartialEq, Eq)]
7pub struct DocumentTtlFeeTier {
8    /// The longest remaining lifetime, in seconds, this tier prices.
9    pub max_ttl_seconds: u32,
10    /// Credits charged per byte the document writes.
11    pub credit_per_byte: u64,
12}
13
14/// Fees of documents whose document type declares a `ttl` (protocol version 14).
15///
16/// Such a document is stored without storage flags, refunds nothing when it goes, and is
17/// deleted by the platform once its time to live has passed. Instead of the perpetual
18/// storage price it pays, when it is written, for the time it will actually occupy the
19/// state, plus the processing its deletion will cost:
20///
21/// * Every byte the document writes (the document, its index entries and its entry in the
22///   expirations tree) costs the `credit_per_byte` of the first tier whose
23///   `max_ttl_seconds` covers the remaining lifetime; tiers are ordered by
24///   `max_ttl_seconds`. A lifetime longer than the last tier costs
25///   `credit_per_byte_per_period` for every `pricing_period_seconds` it spans, rounded up.
26///   The period is part of the schedule, not the node's epoch length, so a network with
27///   short epochs (testnet, local networks) prices a lifetime like mainnet does.
28/// * That amount is storage, paid out over the epochs the document lives in (at most one
29///   era) rather than by the perpetual storage distribution: the block's storage fees for
30///   each lifetime collect in the lifetime storage fee pools, which every epoch change
31///   spreads evenly over the epochs of their lifetime.
32/// * A document created with a `ttl` also prepays its deletion as processing:
33///   `cleanup_base_processing_cost`, plus `cleanup_processing_cost_per_index_level` for
34///   every index level of its document type (each index counts its properties, times the
35///   number of overlapping windows of a `timeRange` index), plus
36///   `cleanup_processing_cost_per_document_byte` for every byte of the stored document. A
37///   change that grows the document prepays the deletion of the bytes it adds.
38///
39/// Every earlier schedule carries the same group; it is unread there because the `ttl`
40/// keyword does not parse before protocol version 14.
41#[derive(Clone, Debug, Encode, Decode, Default, PartialEq, Eq)]
42pub struct FeeDocumentTtlVersion {
43    /// Short lifetimes, priced per byte, ordered by `max_ttl_seconds`.
44    pub tiers: [DocumentTtlFeeTier; 5],
45    /// Credits per byte per pricing period spanned for lifetimes longer than the last tier.
46    pub credit_per_byte_per_period: u64,
47    /// The length, in seconds, of the period `credit_per_byte_per_period` prices.
48    pub pricing_period_seconds: u32,
49    /// Prepaid processing of a document's deletion, charged once when it is created.
50    pub cleanup_base_processing_cost: u64,
51    /// Prepaid processing per index level of the document type, charged once on creation.
52    pub cleanup_processing_cost_per_index_level: u64,
53    /// Prepaid processing per byte of the stored document: charged on creation for the whole
54    /// document, and on a change for the bytes it adds.
55    pub cleanup_processing_cost_per_document_byte: u64,
56}
57
58#[cfg(test)]
59mod tests {
60    use super::v1::FEE_DOCUMENT_TTL_VERSION1;
61
62    #[test]
63    fn should_order_tiers_by_lifetime_with_non_decreasing_prices() {
64        let group = FEE_DOCUMENT_TTL_VERSION1;
65        for pair in group.tiers.windows(2) {
66            assert!(pair[0].max_ttl_seconds < pair[1].max_ttl_seconds);
67            assert!(pair[0].credit_per_byte <= pair[1].credit_per_byte);
68        }
69        // The first period past the last tier costs at least the last tier and outlasts
70        // it, so a longer lifetime never costs less than a shorter one.
71        let last = group.tiers[group.tiers.len() - 1];
72        assert!(group.credit_per_byte_per_period >= last.credit_per_byte);
73        assert!(group.pricing_period_seconds >= last.max_ttl_seconds);
74    }
75}