Skip to content

Commit cdf1dda

Browse files
authored
Gas profiling contract (#346)
* implemented the gas profilling contract * implemented the gas profilling contract
1 parent 836b5f5 commit cdf1dda

9 files changed

Lines changed: 1021 additions & 7 deletions

File tree

contracts/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ strip = "symbols"
1616
debug-assertions = false
1717
panic = "abort"
1818
codegen-units = 1
19-
lto = true
19+
lto = true

contracts/subscription/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ name = "subtrackr_subscription"
1010
path = "src/lib.rs"
1111
crate-type = ["cdylib", "rlib"]
1212

13+
serde = "1.0"
14+
1315
[dependencies]
1416
soroban-sdk = "21.0.0"
1517
subtrackr-types = { path = "../types" }
Lines changed: 375 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,375 @@
1+
/// Gas Optimization and Targeting Module
2+
/// Provides optimization recommendations and tracks gas targets
3+
4+
use soroban_sdk::{String, Vec, Env};
5+
6+
/// Optimization level
7+
#[derive(Clone, Copy)]
8+
pub enum OptimizationLevel {
9+
Critical, // > 150% of target
10+
High, // 100-150% of target
11+
Medium, // 80-100% of target
12+
Optimal, // < 80% of target
13+
}
14+
15+
impl OptimizationLevel {
16+
pub fn to_string(&self) -> &'static str {
17+
match self {
18+
Self::Critical => "critical",
19+
Self::High => "high",
20+
Self::Medium => "medium",
21+
Self::Optimal => "optimal",
22+
}
23+
}
24+
}
25+
26+
/// Optimization recommendation
27+
#[derive(Clone)]
28+
pub struct OptimizationRecommendation {
29+
pub function_name: String,
30+
pub severity: OptimizationLevel,
31+
pub current_gas: u64,
32+
pub target_gas: u64,
33+
pub potential_savings: u64,
34+
pub recommendation: String,
35+
}
36+
37+
/// Gas optimization targets for each function
38+
pub struct GasOptimizationTargets;
39+
40+
impl GasOptimizationTargets {
41+
/// Get target gas for initialization functions
42+
pub fn initialize_target() -> u64 {
43+
25_000 // Minimal storage setup
44+
}
45+
46+
/// Get target gas for plan creation
47+
pub fn create_plan_target() -> u64 {
48+
75_000 // Multiple storage writes
49+
}
50+
51+
/// Get target gas for subscription
52+
pub fn subscribe_target() -> u64 {
53+
65_000 // Create subscription + index
54+
}
55+
56+
/// Get target gas for charge operation
57+
pub fn charge_subscription_target() -> u64 {
58+
150_000 // Token transfer + storage updates
59+
}
60+
61+
/// Get target gas for cancel subscription
62+
pub fn cancel_subscription_target() -> u64 {
63+
45_000 // Remove from indexes + decrement counts
64+
}
65+
66+
/// Get target gas for pause subscription
67+
pub fn pause_subscription_target() -> u64 {
68+
35_000 // Single storage write
69+
}
70+
71+
/// Get target gas for resume subscription
72+
pub fn resume_subscription_target() -> u64 {
73+
40_000 // Single storage write + time calculation
74+
}
75+
76+
/// Get target gas for request refund
77+
pub fn request_refund_target() -> u64 {
78+
30_000 // Storage write + validation
79+
}
80+
81+
/// Get target gas for approve refund
82+
pub fn approve_refund_target() -> u64 {
83+
35_000 // Storage write + transfer
84+
}
85+
86+
/// Get target gas for request transfer
87+
pub fn request_transfer_target() -> u64 {
88+
25_000 // Storage write
89+
}
90+
91+
/// Get target gas for accept transfer
92+
pub fn accept_transfer_target() -> u64 {
93+
85_000 // Multiple storage operations
94+
}
95+
96+
/// Get target gas for plan query
97+
pub fn get_plan_target() -> u64 {
98+
15_000 // Read from storage
99+
}
100+
101+
/// Get target gas for subscription query
102+
pub fn get_subscription_target() -> u64 {
103+
15_000 // Read from storage
104+
}
105+
106+
/// Get target for user subscriptions query
107+
pub fn get_user_subscriptions_target() -> u64 {
108+
20_000 // Read + iteration
109+
}
110+
111+
/// Get all targets as a map
112+
pub fn all_targets(env: &Env) -> Vec<(String, u64)> {
113+
soroban_sdk::vec![
114+
env,
115+
(String::from_str(env, "initialize"), Self::initialize_target()),
116+
(String::from_str(env, "create_plan"), Self::create_plan_target()),
117+
(String::from_str(env, "subscribe"), Self::subscribe_target()),
118+
(String::from_str(env, "charge_subscription"), Self::charge_subscription_target()),
119+
(String::from_str(env, "cancel_subscription"), Self::cancel_subscription_target()),
120+
(String::from_str(env, "pause_subscription"), Self::pause_subscription_target()),
121+
(String::from_str(env, "resume_subscription"), Self::resume_subscription_target()),
122+
(String::from_str(env, "request_refund"), Self::request_refund_target()),
123+
(String::from_str(env, "approve_refund"), Self::approve_refund_target()),
124+
(String::from_str(env, "request_transfer"), Self::request_transfer_target()),
125+
(String::from_str(env, "accept_transfer"), Self::accept_transfer_target()),
126+
(String::from_str(env, "get_plan"), Self::get_plan_target()),
127+
(String::from_str(env, "get_subscription"), Self::get_subscription_target()),
128+
(String::from_str(env, "get_user_subscriptions"), Self::get_user_subscriptions_target()),
129+
]
130+
}
131+
}
132+
133+
/// Gas optimization strategies and recommendations
134+
pub struct GasOptimizations;
135+
136+
impl GasOptimizations {
137+
/// Get optimization recommendations for a specific function
138+
pub fn get_recommendations_for_function(env: &Env, function_name: &str, current_gas: u64) -> Vec<String> {
139+
let mut recommendations = Vec::new(env);
140+
141+
match function_name {
142+
"create_plan" => {
143+
if current_gas > 100_000 {
144+
recommendations.push_back(String::from_str(
145+
env,
146+
"Consider batch validation of plan parameters before storage writes",
147+
));
148+
}
149+
recommendations.push_back(String::from_str(
150+
env,
151+
"Cache merchant address to reduce lookup operations",
152+
));
153+
}
154+
"charge_subscription" => {
155+
if current_gas > 180_000 {
156+
recommendations.push_back(String::from_str(
157+
env,
158+
"Optimize token transfer: consider using batch transfers for multiple subscriptions",
159+
));
160+
}
161+
recommendations.push_back(String::from_str(
162+
env,
163+
"Consider deferring storage writes to a separate operation",
164+
));
165+
}
166+
"accept_transfer" => {
167+
if current_gas > 110_000 {
168+
recommendations.push_back(String::from_str(
169+
env,
170+
"Reduce vector operations: pre-allocate vector size",
171+
));
172+
}
173+
recommendations.push_back(String::from_str(
174+
env,
175+
"Consider removing vector iteration: use index-based updates",
176+
));
177+
}
178+
"get_user_subscriptions" => {
179+
if current_gas > 25_000 {
180+
recommendations.push_back(String::from_str(
181+
env,
182+
"Consider limiting result set with pagination",
183+
));
184+
}
185+
}
186+
"subscribe" => {
187+
if current_gas > 80_000 {
188+
recommendations.push_back(String::from_str(
189+
env,
190+
"Batch storage operations: combine multiple sets into single storage call",
191+
));
192+
}
193+
}
194+
_ => {
195+
recommendations.push_back(String::from_str(env, "Monitor function for optimization opportunities"));
196+
}
197+
}
198+
199+
recommendations
200+
}
201+
202+
/// Get common optimization strategies
203+
pub fn get_general_optimizations(env: &Env) -> Vec<String> {
204+
let mut optimizations = Vec::new(env);
205+
206+
optimizations.push_back(String::from_str(
207+
env,
208+
"Use persistent instead of instance storage for rarely-accessed data",
209+
));
210+
optimizations.push_back(String::from_str(
211+
env,
212+
"Batch multiple storage operations into single contract calls",
213+
));
214+
optimizations.push_back(String::from_str(
215+
env,
216+
"Cache frequently accessed data in local variables",
217+
));
218+
optimizations.push_back(String::from_str(
219+
env,
220+
"Avoid unnecessary vector iterations when possible",
221+
));
222+
optimizations.push_back(String::from_str(
223+
env,
224+
"Pre-allocate vectors with expected capacity",
225+
));
226+
optimizations.push_back(String::from_str(
227+
env,
228+
"Use efficient data structures for lookups (indices/mappings)",
229+
));
230+
optimizations.push_back(String::from_str(
231+
env,
232+
"Minimize cross-contract calls: batch related operations",
233+
));
234+
optimizations.push_back(String::from_str(
235+
env,
236+
"Use event publishing instead of storage for audit trails",
237+
));
238+
optimizations.push_back(String::from_str(
239+
env,
240+
"Consider time-lock patterns for expensive operations",
241+
));
242+
optimizations.push_back(String::from_str(
243+
env,
244+
"Monitor and break down complex functions into optimizable parts",
245+
));
246+
247+
optimizations
248+
}
249+
250+
/// Categorize gas usage by severity
251+
pub fn categorize_gas_usage(current_gas: u64, target_gas: u64) -> OptimizationLevel {
252+
if current_gas > (target_gas * 150) / 100 {
253+
OptimizationLevel::Critical
254+
} else if current_gas > target_gas {
255+
OptimizationLevel::High
256+
} else if current_gas > (target_gas * 80) / 100 {
257+
OptimizationLevel::Medium
258+
} else {
259+
OptimizationLevel::Optimal
260+
}
261+
}
262+
263+
/// Calculate potential gas savings
264+
pub fn calculate_savings(current_gas: u64, target_gas: u64) -> u64 {
265+
if current_gas > target_gas {
266+
current_gas - target_gas
267+
} else {
268+
0
269+
}
270+
}
271+
}
272+
273+
pub fn get_optimization_priorities(
274+
env: &Env,
275+
gas_metrics: Vec<(String, u64)>,
276+
) -> Vec<(String, u64, String)> {
277+
Vec::new(env)
278+
}
279+
280+
/// Best practices for gas efficiency
281+
pub mod best_practices {
282+
use soroban_sdk::{String, Vec, Env};
283+
284+
pub fn get_storage_best_practices(env: &Env) -> Vec<String> {
285+
let mut practices = Vec::new(env);
286+
287+
practices.push_back(String::from_str(
288+
env,
289+
"Use instance storage for frequently accessed config, persistent for user data",
290+
));
291+
practices.push_back(String::from_str(
292+
env,
293+
"Minimize storage key complexity: use simple types when possible",
294+
));
295+
practices.push_back(String::from_str(
296+
env,
297+
"Batch related updates to reduce total storage operations",
298+
));
299+
practices.push_back(String::from_str(
300+
env,
301+
"Consider denormalization to reduce number of storage reads",
302+
));
303+
304+
practices
305+
}
306+
307+
pub fn get_contract_interaction_best_practices(env: &Env) -> Vec<String> {
308+
let mut practices = Vec::new(env);
309+
310+
practices.push_back(String::from_str(
311+
env,
312+
"Minimize cross-contract calls: combine operations when possible",
313+
));
314+
practices.push_back(String::from_str(
315+
env,
316+
"Cache contract client instances for repeated calls",
317+
));
318+
practices.push_back(String::from_str(
319+
env,
320+
"Batch token operations to reduce call count",
321+
));
322+
practices.push_back(String::from_str(
323+
env,
324+
"Use events for audit trails instead of storage",
325+
));
326+
327+
practices
328+
}
329+
330+
pub fn get_computation_best_practices(env: &Env) -> Vec<String> {
331+
let mut practices = Vec::new(env);
332+
333+
practices.push_back(String::from_str(
334+
env,
335+
"Avoid complex computations in hot paths",
336+
));
337+
practices.push_back(String::from_str(
338+
env,
339+
"Pre-compute complex values outside contract when possible",
340+
));
341+
practices.push_back(String::from_str(
342+
env,
343+
"Use efficient algorithms: O(n) preferred over O(n²)",
344+
));
345+
practices.push_back(String::from_str(
346+
env,
347+
"Short-circuit evaluations to exit early",
348+
));
349+
350+
practices
351+
}
352+
353+
pub fn get_validation_best_practices(env: &Env) -> Vec<String> {
354+
let mut practices = Vec::new(env);
355+
356+
practices.push_back(String::from_str(
357+
env,
358+
"Validate inputs early to fail fast",
359+
));
360+
practices.push_back(String::from_str(
361+
env,
362+
"Use assertions for critical validations",
363+
));
364+
practices.push_back(String::from_str(
365+
env,
366+
"Batch validation of related parameters",
367+
));
368+
practices.push_back(String::from_str(
369+
env,
370+
"Cache validation results when applicable",
371+
));
372+
373+
practices
374+
}
375+
}

0 commit comments

Comments
 (0)