Skip to content

Commit b6fc3ff

Browse files
committed
Add a ExpressionStackDepthTooDeep test
Signed-off-by: Jacinta Ferrant <jacinta.ferrant@gmail.com>
1 parent c245ce4 commit b6fc3ff

File tree

1 file changed

+63
-4
lines changed

1 file changed

+63
-4
lines changed

stackslib/src/chainstate/tests/consensus.rs

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ use clarity::types::chainstate::{StacksAddress, StacksPrivateKey, StacksPublicKe
1919
use clarity::types::StacksEpochId;
2020
use clarity::util::hash::{MerkleTree, Sha512Trunc256Sum};
2121
use 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;
2224
use clarity::vm::costs::ExecutionCost;
2325
use clarity::vm::events::StacksTransactionEvent;
2426
use clarity::vm::types::{PrincipalData, ResponseData};
25-
use clarity::vm::Value as ClarityValue;
27+
use clarity::vm::{Value as ClarityValue, MAX_CALL_STACK_DEPTH};
2628
use serde::{Deserialize, Serialize};
2729
use stacks_common::bitvec::BitVec;
2830

@@ -32,10 +34,9 @@ use crate::chainstate::stacks::boot::{RewardSet, RewardSetData};
3234
use crate::chainstate::stacks::db::StacksEpochReceipt;
3335
use crate::chainstate::stacks::{Error as ChainstateError, StacksTransaction, TenureChangeCause};
3436
use 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};
3739
use crate::net::tests::NakamotoBootPlan;
38-
3940
pub const SK_1: &str = "a1289f6438855da7decf9b61b852c882c398cff1446b2a0f823538aa2ebef92e01";
4041
pub const SK_2: &str = "4ce9a8f7539ea93753a36405b16e8b57e15a552430410709c2b6d65dca5c02e201";
4142
pub 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

Comments
 (0)