@@ -19,10 +19,12 @@ use clarity::types::chainstate::{StacksAddress, StacksPrivateKey, StacksPublicKe
1919use clarity:: types:: StacksEpochId ;
2020use clarity:: util:: hash:: { MerkleTree , Sha512Trunc256Sum } ;
2121use clarity:: util:: secp256k1:: MessageSignature ;
22+ use clarity:: vm:: ast:: errors:: { ParseError , ParseErrors } ;
23+ use clarity:: vm:: ast:: stack_depth_checker:: AST_CALL_STACK_DEPTH_BUFFER ;
2224use clarity:: vm:: costs:: ExecutionCost ;
2325use clarity:: vm:: events:: StacksTransactionEvent ;
2426use clarity:: vm:: types:: { PrincipalData , ResponseData } ;
25- use clarity:: vm:: Value as ClarityValue ;
27+ use clarity:: vm:: { Value as ClarityValue , MAX_CALL_STACK_DEPTH } ;
2628use serde:: { Deserialize , Serialize } ;
2729use stacks_common:: bitvec:: BitVec ;
2830
@@ -32,10 +34,9 @@ use crate::chainstate::stacks::boot::{RewardSet, RewardSetData};
3234use crate :: chainstate:: stacks:: db:: StacksEpochReceipt ;
3335use crate :: chainstate:: stacks:: { Error as ChainstateError , StacksTransaction , TenureChangeCause } ;
3436use crate :: chainstate:: tests:: TestChainstate ;
35- use crate :: clarity_vm:: clarity:: PreCommitClarityBlock ;
36- use crate :: core:: test_util:: make_stacks_transfer_tx;
37+ use crate :: clarity_vm:: clarity:: { Error as ClarityError , PreCommitClarityBlock } ;
38+ use crate :: core:: test_util:: { make_contract_publish , make_stacks_transfer_tx} ;
3739use crate :: net:: tests:: NakamotoBootPlan ;
38-
3940pub const SK_1 : & str = "a1289f6438855da7decf9b61b852c882c398cff1446b2a0f823538aa2ebef92e01" ;
4041pub const SK_2 : & str = "4ce9a8f7539ea93753a36405b16e8b57e15a552430410709c2b6d65dca5c02e201" ;
4142pub const SK_3 : & str = "cb95ddd0fe18ec57f4f3533b95ae564b3f1ae063dbf75b46334bd86245aef78501" ;
@@ -487,3 +488,61 @@ fn test_append_stx_transfers() {
487488 } ;
488489 ConsensusTest :: new ( function_name ! ( ) , test_vector) . run ( )
489490}
491+
492+ #[ test]
493+ fn test_append_chainstate_error_expression_stack_depth_too_deep ( ) {
494+ // something just over the limit of the expression depth
495+ let exceeds_repeat_factor = AST_CALL_STACK_DEPTH_BUFFER + ( MAX_CALL_STACK_DEPTH as u64 ) ;
496+ let tx_exceeds_body_start = "{ a : " . repeat ( exceeds_repeat_factor as usize ) ;
497+ let tx_exceeds_body_end = "} " . repeat ( exceeds_repeat_factor as usize ) ;
498+ let tx_exceeds_body = format ! ( "{tx_exceeds_body_start}u1 {tx_exceeds_body_end}" ) ;
499+
500+ let sender_privk = StacksPrivateKey :: from_hex ( SK_1 ) . unwrap ( ) ;
501+ let tx_fee = ( tx_exceeds_body. len ( ) * 100 ) as u64 ;
502+ let initial_balances = vec ! [ (
503+ StacksAddress :: p2pkh( false , & StacksPublicKey :: from_private( & sender_privk) ) . into( ) ,
504+ tx_fee,
505+ ) ] ;
506+ let tx_bytes = make_contract_publish (
507+ & sender_privk,
508+ 0 ,
509+ tx_fee,
510+ CHAIN_ID_TESTNET ,
511+ "test-exceeds" ,
512+ & tx_exceeds_body,
513+ ) ;
514+ let tx = StacksTransaction :: consensus_deserialize ( & mut & tx_bytes[ ..] ) . unwrap ( ) ;
515+ let transfer_result = ExpectedTransactionOutput {
516+ return_type : ClarityValue :: Response ( ResponseData {
517+ committed : true ,
518+ data : Box :: new ( ClarityValue :: Bool ( true ) ) ,
519+ } ) ,
520+ cost : ExecutionCost {
521+ write_length : 0 ,
522+ write_count : 0 ,
523+ read_length : 0 ,
524+ read_count : 0 ,
525+ runtime : 0 ,
526+ } ,
527+ } ;
528+ let outputs = ExpectedBlockOutput {
529+ transactions : vec ! [ transfer_result] ,
530+ total_block_cost : ExecutionCost :: ZERO ,
531+ } ;
532+ // TODO: should look into append_block. It does weird wrapping of ChainstateError variants inside ChainstateError::StacksInvalidBlock.
533+ let e = ChainstateError :: ClarityError ( ClarityError :: Parse ( ParseError :: new (
534+ ParseErrors :: ExpressionStackDepthTooDeep ,
535+ ) ) ) ;
536+ let msg = format ! ( "Invalid Stacks block 518dfea674b5c4874e025a31e01a522c8269005c0685d12658f0359757de6692: {e:?}" ) ;
537+ let test_vector = ConsensusTestVector {
538+ initial_balances,
539+ // Marf hash doesn't matter. It will fail with ExpressionStackDepthTooDeep
540+ marf_hash : "0000000000000000000000000000000000000000000000000000000000000000" . into ( ) ,
541+ epoch_id : StacksEpochId :: Epoch30 as u32 ,
542+ transactions : vec ! [ tx] ,
543+ expected_result : ExpectedResult :: Failure (
544+ ChainstateError :: InvalidStacksBlock ( msg) . to_string ( ) ,
545+ ) ,
546+ } ;
547+ ConsensusTest :: new ( function_name ! ( ) , test_vector) . run ( )
548+ }
0 commit comments