cardano_sdk/cardano/
protocol_parameters.rs

1//  This Source Code Form is subject to the terms of the Mozilla Public
2//  License, v. 2.0. If a copy of the MPL was not distributed with this
3//  file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use num::rational::Ratio;
6
7/// Protocol parameters restricted to the set immediately useful to this library.
8#[derive(Debug, Clone, PartialEq, PartialOrd)]
9pub struct ProtocolParameters {
10    /// Multiplier fee coefficient on the size of transactions
11    fee_per_byte: u64,
12
13    /// Flat/fixed fee for all transactions, in lovelace
14    fee_constant: u64,
15
16    /// Price of a single memory execution unit, in lovelace/unit
17    price_mem: f64,
18
19    /// Price of a single cpu execution unit, in lovelace/unit
20    price_cpu: f64,
21
22    /// Coefficient to apply to fees to obtain the collateral, in lovelace
23    collateral_coefficient: f64,
24
25    /// Initial fee coefficient on the size of referenced scripts, in lovelace/bytes
26    referenced_scripts_base_fee_per_byte: u64,
27
28    /// Multiplier exponentially increasing the cost of reference scripts at each size step.
29    ///
30    /// NOTE: This isn't an actual protocol parameter and is currently hard-wired in the ledger.
31    /// But it may very well be soon enough.
32    referenced_scripts_fee_multiplier: Ratio<u64>,
33
34    /// Size of each step after which the cost of referenced script bytes increases, in bytes
35    ///
36    /// NOTE: This isn't an actual protocol parameter and is currently hard-wired in the ledger.
37    /// But it may very well be soon enough.
38    referenced_scripts_fee_step_size: u64,
39
40    /// Cost model for Plutus version 3, ordered according to the [_"spec"_](https://github.com/IntersectMBO/plutus/blob/b12c894833cae725bab11577c845701aeb05dc97/plutus-ledger-api/CostModel/Params/CostModelParams/costModelParamNames.golden.txt)
41    plutus_v3_cost_model: PlutusV3CostModel,
42
43    /// The network POSIX start time, in seconds.
44    start_time: u64,
45
46    /// The first (not-necessarily active) slot of the Shelley era.
47    first_shelley_slot: u64,
48}
49
50type PlutusV3CostModel = Vec<i64>;
51
52// --------------------------------------------------------------------- Building
53
54impl Default for ProtocolParameters {
55    fn default() -> Self {
56        Self {
57            fee_per_byte: 0,
58            fee_constant: 0,
59            price_mem: 0.0,
60            price_cpu: 0.0,
61            collateral_coefficient: 0.0,
62            referenced_scripts_base_fee_per_byte: 0,
63            referenced_scripts_fee_multiplier: Ratio::ONE,
64            referenced_scripts_fee_step_size: 0,
65            plutus_v3_cost_model: vec![],
66            start_time: 0,
67            first_shelley_slot: 0,
68        }
69    }
70}
71
72impl ProtocolParameters {
73    /// _Current_ Mainnet protocol parameters.
74    ///
75    /// <div class="warning">This may drift from actual parameters based on protocol updates. Ideally, parameters should be
76    /// reconstructed from a blockchain provider.</div>
77    pub fn mainnet() -> Self {
78        Self::default()
79            .with_fee_per_byte(44)
80            .with_fee_constant(155381)
81            .with_collateral_coefficient(1.5)
82            .with_referenced_scripts_base_fee_per_byte(15)
83            .with_referenced_scripts_fee_multiplier(Ratio::new(12, 10))
84            .with_referenced_scripts_fee_step_size(25000)
85            .with_execution_price_mem(0.0577)
86            .with_execution_price_cpu(7.21e-05)
87            .with_start_time(1506203091)
88            .with_first_shelley_slot(4492800)
89            .with_plutus_v3_cost_model(vec![
90                100788, 420, 1, 1, 1000, 173, 0, 1, 1000, 59957, 4, 1, 11183, 32, 201305, 8356, 4,
91                16000, 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 100, 100,
92                16000, 100, 94375, 32, 132994, 32, 61462, 4, 72010, 178, 0, 1, 22151, 32, 91189,
93                769, 4, 2, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 1, 1000, 42921,
94                4, 2, 24548, 29498, 38, 1, 898148, 27279, 1, 51775, 558, 1, 39184, 1000, 60594, 1,
95                141895, 32, 83150, 32, 15299, 32, 76049, 1, 13169, 4, 22100, 10, 28999, 74, 1,
96                28999, 74, 1, 43285, 552, 1, 44749, 541, 1, 33852, 32, 68246, 32, 72362, 32, 7243,
97                32, 7391, 32, 11546, 32, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1,
98                90434, 519, 0, 1, 74433, 32, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1,
99                1, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 955506, 213312, 0, 2,
100                270652, 22588, 4, 1457325, 64566, 4, 20467, 1, 4, 0, 141992, 32, 100788, 420, 1, 1,
101                81663, 32, 59498, 32, 20142, 32, 24588, 32, 20744, 32, 25933, 32, 24623, 32,
102                43053543, 10, 53384111, 14333, 10, 43574283, 26308, 10, 16000, 100, 16000, 100,
103                962335, 18, 2780678, 6, 442008, 1, 52538055, 3756, 18, 267929, 18, 76433006, 8868,
104                18, 52948122, 18, 1995836, 36, 3227919, 12, 901022, 1, 166917843, 4307, 36, 284546,
105                36, 158221314, 26549, 36, 74698472, 36, 333849714, 1, 254006273, 72, 2174038, 72,
106                2261318, 64571, 4, 207616, 8310, 4, 1293828, 28716, 63, 0, 1, 1006041, 43623, 251,
107                0, 1, 100181, 726, 719, 0, 1, 100181, 726, 719, 0, 1, 100181, 726, 719, 0, 1,
108                107878, 680, 0, 1, 95336, 1, 281145, 18848, 0, 1, 180194, 159, 1, 1, 158519, 8942,
109                0, 1, 159378, 8813, 0, 1, 107490, 3298, 1, 106057, 655, 1, 1964219, 24520, 3,
110            ])
111    }
112
113    /// _Current_ PreProd protocol parameters.
114    ///
115    /// <div class="warning">This may drift from actual parameters based on protocol updates. Ideally, parameters should be
116    /// reconstructed from a blockchain provider.</div>
117    pub fn preprod() -> Self {
118        Self::mainnet()
119            .with_start_time(1654041600)
120            .with_first_shelley_slot(86400)
121    }
122
123    /// _Current_ PreProd protocol parameters.
124    ///
125    /// <div class="warning">This may drift from actual parameters based on protocol updates. Ideally, parameters should be
126    /// reconstructed from a blockchain provider.</div>
127    ///
128    /// FIXME :: This has not been verified.
129    pub fn preview() -> Self {
130        Self::mainnet()
131            .with_start_time(1666656000)
132            .with_first_shelley_slot(0)
133    }
134
135    /// Translate a posix time to a slot number for that particular network.
136    pub fn posix_to_slot(&self, posix: std::time::Duration) -> u64 {
137        let delta = posix.as_secs() - self.start_time;
138
139        let byron_duration = 20 * self.first_shelley_slot;
140        let since_shelley_duration = delta - byron_duration;
141
142        self.first_shelley_slot + since_shelley_duration
143    }
144
145    /// Specify the multiplier fee coefficient on the size of transactions, in lovelace/bytes
146    pub fn with_fee_per_byte(mut self, fee_per_byte: u64) -> Self {
147        self.fee_per_byte = fee_per_byte;
148        self
149    }
150
151    /// Flat/fixed fee for all transactions, in lovelace
152    pub fn with_fee_constant(mut self, fee_constant: u64) -> Self {
153        self.fee_constant = fee_constant;
154        self
155    }
156
157    /// Specify the coefficient to apply to fees to obtain the collateral, in lovelace
158    pub fn with_collateral_coefficient(mut self, collateral_coefficient: f64) -> Self {
159        self.collateral_coefficient = collateral_coefficient;
160        self
161    }
162
163    /// Specify the initial fee coefficient on the size of referenced scripts, in lovelace/bytes
164    pub fn with_referenced_scripts_base_fee_per_byte(
165        mut self,
166        referenced_scripts_base_fee_per_byte: u64,
167    ) -> Self {
168        self.referenced_scripts_base_fee_per_byte = referenced_scripts_base_fee_per_byte;
169        self
170    }
171
172    /// Specify the multiplier exponentially increasing the cost of reference scripts at each size step.
173    pub fn with_referenced_scripts_fee_multiplier(
174        mut self,
175        referenced_scripts_fee_multiplier: Ratio<u64>,
176    ) -> Self {
177        self.referenced_scripts_fee_multiplier = referenced_scripts_fee_multiplier;
178        self
179    }
180
181    /// Specify the size of each step after which the cost of referenced script bytes increases, in bytes
182    pub fn with_referenced_scripts_fee_step_size(
183        mut self,
184        referenced_scripts_fee_step_size: u64,
185    ) -> Self {
186        self.referenced_scripts_fee_step_size = referenced_scripts_fee_step_size;
187        self
188    }
189
190    /// Specify the price of a single memory execution unit, in lovelace/unit
191    pub fn with_execution_price_mem(mut self, price_mem: f64) -> Self {
192        self.price_mem = price_mem;
193        self
194    }
195
196    /// Specify the price of a single cpu execution unit, in lovelace/unit
197    pub fn with_execution_price_cpu(mut self, price_cpu: f64) -> Self {
198        self.price_cpu = price_cpu;
199        self
200    }
201
202    /// Specify the network POSIX start time, in seconds.
203    pub fn with_start_time(mut self, start_time: u64) -> Self {
204        self.start_time = start_time;
205        self
206    }
207
208    /// The first (not-necessarily active) slot of the Shelley era.
209    pub fn with_first_shelley_slot(mut self, first_shelley_slot: u64) -> Self {
210        self.first_shelley_slot = first_shelley_slot;
211        self
212    }
213
214    /// Specify the cost model for Plutus version 3, ordered according to the [_"spec"_](https://github.com/IntersectMBO/plutus/blob/b12c894833cae725bab11577c845701aeb05dc97/plutus-ledger-api/CostModel/Params/CostModelParams/costModelParamNames.golden.txt)
215    pub fn with_plutus_v3_cost_model(mut self, cost_model: PlutusV3CostModel) -> Self {
216        self.plutus_v3_cost_model = cost_model;
217        self
218    }
219}
220
221// ------------------------------------------------------------------ Inspecting
222
223impl ProtocolParameters {
224    /// Base transaction fee, computed from the size of a serialised transaction.
225    pub fn base_fee(&self, size: u64) -> u64 {
226        size * self.fee_per_byte + self.fee_constant
227    }
228
229    /// Compute the tiered-fee of included reference scripts according to [ADR- 2024-08-14_009-refscripts-fee-change](https://github.com/IntersectMBO/cardano-ledger/blob/master/docs/adr/2024-08-14_009-refscripts-fee-change.md).
230    pub fn referenced_scripts_fee(&self, mut size: u64) -> u64 {
231        let mut cost: Ratio<u64> = Ratio::ZERO;
232        let mut fee_per_byte: Ratio<u64> = Ratio::from(self.referenced_scripts_base_fee_per_byte);
233
234        loop {
235            if size < self.referenced_scripts_fee_step_size {
236                return (cost + fee_per_byte * size).floor().to_integer();
237            }
238
239            cost += fee_per_byte * self.referenced_scripts_fee_step_size;
240            fee_per_byte *= self.referenced_scripts_fee_multiplier;
241            size -= self.referenced_scripts_fee_step_size;
242        }
243    }
244
245    /// Compute the minimum collateral value, based on the current transaction fee.
246    pub fn minimum_collateral(&self, base_fee: u64) -> u64 {
247        (base_fee as f64 * self.collateral_coefficient).ceil() as u64
248    }
249
250    /// Compute the price, in lovelace, of memory units usage.
251    pub fn price_mem(&self, execution_units: u64) -> u64 {
252        (self.price_mem * execution_units as f64).ceil() as u64
253    }
254
255    /// Compute the price, in lovelace, of cpu units usage.
256    pub fn price_cpu(&self, execution_units: u64) -> u64 {
257        (self.price_cpu * execution_units as f64).ceil() as u64
258    }
259
260    pub fn plutus_v3_cost_model(&self) -> &PlutusV3CostModel {
261        &self.plutus_v3_cost_model
262    }
263}
264
265// -------------------------------------------------------------- Converting (to)
266
267impl From<&ProtocolParameters> for uplc::tx::SlotConfig {
268    fn from(params: &ProtocolParameters) -> Self {
269        let byron_slot_length = 20; // in seconds
270        Self {
271            slot_length: 1000, // Shelley slot length, in milliseconds
272            zero_slot: params.first_shelley_slot,
273            zero_time: (params.start_time + byron_slot_length * params.first_shelley_slot) * 1000,
274        }
275    }
276}
277
278// ------------------------------------------------------------------------ WASM