use crate::{VolatileDataAccess, VolatileDataAccessType, ORACLE_CONTRACT_ADDRESS};
use alloy_primitives::Address;
#[derive(Debug, Clone)]
pub struct VolatileDataAccessTracker {
volatile_data_accessed: VolatileDataAccess,
compute_gas_limit: Option<u64>,
block_env_access_limit: u64,
oracle_access_limit: u64,
disable_depth: Option<usize>,
}
impl VolatileDataAccessTracker {
pub fn new(block_env_access_limit: u64, oracle_access_limit: u64) -> Self {
Self {
volatile_data_accessed: VolatileDataAccess::empty(),
compute_gas_limit: None,
block_env_access_limit,
oracle_access_limit,
disable_depth: None,
}
}
pub fn accessed(&self) -> bool {
!self.volatile_data_accessed.is_empty()
}
pub fn get_volatile_data_info(&self) -> Option<VolatileDataAccess> {
self.accessed().then_some(self.volatile_data_accessed)
}
pub fn get_compute_gas_limit(&self) -> Option<u64> {
self.compute_gas_limit
}
pub fn get_block_env_accesses(&self) -> VolatileDataAccess {
self.volatile_data_accessed.block_env_only()
}
pub fn get_volatile_data_accessed(&self) -> VolatileDataAccess {
self.volatile_data_accessed
}
pub fn mark_block_env_accessed(&mut self, access_type: VolatileDataAccessType) {
self.volatile_data_accessed.insert(access_type.into());
self.apply_or_create_limit(self.block_env_access_limit);
}
pub fn has_accessed_beneficiary_balance(&self) -> bool {
self.volatile_data_accessed.has_beneficiary_balance_access()
}
pub fn mark_beneficiary_balance_accessed(&mut self) {
self.volatile_data_accessed.insert(VolatileDataAccess::BENEFICIARY_BALANCE);
self.apply_or_create_limit(self.block_env_access_limit);
}
pub fn has_accessed_oracle(&self) -> bool {
self.volatile_data_accessed.has_oracle_access()
}
pub fn check_and_mark_oracle_access(&mut self, address: &Address) -> bool {
if address == &ORACLE_CONTRACT_ADDRESS {
self.volatile_data_accessed.insert(VolatileDataAccess::ORACLE);
self.apply_or_create_limit(self.oracle_access_limit);
true
} else {
false
}
}
fn apply_or_create_limit(&mut self, limit: u64) {
if let Some(current_limit) = self.compute_gas_limit {
self.compute_gas_limit = Some(current_limit.min(limit));
} else {
self.compute_gas_limit = Some(limit);
}
}
pub fn disable_access(&mut self, depth: usize) {
match self.disable_depth {
Some(current) if depth >= current => {}
_ => self.disable_depth = Some(depth),
}
}
pub fn volatile_access_disabled(&self, current_depth: usize) -> bool {
self.disable_depth.is_some_and(|d| current_depth >= d)
}
pub fn enable_access(&mut self, caller_depth: usize) -> bool {
match self.disable_depth {
None => true,
Some(d) if caller_depth <= d => {
self.disable_depth = None;
true
}
Some(_) => false,
}
}
pub fn enable_access_if_returning(&mut self, current_depth: usize) {
if self.disable_depth.is_some_and(|d| current_depth < d) {
self.disable_depth = None;
}
}
pub fn reset(&mut self) {
self.volatile_data_accessed = VolatileDataAccess::empty();
self.compute_gas_limit = None;
self.disable_depth = None;
}
}