@@ -69,46 +69,49 @@ pub(crate) async fn endpoint(
6969 }
7070 }
7171
72- let Some ( persistent_session) = CassandraSession :: get ( true ) else {
73- tracing:: error!( "Failed to acquire persistent db session" ) ;
74- return AllResponses :: service_unavailable (
75- & anyhow:: anyhow!( "Failed to acquire db session" ) ,
76- RetryAfterOption :: Default ,
77- ) ;
78- } ;
79- let Some ( volatile_session) = CassandraSession :: get ( false ) else {
80- tracing:: error!( "Failed to acquire volatile db session" ) ;
81- return AllResponses :: service_unavailable (
82- & anyhow:: anyhow!( "Failed to acquire volatile db session" ) ,
83- RetryAfterOption :: Default ,
84- ) ;
72+ let ( persistent_stake_info, txo_state) = {
73+ let Some ( persistent_session) = CassandraSession :: get ( true ) else {
74+ tracing:: error!( "Failed to acquire persistent db session" ) ;
75+ return AllResponses :: service_unavailable (
76+ & anyhow:: anyhow!( "Failed to acquire db session" ) ,
77+ RetryAfterOption :: Default ,
78+ ) ;
79+ } ;
80+ let persistent_res =
81+ calculate_stake_info ( persistent_session, stake_address. clone ( ) , slot_num, None ) . await ;
82+ match persistent_res {
83+ Ok ( Some ( ( stake_info, txo_state) ) ) => ( stake_info, txo_state) ,
84+ Ok ( None ) => return Responses :: NotFound . into ( ) ,
85+ Err ( err) => return AllResponses :: handle_error ( & err) ,
86+ }
8587 } ;
8688
87- let ( persistent_res, volatile_res) = futures:: join!(
88- calculate_stake_info( persistent_session, stake_address. clone( ) , slot_num) ,
89- calculate_stake_info( volatile_session, stake_address, slot_num)
90- ) ;
91- let persistent_stake_info = match persistent_res {
92- Ok ( stake_info) => stake_info,
93- Err ( err) => return AllResponses :: handle_error ( & err) ,
94- } ;
95- let volatile_stake_info = match volatile_res {
96- Ok ( stake_info) => stake_info,
97- Err ( err) => return AllResponses :: handle_error ( & err) ,
89+ let volatile_stake_info = {
90+ let Some ( volatile_session) = CassandraSession :: get ( false ) else {
91+ tracing:: error!( "Failed to acquire volatile db session" ) ;
92+ return AllResponses :: service_unavailable (
93+ & anyhow:: anyhow!( "Failed to acquire volatile db session" ) ,
94+ RetryAfterOption :: Default ,
95+ ) ;
96+ } ;
97+ let volatile_res =
98+ calculate_stake_info ( volatile_session, stake_address, slot_num, Some ( txo_state) ) . await ;
99+ match volatile_res {
100+ Ok ( Some ( ( stake_info, _) ) ) => stake_info,
101+ Ok ( None ) => return Responses :: NotFound . into ( ) ,
102+ Err ( err) => return AllResponses :: handle_error ( & err) ,
103+ }
98104 } ;
99105
100- if persistent_stake_info. is_none ( ) && volatile_stake_info. is_none ( ) {
101- return Responses :: NotFound . into ( ) ;
102- }
103-
104106 Responses :: Ok ( Json ( FullStakeInfo {
105- volatile : volatile_stake_info. unwrap_or_default ( ) . into ( ) ,
106- persistent : persistent_stake_info. unwrap_or_default ( ) . into ( ) ,
107+ volatile : volatile_stake_info. into ( ) ,
108+ persistent : persistent_stake_info. into ( ) ,
107109 } ) )
108110 . into ( )
109111}
110112
111113/// TXO asset information.
114+ #[ derive( Clone ) ]
112115struct TxoAssetInfo {
113116 /// Asset hash.
114117 id : Vec < u8 > ,
@@ -119,6 +122,7 @@ struct TxoAssetInfo {
119122}
120123
121124/// TXO information used when calculating a user's stake info.
125+ #[ derive( Clone ) ]
122126struct TxoInfo {
123127 /// TXO value.
124128 value : num_bigint:: BigInt ,
@@ -138,17 +142,29 @@ struct TxoInfo {
138142/// between lookups.
139143async fn calculate_stake_info (
140144 session : Arc < CassandraSession > , stake_address : Cip19StakeAddress , slot_num : Option < SlotNo > ,
141- ) -> anyhow:: Result < Option < StakeInfo > > {
145+ txo_base_state : Option < TxoAssetsState > ,
146+ ) -> anyhow:: Result < Option < ( StakeInfo , TxoAssetsState ) > > {
142147 let address: StakeAddress = stake_address. try_into ( ) ?;
143148 let adjusted_slot_num = slot_num. unwrap_or ( SlotNo :: MAXIMUM ) ;
144149
145- let ( mut txos, txo_assets) = futures:: try_join!(
150+ let ( txos, txo_assets) = futures:: try_join!(
146151 get_txo( & session, & address, adjusted_slot_num) ,
147152 get_txo_assets( & session, & address, adjusted_slot_num)
148153 ) ?;
149- if txos. is_empty ( ) {
150- return Ok ( None ) ;
151- }
154+
155+ let ( mut txos, txo_assets) = if let Some ( TxoAssetsState {
156+ txos : base_txos,
157+ txo_assets : base_assets,
158+ } ) = txo_base_state
159+ {
160+ // Extend the base state with current session data (used to calculate volatile data)
161+ (
162+ base_txos. into_iter ( ) . chain ( txos) . collect ( ) ,
163+ base_assets. into_iter ( ) . chain ( txo_assets) . collect ( ) ,
164+ )
165+ } else {
166+ ( txos, txo_assets)
167+ } ;
152168
153169 let params = update_spent ( & session, & address, & mut txos) . await ?;
154170
@@ -159,9 +175,13 @@ async fn calculate_stake_info(
159175 }
160176 } ) ;
161177
162- let stake_info = build_stake_info ( txos, txo_assets, adjusted_slot_num) ?;
178+ if txos. is_empty ( ) && txo_assets. is_empty ( ) {
179+ return Ok ( None ) ;
180+ }
181+
182+ let stake_info = build_stake_info ( txos. clone ( ) , txo_assets. clone ( ) , adjusted_slot_num) ?;
163183
164- Ok ( Some ( stake_info) )
184+ Ok ( Some ( ( stake_info, TxoAssetsState { txos , txo_assets } ) ) )
165185}
166186
167187/// `TxoInfo` map type alias
@@ -199,6 +219,14 @@ async fn get_txo(
199219/// TXO Assets map type alias
200220type TxoAssetsMap = HashMap < ( Slot , TxnIndex , i16 ) , TxoAssetInfo > ;
201221
222+ /// TXO Assets state
223+ struct TxoAssetsState {
224+ /// TXO Info map
225+ txos : TxoMap ,
226+ /// TXO Assets map
227+ txo_assets : TxoAssetsMap ,
228+ }
229+
202230/// Returns a map of txo asset infos for the given stake address.
203231async fn get_txo_assets (
204232 session : & CassandraSession , stake_address : & StakeAddress , slot_num : SlotNo ,
0 commit comments