1#![cfg_attr(
2 not(feature = "agave-unstable-api"),
3 deprecated(
4 since = "3.1.0",
5 note = "This crate has been marked for formal inclusion in the Agave Unstable API. From \
6 v4.0.0 onward, the `agave-unstable-api` crate feature must be specified to \
7 acknowledge use of an interface that may break without warning."
8 )
9)]
10use {
11 agave_feature_set::{enable_secp256r1_precompile, FeatureSet},
12 solana_fee_structure::FeeDetails,
13 solana_svm_transaction::svm_message::SVMMessage,
14};
15
16#[derive(Copy, Clone)]
23pub struct FeeFeatures {
24 pub enable_secp256r1_precompile: bool,
25}
26
27impl From<&FeatureSet> for FeeFeatures {
28 fn from(feature_set: &FeatureSet) -> Self {
29 Self {
30 enable_secp256r1_precompile: feature_set.is_active(&enable_secp256r1_precompile::ID),
31 }
32 }
33}
34
35pub fn calculate_fee(
37 message: &impl SVMMessage,
38 zero_fees_for_test: bool,
39 lamports_per_signature: u64,
40 prioritization_fee: u64,
41 fee_features: FeeFeatures,
42) -> u64 {
43 calculate_fee_details(
44 message,
45 zero_fees_for_test,
46 lamports_per_signature,
47 prioritization_fee,
48 fee_features,
49 )
50 .total_fee()
51}
52
53pub fn calculate_fee_details(
54 message: &impl SVMMessage,
55 zero_fees_for_test: bool,
56 lamports_per_signature: u64,
57 prioritization_fee: u64,
58 fee_features: FeeFeatures,
59) -> FeeDetails {
60 if zero_fees_for_test {
61 return FeeDetails::default();
62 }
63
64 FeeDetails::new(
65 calculate_signature_fee(
66 SignatureCounts::from(message),
67 lamports_per_signature,
68 fee_features.enable_secp256r1_precompile,
69 ),
70 prioritization_fee,
71 )
72}
73
74pub fn calculate_signature_fee(
76 SignatureCounts {
77 num_transaction_signatures,
78 num_ed25519_signatures,
79 num_secp256k1_signatures,
80 num_secp256r1_signatures,
81 }: SignatureCounts,
82 lamports_per_signature: u64,
83 enable_secp256r1_precompile: bool,
84) -> u64 {
85 let signature_count = num_transaction_signatures
86 .saturating_add(num_ed25519_signatures)
87 .saturating_add(num_secp256k1_signatures)
88 .saturating_add(
89 u64::from(enable_secp256r1_precompile).wrapping_mul(num_secp256r1_signatures),
90 );
91 signature_count.saturating_mul(lamports_per_signature)
92}
93
94pub struct SignatureCounts {
95 pub num_transaction_signatures: u64,
96 pub num_ed25519_signatures: u64,
97 pub num_secp256k1_signatures: u64,
98 pub num_secp256r1_signatures: u64,
99}
100
101impl<Tx: SVMMessage> From<&Tx> for SignatureCounts {
102 fn from(message: &Tx) -> Self {
103 Self {
104 num_transaction_signatures: message.num_transaction_signatures(),
105 num_ed25519_signatures: message.num_ed25519_signatures(),
106 num_secp256k1_signatures: message.num_secp256k1_signatures(),
107 num_secp256r1_signatures: message.num_secp256r1_signatures(),
108 }
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_calculate_signature_fee() {
118 const LAMPORTS_PER_SIGNATURE: u64 = 5_000;
119
120 assert_eq!(
122 calculate_signature_fee(
123 SignatureCounts {
124 num_transaction_signatures: 0,
125 num_ed25519_signatures: 0,
126 num_secp256k1_signatures: 0,
127 num_secp256r1_signatures: 0,
128 },
129 LAMPORTS_PER_SIGNATURE,
130 true,
131 ),
132 0
133 );
134
135 assert_eq!(
137 calculate_signature_fee(
138 SignatureCounts {
139 num_transaction_signatures: 1,
140 num_ed25519_signatures: 0,
141 num_secp256k1_signatures: 0,
142 num_secp256r1_signatures: 0,
143 },
144 LAMPORTS_PER_SIGNATURE,
145 true,
146 ),
147 LAMPORTS_PER_SIGNATURE
148 );
149
150 assert_eq!(
152 calculate_signature_fee(
153 SignatureCounts {
154 num_transaction_signatures: 1,
155 num_ed25519_signatures: 2,
156 num_secp256k1_signatures: 3,
157 num_secp256r1_signatures: 4,
158 },
159 LAMPORTS_PER_SIGNATURE,
160 true,
161 ),
162 10 * LAMPORTS_PER_SIGNATURE
163 );
164
165 assert_eq!(
167 calculate_signature_fee(
168 SignatureCounts {
169 num_transaction_signatures: 1,
170 num_ed25519_signatures: 2,
171 num_secp256k1_signatures: 3,
172 num_secp256r1_signatures: 4,
173 },
174 LAMPORTS_PER_SIGNATURE,
175 false,
176 ),
177 6 * LAMPORTS_PER_SIGNATURE
178 );
179 }
180}