Skip to content

Commit 0596a3d

Browse files
authored
Merge branch 'develop' into chore/remove-unused-dependencies
2 parents c8e0613 + fb311cb commit 0596a3d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+4964
-1173
lines changed

.gitattributes

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
legacy/* linguist-vendored
2-
* text=lf
2+
# Enforcing 'lf' eol mainly for:
3+
# - 'stx-genesis' package, where txt files need hash computation and comparison
4+
# - 'clarity' package, where clarity language is sensitive to line endings for .clar files
5+
# anyhow, setting eol for all text files to have a homogeneous management over the whole code base
6+
* text eol=lf

.github/workflows/bitcoin-tests.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ jobs:
106106
- test-name: tests::epoch_24::verify_auto_unlock_behavior
107107
# Disable this flaky test. We don't need continue testing Epoch 2 -> 3 transition
108108
- test-name: tests::nakamoto_integrations::flash_blocks_on_epoch_3_FLAKY
109+
# These mempool tests take a long time to run, and are meant to be run manually
110+
- test-name: tests::nakamoto_integrations::large_mempool_original_constant_fee
111+
- test-name: tests::nakamoto_integrations::large_mempool_original_random_fee
112+
- test-name: tests::nakamoto_integrations::large_mempool_next_constant_fee
113+
- test-name: tests::nakamoto_integrations::large_mempool_next_random_fee
114+
- test-name: tests::nakamoto_integrations::larger_mempool
115+
- test-name: tests::signer::v0::larger_mempool
109116

110117
steps:
111118
## Setup test environment

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
},
88
"rust-analyzer.rustfmt.extraArgs": [
99
"+nightly"
10-
]
10+
],
11+
"files.eol": "\n"
1112
}

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
1010
### Added
1111

1212
- Add fee information to transaction log ending with "success" or "skipped", while building a new block
13+
- Add `max_execution_time_secs` to miner config for limiting duration of contract calls
1314
- When a miner's config file is updated (ie with a new fee rate), a new block commit is issued using
1415
the new values ([#5924](https://github.com/stacks-network/stacks-core/pull/5924))
1516

Cargo.lock

Lines changed: 78 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ _Warning, this typically takes a few minutes_
7777
cargo nextest run
7878
```
7979

80+
_On Windows, many tests will fail, mainly due to parallelism. To mitigate the issue you may need to run the tests individually._
81+
8082
## Run the testnet
8183

8284
You can observe the state machine in action locally by running:
@@ -85,8 +87,6 @@ You can observe the state machine in action locally by running:
8587
cargo run --bin stacks-node -- start --config ./sample/conf/testnet-follower-conf.toml
8688
```
8789

88-
_On Windows, many tests will fail if the line endings aren't `LF`. Please ensure that you have git's `core.autocrlf` set to `input` when you clone the repository to avoid any potential issues. This is due to the Clarity language currently being sensitive to line endings._
89-
9090
Additional testnet documentation is available [here](./docs/testnet.md) and [here](https://docs.stacks.co/docs/nodes-and-miners/miner-testnet)
9191

9292
## Release Process

clarity/src/vm/analysis/errors.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ pub enum CheckErrors {
194194

195195
WriteAttemptedInReadOnly,
196196
AtBlockClosureMustBeReadOnly,
197+
198+
// time checker errors
199+
ExecutionTimeExpired,
197200
}
198201

199202
#[derive(Debug, PartialEq)]
@@ -277,6 +280,7 @@ impl From<CostErrors> for CheckErrors {
277280
CheckErrors::Expects("Unexpected interpreter failure in cost computation".into())
278281
}
279282
CostErrors::Expect(s) => CheckErrors::Expects(s),
283+
CostErrors::ExecutionTimeExpired => CheckErrors::ExecutionTimeExpired,
280284
}
281285
}
282286
}
@@ -466,6 +470,7 @@ impl DiagnosableError for CheckErrors {
466470
CheckErrors::UncheckedIntermediaryResponses => "intermediary responses in consecutive statements must be checked".into(),
467471
CheckErrors::CostComputationFailed(s) => format!("contract cost computation failed: {}", s),
468472
CheckErrors::CouldNotDetermineSerializationType => "could not determine the input type for the serialization function".into(),
473+
CheckErrors::ExecutionTimeExpired => "execution time expired".into(),
469474
}
470475
}
471476

clarity/src/vm/ast/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ pub enum ParseErrors {
9292
UnexpectedParserFailure,
9393
/// Should be an unreachable failure which invalidates the transaction
9494
InterpreterFailure,
95+
96+
ExecutionTimeExpired,
9597
}
9698

9799
#[derive(Debug, PartialEq)]
@@ -173,6 +175,7 @@ impl From<CostErrors> for ParseError {
173175
CostErrors::InterpreterFailure | CostErrors::Expect(_) => {
174176
ParseError::new(ParseErrors::InterpreterFailure)
175177
}
178+
CostErrors::ExecutionTimeExpired => ParseError::new(ParseErrors::ExecutionTimeExpired),
176179
}
177180
}
178181
}
@@ -299,6 +302,7 @@ impl DiagnosableError for ParseErrors {
299302
ParseErrors::NoteToMatchThis(token) => format!("to match this '{}'", token),
300303
ParseErrors::UnexpectedParserFailure => "unexpected failure while parsing".to_string(),
301304
ParseErrors::InterpreterFailure => "unexpected failure while parsing".to_string(),
305+
ParseErrors::ExecutionTimeExpired => "max execution time expired".to_string(),
302306
}
303307
}
304308

clarity/src/vm/clarity.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ impl From<CheckError> for Error {
6161
CheckErrors::MemoryBalanceExceeded(_a, _b) => {
6262
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
6363
}
64+
CheckErrors::ExecutionTimeExpired => {
65+
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
66+
}
6467
_ => Error::Analysis(e),
6568
}
6669
}
@@ -75,6 +78,9 @@ impl From<InterpreterError> for Error {
7578
InterpreterError::Unchecked(CheckErrors::CostOverflow) => {
7679
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
7780
}
81+
InterpreterError::Unchecked(CheckErrors::ExecutionTimeExpired) => {
82+
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
83+
}
7884
_ => Error::Interpreter(e),
7985
}
8086
}
@@ -90,6 +96,9 @@ impl From<ParseError> for Error {
9096
ParseErrors::MemoryBalanceExceeded(_a, _b) => {
9197
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
9298
}
99+
ParseErrors::ExecutionTimeExpired => {
100+
Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value())
101+
}
93102
_ => Error::Parse(e),
94103
}
95104
}
@@ -284,6 +293,7 @@ pub trait TransactionConnection: ClarityConnection {
284293
/// abort_call_back is called with an AssetMap and a ClarityDatabase reference,
285294
/// if abort_call_back returns true, all modifications from this transaction will be rolled back.
286295
/// otherwise, they will be committed (though they may later be rolled back if the block itself is rolled back).
296+
#[allow(clippy::too_many_arguments)]
287297
fn run_contract_call<F>(
288298
&mut self,
289299
sender: &PrincipalData,
@@ -292,6 +302,7 @@ pub trait TransactionConnection: ClarityConnection {
292302
public_function: &str,
293303
args: &[Value],
294304
abort_call_back: F,
305+
max_execution_time: Option<std::time::Duration>,
295306
) -> Result<(Value, AssetMap, Vec<StacksTransactionEvent>), Error>
296307
where
297308
F: FnOnce(&AssetMap, &mut ClarityDatabase) -> bool,
@@ -303,6 +314,11 @@ pub trait TransactionConnection: ClarityConnection {
303314

304315
self.with_abort_callback(
305316
|vm_env| {
317+
if let Some(max_execution_time_duration) = max_execution_time {
318+
vm_env
319+
.context
320+
.set_max_execution_time(max_execution_time_duration);
321+
}
306322
vm_env
307323
.execute_transaction(
308324
sender.clone(),
@@ -329,6 +345,7 @@ pub trait TransactionConnection: ClarityConnection {
329345
/// abort_call_back is called with an AssetMap and a ClarityDatabase reference,
330346
/// if abort_call_back returns true, all modifications from this transaction will be rolled back.
331347
/// otherwise, they will be committed (though they may later be rolled back if the block itself is rolled back).
348+
#[allow(clippy::too_many_arguments)]
332349
fn initialize_smart_contract<F>(
333350
&mut self,
334351
identifier: &QualifiedContractIdentifier,
@@ -337,12 +354,18 @@ pub trait TransactionConnection: ClarityConnection {
337354
contract_str: &str,
338355
sponsor: Option<PrincipalData>,
339356
abort_call_back: F,
357+
max_execution_time: Option<std::time::Duration>,
340358
) -> Result<(AssetMap, Vec<StacksTransactionEvent>), Error>
341359
where
342360
F: FnOnce(&AssetMap, &mut ClarityDatabase) -> bool,
343361
{
344362
let (_, asset_map, events, aborted) = self.with_abort_callback(
345363
|vm_env| {
364+
if let Some(max_execution_time_duration) = max_execution_time {
365+
vm_env
366+
.context
367+
.set_max_execution_time(max_execution_time_duration);
368+
}
346369
vm_env
347370
.initialize_contract_from_ast(
348371
identifier.clone(),

clarity/src/vm/contexts.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use std::collections::BTreeMap;
1818
use std::fmt;
1919
use std::mem::replace;
20+
use std::time::{Duration, Instant};
2021

2122
use hashbrown::{HashMap, HashSet};
2223
use serde::Serialize;
@@ -181,6 +182,17 @@ pub struct EventBatch {
181182
pub events: Vec<StacksTransactionEvent>,
182183
}
183184

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+
184196
/** GlobalContext represents the outermost context for a single transaction's
185197
execution. It tracks an asset changes that occurred during the
186198
processing of the transaction, whether or not the current context is read_only,
@@ -199,6 +211,7 @@ pub struct GlobalContext<'a, 'hooks> {
199211
/// This is the chain ID of the transaction
200212
pub chain_id: u32,
201213
pub eval_hooks: Option<Vec<&'hooks mut dyn EvalHook>>,
214+
pub execution_time_tracker: ExecutionTimeTracker,
202215
}
203216

204217
#[derive(Serialize, Deserialize, Clone)]
@@ -1553,13 +1566,21 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> {
15531566
epoch_id,
15541567
chain_id,
15551568
eval_hooks: None,
1569+
execution_time_tracker: ExecutionTimeTracker::NoTracking,
15561570
}
15571571
}
15581572

15591573
pub fn is_top_level(&self) -> bool {
15601574
self.asset_maps.is_empty()
15611575
}
15621576

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+
}
1582+
}
1583+
15631584
fn get_asset_map(&mut self) -> Result<&mut AssetMap> {
15641585
self.asset_maps
15651586
.last_mut()

0 commit comments

Comments
 (0)