Skip to content

Commit 19b073f

Browse files
Add tests to InvalidCharactersDetected
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent 33b3fd6 commit 19b073f

3 files changed

+225
-3
lines changed

stackslib/src/chainstate/tests/runtime_analysis_tests.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
#[allow(unused_imports)]
1919
use clarity::vm::analysis::CheckErrorKind;
2020
use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier};
21-
use clarity::vm::Value as ClarityValue;
21+
use clarity::vm::{ClarityVersion, Value as ClarityValue};
2222

2323
use crate::chainstate::tests::consensus::{
24-
contract_call_consensus_test, SetupContract, FAUCET_ADDRESS,
24+
contract_call_consensus_test, contract_deploy_consensus_test, SetupContract, FAUCET_ADDRESS,
2525
};
2626

2727
/// Generates a coverage classification report for a specific [`CheckErrorKind`] variant.
@@ -235,7 +235,11 @@ fn variant_coverage_report(variant: CheckErrorKind) {
235235
"Trait method count limits are enforced during deployment; \
236236
oversized traits cannot appear at runtime.",
237237
),
238-
InvalidCharactersDetected | InvalidUTF8Encoding => {
238+
InvalidCharactersDetected => Tested(vec![
239+
invalid_characters_detected_invalid_ascii,
240+
invalid_characters_detected_invalid_utf8
241+
]),
242+
InvalidUTF8Encoding => {
239243
Ignored("Only reachable via legacy v1 parsing paths")
240244
}
241245
WriteAttemptedInReadOnly | AtBlockClosureMustBeReadOnly => Unreachable_Functionally(
@@ -357,3 +361,41 @@ fn bad_trait_implementation_mismatched_args() {
357361
setup_contracts: &[trait_definer, target_contract],
358362
);
359363
}
364+
365+
/// Error: [`CheckErrorKind::InvalidCharactersDetected`]
366+
/// Caused by: deserializing an invalid ascii string using `from-consensus-buf` which eventually calls [`ClarityValue::string_ascii_from_bytes`].
367+
/// Outcome: Block accepted
368+
/// Note: [`CheckErrorKind::InvalidCharactersDetected`] is converted to a serialization error in `inner_deserialize_read` which in turn is
369+
/// converted to `None` in `conversions::from_consensus_buff` during its handling of the result of `try_deserialize_bytes_exact`.
370+
#[test]
371+
fn invalid_characters_detected_invalid_ascii() {
372+
contract_deploy_consensus_test!(
373+
contract_name: "invalid-ascii",
374+
contract_code: "
375+
(define-constant deserialized-invalid-ascii
376+
;; This buffer represents: string-ascii with bytes [0x00, 0x01, 0x02]
377+
;; (0x0d = string-ascii type, 0x00000003 = length 3, then invalid bytes)
378+
(from-consensus-buff? (string-ascii 3) 0x0d00000003000102))
379+
",
380+
exclude_clarity_versions: &[ClarityVersion::Clarity1], // Clarity1 does not support from-consensus-buf?
381+
);
382+
}
383+
384+
/// Error: [`CheckErrorKind::InvalidCharactersDetected`]
385+
/// Caused by: deserializing an invalid utf8 string using `from-consensus-buf` which eventually calls [`ClarityValue::string_utf8_from_bytes`].
386+
/// Outcome: Block accepted
387+
/// Note: [`CheckErrorKind::InvalidCharactersDetected`] is converted to a serialization error in `inner_deserialize_read` which in turn is
388+
/// converted to `None` in `conversions::from_consensus_buff` during its handling of the result of `try_deserialize_bytes_exact`.
389+
#[test]
390+
fn invalid_characters_detected_invalid_utf8() {
391+
contract_deploy_consensus_test!(
392+
contract_name: "invalid-utf8",
393+
contract_code: "
394+
(define-constant deserialized-invalid-utf8
395+
;; This buffer represents: string-utf8 with invalid UTF-8 bytes [0xff, 0xfe]
396+
;; (0x0e = string-utf8 type, 0x00000002 = length 2, then invalid UTF-8)
397+
(from-consensus-buff? (string-utf8 2) 0x0e00000002fffe))
398+
",
399+
exclude_clarity_versions: &[ClarityVersion::Clarity1], // Clarity1 does not support from-consensus-buf?
400+
);
401+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs
3+
expression: result
4+
---
5+
[
6+
Success(ExpectedBlockOutput(
7+
marf_hash: "7079e963a2c4cab5f00fe7ee2c68b3763bc0b842bb330113782ebcd5cffa188c",
8+
evaluated_epoch: Epoch33,
9+
transactions: [
10+
ExpectedTransactionOutput(
11+
tx: "SmartContract(name: invalid-ascii-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))",
12+
vm_error: "None [NON-CONSENSUS BREAKING]",
13+
return_type: Response(ResponseData(
14+
committed: true,
15+
data: Bool(true),
16+
)),
17+
cost: ExecutionCost(
18+
write_length: 327,
19+
write_count: 2,
20+
read_length: 1,
21+
read_count: 1,
22+
runtime: 20596,
23+
),
24+
),
25+
],
26+
total_block_cost: ExecutionCost(
27+
write_length: 327,
28+
write_count: 2,
29+
read_length: 1,
30+
read_count: 1,
31+
runtime: 20596,
32+
),
33+
)),
34+
Success(ExpectedBlockOutput(
35+
marf_hash: "7ca4191a3af9a30567e7e5ff1c35e36930113a23fca96b1b5f15d0c970579525",
36+
evaluated_epoch: Epoch33,
37+
transactions: [
38+
ExpectedTransactionOutput(
39+
tx: "SmartContract(name: invalid-ascii-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))",
40+
vm_error: "None [NON-CONSENSUS BREAKING]",
41+
return_type: Response(ResponseData(
42+
committed: true,
43+
data: Bool(true),
44+
)),
45+
cost: ExecutionCost(
46+
write_length: 327,
47+
write_count: 2,
48+
read_length: 1,
49+
read_count: 1,
50+
runtime: 20596,
51+
),
52+
),
53+
],
54+
total_block_cost: ExecutionCost(
55+
write_length: 327,
56+
write_count: 2,
57+
read_length: 1,
58+
read_count: 1,
59+
runtime: 20596,
60+
),
61+
)),
62+
Success(ExpectedBlockOutput(
63+
marf_hash: "001825f3da07df3e2a6c7e1ffe80327924c7523934e529896f6335da1a46e0cf",
64+
evaluated_epoch: Epoch33,
65+
transactions: [
66+
ExpectedTransactionOutput(
67+
tx: "SmartContract(name: invalid-ascii-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))",
68+
vm_error: "None [NON-CONSENSUS BREAKING]",
69+
return_type: Response(ResponseData(
70+
committed: true,
71+
data: Bool(true),
72+
)),
73+
cost: ExecutionCost(
74+
write_length: 327,
75+
write_count: 2,
76+
read_length: 1,
77+
read_count: 1,
78+
runtime: 20596,
79+
),
80+
),
81+
],
82+
total_block_cost: ExecutionCost(
83+
write_length: 327,
84+
write_count: 2,
85+
read_length: 1,
86+
read_count: 1,
87+
runtime: 20596,
88+
),
89+
)),
90+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs
3+
expression: result
4+
---
5+
[
6+
Success(ExpectedBlockOutput(
7+
marf_hash: "c395a2c99784293377d7e609402a723090a40fe3e9046b2c5978738307020374",
8+
evaluated_epoch: Epoch33,
9+
transactions: [
10+
ExpectedTransactionOutput(
11+
tx: "SmartContract(name: invalid-utf8-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))",
12+
vm_error: "None [NON-CONSENSUS BREAKING]",
13+
return_type: Response(ResponseData(
14+
committed: true,
15+
data: Bool(true),
16+
)),
17+
cost: ExecutionCost(
18+
write_length: 329,
19+
write_count: 2,
20+
read_length: 1,
21+
read_count: 1,
22+
runtime: 20642,
23+
),
24+
),
25+
],
26+
total_block_cost: ExecutionCost(
27+
write_length: 329,
28+
write_count: 2,
29+
read_length: 1,
30+
read_count: 1,
31+
runtime: 20642,
32+
),
33+
)),
34+
Success(ExpectedBlockOutput(
35+
marf_hash: "13a28b3e6e03a0f7df76fe6bf5a0e9ba3b2ea861492c6f733f0bb058cb17f262",
36+
evaluated_epoch: Epoch33,
37+
transactions: [
38+
ExpectedTransactionOutput(
39+
tx: "SmartContract(name: invalid-utf8-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))",
40+
vm_error: "None [NON-CONSENSUS BREAKING]",
41+
return_type: Response(ResponseData(
42+
committed: true,
43+
data: Bool(true),
44+
)),
45+
cost: ExecutionCost(
46+
write_length: 329,
47+
write_count: 2,
48+
read_length: 1,
49+
read_count: 1,
50+
runtime: 20642,
51+
),
52+
),
53+
],
54+
total_block_cost: ExecutionCost(
55+
write_length: 329,
56+
write_count: 2,
57+
read_length: 1,
58+
read_count: 1,
59+
runtime: 20642,
60+
),
61+
)),
62+
Success(ExpectedBlockOutput(
63+
marf_hash: "e00ad089a899f83bce873285ea3511cad79db028794602937bac95ed68e3c569",
64+
evaluated_epoch: Epoch33,
65+
transactions: [
66+
ExpectedTransactionOutput(
67+
tx: "SmartContract(name: invalid-utf8-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))",
68+
vm_error: "None [NON-CONSENSUS BREAKING]",
69+
return_type: Response(ResponseData(
70+
committed: true,
71+
data: Bool(true),
72+
)),
73+
cost: ExecutionCost(
74+
write_length: 329,
75+
write_count: 2,
76+
read_length: 1,
77+
read_count: 1,
78+
runtime: 20642,
79+
),
80+
),
81+
],
82+
total_block_cost: ExecutionCost(
83+
write_length: 329,
84+
write_count: 2,
85+
read_length: 1,
86+
read_count: 1,
87+
runtime: 20642,
88+
),
89+
)),
90+
]

0 commit comments

Comments
 (0)