@@ -37,6 +37,7 @@ use std::time::{Duration, Instant};
37
37
38
38
use clarity:: boot_util:: boot_code_id;
39
39
use clarity:: vm:: types:: PrincipalData ;
40
+ use libsigner:: v0:: messages:: { BlockResponse , RejectCode , SignerMessage } ;
40
41
use libsigner:: { SignerEntries , SignerEventTrait } ;
41
42
use stacks:: chainstate:: coordinator:: comm:: CoordinatorChannels ;
42
43
use stacks:: chainstate:: nakamoto:: signer_set:: NakamotoSigners ;
@@ -46,7 +47,9 @@ use stacks::core::StacksEpoch;
46
47
use stacks:: net:: api:: postblock_proposal:: {
47
48
BlockValidateOk , BlockValidateReject , BlockValidateResponse ,
48
49
} ;
49
- use stacks:: types:: chainstate:: StacksAddress ;
50
+ use stacks:: types:: chainstate:: { StacksAddress , StacksPublicKey } ;
51
+ use stacks:: types:: PublicKey ;
52
+ use stacks:: util:: hash:: MerkleHashFunc ;
50
53
use stacks:: util:: secp256k1:: { MessageSignature , Secp256k1PublicKey } ;
51
54
use stacks_common:: codec:: StacksMessageCodec ;
52
55
use stacks_common:: consts:: SIGNER_SLOTS_PER_USER ;
@@ -678,6 +681,82 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SignerTest<Sp
678
681
assert ! ( signer. stop( ) . is_none( ) ) ;
679
682
}
680
683
}
684
+
685
+ pub fn wait_for_block_acceptance (
686
+ & self ,
687
+ timeout_secs : u64 ,
688
+ signer_signature_hash : & Sha512Trunc256Sum ,
689
+ expected_signers : & [ StacksPublicKey ] ,
690
+ ) -> Result < ( ) , String > {
691
+ // Make sure that ALL signers accepted the block proposal
692
+ wait_for ( timeout_secs, || {
693
+ let signatures = test_observer:: get_stackerdb_chunks ( )
694
+ . into_iter ( )
695
+ . flat_map ( |chunk| chunk. modified_slots )
696
+ . filter_map ( |chunk| {
697
+ let message = SignerMessage :: consensus_deserialize ( & mut chunk. data . as_slice ( ) )
698
+ . expect ( "Failed to deserialize SignerMessage" ) ;
699
+ match message {
700
+ SignerMessage :: BlockResponse ( BlockResponse :: Accepted ( (
701
+ hash,
702
+ signature,
703
+ ) ) ) => {
704
+ if hash == * signer_signature_hash
705
+ && expected_signers. iter ( ) . any ( |pk| {
706
+ pk. verify ( hash. bits ( ) , & signature)
707
+ . expect ( "Failed to verify signature" )
708
+ } )
709
+ {
710
+ Some ( signature)
711
+ } else {
712
+ None
713
+ }
714
+ }
715
+ _ => None ,
716
+ }
717
+ } )
718
+ . collect :: < HashSet < _ > > ( ) ;
719
+ Ok ( signatures. len ( ) == expected_signers. len ( ) )
720
+ } )
721
+ }
722
+
723
+ pub fn wait_for_block_rejections (
724
+ & self ,
725
+ timeout_secs : u64 ,
726
+ expected_signers : & [ StacksPublicKey ] ,
727
+ reject_code : Option < RejectCode > ,
728
+ ) -> Result < ( ) , String > {
729
+ wait_for ( timeout_secs, || {
730
+ let stackerdb_events = test_observer:: get_stackerdb_chunks ( ) ;
731
+ let block_rejections = stackerdb_events
732
+ . into_iter ( )
733
+ . flat_map ( |chunk| chunk. modified_slots )
734
+ . filter_map ( |chunk| {
735
+ let message = SignerMessage :: consensus_deserialize ( & mut chunk. data . as_slice ( ) )
736
+ . expect ( "Failed to deserialize SignerMessage" ) ;
737
+ match message {
738
+ SignerMessage :: BlockResponse ( BlockResponse :: Rejected ( rejection) ) => {
739
+ let rejected_pubkey = rejection
740
+ . recover_public_key ( )
741
+ . expect ( "Failed to recover public key from rejection" ) ;
742
+ if expected_signers. contains ( & rejected_pubkey) {
743
+ if let Some ( reject_code) = reject_code. as_ref ( ) {
744
+ if reject_code != & rejection. reason_code {
745
+ return None ;
746
+ }
747
+ }
748
+ Some ( rejection)
749
+ } else {
750
+ None
751
+ }
752
+ }
753
+ _ => None ,
754
+ }
755
+ } )
756
+ . collect :: < Vec < _ > > ( ) ;
757
+ Ok ( block_rejections. len ( ) == expected_signers. len ( ) )
758
+ } )
759
+ }
681
760
}
682
761
683
762
fn setup_stx_btc_node < G : FnMut ( & mut NeonConfig ) -> ( ) > (
0 commit comments