@@ -23,7 +23,7 @@ use std::{env, thread};
23
23
use clarity:: vm:: types:: PrincipalData ;
24
24
use clarity:: vm:: StacksEpoch ;
25
25
use libsigner:: v0:: messages:: {
26
- BlockRejection , BlockResponse , MessageSlotID , RejectCode , SignerMessage ,
26
+ BlockRejection , BlockResponse , MessageSlotID , MinerSlotID , RejectCode , SignerMessage ,
27
27
} ;
28
28
use libsigner:: { BlockProposal , SignerSession , StackerDBSession } ;
29
29
use rand:: RngCore ;
@@ -36,7 +36,7 @@ use stacks::chainstate::stacks::db::{StacksBlockHeaderTypes, StacksChainState, S
36
36
use stacks:: codec:: StacksMessageCodec ;
37
37
use stacks:: core:: { StacksEpochId , CHAIN_ID_TESTNET } ;
38
38
use stacks:: libstackerdb:: StackerDBChunkData ;
39
- use stacks:: net:: api:: postblock_proposal:: TEST_VALIDATE_STALL ;
39
+ use stacks:: net:: api:: postblock_proposal:: { ValidateRejectCode , TEST_VALIDATE_STALL } ;
40
40
use stacks:: types:: chainstate:: { StacksAddress , StacksBlockId , StacksPrivateKey , StacksPublicKey } ;
41
41
use stacks:: types:: PublicKey ;
42
42
use stacks:: util:: hash:: MerkleHashFunc ;
@@ -51,7 +51,6 @@ use stacks_common::util::sleep_ms;
51
51
use stacks_signer:: chainstate:: { ProposalEvalConfig , SortitionsView } ;
52
52
use stacks_signer:: client:: { SignerSlotID , StackerDB } ;
53
53
use stacks_signer:: config:: { build_signer_config_tomls, GlobalConfig as SignerConfig , Network } ;
54
- use stacks_signer:: runloop:: State ;
55
54
use stacks_signer:: v0:: SpawnedSigner ;
56
55
use tracing_subscriber:: prelude:: * ;
57
56
use tracing_subscriber:: { fmt, EnvFilter } ;
@@ -64,9 +63,8 @@ use crate::nakamoto_node::sign_coordinator::TEST_IGNORE_SIGNERS;
64
63
use crate :: neon:: Counters ;
65
64
use crate :: run_loop:: boot_nakamoto;
66
65
use crate :: tests:: nakamoto_integrations:: {
67
- boot_to_epoch_25, boot_to_epoch_3_reward_set, boot_to_epoch_3_reward_set_calculation_boundary,
68
- next_block_and, setup_epoch_3_reward_set, wait_for, POX_4_DEFAULT_STACKER_BALANCE ,
69
- POX_4_DEFAULT_STACKER_STX_AMT ,
66
+ boot_to_epoch_25, boot_to_epoch_3_reward_set, next_block_and, setup_epoch_3_reward_set,
67
+ wait_for, POX_4_DEFAULT_STACKER_BALANCE , POX_4_DEFAULT_STACKER_STX_AMT ,
70
68
} ;
71
69
use crate :: tests:: neon_integrations:: {
72
70
get_account, get_chain_info, next_block_and_wait, run_until_burnchain_height, submit_tx,
@@ -298,7 +296,9 @@ impl SignerTest<SpawnedSigner> {
298
296
self . mine_nakamoto_block ( timeout) ;
299
297
300
298
// Verify that the signers accepted the proposed block, sending back a validate ok response
301
- let proposed_signer_signature_hash = self . wait_for_validate_ok_response ( timeout) ;
299
+ let proposed_signer_signature_hash = self
300
+ . wait_for_validate_ok_response ( timeout)
301
+ . signer_signature_hash ;
302
302
let message = proposed_signer_signature_hash. 0 ;
303
303
304
304
info ! ( "------------------------- Test Block Signed -------------------------" ) ;
@@ -368,7 +368,7 @@ impl SignerTest<SpawnedSigner> {
368
368
}
369
369
370
370
/// Propose an invalid block to the signers
371
- fn propose_block ( & mut self , slot_id : u32 , version : u32 , block : NakamotoBlock ) {
371
+ fn propose_block ( & mut self , block : NakamotoBlock , timeout : Duration ) {
372
372
let miners_contract_id = boot_code_id ( MINERS_NAME , false ) ;
373
373
let mut session =
374
374
StackerDBSession :: new ( & self . running_nodes . conf . node . rpc_bind , miners_contract_id) ;
@@ -388,17 +388,26 @@ impl SignerTest<SpawnedSigner> {
388
388
. miner
389
389
. mining_key
390
390
. expect ( "No mining key" ) ;
391
-
392
391
// Submit the block proposal to the miner's slot
393
- let mut chunk = StackerDBChunkData :: new ( slot_id, version, message. serialize_to_vec ( ) ) ;
394
- chunk. sign ( & miner_sk) . expect ( "Failed to sign message chunk" ) ;
395
- debug ! ( "Produced a signature: {:?}" , chunk. sig) ;
396
- let result = session. put_chunk ( & chunk) . expect ( "Failed to put chunk" ) ;
397
- debug ! ( "Test Put Chunk ACK: {result:?}" ) ;
398
- assert ! (
399
- result. accepted,
400
- "Failed to submit block proposal to signers"
401
- ) ;
392
+ let mut accepted = false ;
393
+ let mut version = 0 ;
394
+ let slot_id = MinerSlotID :: BlockProposal . to_u8 ( ) as u32 ;
395
+ let start = Instant :: now ( ) ;
396
+ debug ! ( "Proposing invalid block to signers" ) ;
397
+ while !accepted {
398
+ let mut chunk =
399
+ StackerDBChunkData :: new ( slot_id * 2 , version, message. serialize_to_vec ( ) ) ;
400
+ chunk. sign ( & miner_sk) . expect ( "Failed to sign message chunk" ) ;
401
+ debug ! ( "Produced a signature: {:?}" , chunk. sig) ;
402
+ let result = session. put_chunk ( & chunk) . expect ( "Failed to put chunk" ) ;
403
+ accepted = result. accepted ;
404
+ version += 1 ;
405
+ debug ! ( "Test Put Chunk ACK: {result:?}" ) ;
406
+ assert ! (
407
+ start. elapsed( ) < timeout,
408
+ "Timed out waiting for block proposal to be accepted"
409
+ ) ;
410
+ }
402
411
}
403
412
}
404
413
@@ -434,12 +443,10 @@ fn block_proposal_rejection() {
434
443
let short_timeout = Duration :: from_secs ( 30 ) ;
435
444
436
445
info ! ( "------------------------- Send Block Proposal To Signers -------------------------" ) ;
437
- let reward_cycle = signer_test. get_current_reward_cycle ( ) ;
438
446
let proposal_conf = ProposalEvalConfig {
439
447
first_proposal_burn_block_timing : Duration :: from_secs ( 0 ) ,
440
448
block_proposal_timeout : Duration :: from_secs ( 100 ) ,
441
449
} ;
442
- let view = SortitionsView :: fetch_view ( proposal_conf, & signer_test. stacks_client ) . unwrap ( ) ;
443
450
let mut block = NakamotoBlock {
444
451
header : NakamotoBlockHeader :: empty ( ) ,
445
452
txs : vec ! [ ] ,
@@ -448,48 +455,44 @@ fn block_proposal_rejection() {
448
455
// First propose a block to the signers that does not have the correct consensus hash or BitVec. This should be rejected BEFORE
449
456
// the block is submitted to the node for validation.
450
457
let block_signer_signature_hash_1 = block. header . signer_signature_hash ( ) ;
451
- signer_test. propose_block ( 0 , 1 , block. clone ( ) ) ;
458
+ signer_test. propose_block ( block. clone ( ) , short_timeout) ;
459
+
460
+ // Wait for the first block to be mined successfully so we have the most up to date sortition view
461
+ signer_test. wait_for_validate_ok_response ( short_timeout) ;
452
462
453
463
// Propose a block to the signers that passes initial checks but will be rejected by the stacks node
464
+ let view = SortitionsView :: fetch_view ( proposal_conf, & signer_test. stacks_client ) . unwrap ( ) ;
454
465
block. header . pox_treatment = BitVec :: ones ( 1 ) . unwrap ( ) ;
455
466
block. header . consensus_hash = view. cur_sortition . consensus_hash ;
467
+ block. header . chain_length = 35 ; // We have mined 35 blocks so far.
456
468
457
469
let block_signer_signature_hash_2 = block. header . signer_signature_hash ( ) ;
458
- signer_test. propose_block ( 0 , 2 , block ) ;
470
+ signer_test. propose_block ( block , short_timeout ) ;
459
471
460
472
info ! ( "------------------------- Test Block Proposal Rejected -------------------------" ) ;
461
473
// Verify the signers rejected the second block via the endpoint
462
- let rejected_block_hash = signer_test. wait_for_validate_reject_response ( short_timeout) ;
463
- assert_eq ! ( rejected_block_hash, block_signer_signature_hash_2) ;
464
-
465
- let mut stackerdb = StackerDB :: new (
466
- & signer_test. running_nodes . conf . node . rpc_bind ,
467
- StacksPrivateKey :: new ( ) , // We are just reading so don't care what the key is
468
- false ,
469
- reward_cycle,
470
- SignerSlotID ( 0 ) , // We are just reading so again, don't care about index.
471
- ) ;
472
-
473
- let signer_slot_ids: Vec < _ > = signer_test
474
- . get_signer_indices ( reward_cycle)
475
- . iter ( )
476
- . map ( |id| id. 0 )
477
- . collect ( ) ;
478
- assert_eq ! ( signer_slot_ids. len( ) , num_signers) ;
474
+ let reject =
475
+ signer_test. wait_for_validate_reject_response ( short_timeout, block_signer_signature_hash_2) ;
476
+ assert ! ( matches!(
477
+ reject. reason_code,
478
+ ValidateRejectCode :: UnknownParent
479
+ ) ) ;
479
480
480
481
let start_polling = Instant :: now ( ) ;
481
482
let mut found_signer_signature_hash_1 = false ;
482
483
let mut found_signer_signature_hash_2 = false ;
483
484
while !found_signer_signature_hash_1 && !found_signer_signature_hash_2 {
484
485
std:: thread:: sleep ( Duration :: from_secs ( 1 ) ) ;
485
- let messages: Vec < SignerMessage > = StackerDB :: get_messages (
486
- stackerdb
487
- . get_session_mut ( & MessageSlotID :: BlockResponse )
488
- . expect ( "Failed to get BlockResponse stackerdb session" ) ,
489
- & signer_slot_ids,
490
- )
491
- . expect ( "Failed to get message from stackerdb" ) ;
492
- for message in messages {
486
+ let chunks = test_observer:: get_stackerdb_chunks ( ) ;
487
+ for chunk in chunks
488
+ . into_iter ( )
489
+ . map ( |chunk| chunk. modified_slots )
490
+ . flatten ( )
491
+ {
492
+ let Ok ( message) = SignerMessage :: consensus_deserialize ( & mut chunk. data . as_slice ( ) )
493
+ else {
494
+ continue ;
495
+ } ;
493
496
if let SignerMessage :: BlockResponse ( BlockResponse :: Rejected ( BlockRejection {
494
497
reason : _reason,
495
498
reason_code,
@@ -503,10 +506,10 @@ fn block_proposal_rejection() {
503
506
found_signer_signature_hash_2 = true ;
504
507
assert ! ( matches!( reason_code, RejectCode :: ValidationFailed ( _) ) ) ;
505
508
} else {
506
- panic ! ( "Unexpected signer signature hash" ) ;
509
+ continue ;
507
510
}
508
511
} else {
509
- panic ! ( "Unexpected message type" ) ;
512
+ continue ;
510
513
}
511
514
}
512
515
assert ! (
0 commit comments