@@ -39,6 +39,9 @@ pub enum ApplyError {
3939 /// Height arithmetic overflowed `u32::MAX`.
4040 #[ error( "height overflow at tip {0}" ) ]
4141 HeightOverflow ( u32 ) ,
42+ /// Consensus validation rejected the block.
43+ #[ error( "consensus: {0}" ) ]
44+ Consensus ( #[ from] bitcoin_rs_consensus:: ConsensusError ) ,
4245 /// UTXO commit failed during block apply.
4346 #[ error( "utxo commit: {0}" ) ]
4447 UtxoCommit ( #[ from] bitcoin_rs_utxo:: UtxoError ) ,
@@ -274,13 +277,13 @@ impl NodeState {
274277 crate :: crash_recovery:: write_meta ( self , & meta)
275278 }
276279
277- /// Synthetically applies `block` as the next tip without consensus validation .
280+ /// Applies `block` as the next tip after non-contextual consensus checks .
278281 ///
279282 /// This is the v1 contract: the block hash is taken from the decoded
280283 /// header, the new height is `current_tip.height + 1` (or zero when no
281284 /// tip is published yet), chainwork is approximated by accumulating the
282285 /// block header's own work onto the prior tip's chainwork, and the block
283- /// is stored in `blocks` for RPC consumers. Real consensus validation ,
286+ /// is stored in `blocks` for RPC consumers. Contextual consensus checks ,
284287 /// BIP30 / BIP34 / soft-fork checks, BIP9 deployment state, and reorg
285288 /// planning land in follow-up turns.
286289 ///
@@ -300,7 +303,7 @@ impl NodeState {
300303 bitcoin_rs_chain:: node:: ChainWork :: from_be_bytes ( block. header . work ( ) . to_be_bytes ( ) ) ;
301304
302305 let prior = self . chain_tip . load_full ( ) ;
303- let ( height, chainwork) = match prior {
306+ let ( height, chainwork) = match prior. as_deref ( ) {
304307 Some ( tip) => {
305308 if tip. hash != prev_hash {
306309 return Err ( ApplyError :: PrevHashMismatch {
@@ -317,6 +320,20 @@ impl NodeState {
317320 None => ( 0_u32 , header_work) ,
318321 } ;
319322
323+ let prev_tip_state = match prior. as_deref ( ) {
324+ Some ( tip) => bitcoin_rs_consensus:: rust_path:: TipState {
325+ height : Some ( tip. height ) ,
326+ block_hash : None ,
327+ median_time_past : 0 ,
328+ } ,
329+ None => bitcoin_rs_consensus:: rust_path:: TipState {
330+ height : None ,
331+ block_hash : None ,
332+ median_time_past : 0 ,
333+ } ,
334+ } ;
335+ bitcoin_rs_consensus:: verify_block:: verify_block_rules_borrowed ( block, & prev_tip_state) ?;
336+
320337 let mut changes = BlockChanges :: default ( ) ;
321338 for tx in & block. txdata {
322339 let txid = tx. compute_txid ( ) ;
0 commit comments