Skip to main content

rialo_s_fee/
lib.rs

1// Copyright (c) Subzero Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3// This file is either (a) original to Subzero Labs, Inc. or (b) derived from the Anza codebase and modified by Subzero Labs, Inc.
4
5use rialo_s_feature_set::{enable_secp256r1_precompile, FeatureSet};
6use rialo_s_fee_structure::FeeDetails;
7use rialo_s_svm_transaction::svm_message::SVMMessage;
8
9/// Bools indicating the activation of features relevant
10/// to the fee calculation.
11// DEVELOPER NOTE:
12// This struct may become empty at some point. It is preferable to keep it
13// instead of removing, since fees will naturally be changed via feature-gates
14// in the future. Keeping this struct will help keep things organized.
15#[derive(Copy, Clone)]
16pub struct FeeFeatures {
17    pub enable_secp256r1_precompile: bool,
18}
19
20impl From<&FeatureSet> for FeeFeatures {
21    fn from(feature_set: &FeatureSet) -> Self {
22        Self {
23            enable_secp256r1_precompile: feature_set.is_active(&enable_secp256r1_precompile::ID),
24        }
25    }
26}
27
28/// Calculate fee for `SanitizedMessage`
29pub fn calculate_fee(
30    message: &impl SVMMessage,
31    zero_fees_for_test: bool,
32    kelvins_per_signature: u64,
33    prioritization_fee: u64,
34    fee_features: FeeFeatures,
35) -> u64 {
36    calculate_fee_details(
37        message,
38        zero_fees_for_test,
39        kelvins_per_signature,
40        prioritization_fee,
41        fee_features,
42    )
43    .total_fee()
44}
45
46pub fn calculate_fee_details(
47    message: &impl SVMMessage,
48    zero_fees_for_test: bool,
49    kelvins_per_signature: u64,
50    prioritization_fee: u64,
51    fee_features: FeeFeatures,
52) -> FeeDetails {
53    if zero_fees_for_test {
54        return FeeDetails::default();
55    }
56
57    FeeDetails::new(
58        calculate_signature_fee(
59            SignatureCounts::from(message),
60            kelvins_per_signature,
61            fee_features.enable_secp256r1_precompile,
62        ),
63        prioritization_fee,
64    )
65}
66
67/// Calculate fees from signatures.
68fn calculate_signature_fee(
69    SignatureCounts {
70        num_transaction_signatures,
71        num_ed25519_signatures,
72        num_secp256k1_signatures,
73        num_secp256r1_signatures,
74    }: SignatureCounts,
75    kelvins_per_signature: u64,
76    enable_secp256r1_precompile: bool,
77) -> u64 {
78    let signature_count = num_transaction_signatures
79        .saturating_add(num_ed25519_signatures)
80        .saturating_add(num_secp256k1_signatures)
81        .saturating_add(
82            u64::from(enable_secp256r1_precompile).wrapping_mul(num_secp256r1_signatures),
83        );
84    signature_count.saturating_mul(kelvins_per_signature)
85}
86
87struct SignatureCounts {
88    pub num_transaction_signatures: u64,
89    pub num_ed25519_signatures: u64,
90    pub num_secp256k1_signatures: u64,
91    pub num_secp256r1_signatures: u64,
92}
93
94impl<Tx: SVMMessage> From<&Tx> for SignatureCounts {
95    fn from(message: &Tx) -> Self {
96        Self {
97            num_transaction_signatures: message.num_transaction_signatures(),
98            num_ed25519_signatures: message.num_ed25519_signatures(),
99            num_secp256k1_signatures: message.num_secp256k1_signatures(),
100            num_secp256r1_signatures: message.num_secp256r1_signatures(),
101        }
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn test_calculate_signature_fee() {
111        const KELVINS_PER_SIGNATURE: u64 = 5_000;
112
113        // Impossible case - 0 signatures.
114        assert_eq!(
115            calculate_signature_fee(
116                SignatureCounts {
117                    num_transaction_signatures: 0,
118                    num_ed25519_signatures: 0,
119                    num_secp256k1_signatures: 0,
120                    num_secp256r1_signatures: 0,
121                },
122                KELVINS_PER_SIGNATURE,
123                true,
124            ),
125            0
126        );
127
128        // Simple signature
129        assert_eq!(
130            calculate_signature_fee(
131                SignatureCounts {
132                    num_transaction_signatures: 1,
133                    num_ed25519_signatures: 0,
134                    num_secp256k1_signatures: 0,
135                    num_secp256r1_signatures: 0,
136                },
137                KELVINS_PER_SIGNATURE,
138                true,
139            ),
140            KELVINS_PER_SIGNATURE
141        );
142
143        // Pre-compile signatures.
144        assert_eq!(
145            calculate_signature_fee(
146                SignatureCounts {
147                    num_transaction_signatures: 1,
148                    num_ed25519_signatures: 2,
149                    num_secp256k1_signatures: 3,
150                    num_secp256r1_signatures: 4,
151                },
152                KELVINS_PER_SIGNATURE,
153                true,
154            ),
155            10 * KELVINS_PER_SIGNATURE
156        );
157
158        // Pre-compile signatures (no secp256r1)
159        assert_eq!(
160            calculate_signature_fee(
161                SignatureCounts {
162                    num_transaction_signatures: 1,
163                    num_ed25519_signatures: 2,
164                    num_secp256k1_signatures: 3,
165                    num_secp256r1_signatures: 4,
166                },
167                KELVINS_PER_SIGNATURE,
168                false,
169            ),
170            6 * KELVINS_PER_SIGNATURE
171        );
172    }
173}