@@ -6,8 +6,8 @@ use sneed::{RoTxn, RwTxn};
66use crate :: {
77 state:: { Error , PrevalidatedBlock , State , amm, dutch_auction, error} ,
88 types:: {
9- AmountOverflowError , Authorization , BitAssetId , BlockHash , Body ,
10- FilledOutput , FilledOutputContent , GetAddress as _,
9+ AddressOutPointKey , AmountOverflowError , Authorization , BitAssetId ,
10+ BlockHash , Body , FilledOutput , FilledOutputContent , GetAddress as _,
1111 GetBitcoinValue as _, Hash , Header , InPoint , OutPoint , OutPointKey ,
1212 OutputContent , SpentOutput , TxData , Verify as _,
1313 } ,
@@ -207,8 +207,6 @@ pub fn connect_prevalidated(
207207 . sum :: < usize > ( )
208208 + body. coinbase . len ( ) ;
209209
210- // Use Vec + sort_unstable instead of individual DB operations for better performance
211- let mut utxo_deletes: Vec < OutPointKey > = Vec :: with_capacity ( total_inputs) ;
212210 let mut stxo_puts: Vec < ( OutPointKey , SpentOutput ) > =
213211 Vec :: with_capacity ( total_inputs) ;
214212 let mut utxo_puts: Vec < ( OutPointKey , FilledOutput ) > =
@@ -263,7 +261,6 @@ pub fn connect_prevalidated(
263261 vin : vin as u32 ,
264262 } ,
265263 } ;
266- utxo_deletes. push ( key) ;
267264 stxo_puts. push ( ( key, spent_output) ) ;
268265 }
269266
@@ -358,21 +355,20 @@ pub fn connect_prevalidated(
358355 }
359356
360357 // Sort all vectors in parallel for optimal cursor access
361- utxo_deletes. par_sort_unstable ( ) ;
362358 stxo_puts. par_sort_unstable_by_key ( |( key, _) | * key) ;
363359 utxo_puts. par_sort_unstable_by_key ( |( key, _) | * key) ;
364360
365- // Apply all database operations using pre-sorted keys for optimal B-tree access
366- for key in & utxo_deletes {
367- state . utxos . delete ( rwtxn , key ) ? ;
368- }
369-
370- for ( key , spent_output ) in & stxo_puts {
371- state . stxos . put ( rwtxn , key , spent_output ) ? ;
361+ for ( key , output ) in stxo_puts {
362+ if !state . spend_utxo ( rwtxn , key , output ) ? {
363+ return Err ( error :: NoUtxo {
364+ outpoint : key . to_outpoint ( ) ,
365+ }
366+ . into ( ) ) ;
367+ }
372368 }
373369
374- for ( key, filled_output) in & utxo_puts {
375- state. utxos . put ( rwtxn, key, filled_output) ?;
370+ for ( key, filled_output) in utxo_puts {
371+ state. put_utxo ( rwtxn, key, filled_output, prevalidated . next_height ) ?;
376372 }
377373
378374 // Update tip and height using precomputed values
@@ -433,7 +429,7 @@ pub fn connect(
433429 content : filled_content,
434430 memo : output. memo . clone ( ) ,
435431 } ;
436- state. utxos . put ( rwtxn, & outpoint_key, & filled_output) ?;
432+ state. put_utxo ( rwtxn, outpoint_key, filled_output, height ) ?;
437433 }
438434 for transaction in & body. transactions {
439435 let filled_tx = state. fill_transaction ( rwtxn, transaction) ?;
@@ -451,20 +447,21 @@ pub fn connect(
451447 vin : vin as u32 ,
452448 } ,
453449 } ;
454- state. utxos . delete ( rwtxn, & input_key) ?;
455- state. stxos . put ( rwtxn, & input_key, & spent_output) ?;
450+ if !state. spend_utxo ( rwtxn, input_key, spent_output) ? {
451+ return Err ( error:: NoUtxo { outpoint : * input } . into ( ) ) ;
452+ }
456453 }
457454 let Some ( filled_outputs) = filled_tx. filled_outputs ( ) else {
458455 let err = error:: FillTxOutputContents ( Box :: new ( filled_tx) ) ;
459456 return Err ( err. into ( ) ) ;
460457 } ;
461- for ( vout, filled_output) in filled_outputs. iter ( ) . enumerate ( ) {
458+ for ( vout, filled_output) in filled_outputs. into_iter ( ) . enumerate ( ) {
462459 let outpoint = OutPoint :: Regular {
463460 txid,
464461 vout : vout as u32 ,
465462 } ;
466463 let outpoint_key = OutPointKey :: from_outpoint ( & outpoint) ;
467- state. utxos . put ( rwtxn, & outpoint_key, filled_output) ?;
464+ state. put_utxo ( rwtxn, outpoint_key, filled_output, height ) ?;
468465 }
469466 match & transaction. data {
470467 None => ( ) ,
@@ -646,13 +643,15 @@ pub fn disconnect_tip(
646643 }
647644 // delete UTXOs, last-to-first
648645 tx. outputs . iter ( ) . enumerate ( ) . rev ( ) . try_for_each (
649- |( vout, _output ) | {
646+ |( vout, output ) | {
650647 let outpoint = OutPoint :: Regular {
651648 txid,
652649 vout : vout as u32 ,
653650 } ;
654651 let outpoint_key = OutPointKey :: from_outpoint ( & outpoint) ;
655- if state. utxos . delete ( rwtxn, & outpoint_key) ? {
652+ let address_key =
653+ AddressOutPointKey :: new ( output. address , outpoint_key) ;
654+ if state. delete_utxo ( rwtxn, & address_key) ? {
656655 Ok :: < _ , Error > ( ( ) )
657656 } else {
658657 Err ( error:: NoUtxo { outpoint } . into ( ) )
@@ -662,13 +661,7 @@ pub fn disconnect_tip(
662661 // unspend STXOs, last-to-first
663662 tx. inputs . iter ( ) . rev ( ) . try_for_each ( |outpoint| {
664663 let outpoint_key = OutPointKey :: from_outpoint ( outpoint) ;
665- if let Some ( spent_output) =
666- state. stxos . try_get ( rwtxn, & outpoint_key) ?
667- {
668- state. stxos . delete ( rwtxn, & outpoint_key) ?;
669- state
670- . utxos
671- . put ( rwtxn, & outpoint_key, & spent_output. output ) ?;
664+ if state. unspend_utxo ( rwtxn, & outpoint_key) ? {
672665 Ok ( ( ) )
673666 } else {
674667 Err ( Error :: NoStxo {
@@ -678,20 +671,24 @@ pub fn disconnect_tip(
678671 } )
679672 } ) ?;
680673 // delete coinbase UTXOs, last-to-first
681- body. coinbase . iter ( ) . enumerate ( ) . rev ( ) . try_for_each (
682- |( vout, _output) | {
674+ body. coinbase
675+ . iter ( )
676+ . enumerate ( )
677+ . rev ( )
678+ . try_for_each ( |( vout, output) | {
683679 let outpoint = OutPoint :: Coinbase {
684680 merkle_root : header. merkle_root ,
685681 vout : vout as u32 ,
686682 } ;
687683 let outpoint_key = OutPointKey :: from_outpoint ( & outpoint) ;
688- if state. utxos . delete ( rwtxn, & outpoint_key) ? {
684+ let address_key =
685+ AddressOutPointKey :: new ( output. address , outpoint_key) ;
686+ if state. delete_utxo ( rwtxn, & address_key) ? {
689687 Ok :: < _ , Error > ( ( ) )
690688 } else {
691689 Err ( error:: NoUtxo { outpoint } . into ( ) )
692690 }
693- } ,
694- ) ?;
691+ } ) ?;
695692 match ( header. prev_side_hash , height) {
696693 ( None , 0 ) => {
697694 state. tip . delete ( rwtxn, & ( ) ) ?;
0 commit comments