@@ -238,6 +238,7 @@ pub fn build_ast<T: CostTracker>(
238238mod test {
239239 use std:: collections:: HashMap ;
240240
241+ use clarity_types:: types:: MAX_VALUE_SIZE ;
241242 use stacks_common:: types:: StacksEpochId ;
242243
243244 use crate :: vm:: ast:: build_ast;
@@ -447,4 +448,141 @@ mod test {
447448 }
448449 }
449450 }
451+
452+ #[ test]
453+ fn test_build_ast_error_exceeding_cost_balance_due_to_ast_parse ( ) {
454+ let limit = ExecutionCost {
455+ read_count : u64:: MAX ,
456+ write_count : u64:: MAX ,
457+ read_length : u64:: MAX ,
458+ write_length : u64:: MAX ,
459+ runtime : 1 ,
460+ } ;
461+ let mut tracker = LimitedCostTracker :: new_with_limit ( StacksEpochId :: Epoch33 , limit) ;
462+
463+ let err = build_ast (
464+ & QualifiedContractIdentifier :: transient ( ) ,
465+ "(define-constant my-const u1)" ,
466+ & mut tracker,
467+ ClarityVersion :: Clarity4 ,
468+ StacksEpochId :: Epoch33 ,
469+ )
470+ . unwrap_err ( ) ;
471+
472+ assert ! (
473+ matches!( * err. err, ParseErrorKind :: CostBalanceExceeded ( _, _) ) ,
474+ "Instead found: {err}"
475+ ) ;
476+ }
477+
478+ #[ test]
479+ fn test_build_ast_error_exceeding_cost_balance_due_to_ast_cycle_detection_with_0_edges ( ) {
480+ let expected_ast_parse_cost = 1215 ;
481+ let expected_cycle_det_cost = 72 ;
482+ let expected_total = expected_ast_parse_cost + expected_cycle_det_cost;
483+
484+ let limit = ExecutionCost {
485+ read_count : u64:: MAX ,
486+ write_count : u64:: MAX ,
487+ read_length : u64:: MAX ,
488+ write_length : u64:: MAX ,
489+ runtime : expected_ast_parse_cost,
490+ } ;
491+ let mut tracker = LimitedCostTracker :: new_with_limit ( StacksEpochId :: Epoch33 , limit) ;
492+
493+ let err = build_ast (
494+ & QualifiedContractIdentifier :: transient ( ) ,
495+ "(define-constant a 0)(define-constant b 1)" , // no dependency = 0 graph edge
496+ & mut tracker,
497+ ClarityVersion :: Clarity4 ,
498+ StacksEpochId :: Epoch33 ,
499+ )
500+ . expect_err ( "Expected parse error, but found success!" ) ;
501+
502+ let total = match * err. err {
503+ ParseErrorKind :: CostBalanceExceeded ( total, _) => total,
504+ _ => panic ! ( "Expected CostBalanceExceeded, but found: {err}" ) ,
505+ } ;
506+
507+ assert_eq ! ( expected_total, total. runtime) ;
508+ }
509+
510+ #[ test]
511+ fn test_build_ast_error_exceeding_cost_balance_due_to_ast_cycle_detection_with_1_edge ( ) {
512+ let expected_ast_parse_cost = 1215 ;
513+ let expected_cycle_det_cost = 213 ;
514+ let expected_total = expected_ast_parse_cost + expected_cycle_det_cost;
515+
516+ let limit = ExecutionCost {
517+ read_count : u64:: MAX ,
518+ write_count : u64:: MAX ,
519+ read_length : u64:: MAX ,
520+ write_length : u64:: MAX ,
521+ runtime : expected_ast_parse_cost,
522+ } ;
523+ let mut tracker = LimitedCostTracker :: new_with_limit ( StacksEpochId :: Epoch33 , limit) ;
524+
525+ let err = build_ast (
526+ & QualifiedContractIdentifier :: transient ( ) ,
527+ "(define-constant a 0)(define-constant b a)" , // 1 dependency = 1 graph edge
528+ & mut tracker,
529+ ClarityVersion :: Clarity4 ,
530+ StacksEpochId :: Epoch33 ,
531+ )
532+ . expect_err ( "Expected parse error, but found success!" ) ;
533+
534+ let total = match * err. err {
535+ ParseErrorKind :: CostBalanceExceeded ( total, _) => total,
536+ _ => panic ! ( "Expected CostBalanceExceeded, but found: {err}" ) ,
537+ } ;
538+
539+ assert_eq ! ( expected_total, total. runtime) ;
540+ }
541+
542+ #[ test]
543+ fn test_build_ast_error_vary_stack_too_deep ( ) {
544+ // This contract pass the parse v2 MAX_NESTING_DEPTH but fails the [`VaryStackDepthChecker`]
545+ let contract = {
546+ let count = AST_CALL_STACK_DEPTH_BUFFER + ( MAX_CALL_STACK_DEPTH as u64 ) - 1 ;
547+ let body_start = "(list " . repeat ( count as usize ) ;
548+ let body_end = ")" . repeat ( count as usize ) ;
549+ format ! ( "{{ a: {body_start}u1 {body_end} }}" )
550+ } ;
551+
552+ let err = build_ast (
553+ & QualifiedContractIdentifier :: transient ( ) ,
554+ & contract,
555+ & mut ( ) ,
556+ ClarityVersion :: Clarity4 ,
557+ StacksEpochId :: Epoch33 ,
558+ )
559+ . expect_err ( "Expected parse error, but found success!" ) ;
560+
561+ assert ! (
562+ matches!( * err. err, ParseErrorKind :: VaryExpressionStackDepthTooDeep ) ,
563+ "Instead found: {err}"
564+ ) ;
565+ }
566+
567+ #[ test]
568+ fn test_build_ast_error_illegal_ascii_string_due_to_size ( ) {
569+ let contract = {
570+ let string = "a" . repeat ( MAX_VALUE_SIZE as usize + 1 ) ;
571+ format ! ( "(define-constant my-str \" {string}\" )" )
572+ } ;
573+
574+ let err = build_ast (
575+ & QualifiedContractIdentifier :: transient ( ) ,
576+ & contract,
577+ & mut ( ) ,
578+ ClarityVersion :: Clarity4 ,
579+ StacksEpochId :: Epoch33 ,
580+ )
581+ . expect_err ( "Expected parse error, but found success!" ) ;
582+
583+ assert ! (
584+ matches!( * err. err, ParseErrorKind :: IllegalASCIIString ( _) ) ,
585+ "Instead found: {err}"
586+ ) ;
587+ }
450588}
0 commit comments