Skip to content

Commit dbad580

Browse files
fix(cat-gateway): Use persistent state in volatile asset calculation (#2160)
* fix(cat-gateway): separate futures * fix(cat-gateway): calculate volatile assets * wip * remove unused code --------- Co-authored-by: Mr-Leshiy <[email protected]>
1 parent 33cdc75 commit dbad580

File tree

1 file changed

+65
-37
lines changed
  • catalyst-gateway/bin/src/service/api/cardano/staking

1 file changed

+65
-37
lines changed

catalyst-gateway/bin/src/service/api/cardano/staking/assets_get.rs

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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)]
112115
struct 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)]
122126
struct TxoInfo {
123127
/// TXO value.
124128
value: num_bigint::BigInt,
@@ -138,17 +142,29 @@ struct TxoInfo {
138142
/// between lookups.
139143
async 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
200220
type 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.
203231
async fn get_txo_assets(
204232
session: &CassandraSession, stake_address: &StakeAddress, slot_num: SlotNo,

0 commit comments

Comments
 (0)