-
Notifications
You must be signed in to change notification settings - Fork 55
feat(benchmark): add gas and footprint profiling for critical admin operations #277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| use soroban_sdk::{Env, Address}; | ||
| use super::storage::get_admin; | ||
|
|
||
| /// 🔒 Require admin authentication | ||
| pub fn require_admin(env: &Env) -> Address { | ||
| let admin = get_admin(env); | ||
|
|
||
| // Enforce authentication | ||
| admin.require_auth(); | ||
|
|
||
| admin | ||
| } | ||
|
|
||
| /// 🔄 Optional: transfer admin ownership | ||
| pub fn transfer_admin(env: &Env, new_admin: Address) { | ||
| let current_admin = require_admin(env); | ||
|
|
||
| // Prevent accidental self-transfer (optional safety) | ||
| if current_admin == new_admin { | ||
| panic!("New admin must be different"); | ||
| } | ||
|
|
||
| super::storage::set_admin(env, &new_admin); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| pub mod admin; | ||
| pub mod storage; | ||
|
|
||
| // Re-export for easy use | ||
| pub use admin::{require_admin, transfer_admin}; | ||
| pub use storage::{set_admin, get_admin}; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| use soroban_sdk::{Env, Address, Symbol}; | ||
|
|
||
| const ADMIN_KEY: Symbol = Symbol::short("ADMIN"); | ||
|
|
||
| pub fn set_admin(env: &Env, admin: &Address) { | ||
| env.storage().instance().set(&ADMIN_KEY, admin); | ||
| } | ||
|
|
||
| pub fn get_admin(env: &Env) -> Address { | ||
| env.storage() | ||
| .instance() | ||
| .get(&ADMIN_KEY) | ||
| .expect("Admin not initialized") | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| pub mod profiler; | ||
|
|
||
| pub use profiler::{GasProfile}; | ||
| use soroban_sdk::Env; | ||
|
|
||
| /// Measure gas/footprint for a closure | ||
| pub fn profile<F>(env: &Env, f: F) -> GasProfile | ||
| where | ||
| F: FnOnce(), | ||
| { | ||
| let start = GasProfile::new(env); | ||
| f(); | ||
| let end = GasProfile::new(env); | ||
| start.delta(&end) | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,21 @@ | ||||||||||||||||||||||||||
| use soroban_sdk::{Env, BytesN}; | ||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unused import
🧹 Proposed fix-use soroban_sdk::{Env, BytesN};
+use soroban_sdk::Env;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| pub struct GasProfile { | ||||||||||||||||||||||||||
| pub cpu_insns: u64, | ||||||||||||||||||||||||||
| pub mem_bytes: u64, | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| impl GasProfile { | ||||||||||||||||||||||||||
| pub fn new(env: &Env) -> Self { | ||||||||||||||||||||||||||
| let cpu_insns = env.budget().cpu_insns(); | ||||||||||||||||||||||||||
| let mem_bytes = env.budget().mem_bytes(); | ||||||||||||||||||||||||||
| Self { cpu_insns, mem_bytes } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| pub fn delta(&self, after: &GasProfile) -> GasProfile { | ||||||||||||||||||||||||||
| GasProfile { | ||||||||||||||||||||||||||
| cpu_insns: after.cpu_insns - self.cpu_insns, | ||||||||||||||||||||||||||
| mem_bytes: after.mem_bytes - self.mem_bytes, | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
Comment on lines
+15
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unchecked subtraction can panic or silently wrap on underflow. The Consider using 🛡️ Proposed fix using saturating subtraction pub fn delta(&self, after: &GasProfile) -> GasProfile {
GasProfile {
- cpu_insns: after.cpu_insns - self.cpu_insns,
- mem_bytes: after.mem_bytes - self.mem_bytes,
+ cpu_insns: after.cpu_insns.saturating_sub(self.cpu_insns),
+ mem_bytes: after.mem_bytes.saturating_sub(self.mem_bytes),
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider requiring
new_admin.require_auth()for two-sided authorization.The
transfer_adminfunction only authenticates the current admin, not the new admin. This allows transferring ownership to any address without the recipient's consent, which could lead to:Per the relevant code snippets, sibling contracts (
staking,multisig) use a two-sided pattern where the admin authenticates themselves during initialization. Consider requiringnew_admin.require_auth()to ensure the recipient can control the address before accepting ownership.🔒 Proposed fix for two-sided authorization
pub fn transfer_admin(env: &Env, new_admin: Address) { let current_admin = require_admin(env); // Prevent accidental self-transfer (optional safety) if current_admin == new_admin { panic!("New admin must be different"); } + // Require new admin to consent to ownership transfer + new_admin.require_auth(); + super::storage::set_admin(env, &new_admin); }📝 Committable suggestion
🤖 Prompt for AI Agents