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}