Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions stacks-node/src/tests/neon_integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9608,3 +9608,110 @@ fn mock_miner_replay() {
miner_channel.stop_chains_coordinator();
follower_channel.stop_chains_coordinator();
}

#[test]
#[ignore]
fn least_supertype_test() {
Copy link
Contributor

@jacinta-stacks jacinta-stacks Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is nothing wrong with this, but it might be better suited as a ConsensusTest.

For e.g. this could reduce to:

contract_deploy_consensus_test!(
    chainstate_error_expression_stack_depth_too_deep,
    contract_name: "test-exceeds",
    contract_code: "(define-data-var my-list (list 10 { a: int }) (list { a: 1 }))
(var-set my-list
  (unwrap! (as-max-len?
    (append (var-get my-list)
            { a: 2, b: 2 })
    u10)
  (err  1)))
(print (var-get my-list))
",
);

And the output snapshot will basically show that for both Epoch 3.2 and Epoch 3.3 the transaction publish fails and with what error specifically.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, that certainly is concise! I don't like that there is no explicit check that the contract is not deployed in the test. I guess that would show up in the snapshot though? I still haven't looked into how these tests work exactly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it would show that the transaction itself fails with an error. If you want I can run through it with you :)

if env::var("BITCOIND_TEST") != Ok("1".into()) {
return;
}

// the contract that we want to make sure is not published
let caller_src = "
(define-data-var my-list (list 10 { a: int }) (list { a: 1 }))
(var-set my-list
(unwrap! (as-max-len?
(append (var-get my-list)
{ a: 2, b: 2 })
u10)
(err 1)))
(print (var-get my-list))
";

let spender_sk = StacksPrivateKey::random();
let spender_addr = to_addr(&spender_sk);
let spender_princ: PrincipalData = spender_addr.clone().into();

let (mut conf, _miner_account) = neon_integration_test_conf();

test_observer::spawn();

conf.events_observers.insert(EventObserverConfig {
endpoint: format!("localhost:{}", test_observer::EVENT_OBSERVER_PORT),
events_keys: vec![EventKeyType::AnyEvent],
timeout_ms: 1_000,
disable_retries: false,
});

let spender_bal = 10_000_000_000 * (core::MICROSTACKS_PER_STACKS as u64);

conf.initial_balances.push(InitialBalance {
address: spender_princ,
amount: spender_bal,
});

let mut btcd_controller = BitcoinCoreController::from_stx_config(&conf);
btcd_controller
.start_bitcoind()
.expect("Failed starting bitcoind");

let burnchain_config = Burnchain::regtest(&conf.get_burn_db_path());

let mut btc_regtest_controller = BitcoinRegtestController::with_burnchain(
conf.clone(),
None,
Some(burnchain_config.clone()),
None,
);
let http_origin = format!("http://{}", &conf.node.rpc_bind);

btc_regtest_controller.bootstrap_chain(201);

eprintln!("Chain bootstrapped...");

let mut run_loop = neon::RunLoop::new(conf.clone());
let blocks_processed = run_loop.get_blocks_processed_arc();
let _client = reqwest::blocking::Client::new();
let channel = run_loop.get_coordinator_channel().unwrap();

thread::spawn(move || run_loop.start(Some(burnchain_config), 0));

// give the run loop some time to start up!
wait_for_runloop(&blocks_processed);

// first block wakes up the run loop
next_block_and_wait(&mut btc_regtest_controller, &blocks_processed);

// first block will hold our VRF registration
next_block_and_wait(&mut btc_regtest_controller, &blocks_processed);

// second block will be the first mined Stacks block
next_block_and_wait(&mut btc_regtest_controller, &blocks_processed);

let _sort_height = channel.get_sortitions_processed();

let publish = make_contract_publish(
&spender_sk,
0,
1000,
conf.burnchain.chain_id,
"caller",
caller_src,
);

let txid = submit_tx(&http_origin, &publish);
println!("Submitted contract publish txid: {txid}");

// mine 1 burn block for the miner to issue the next block
next_block_and_wait(&mut btc_regtest_controller, &blocks_processed);
// mine next burn block for the miner to win
next_block_and_wait(&mut btc_regtest_controller, &blocks_processed);

// clear and mine another burnchain block, so that the new winner is seen by the observer
// (the observer is logically "one block behind" the miner
next_block_and_wait(&mut btc_regtest_controller, &blocks_processed);

// Ensure that the transaction was not mined by checking the account nonce
let account = get_account(&http_origin, &spender_addr);
assert_eq!(account.nonce, 0);
}
Loading