1use {
2 solana_feature_set::{enable_secp256r1_precompile, FeatureSet},
3 solana_fee_structure::FeeDetails,
4 solana_svm_transaction::svm_message::SVMMessage,
5};
6
7#[derive(Copy, Clone)]
14pub struct FeeFeatures {
15 pub enable_secp256r1_precompile: bool,
16}
17
18impl From<&FeatureSet> for FeeFeatures {
19 fn from(feature_set: &FeatureSet) -> Self {
20 Self {
21 enable_secp256r1_precompile: feature_set.is_active(&enable_secp256r1_precompile::ID),
22 }
23 }
24}
25
26pub fn calculate_fee(
28 message: &impl SVMMessage,
29 zero_fees_for_test: bool,
30 lamports_per_signature: u64,
31 prioritization_fee: u64,
32 fee_features: FeeFeatures,
33) -> u64 {
34 calculate_fee_details(
35 message,
36 zero_fees_for_test,
37 lamports_per_signature,
38 prioritization_fee,
39 fee_features,
40 )
41 .total_fee()
42}
43
44pub fn calculate_fee_details(
45 message: &impl SVMMessage,
46 zero_fees_for_test: bool,
47 lamports_per_signature: u64,
48 prioritization_fee: u64,
49 fee_features: FeeFeatures,
50) -> FeeDetails {
51 if zero_fees_for_test {
52 return FeeDetails::default();
53 }
54
55 FeeDetails::new(
56 calculate_signature_fee(
57 SignatureCounts::from(message),
58 lamports_per_signature,
59 fee_features.enable_secp256r1_precompile,
60 ),
61 prioritization_fee,
62 )
63}
64
65fn calculate_signature_fee(
67 SignatureCounts {
68 num_transaction_signatures,
69 num_ed25519_signatures,
70 num_secp256k1_signatures,
71 num_secp256r1_signatures,
72 }: SignatureCounts,
73 lamports_per_signature: u64,
74 enable_secp256r1_precompile: bool,
75) -> u64 {
76 let signature_count = num_transaction_signatures
77 .saturating_add(num_ed25519_signatures)
78 .saturating_add(num_secp256k1_signatures)
79 .saturating_add(
80 u64::from(enable_secp256r1_precompile).wrapping_mul(num_secp256r1_signatures),
81 );
82 signature_count.saturating_mul(lamports_per_signature)
83}
84
85struct SignatureCounts {
86 pub num_transaction_signatures: u64,
87 pub num_ed25519_signatures: u64,
88 pub num_secp256k1_signatures: u64,
89 pub num_secp256r1_signatures: u64,
90}
91
92impl<Tx: SVMMessage> From<&Tx> for SignatureCounts {
93 fn from(message: &Tx) -> Self {
94 Self {
95 num_transaction_signatures: message.num_transaction_signatures(),
96 num_ed25519_signatures: message.num_ed25519_signatures(),
97 num_secp256k1_signatures: message.num_secp256k1_signatures(),
98 num_secp256r1_signatures: message.num_secp256r1_signatures(),
99 }
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_calculate_signature_fee() {
109 const LAMPORTS_PER_SIGNATURE: u64 = 5_000;
110
111 assert_eq!(
113 calculate_signature_fee(
114 SignatureCounts {
115 num_transaction_signatures: 0,
116 num_ed25519_signatures: 0,
117 num_secp256k1_signatures: 0,
118 num_secp256r1_signatures: 0,
119 },
120 LAMPORTS_PER_SIGNATURE,
121 true,
122 ),
123 0
124 );
125
126 assert_eq!(
128 calculate_signature_fee(
129 SignatureCounts {
130 num_transaction_signatures: 1,
131 num_ed25519_signatures: 0,
132 num_secp256k1_signatures: 0,
133 num_secp256r1_signatures: 0,
134 },
135 LAMPORTS_PER_SIGNATURE,
136 true,
137 ),
138 LAMPORTS_PER_SIGNATURE
139 );
140
141 assert_eq!(
143 calculate_signature_fee(
144 SignatureCounts {
145 num_transaction_signatures: 1,
146 num_ed25519_signatures: 2,
147 num_secp256k1_signatures: 3,
148 num_secp256r1_signatures: 4,
149 },
150 LAMPORTS_PER_SIGNATURE,
151 true,
152 ),
153 10 * LAMPORTS_PER_SIGNATURE
154 );
155
156 assert_eq!(
158 calculate_signature_fee(
159 SignatureCounts {
160 num_transaction_signatures: 1,
161 num_ed25519_signatures: 2,
162 num_secp256k1_signatures: 3,
163 num_secp256r1_signatures: 4,
164 },
165 LAMPORTS_PER_SIGNATURE,
166 false,
167 ),
168 6 * LAMPORTS_PER_SIGNATURE
169 );
170 }
171}