@@ -467,7 +467,7 @@ impl State {
467467 . ok_or ( AmountOverflowError ) ?;
468468 }
469469 if let InPoint :: Withdrawal { .. } = spent_output. inpoint {
470- total_withdrawal_stxo_value = total_deposit_stxo_value
470+ total_withdrawal_stxo_value = total_withdrawal_stxo_value
471471 . checked_add ( spent_output. output . get_value ( ) )
472472 . ok_or ( AmountOverflowError ) ?;
473473 }
@@ -568,3 +568,124 @@ impl Watchable<()> for State {
568568 tokio_stream:: wrappers:: WatchStream :: new ( self . tip . watch ( ) . clone ( ) )
569569 }
570570}
571+
572+ #[ cfg( test) ]
573+ mod test {
574+ use crate :: {
575+ state:: State ,
576+ types:: {
577+ Address , InPoint , OutPoint , OutPointKey , Output , OutputContent ,
578+ SpentOutput ,
579+ } ,
580+ } ;
581+
582+ fn temp_env_path ( test_name : & str ) -> anyhow:: Result < std:: path:: PathBuf > {
583+ let mut path = std:: env:: temp_dir ( ) ;
584+ let nanos = std:: time:: SystemTime :: now ( )
585+ . duration_since ( std:: time:: UNIX_EPOCH ) ?
586+ . as_nanos ( ) ;
587+ path. push ( format ! (
588+ "photon-{test_name}-{}-{nanos}" ,
589+ std:: process:: id( )
590+ ) ) ;
591+ Ok ( path)
592+ }
593+
594+ // open a fresh state-backed env in a unique temp dir
595+ fn temp_env ( test_name : & str ) -> anyhow:: Result < sneed:: Env > {
596+ let path = temp_env_path ( test_name) ?;
597+ std:: fs:: create_dir_all ( & path) ?;
598+ let mut opts = heed:: EnvOpenOptions :: new ( ) ;
599+ opts. map_size ( 16 * 1024 * 1024 ) . max_dbs ( State :: NUM_DBS ) ;
600+ let res = unsafe { sneed:: Env :: open ( & opts, & path) } ?;
601+ Ok ( res)
602+ }
603+
604+ fn fresh_state ( test_name : & str ) -> anyhow:: Result < ( sneed:: Env , State ) > {
605+ let env = temp_env ( test_name) ?;
606+ let state = State :: new ( & env) ?;
607+ Ok ( ( env, state) )
608+ }
609+
610+ #[ test]
611+ fn sidechain_wealth ( ) -> anyhow:: Result < ( ) > {
612+ use std:: str:: FromStr ;
613+
614+ use bitcoin:: hashes:: Hash as _;
615+
616+ let value_output = |sats : u64 | Output {
617+ address : Address :: ALL_ZEROS ,
618+ content : OutputContent :: Value ( bitcoin:: Amount :: from_sat ( sats) ) ,
619+ } ;
620+ let ( env, state) = fresh_state ( "sidechain-wealth" ) ?;
621+ {
622+ let mut rwtxn = env. write_txn ( ) ?;
623+
624+ // One unspent DEPOSIT UTXO: 50 sats.
625+ let deposit_utxo_op = OutPoint :: Deposit ( bitcoin:: OutPoint {
626+ txid : bitcoin:: Txid :: from_str (
627+ "0000000000000000000000000000000000000000000000000000000000000001" ,
628+ ) ?,
629+ vout : 0 ,
630+ } ) ;
631+ state. utxos . put (
632+ & mut rwtxn,
633+ & OutPointKey :: from ( & deposit_utxo_op) ,
634+ & value_output ( 50 ) ,
635+ ) ?;
636+
637+ // Two spent DEPOSIT STXOs: 100 + 100 sats.
638+ for ( i, sats) in [ ( 2u8 , 100u64 ) , ( 3u8 , 100u64 ) ] {
639+ let op = OutPoint :: Deposit ( bitcoin:: OutPoint {
640+ txid : bitcoin:: Txid :: from_byte_array ( [ i; 32 ] ) ,
641+ vout : 0 ,
642+ } ) ;
643+ let stxo = SpentOutput {
644+ output : value_output ( sats) ,
645+ inpoint : InPoint :: Regular {
646+ txid : [ i; 32 ] . into ( ) ,
647+ vin : 0 ,
648+ } ,
649+ } ;
650+ state
651+ . stxos
652+ . put ( & mut rwtxn, & OutPointKey :: from ( & op) , & stxo) ?;
653+ }
654+
655+ // Two WITHDRAWAL STXOs: 10 + 10 sats
656+ for ( i, sats) in [ ( 4u8 , 10u64 ) , ( 5u8 , 10u64 ) ] {
657+ let op = OutPoint :: Regular {
658+ txid : [ i; 32 ] . into ( ) ,
659+ vout : 0 ,
660+ } ;
661+ let stxo = SpentOutput {
662+ output : value_output ( sats) ,
663+ inpoint : InPoint :: Withdrawal {
664+ m6id : crate :: types:: M6id (
665+ bitcoin:: Txid :: from_byte_array ( [ i; 32 ] ) ,
666+ ) ,
667+ } ,
668+ } ;
669+ state
670+ . stxos
671+ . put ( & mut rwtxn, & OutPointKey :: from ( & op) , & stxo) ?;
672+ }
673+
674+ rwtxn. commit ( ) ?;
675+ }
676+
677+ let rotxn = env. read_txn ( ) ?;
678+ let sidechain_wealth = state. sidechain_wealth ( & rotxn) ?;
679+
680+ // Correct value: deposit UTXO 50 + deposit STXOs 200 - withdrawal
681+ // STXOs 20 = 230 sats.
682+ let expected_sidechain_wealth = bitcoin:: Amount :: from_sat ( 230 ) ;
683+ anyhow:: ensure!(
684+ sidechain_wealth == expected_sidechain_wealth,
685+ "Expected sidechain wealth ({}), but computed ({})" ,
686+ expected_sidechain_wealth,
687+ sidechain_wealth,
688+ ) ;
689+ Ok ( ( ) )
690+ }
691+ }
0 commit comments