@@ -533,7 +533,10 @@ mod tests {
533533 use super :: * ;
534534 use crate :: consensus:: encode:: { deserialize, serialize} ;
535535 use crate :: pow:: test_utils:: { u128_to_work, u64_to_work} ;
536+ use crate :: script:: ScriptBuf ;
537+ use crate :: transaction:: { OutPoint , Transaction , TxIn , TxOut , Txid } ;
536538 use crate :: { block, CompactTarget , Network , TestnetVersion } ;
539+ use crate :: { Amount , Sequence , Witness } ;
537540
538541 #[ test]
539542 fn static_vector ( ) {
@@ -781,6 +784,140 @@ mod tests {
781784 assert ! ( segwit_signal. is_signalling_soft_fork( 1 ) ) ;
782785 assert ! ( !segwit_signal. is_signalling_soft_fork( 2 ) ) ;
783786 }
787+
788+ #[ test]
789+ fn block_validation_no_transactions ( ) {
790+ let header = header ( ) ;
791+ let transactions = Vec :: new ( ) ; // Empty transactions
792+
793+ let block = Block :: new_unchecked ( header, transactions) ;
794+ match block. validate ( ) {
795+ Err ( InvalidBlockError :: NoTransactions ) => ( ) ,
796+ other => panic ! ( "Expected NoTransactions error, got: {:?}" , other) ,
797+ }
798+ }
799+
800+ #[ test]
801+ fn block_validation_invalid_coinbase ( ) {
802+ let header = header ( ) ;
803+
804+ // Create a non-coinbase transaction (has a real previous output, not all zeros)
805+ let non_coinbase_tx = Transaction {
806+ version : primitives:: transaction:: Version :: TWO ,
807+ lock_time : crate :: absolute:: LockTime :: ZERO ,
808+ input : vec ! [ TxIn {
809+ previous_output: OutPoint {
810+ txid: Txid :: from_byte_array( [ 1 ; 32 ] ) , // Not all zeros
811+ vout: 0 ,
812+ } ,
813+ script_sig: ScriptBuf :: new( ) ,
814+ sequence: Sequence :: ENABLE_LOCKTIME_AND_RBF ,
815+ witness: Witness :: new( ) ,
816+ } ] ,
817+ output : vec ! [ TxOut { value: Amount :: ONE_BTC , script_pubkey: ScriptBuf :: new( ) } ] ,
818+ } ;
819+
820+ let transactions = vec ! [ non_coinbase_tx] ;
821+ let block = Block :: new_unchecked ( header, transactions) ;
822+
823+ match block. validate ( ) {
824+ Err ( InvalidBlockError :: InvalidCoinbase ) => ( ) ,
825+ other => panic ! ( "Expected InvalidCoinbase error, got: {:?}" , other) ,
826+ }
827+ }
828+
829+ #[ test]
830+ fn block_validation_success_with_coinbase ( ) {
831+ use crate :: constants;
832+
833+ // Use the genesis block which has a valid coinbase
834+ let genesis = constants:: genesis_block ( Network :: Bitcoin ) ;
835+
836+ let header = * genesis. header ( ) ;
837+ let transactions = genesis. transactions ( ) . to_vec ( ) ;
838+
839+ let unchecked_block = Block :: new_unchecked ( header, transactions) ;
840+ let validated_block = unchecked_block. validate ( ) ;
841+
842+ assert ! ( validated_block. is_ok( ) , "Genesis block should validate successfully" ) ;
843+ }
844+
845+ #[ test]
846+ fn checked_block_coinbase_method ( ) {
847+ use crate :: constants;
848+
849+ let genesis = constants:: genesis_block ( Network :: Bitcoin ) ;
850+ let coinbase = genesis. coinbase ( ) ;
851+
852+ // Test that coinbase method returns the expected transaction
853+ let expected_txid = genesis. transactions ( ) [ 0 ] . compute_txid ( ) ;
854+ assert_eq ! ( coinbase. compute_txid( ) , expected_txid) ;
855+ assert_eq ! ( coinbase. wtxid( ) , Wtxid :: COINBASE ) ;
856+
857+ // Test that as_inner() returns the correct transaction
858+ assert_eq ! ( coinbase. as_transaction( ) , & genesis. transactions( ) [ 0 ] ) ;
859+ }
860+
861+ #[ test]
862+ fn block_new_checked_validation ( ) {
863+ use crate :: constants;
864+
865+ // Test successful validation with genesis block
866+ let genesis = constants:: genesis_block ( Network :: Bitcoin ) ;
867+ let header = * genesis. header ( ) ;
868+ let transactions = genesis. transactions ( ) . to_vec ( ) ;
869+
870+ let checked_block = Block :: new_checked ( header, transactions. clone ( ) ) ;
871+ assert ! ( checked_block. is_ok( ) , "Genesis block should validate via new_checked" ) ;
872+
873+ // Test validation failure with empty transactions
874+ let empty_result = Block :: new_checked ( header, Vec :: new ( ) ) ;
875+ match empty_result {
876+ Err ( InvalidBlockError :: NoTransactions ) => ( ) ,
877+ other => panic ! ( "Expected NoTransactions error, got: {:?}" , other) ,
878+ }
879+
880+ // Test validation failure with invalid coinbase
881+ let non_coinbase_tx = Transaction {
882+ version : primitives:: transaction:: Version :: TWO ,
883+ lock_time : crate :: absolute:: LockTime :: ZERO ,
884+ input : vec ! [ TxIn {
885+ previous_output: OutPoint {
886+ txid: Txid :: from_byte_array( [ 1 ; 32 ] ) , // Not all zeros
887+ vout: 0 ,
888+ } ,
889+ script_sig: ScriptBuf :: new( ) ,
890+ sequence: Sequence :: ENABLE_LOCKTIME_AND_RBF ,
891+ witness: Witness :: new( ) ,
892+ } ] ,
893+ output : vec ! [ TxOut { value: Amount :: ONE_BTC , script_pubkey: ScriptBuf :: new( ) } ] ,
894+ } ;
895+
896+ let invalid_coinbase_result = Block :: new_checked ( header, vec ! [ non_coinbase_tx] ) ;
897+ match invalid_coinbase_result {
898+ Err ( InvalidBlockError :: InvalidCoinbase ) => ( ) ,
899+ other => panic ! ( "Expected InvalidCoinbase error, got: {:?}" , other) ,
900+ }
901+ }
902+
903+ #[ test]
904+ fn coinbase_bip34_height_with_coinbase_type ( ) {
905+ // testnet block 100,000
906+ const BLOCK_HEX : & str = "0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc56490000000038ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc055227f1001c29c1ea3b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3703a08601000427f1001c046a510100522cfabe6d6d0000000000000000000068692066726f6d20706f6f6c7365727665726aac1eeeed88ffffffff0100f2052a010000001976a914912e2b234f941f30b18afbb4fa46171214bf66c888ac00000000" ;
907+ let block: Block = deserialize ( & hex ! ( BLOCK_HEX ) ) . unwrap ( ) ;
908+ let block = block. assume_checked ( None ) ;
909+
910+ // Test that BIP34 height extraction works with the Coinbase type
911+ assert_eq ! ( block. bip34_block_height( ) , Ok ( 100_000 ) ) ;
912+
913+ // Test that coinbase method returns a Coinbase type
914+ let coinbase = block. coinbase ( ) ;
915+ assert ! ( coinbase. as_transaction( ) . is_coinbase( ) ) ;
916+
917+ // Test that the coinbase transaction ID matches expected
918+ let cb_txid = "d574f343976d8e70d91cb278d21044dd8a396019e6db70755a0a50e4783dba38" ;
919+ assert_eq ! ( coinbase. compute_txid( ) . to_string( ) , cb_txid) ;
920+ }
784921}
785922
786923#[ cfg( bench) ]
0 commit comments