@@ -10,6 +10,7 @@ use rand_distr::Distribution;
1010use rand_distr:: Geometric ;
1111use rand_pcg:: rand_core:: { RngCore , SeedableRng } ;
1212use rand_pcg:: Pcg64 ;
13+ use serde:: Serialize ;
1314
1415use crate :: bulletin_board:: BroadcastMessageType ;
1516use crate :: bulletin_board:: BulletinBoardData ;
@@ -726,6 +727,26 @@ pub struct WalletUtxoStats {
726727 pub p90 : Option < Amount > ,
727728}
728729
730+ #[ derive( Serialize ) ]
731+ struct SimulationResultJson {
732+ total_payment_obligations : usize ,
733+ percentage_payment_obligations_missed : f64 ,
734+ total_block_weight_wu : u64 ,
735+ average_fee_cost_sats : u64 ,
736+ dust_utxo_count : usize ,
737+ utxo_size_distribution_sats : Vec < u64 > ,
738+ wallet_utxo_stats : Vec < WalletUtxoStatsJson > ,
739+ }
740+
741+ #[ derive( Serialize ) ]
742+ struct WalletUtxoStatsJson {
743+ wallet_id : usize ,
744+ dust_count : usize ,
745+ total_count : usize ,
746+ p50_sats : Option < u64 > ,
747+ p90_sats : Option < u64 > ,
748+ }
749+
729750impl SimulationResult {
730751 pub fn new ( sim : & Simulation ) -> Self {
731752 Self {
@@ -873,7 +894,38 @@ impl SimulationResult {
873894 . unwrap ( ) ;
874895 std:: fs:: write ( path, graph_svg) . unwrap ( ) ;
875896 }
876- // TODO: utxo fragmentation, anon set metrics
897+
898+ /// Save simulation results as a JSON file.
899+ pub fn save_results_json ( & self , path : impl AsRef < Path > ) {
900+ let utxo_sizes = self
901+ . utxo_size_distribution ( )
902+ . into_iter ( )
903+ . map ( |amount| amount. to_sat ( ) )
904+ . collect ( ) ;
905+ let wallet_utxo_stats = self
906+ . wallet_utxo_stats ( )
907+ . into_iter ( )
908+ . map ( |stats| WalletUtxoStatsJson {
909+ wallet_id : stats. wallet_id ,
910+ dust_count : stats. dust_count ,
911+ total_count : stats. total_count ,
912+ p50_sats : stats. p50 . map ( |amount| amount. to_sat ( ) ) ,
913+ p90_sats : stats. p90 . map ( |amount| amount. to_sat ( ) ) ,
914+ } )
915+ . collect ( ) ;
916+ let result = SimulationResultJson {
917+ total_payment_obligations : self . total_payment_obligations ( ) ,
918+ percentage_payment_obligations_missed : self . percentage_of_payment_obligations_missed ( ) ,
919+ total_block_weight_wu : self . total_block_weight ( ) ,
920+ average_fee_cost_sats : self . average_fee_cost ( ) . to_sat ( ) ,
921+ dust_utxo_count : self . dust_utxo_count ( ) ,
922+ utxo_size_distribution_sats : utxo_sizes,
923+ wallet_utxo_stats,
924+ } ;
925+ let file = std:: fs:: File :: create ( path) . unwrap ( ) ;
926+ serde_json:: to_writer_pretty ( file, & result) . unwrap ( ) ;
927+ }
928+ // TODO: anon set metrics
877929}
878930
879931fn percentile_amount ( sorted : & [ Amount ] , percentile : f64 ) -> Option < Amount > {
0 commit comments