@@ -627,6 +627,8 @@ pub fn get_signers_db_signer_set_message_id(name: &str) -> Option<(u32, u32)> {
627
627
628
628
#[ cfg( test) ]
629
629
mod tests {
630
+ use blockstack_lib:: chainstate:: nakamoto:: NakamotoBlockHeader ;
631
+
630
632
use super :: * ;
631
633
632
634
#[ test]
@@ -644,4 +646,101 @@ mod tests {
644
646
let name = "signer--2" ;
645
647
assert ! ( get_signers_db_signer_set_message_id( name) . is_none( ) ) ;
646
648
}
649
+
650
+ // Older version of BlockProposal to ensure backwards compatibility
651
+
652
+ #[ derive( Clone , Debug , PartialEq , Serialize , Deserialize ) ]
653
+ /// BlockProposal sent to signers
654
+ pub struct BlockProposalOld {
655
+ /// The block itself
656
+ pub block : NakamotoBlock ,
657
+ /// The burn height the block is mined during
658
+ pub burn_height : u64 ,
659
+ /// The reward cycle the block is mined during
660
+ pub reward_cycle : u64 ,
661
+ }
662
+
663
+ impl StacksMessageCodec for BlockProposalOld {
664
+ fn consensus_serialize < W : Write > ( & self , fd : & mut W ) -> Result < ( ) , CodecError > {
665
+ self . block . consensus_serialize ( fd) ?;
666
+ self . burn_height . consensus_serialize ( fd) ?;
667
+ self . reward_cycle . consensus_serialize ( fd) ?;
668
+ Ok ( ( ) )
669
+ }
670
+
671
+ fn consensus_deserialize < R : Read > ( fd : & mut R ) -> Result < Self , CodecError > {
672
+ let block = NakamotoBlock :: consensus_deserialize ( fd) ?;
673
+ let burn_height = u64:: consensus_deserialize ( fd) ?;
674
+ let reward_cycle = u64:: consensus_deserialize ( fd) ?;
675
+ Ok ( BlockProposalOld {
676
+ block,
677
+ burn_height,
678
+ reward_cycle,
679
+ } )
680
+ }
681
+ }
682
+
683
+ #[ test]
684
+ /// Test that the old version of the code can deserialize the new
685
+ /// version without crashing.
686
+ fn test_old_deserialization_works ( ) {
687
+ let header = NakamotoBlockHeader :: empty ( ) ;
688
+ let block = NakamotoBlock {
689
+ header,
690
+ txs : vec ! [ ] ,
691
+ } ;
692
+ let new_block_proposal = BlockProposal {
693
+ block : block. clone ( ) ,
694
+ burn_height : 1 ,
695
+ reward_cycle : 2 ,
696
+ block_proposal_data : BlockProposalData :: from_current_version ( ) ,
697
+ } ;
698
+ let mut bytes = vec ! [ ] ;
699
+ new_block_proposal. consensus_serialize ( & mut bytes) . unwrap ( ) ;
700
+ let old_block_proposal =
701
+ BlockProposalOld :: consensus_deserialize ( & mut bytes. as_slice ( ) ) . unwrap ( ) ;
702
+ assert_eq ! ( old_block_proposal. block, block) ;
703
+ assert_eq ! (
704
+ old_block_proposal. burn_height,
705
+ new_block_proposal. burn_height
706
+ ) ;
707
+ assert_eq ! (
708
+ old_block_proposal. reward_cycle,
709
+ new_block_proposal. reward_cycle
710
+ ) ;
711
+ // assert_eq!();
712
+ }
713
+
714
+ #[ test]
715
+ /// Test that the old version of the code can be serialized
716
+ /// and then deserialized into the new version.
717
+ fn test_old_proposal_can_deserialize ( ) {
718
+ let header = NakamotoBlockHeader :: empty ( ) ;
719
+ let block = NakamotoBlock {
720
+ header,
721
+ txs : vec ! [ ] ,
722
+ } ;
723
+ let old_block_proposal = BlockProposalOld {
724
+ block : block. clone ( ) ,
725
+ burn_height : 1 ,
726
+ reward_cycle : 2 ,
727
+ } ;
728
+ let mut bytes = vec ! [ ] ;
729
+ old_block_proposal. consensus_serialize ( & mut bytes) . unwrap ( ) ;
730
+ let new_block_proposal =
731
+ BlockProposal :: consensus_deserialize ( & mut bytes. as_slice ( ) ) . unwrap ( ) ;
732
+ assert_eq ! ( new_block_proposal. block, block) ;
733
+ assert_eq ! (
734
+ new_block_proposal. burn_height,
735
+ old_block_proposal. burn_height
736
+ ) ;
737
+ assert_eq ! (
738
+ new_block_proposal. reward_cycle,
739
+ old_block_proposal. reward_cycle
740
+ ) ;
741
+ assert_eq ! (
742
+ new_block_proposal. block_proposal_data. server_version,
743
+ String :: new( )
744
+ ) ;
745
+ }
647
746
}
0 commit comments