Skip to content

Commit e566692

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

File tree

1 file changed

+64
-4
lines changed

1 file changed

+64
-4
lines changed

stackslib/src/chainstate/tests/consensus.rs

Lines changed: 64 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";
@@ -207,6 +208,7 @@ impl ConsensusMismatch {
207208
(Err(actual_err), ExpectedResult::Failure(expected_err)) => {
208209
let actual_err_str = actual_err.to_string();
209210
if actual_err_str != expected_err {
211+
panic!("actual_err_str: {actual_err_str}");
210212
mismatches.error = Some((actual_err_str, expected_err));
211213
}
212214
}
@@ -487,3 +489,61 @@ fn test_append_stx_transfers() {
487489
};
488490
ConsensusTest::new(function_name!(), test_vector).run()
489491
}
492+
493+
#[test]
494+
fn test_append_chainstate_error_expression_stack_depth_too_deep() {
495+
// something just over the limit of the expression depth
496+
let exceeds_repeat_factor = AST_CALL_STACK_DEPTH_BUFFER + (MAX_CALL_STACK_DEPTH as u64);
497+
let tx_exceeds_body_start = "{ a : ".repeat(exceeds_repeat_factor as usize);
498+
let tx_exceeds_body_end = "} ".repeat(exceeds_repeat_factor as usize);
499+
let tx_exceeds_body = format!("{tx_exceeds_body_start}u1 {tx_exceeds_body_end}");
500+
501+
let sender_privk = StacksPrivateKey::from_hex(SK_1).unwrap();
502+
let tx_fee = (tx_exceeds_body.len() * 100) as u64;
503+
let initial_balances = vec![(
504+
StacksAddress::p2pkh(false, &StacksPublicKey::from_private(&sender_privk)).into(),
505+
tx_fee,
506+
)];
507+
let tx_bytes = make_contract_publish(
508+
&sender_privk,
509+
0,
510+
tx_fee,
511+
CHAIN_ID_TESTNET,
512+
"test-exceeds",
513+
&tx_exceeds_body,
514+
);
515+
let tx = StacksTransaction::consensus_deserialize(&mut &tx_bytes[..]).unwrap();
516+
let transfer_result = ExpectedTransactionOutput {
517+
return_type: ClarityValue::Response(ResponseData {
518+
committed: true,
519+
data: Box::new(ClarityValue::Bool(true)),
520+
}),
521+
cost: ExecutionCost {
522+
write_length: 0,
523+
write_count: 0,
524+
read_length: 0,
525+
read_count: 0,
526+
runtime: 0,
527+
},
528+
};
529+
let outputs = ExpectedBlockOutput {
530+
transactions: vec![transfer_result],
531+
total_block_cost: ExecutionCost::ZERO,
532+
};
533+
// TODO: should look into append_block. It does weird wrapping of ChainstateError variants inside ChainstateError::StacksInvalidBlock.
534+
let e = ChainstateError::ClarityError(ClarityError::Parse(ParseError::new(
535+
ParseErrors::ExpressionStackDepthTooDeep,
536+
)));
537+
let msg = format!("Invalid Stacks block 518dfea674b5c4874e025a31e01a522c8269005c0685d12658f0359757de6692: {e:?}");
538+
let test_vector = ConsensusTestVector {
539+
initial_balances,
540+
// Marf hash doesn't matter. It will fail with ExpressionStackDepthTooDeep
541+
marf_hash: "0000000000000000000000000000000000000000000000000000000000000000".into(),
542+
epoch_id: StacksEpochId::Epoch30 as u32,
543+
transactions: vec![tx],
544+
expected_result: ExpectedResult::Failure(
545+
ChainstateError::InvalidStacksBlock(msg).to_string(),
546+
),
547+
};
548+
ConsensusTest::new(function_name!(), test_vector).run()
549+
}

0 commit comments

Comments
 (0)