Skip to content

Commit 13782eb

Browse files
committed
added ExecutionTimeTracker
1 parent 9eda9c5 commit 13782eb

File tree

3 files changed

+39
-21
lines changed

3 files changed

+39
-21
lines changed

clarity/src/vm/clarity.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,11 @@ pub trait TransactionConnection: ClarityConnection {
304304

305305
self.with_abort_callback(
306306
|vm_env| {
307-
vm_env.context.set_max_execution_time(max_execution_time);
307+
if let Some(max_execution_time_duration) = max_execution_time {
308+
vm_env
309+
.context
310+
.set_max_execution_time(max_execution_time_duration);
311+
}
308312
vm_env
309313
.execute_transaction(
310314
sender.clone(),

clarity/src/vm/contexts.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,17 @@ pub struct EventBatch {
182182
pub events: Vec<StacksTransactionEvent>,
183183
}
184184

185+
/** ExecutionTimeTracker keeps track of how much time a contract call is taking.
186+
It is checked at every eval call.
187+
*/
188+
pub enum ExecutionTimeTracker {
189+
NoTracking,
190+
MaxTime {
191+
start_time: Instant,
192+
max_duration: Duration,
193+
},
194+
}
195+
185196
/** GlobalContext represents the outermost context for a single transaction's
186197
execution. It tracks an asset changes that occurred during the
187198
processing of the transaction, whether or not the current context is read_only,
@@ -200,8 +211,7 @@ pub struct GlobalContext<'a, 'hooks> {
200211
/// This is the chain ID of the transaction
201212
pub chain_id: u32,
202213
pub eval_hooks: Option<Vec<&'hooks mut dyn EvalHook>>,
203-
pub execution_time_tracker: Instant,
204-
pub max_execution_time: Option<Duration>,
214+
pub execution_time_tracker: ExecutionTimeTracker,
205215
}
206216

207217
#[derive(Serialize, Deserialize, Clone)]
@@ -1556,17 +1566,19 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> {
15561566
epoch_id,
15571567
chain_id,
15581568
eval_hooks: None,
1559-
execution_time_tracker: Instant::now(),
1560-
max_execution_time: None,
1569+
execution_time_tracker: ExecutionTimeTracker::NoTracking,
15611570
}
15621571
}
15631572

15641573
pub fn is_top_level(&self) -> bool {
15651574
self.asset_maps.is_empty()
15661575
}
15671576

1568-
pub fn set_max_execution_time(&mut self, max_execution_time: Option<Duration>) {
1569-
self.max_execution_time = max_execution_time
1577+
pub fn set_max_execution_time(&mut self, max_execution_time: Duration) {
1578+
self.execution_time_tracker = ExecutionTimeTracker::MaxTime {
1579+
start_time: Instant::now(),
1580+
max_duration: max_execution_time,
1581+
}
15701582
}
15711583

15721584
fn get_asset_map(&mut self) -> Result<&mut AssetMap> {

clarity/src/vm/mod.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ use self::ast::ContractAST;
6464
use self::costs::ExecutionCost;
6565
use self::diagnostic::Diagnostic;
6666
use crate::vm::callables::CallableType;
67-
use crate::vm::contexts::GlobalContext;
6867
pub use crate::vm::contexts::{
6968
CallStack, ContractContext, Environment, LocalContext, MAX_CONTEXT_DEPTH,
7069
};
70+
use crate::vm::contexts::{ExecutionTimeTracker, GlobalContext};
7171
use crate::vm::costs::cost_functions::ClarityCostFunction;
7272
use crate::vm::costs::{
7373
runtime_cost, CostOverflowingMath, CostTracker, LimitedCostTracker, MemoryConsumer,
@@ -304,11 +304,20 @@ pub fn apply(
304304
}
305305
}
306306

307-
fn check_max_execution_time_expired(global_context: &GlobalContext) -> bool {
308-
if let Some(max_execution_time) = global_context.max_execution_time {
309-
return global_context.execution_time_tracker.elapsed() >= max_execution_time;
307+
fn check_max_execution_time_expired(global_context: &GlobalContext) -> Result<()> {
308+
match global_context.execution_time_tracker {
309+
ExecutionTimeTracker::NoTracking => Ok(()),
310+
ExecutionTimeTracker::MaxTime {
311+
start_time,
312+
max_duration,
313+
} => {
314+
if start_time.elapsed() >= max_duration {
315+
Err(CostErrors::ExecutionTimeExpired.into())
316+
} else {
317+
Ok(())
318+
}
319+
}
310320
}
311-
false
312321
}
313322

314323
pub fn eval(
@@ -320,14 +329,7 @@ pub fn eval(
320329
Atom, AtomValue, Field, List, LiteralValue, TraitReference,
321330
};
322331

323-
if check_max_execution_time_expired(env.global_context) {
324-
warn!(
325-
"ExecutionTime expired while running {:?} ({:?} elapsed)",
326-
exp,
327-
env.global_context.execution_time_tracker.elapsed()
328-
);
329-
return Err(CostErrors::ExecutionTimeExpired.into());
330-
}
332+
check_max_execution_time_expired(env.global_context)?;
331333

332334
if let Some(mut eval_hooks) = env.global_context.eval_hooks.take() {
333335
for hook in eval_hooks.iter_mut() {
@@ -616,7 +618,7 @@ pub fn execute_with_max_execution_time(
616618
ast::ASTRules::PrecheckSize,
617619
false,
618620
|g| {
619-
g.set_max_execution_time(Some(max_execution_time));
621+
g.set_max_execution_time(max_execution_time);
620622
Ok(())
621623
},
622624
)

0 commit comments

Comments
 (0)