radix_engine/system/system_modules/costing/
fee_table.rs

1use crate::internal_prelude::*;
2use crate::kernel::kernel_callback_api::{
3    CheckReferenceEvent, CloseSubstateEvent, CreateNodeEvent, DrainSubstatesEvent, DropNodeEvent,
4    MoveModuleEvent, OpenSubstateEvent, ReadSubstateEvent, RemoveSubstateEvent, ScanKeysEvent,
5    ScanSortedSubstatesEvent, SetSubstateEvent, WriteSubstateEvent,
6};
7use crate::kernel::substate_io::SubstateDevice;
8use crate::system::actor::Actor;
9use crate::system::system_callback::SystemVersion;
10use crate::system::system_modules::transaction_runtime::Event;
11use crate::{
12    blueprints::package::*,
13    track::interface::{IOAccess, StoreCommit},
14};
15use lazy_static::lazy_static;
16
17// Reference EC2 instance c5.4xlarge has CPU clock 3.4 GHz which means in 1 µs it executes 3400 instructions
18// (1 core, single-threaded operation, skipping CPU cache influence).
19// Basing on above assumptions converting CPU instructions count to cost units requires divistion CPU instructions
20// by 3400 and multiplication by 100 (1 µs = 100 cost units), so it is enough to divide by 34.
21const CPU_INSTRUCTIONS_TO_COST_UNIT: u32 = 34;
22
23lazy_static! {
24    pub static ref NATIVE_FUNCTION_BASE_COSTS: IndexMap<PackageAddress, IndexMap<&'static str, u32>> = {
25        let mut costs: IndexMap<PackageAddress, IndexMap<&'static str, u32>> = index_map_new();
26        include_str!("../../../../assets/native_function_base_costs.csv")
27            .split("\n")
28            .filter(|x| x.len() > 0)
29            .for_each(|x| {
30                let mut tokens = x.split(",");
31                let package_address =
32                    PackageAddress::try_from_hex(tokens.next().unwrap().trim()).unwrap();
33                let export_name = tokens.next().unwrap().trim();
34                let cost = u32::from_str(tokens.next().unwrap().trim()).unwrap();
35                costs
36                    .entry(package_address)
37                    .or_default()
38                    .insert(export_name, cost);
39            });
40        costs
41    };
42    pub static ref NATIVE_FUNCTION_BASE_COSTS_SIZE_DEPENDENT: IndexMap<PackageAddress, IndexMap<&'static str, (u32, u32)>> = {
43        let mut costs: IndexMap<PackageAddress, IndexMap<&'static str, (u32, u32)>> =
44            index_map_new();
45        costs
46            .entry(PACKAGE_PACKAGE)
47            .or_default()
48            .insert(PACKAGE_PUBLISH_NATIVE_IDENT, (875, 11477486));
49        costs
50            .entry(PACKAGE_PACKAGE)
51            .or_default()
52            // TODO: publish_wasm_advanced is too expensive, dividing by 6 to let large package (1MiB) to be published, consider using cubic approximation
53            .insert(PACKAGE_PUBLISH_WASM_ADVANCED_IDENT, (9063 / 6, 11072798));
54    costs
55    };
56}
57
58/// Fee table specifies how each costing entry should be costed.
59///
60/// ## High Level Guideline
61/// - Max execution cost unit limit: 100,000,000
62/// - Max execution cost unit limit: 50,000,000
63/// - Transaction fee = Network Execution + Network Finalization + Tip + Network Storage + Royalties
64/// - Execution time for 100,000,000 cost units' worth of computation: <= 1 second
65/// - Baseline: 1 microsecond = 100 cost units
66///
67#[derive(Debug, Clone, ScryptoSbor)]
68pub struct FeeTable {
69    wasm_execution_units_divider: u32,
70}
71
72impl FeeTable {
73    pub fn new(version: SystemVersion) -> Self {
74        let wasm_execution_units_divider = match version {
75            // From `costing::spin_loop`, it takes 5.5391 ms for 1918122691 wasm execution units.
76            // Therefore, cost for single unit: 5.5391 *  1000 / 1918122691 * 100 = 0.00028877714
77            // 1 / 0.00028877714 = 3462 rounded down gives 3000
78            SystemVersion::V1 => 3000,
79
80            // W - WASM execution units
81            // C - cost units
82            // c - single cost unit
83            // T - execution time (1 µs = 100 c => 1 ms = 100,000 c)
84            //
85            // Cost units might be expressed as
86            //  C = T * c
87            //
88            // To convert W to C, we need a d.
89            //   C = W / divider
90            //   divider = W / C
91            //   divider = W / (T * c)
92            //
93            // From `costing::spin_loop_v2` it consumes W=438,729,340,586 wasm execution
94            // units and it should never take more than T = 1s.
95            //   T = 1s = 1000 ms = 1 * 100,000
96            //   W = 438,729,340,586
97            // Therefore
98            //   divider = 438,729,340,586 / (1000 * 100,000) = 4387.293 ~= 4500
99            //
100            // With divider set to 4500 it takes 543 ms (measured at GH benchmark, git rev c591c4003a,
101            // EC2 instance type c6a.4xlarge) which is fine.
102            SystemVersion::V2 | SystemVersion::V3 => 4500,
103        };
104
105        Self {
106            wasm_execution_units_divider,
107        }
108    }
109
110    pub fn latest() -> Self {
111        Self::cuttlefish()
112    }
113
114    pub fn cuttlefish() -> Self {
115        Self::new(SystemVersion::V2)
116    }
117
118    pub fn bottlenose() -> Self {
119        Self::new(SystemVersion::V1)
120    }
121
122    pub fn anemone() -> Self {
123        Self::new(SystemVersion::V1)
124    }
125
126    pub fn babylon() -> Self {
127        Self::new(SystemVersion::V1)
128    }
129
130    //======================
131    // Execution costs
132    //======================
133
134    fn data_processing_cost(size: usize) -> u32 {
135        // Based on benchmark `bench_decode_sbor`
136        // Time for processing a byte: 10.244 µs / 1068 = 0.00959176029
137
138        // Based on benchmark `bench_validate_sbor_payload`
139        // Time for processing a byte: 10.075 µs / 1169 = 0.00861847733
140
141        mul(cast(size), 2)
142    }
143
144    fn io_access_cost(&self, io_access: &IOAccess) -> u32 {
145        match io_access {
146            IOAccess::ReadFromDb(_, size) => {
147                // Execution time (µs): 0.0009622109 * size + 389.5155
148                // Execution cost: (0.0009622109 * size + 389.5155) * 100 = 0.1 * size + 40,000
149                // See: https://radixdlt.atlassian.net/wiki/spaces/S/pages/3091562563/RocksDB+metrics
150                add(cast(*size) / 10, 40_000)
151            }
152            IOAccess::ReadFromDbNotFound(_) => {
153                // Execution time (µs): varies, using max 1,600
154                // Execution cost: 1,600 * 100
155                // See: https://radixdlt.atlassian.net/wiki/spaces/S/pages/3091562563/RocksDB+metrics
156                160_000
157            }
158            IOAccess::HeapSubstateUpdated { .. } | IOAccess::TrackSubstateUpdated { .. } => {
159                // Heap/track substate total size is limited by limits module.
160                0
161            }
162        }
163    }
164
165    #[inline]
166    pub fn verify_tx_signatures_cost(&self, n: usize) -> u32 {
167        // Based on benchmark `bench_validate_secp256k1`
168        // The cost for validating a single signature is: 67.522 µs * 100 units/µs = 7,000 cost units
169        mul(cast(n), 7_000)
170    }
171
172    #[inline]
173    pub fn validate_tx_payload_cost(&self, size: usize) -> u32 {
174        // Rational:
175        // Transaction payload is propagated over a P2P network.
176        // Larger size may slows down the network performance.
177        // The size of a typical transfer transaction is 400 bytes, and the cost will be 400 * 40 = 16,000 cost units
178        // The max size of a transaction is 1 MiB, and the cost will be 1,048,576 * 40 = 41,943,040 cost units
179        // This is roughly 1/24 of storing data in substate store per current setup.
180        mul(cast(size), 40)
181    }
182
183    #[inline]
184    pub fn check_reference(&self, event: &CheckReferenceEvent) -> u32 {
185        match event {
186            CheckReferenceEvent::IOAccess(io_access) => self.io_access_cost(io_access),
187        }
188    }
189
190    #[inline]
191    pub fn check_intent_validity(&self) -> u32 {
192        // Equivalent to an `IOAccess::ReadFromDbNotFound`
193        160000
194    }
195
196    #[inline]
197    pub fn check_timestamp(&self) -> u32 {
198        // Equivalent to an `IOAccess::ReadFromDb`
199        40_000
200    }
201
202    #[inline]
203    pub fn run_native_code_cost(
204        &self,
205        package_address: &PackageAddress,
206        export_name: &str,
207        input_size: &usize,
208    ) -> u32 {
209        let native_execution_units = NATIVE_FUNCTION_BASE_COSTS
210            .get(package_address)
211            .and_then(|x| x.get(export_name).cloned())
212            .unwrap_or_else(|| {
213                NATIVE_FUNCTION_BASE_COSTS_SIZE_DEPENDENT
214                    .get(package_address)
215                    .and_then(|x| x.get(export_name))
216                    .and_then(|value| Some(add(value.1, mul(value.0, cast(*input_size)))))
217                    .unwrap_or_else(|| {
218                        panic!(
219                            "Native function not found: {:?}::{}. ",
220                            package_address, export_name
221                        )
222                    })
223            });
224
225        native_execution_units / CPU_INSTRUCTIONS_TO_COST_UNIT
226    }
227
228    #[inline]
229    pub fn run_wasm_code_cost(
230        &self,
231        _package_address: &PackageAddress,
232        _export_name: &str,
233        wasm_execution_units: u32,
234    ) -> u32 {
235        wasm_execution_units / self.wasm_execution_units_divider
236    }
237
238    #[inline]
239    pub fn instantiate_wasm_code_cost(&self, size: usize) -> u32 {
240        // From `costing::instantiate_radiswap`, it takes 3.3271 ms to instantiate WASM of length 288406.
241        // Therefore, cost for byte: 3.3271 *  1000 / 203950 * 100 = 1.63133120863
242
243        mul(cast(size), 2)
244    }
245
246    #[inline]
247    pub fn before_invoke_cost(&self, _actor: &Actor, input_size: usize) -> u32 {
248        Self::data_processing_cost(input_size)
249    }
250
251    #[inline]
252    pub fn after_invoke_cost(&self, input_size: usize) -> u32 {
253        Self::data_processing_cost(input_size)
254    }
255
256    #[inline]
257    pub fn allocate_node_id_cost(&self) -> u32 {
258        3312 / CPU_INSTRUCTIONS_TO_COST_UNIT
259    }
260
261    #[inline]
262    pub fn create_node_cost(&self, event: &CreateNodeEvent) -> u32 {
263        match event {
264            CreateNodeEvent::Start(_node_id, node_substates) => {
265                let total_substate_size = node_substates
266                    .values()
267                    .map(|x| x.values().map(|x| x.len()).sum::<usize>())
268                    .sum::<usize>();
269                add(
270                    15510 / CPU_INSTRUCTIONS_TO_COST_UNIT,
271                    Self::data_processing_cost(total_substate_size),
272                )
273            }
274            CreateNodeEvent::IOAccess(io_access) => self.io_access_cost(io_access),
275            CreateNodeEvent::End(..) => 0,
276        }
277    }
278
279    #[inline]
280    pub fn pin_node_cost(&self, _node_id: &NodeId) -> u32 {
281        424 / CPU_INSTRUCTIONS_TO_COST_UNIT
282    }
283
284    #[inline]
285    pub fn drop_node_cost(&self, event: &DropNodeEvent) -> u32 {
286        match event {
287            DropNodeEvent::Start(..) => 0,
288            DropNodeEvent::IOAccess(io_access) => self.io_access_cost(io_access),
289            DropNodeEvent::End(_node_id, node_substates) => {
290                let total_substate_size = node_substates
291                    .values()
292                    .map(|x| x.values().map(|x| x.len()).sum::<usize>())
293                    .sum::<usize>();
294                add(
295                    38883 / CPU_INSTRUCTIONS_TO_COST_UNIT,
296                    Self::data_processing_cost(total_substate_size),
297                )
298            }
299        }
300    }
301
302    #[inline]
303    pub fn move_module_cost(&self, event: &MoveModuleEvent) -> u32 {
304        match event {
305            MoveModuleEvent::IOAccess(io_access) => add(
306                4791 / CPU_INSTRUCTIONS_TO_COST_UNIT,
307                self.io_access_cost(io_access),
308            ),
309        }
310    }
311
312    #[inline]
313    pub fn open_substate_cost(&self, event: &OpenSubstateEvent) -> u32 {
314        match event {
315            OpenSubstateEvent::Start { .. } => 0,
316            OpenSubstateEvent::IOAccess(io_access) => self.io_access_cost(io_access),
317            OpenSubstateEvent::End { size, .. } => add(
318                10318 / CPU_INSTRUCTIONS_TO_COST_UNIT,
319                Self::data_processing_cost(*size),
320            ),
321        }
322    }
323
324    #[inline]
325    pub fn read_substate_cost(&self, event: &ReadSubstateEvent) -> u32 {
326        match event {
327            ReadSubstateEvent::OnRead { value, device, .. } => {
328                let base_cost: u32 = match device {
329                    SubstateDevice::Heap => 2234,
330                    SubstateDevice::Store => 3868,
331                };
332
333                add(
334                    base_cost / CPU_INSTRUCTIONS_TO_COST_UNIT,
335                    Self::data_processing_cost(value.len()),
336                )
337            }
338            ReadSubstateEvent::IOAccess(io_access) => self.io_access_cost(io_access),
339        }
340    }
341
342    #[inline]
343    pub fn write_substate_cost(&self, event: &WriteSubstateEvent) -> u32 {
344        match event {
345            WriteSubstateEvent::IOAccess(io_access) => self.io_access_cost(io_access),
346            WriteSubstateEvent::Start { value, .. } => add(
347                7441 / CPU_INSTRUCTIONS_TO_COST_UNIT,
348                Self::data_processing_cost(value.len()),
349            ),
350        }
351    }
352
353    #[inline]
354    pub fn close_substate_cost(&self, event: &CloseSubstateEvent) -> u32 {
355        match event {
356            CloseSubstateEvent::Start(..) => 4390 / CPU_INSTRUCTIONS_TO_COST_UNIT,
357        }
358    }
359
360    #[inline]
361    pub fn set_substate_cost(&self, event: &SetSubstateEvent) -> u32 {
362        match event {
363            SetSubstateEvent::Start(.., value) => add(
364                4530 / CPU_INSTRUCTIONS_TO_COST_UNIT,
365                Self::data_processing_cost(value.len()),
366            ),
367            SetSubstateEvent::IOAccess(io_access) => self.io_access_cost(io_access),
368        }
369    }
370
371    #[inline]
372    pub fn remove_substate_cost(&self, event: &RemoveSubstateEvent) -> u32 {
373        match event {
374            RemoveSubstateEvent::Start(..) => 24389 / CPU_INSTRUCTIONS_TO_COST_UNIT,
375            RemoveSubstateEvent::IOAccess(io_access) => self.io_access_cost(io_access),
376        }
377    }
378
379    #[inline]
380    pub fn mark_substate_as_transient_cost(
381        &self,
382        _node_id: &NodeId,
383        _partition_number: &PartitionNumber,
384        _substate_key: &SubstateKey,
385    ) -> u32 {
386        1896 / CPU_INSTRUCTIONS_TO_COST_UNIT
387    }
388
389    #[inline]
390    pub fn scan_keys_cost(&self, event: &ScanKeysEvent) -> u32 {
391        match event {
392            ScanKeysEvent::Start => 16938 / CPU_INSTRUCTIONS_TO_COST_UNIT,
393            ScanKeysEvent::IOAccess(io_access) => self.io_access_cost(io_access),
394        }
395    }
396
397    #[inline]
398    pub fn drain_substates_cost(&self, event: &DrainSubstatesEvent) -> u32 {
399        match event {
400            DrainSubstatesEvent::Start(count) => {
401                let cpu_instructions = add(9262, mul(9286, *count));
402                cpu_instructions / CPU_INSTRUCTIONS_TO_COST_UNIT
403            }
404            DrainSubstatesEvent::IOAccess(io_access) => self.io_access_cost(io_access),
405        }
406    }
407
408    #[inline]
409    pub fn scan_sorted_substates_cost(&self, event: &ScanSortedSubstatesEvent) -> u32 {
410        match event {
411            ScanSortedSubstatesEvent::Start => 6369 / CPU_INSTRUCTIONS_TO_COST_UNIT,
412            ScanSortedSubstatesEvent::IOAccess(io_access) => self.io_access_cost(io_access),
413        }
414    }
415
416    #[inline]
417    pub fn get_stack_id(&self) -> u32 {
418        500
419    }
420
421    #[inline]
422    pub fn get_owned_nodes(&self) -> u32 {
423        500
424    }
425
426    #[inline]
427    pub fn switch_stack(&self) -> u32 {
428        500
429    }
430
431    #[inline]
432    pub fn send_to_stack(&self, data_len: usize) -> u32 {
433        500 + Self::data_processing_cost(data_len)
434    }
435
436    #[inline]
437    pub fn set_call_frame_data(&self, data_len: usize) -> u32 {
438        500 + Self::data_processing_cost(data_len)
439    }
440
441    #[inline]
442    pub fn lock_fee_cost(&self) -> u32 {
443        500
444    }
445
446    #[inline]
447    pub fn query_fee_reserve_cost(&self) -> u32 {
448        500
449    }
450
451    #[inline]
452    pub fn query_costing_module(&self) -> u32 {
453        500
454    }
455
456    #[inline]
457    pub fn query_actor_cost(&self) -> u32 {
458        500
459    }
460
461    #[inline]
462    pub fn query_transaction_hash_cost(&self) -> u32 {
463        500
464    }
465
466    #[inline]
467    pub fn generate_ruid_cost(&self) -> u32 {
468        500
469    }
470
471    #[inline]
472    pub fn emit_event_cost(&self, size: usize) -> u32 {
473        500 + Self::data_processing_cost(size)
474    }
475
476    #[inline]
477    pub fn emit_log_cost(&self, size: usize) -> u32 {
478        500 + Self::data_processing_cost(size)
479    }
480
481    #[inline]
482    pub fn encode_bech32_address_cost(&self) -> u32 {
483        500
484    }
485
486    #[inline]
487    pub fn panic_cost(&self, size: usize) -> u32 {
488        500 + Self::data_processing_cost(size)
489    }
490
491    #[inline]
492    pub fn bls12381_v1_verify_cost(&self, size: usize) -> u32 {
493        // Based on  `test_crypto_scrypto_verify_bls12381_v1_costing`
494        // - For sizes less than 1024, instruction count remains the same.
495        // - For greater sizes following linear equation might be applied:
496        //   (used: https://www.socscistatistics.com/tests/regression/default.aspx)
497        //   instructions_cnt = 35.83223 * size + 15563087.39
498        //   Lets round:
499        //    35.83223       -> 36
500        //    15563087.39    -> 15650000 (increased slightly to get the positive difference between
501        //             calculated and measured number of instructions)
502        let size = if size < 1024 { 1024 } else { cast(size) };
503        let instructions_cnt = add(mul(size, 36), 15650000);
504        // Convert to cost units
505        instructions_cnt / CPU_INSTRUCTIONS_TO_COST_UNIT
506    }
507
508    #[inline]
509    pub fn bls12381_v1_aggregate_verify_cost(&self, sizes: &[usize]) -> u32 {
510        // Observed that aggregated verify might be broken down into:
511        // - steps depending on message size
512        //   - aggregation of pairings of each corresponding key and message pair
513        //   - commit each above aggregation
514        // - steps that do not depend on message size
515        //   - read signature from bytes: 281125 instructions
516        //   - signature validation: 583573 instructions
517        //   - aggregated pairing of signature to verify and initialization point: 3027639 instructions
518        //   - final verification: 4280077 instructions
519        //
520        // more details and data in https://docs.google.com/spreadsheets/d/1rV0KyB7UQrg2tOenbh2MQ1fo9MXwrwPFW4l0_CVO-6o/edit?usp=sharing
521
522        // Pairing aggregate
523        // Following linerar equation might be applied:
524        //   (used: https://www.socscistatistics.com/tests/regression/default.aspx)
525        //   instructions_cnt = 34.42199 * size + 2620295.64271
526        //   Lets round:
527        //    34.42199      -> 35
528        //    2620295.64271 -> 2620296
529        //
530        // Also observed that additional 16850000 instructions are performed
531        // every multiple of 8
532        let mut instructions_cnt = 0u32;
533
534        for s in sizes {
535            instructions_cnt = add(add(instructions_cnt, mul(35, cast(*s))), 2620296);
536        }
537        let multiplier = cast(sizes.len() / 8);
538        instructions_cnt = add(instructions_cnt, mul(multiplier, 16850000));
539
540        // Pairing commit
541        // Observed that number commit instructions repeats every multiple of 8
542        instructions_cnt = add(
543            instructions_cnt,
544            match sizes.len() % 8 {
545                0 => 0,
546                1 => 3051556,
547                2 => 5020768,
548                3 => 6990111,
549                4 => 8959454,
550                5 => 10928798,
551                6 => 12898141,
552                7 => 14867484,
553                _ => unreachable!(),
554            },
555        );
556
557        // Instructions that do not depend on size
558        instructions_cnt = add(instructions_cnt, 281125 + 583573 + 3027639 + 4280077);
559
560        // Observed that threaded takes ~1.21 more instructions than no threaded
561        instructions_cnt = mul(instructions_cnt / 100, 121);
562        // Convert to cost units
563        instructions_cnt / CPU_INSTRUCTIONS_TO_COST_UNIT
564    }
565
566    #[inline]
567    pub fn bls12381_v1_fast_aggregate_verify_cost(&self, size: usize, keys_cnt: usize) -> u32 {
568        // Based on  `test_crypto_scrypto_bls12381_v1_fast_aggregate_verify_costing`
569        // - For sizes less than 1024, instruction count remains the same.
570        // - For greater sizes following linear equation might be applied:
571        //   instructions_cnt = 35.008 * size + 626055.4801 * keys_cnt + 15125588.5419
572        //   (used: https://www.socscistatistics.com/tests/multipleregression/default.aspx)
573        //   Lets round:
574        //    35.008        -> 36
575        //    626055.4801   -> 626056
576        //    15125588.5419 -> 15200000  (increased slightly to get the positive difference between
577        //             calculated and measured number of instructions)
578        let size = if size < 1024 { 1024 } else { cast(size) };
579        let instructions_cnt = add(add(mul(size, 36), mul(cast(keys_cnt), 626056)), 15200000);
580        // Convert to cost units
581        instructions_cnt / CPU_INSTRUCTIONS_TO_COST_UNIT
582    }
583
584    #[inline]
585    pub fn bls12381_g2_signature_aggregate_cost(&self, signatures_cnt: usize) -> u32 {
586        // Based on  `test_crypto_scrypto_bls12381_g2_signature_aggregate_costing`
587        // Following linear equation might be applied:
588        //   instructions_cnt = 879553.91557 * signatures_cnt - 567872.58948
589        //   (used: https://www.socscistatistics.com/tests/regression/default.aspx)
590        //   Lets round:
591        //    879553.91557 -> 879554
592        //    567872.5895  -> 500000 (decreased to get more accurate difference between calculated
593        //           and measured instructions)
594        let instructions_cnt = sub(mul(cast(signatures_cnt), 879554), 500000);
595        // Convert to cost units
596        instructions_cnt / CPU_INSTRUCTIONS_TO_COST_UNIT
597    }
598
599    #[inline]
600    pub fn keccak256_hash_cost(&self, size: usize) -> u32 {
601        // Based on  `test_crypto_scrypto_keccak256_costing`
602        // - For sizes less than 100, instruction count remains the same.
603        // - For greater sizes following linear equation might be applied:
604        //   instructions_cnt = 46.41919 * size + 2641.66077
605        //   (used: https://www.socscistatistics.com/tests/regression/default.aspx)
606        //   Lets round:
607        //     46.41919  -> 47
608        //     2641.66077 -> 2642
609        let size = if size < 100 { 100 } else { cast(size) };
610        let instructions_cnt = add(mul(size, 47), 2642);
611        // Convert to cost units
612        instructions_cnt / CPU_INSTRUCTIONS_TO_COST_UNIT
613    }
614
615    #[inline]
616    pub fn blake2b256_hash_cost(&self, size: usize) -> u32 {
617        // Based on  `test_crypto_scrypto_blake2b_256_costing`
618        // - For sizes less than 100, instruction count remains the same.
619        // - For greater sizes following linear equation might be applied:
620        //   instructions_cnt = 14.79642 * size + 1111.02264
621        //   (used: https://www.socscistatistics.com/tests/regression/default.aspx)
622        //   Lets round:
623        //     14.79642  -> 15
624        //     1111.02264 -> 1600 (increased to get more accurate difference between calculated
625        //          and measured instruction)
626        let size = if size < 100 { 100 } else { cast(size) };
627        let instructions_cnt = add(mul(size, 15), 1600);
628        // Convert to cost units
629        instructions_cnt / CPU_INSTRUCTIONS_TO_COST_UNIT
630    }
631
632    #[inline]
633    pub fn ed25519_verify_cost(&self, size: usize) -> u32 {
634        // Based on  `test_crypto_scrypto_verify_ed25519_costing`
635        //   instructions_cnt = 33.08798 * size + 444420.94242
636        //   (used: https://www.socscistatistics.com/tests/regression/default.aspx)
637        //   Lets round:
638        //     33.08798 -> 34
639        //     444420.94242 -> 500000 (increased slightly make sure we get the positive difference between
640        //             calculated and measured number of instructions)
641        let instructions_cnt = add(mul(cast(size), 34), 500000);
642        // Convert to cost units
643        instructions_cnt / CPU_INSTRUCTIONS_TO_COST_UNIT
644    }
645
646    #[inline]
647    pub fn secp256k1_ecdsa_verify_cost(&self) -> u32 {
648        // Based on  `test_crypto_scrypto_verify_secp256k1_ecdsa_costing`
649        //   instructions_cnt = 464236 (input is always 32 bytes long)
650        //   Lets round:
651        //     464236 -> 500000
652        let instructions_cnt = 500000;
653        // Convert to cost units
654        instructions_cnt / CPU_INSTRUCTIONS_TO_COST_UNIT
655    }
656
657    #[inline]
658    pub fn secp256k1_ecdsa_verify_and_key_recover_cost(&self) -> u32 {
659        // Based on  `test_crypto_scrypto_key_recover_secp256k1_ecdsa`
660        //   instructions_cnt = 464236 (input is always 32 bytes long)
661        //   Lets round:
662        //     463506 -> 500000
663        let instructions_cnt = 500000;
664        // Convert to cost units
665        instructions_cnt / CPU_INSTRUCTIONS_TO_COST_UNIT
666    }
667
668    //======================
669    // Finalization costs
670    // This is primarily to account for the additional work on the Node side
671    //======================
672
673    #[inline]
674    pub fn commit_state_updates_cost(&self, store_commit: &StoreCommit) -> u32 {
675        // Committing state time (µs): 0.0025 * size + 1000
676        // Finalization cost: (0.0025 * size + 1000) * 100 = 0.25 * size + 100,000
677        // See: https://radixdlt.atlassian.net/wiki/spaces/S/pages/3091562563/RocksDB+metrics
678        match store_commit {
679            StoreCommit::Insert { size, .. } => add(cast(*size) / 4, 100_000),
680            StoreCommit::Update { size, .. } => add(cast(*size) / 4, 100_000),
681            StoreCommit::Delete { .. } => 100_000,
682        }
683    }
684
685    #[inline]
686    pub fn commit_events_cost(&self, events: &Vec<Event>) -> u32 {
687        let mut sum = 0;
688        for event in events {
689            sum += add(cast(event.payload.len()) / 4, 5_000)
690        }
691        sum
692    }
693
694    #[inline]
695    pub fn commit_logs_cost(&self, logs: &Vec<(Level, String)>) -> u32 {
696        let mut sum = 0;
697        for log in logs {
698            sum += add(cast(log.1.len()) / 4, 1_000)
699        }
700        sum
701    }
702
703    #[inline]
704    pub fn commit_intent_status(&self, num_of_intent_statuses: usize) -> u32 {
705        // Equivalent to a substate insertion
706        mul(cast(num_of_intent_statuses), 100_000)
707    }
708}
709
710#[inline]
711fn cast(a: usize) -> u32 {
712    u32::try_from(a).unwrap_or(u32::MAX)
713}
714
715#[inline]
716fn add(a: u32, b: u32) -> u32 {
717    a.checked_add(b).unwrap_or(u32::MAX)
718}
719
720#[inline]
721fn sub(a: u32, b: u32) -> u32 {
722    a.checked_sub(b).unwrap_or(u32::MAX)
723}
724
725#[inline]
726fn mul(a: u32, b: u32) -> u32 {
727    a.checked_mul(b).unwrap_or(u32::MAX)
728}