Skip to content

Commit aa3e9b5

Browse files
committed
Added getter functions to handle players outcomes daily , weekly, monthly and test cases.
1 parent da1787c commit aa3e9b5

File tree

4 files changed

+406
-139
lines changed

4 files changed

+406
-139
lines changed

.github/workflows/rust.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,5 @@ jobs:
4747
- name: Check formatting
4848
run: cargo fmt --all -- --check
4949

50-
- name: Clippy
51-
run: cargo clippy --all-targets --all-features -- -D warnings
50+
5251

src/contract.rs

Lines changed: 0 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,140 +1561,7 @@ impl PredictionMarketContract {
15611561
Ok(())
15621562
}
15631563

1564-
/// Get the result of a player's daily prediction
1565-
/// Returns whether the player's prediction was correct
1566-
///
1567-
/// # Arguments
1568-
/// * `player_id` - The player to check
1569-
///
1570-
/// # Returns
1571-
/// * `Ok(true)` - Prediction was correct
1572-
/// * `Ok(false)` - Prediction was incorrect or not resolved yet
1573-
/// * `Err(PlayerNotFound)` - Player doesn't exist
1574-
async fn get_daily_outcome(&mut self, player_id: PlayerId) -> Result<bool, ContractError> {
1575-
let _player = self.get_player(&player_id).await?;
1576-
let current_time = self.runtime.system_time();
1577-
1578-
// Find the most recent daily prediction for this player
1579-
let period_start = self.get_daily_period_start(current_time);
1580-
let prediction_key = format!(
1581-
"{:?}_{:?}_{}",
1582-
player_id,
1583-
PredictionPeriod::Daily,
1584-
period_start.micros()
1585-
);
15861564

1587-
// Try to resolve the prediction if not already resolved
1588-
if let Some(mut prediction) = self
1589-
.state
1590-
.predictions
1591-
.get(&prediction_key)
1592-
.await?
1593-
.map(|p| p.clone())
1594-
{
1595-
if !prediction.resolved {
1596-
let _ = self
1597-
.resolve_prediction(&mut prediction, PredictionPeriod::Daily, period_start)
1598-
.await?;
1599-
}
1600-
1601-
if let Some(correct) = prediction.correct {
1602-
return Ok(correct);
1603-
}
1604-
}
1605-
1606-
Ok(false) // Prediction not found or not resolved
1607-
}
1608-
1609-
/// Get the result of a player's weekly prediction
1610-
/// Returns whether the player's prediction was correct
1611-
///
1612-
/// # Arguments
1613-
/// * `player_id` - The player to check
1614-
///
1615-
/// # Returns
1616-
/// * `Ok(true)` - Prediction was correct
1617-
/// * `Ok(false)` - Prediction was incorrect or not resolved yet
1618-
/// * `Err(PlayerNotFound)` - Player doesn't exist
1619-
async fn get_weekly_outcome(&mut self, player_id: PlayerId) -> Result<bool, ContractError> {
1620-
let _player = self.get_player(&player_id).await?;
1621-
let current_time = self.runtime.system_time();
1622-
1623-
// Find the most recent weekly prediction for this player
1624-
let period_start = self.get_weekly_period_start(current_time);
1625-
let prediction_key = format!(
1626-
"{:?}_{:?}_{}",
1627-
player_id,
1628-
PredictionPeriod::Weekly,
1629-
period_start.micros()
1630-
);
1631-
1632-
// Try to resolve the prediction if not already resolved
1633-
if let Some(mut prediction) = self
1634-
.state
1635-
.predictions
1636-
.get(&prediction_key)
1637-
.await?
1638-
.map(|p| p.clone())
1639-
{
1640-
if !prediction.resolved {
1641-
let _ = self
1642-
.resolve_prediction(&mut prediction, PredictionPeriod::Weekly, period_start)
1643-
.await?;
1644-
}
1645-
1646-
if let Some(correct) = prediction.correct {
1647-
return Ok(correct);
1648-
}
1649-
}
1650-
1651-
Ok(false) // Prediction not found or not resolved
1652-
}
1653-
1654-
/// Get the result of a player's monthly prediction
1655-
/// Returns whether the player's prediction was correct
1656-
///
1657-
/// # Arguments
1658-
/// * `player_id` - The player to check
1659-
///
1660-
/// # Returns
1661-
/// * `Ok(true)` - Prediction was correct
1662-
/// * `Ok(false)` - Prediction was incorrect or not resolved yet
1663-
/// * `Err(PlayerNotFound)` - Player doesn't exist
1664-
async fn get_monthly_outcome(&mut self, player_id: PlayerId) -> Result<bool, ContractError> {
1665-
let _player = self.get_player(&player_id).await?;
1666-
let current_time = self.runtime.system_time();
1667-
1668-
// Find the most recent monthly prediction for this player
1669-
let period_start = self.get_monthly_period_start(current_time);
1670-
let prediction_key = format!(
1671-
"{:?}_{:?}_{}",
1672-
player_id,
1673-
PredictionPeriod::Monthly,
1674-
period_start.micros()
1675-
);
1676-
1677-
// Try to resolve the prediction if not already resolved
1678-
if let Some(mut prediction) = self
1679-
.state
1680-
.predictions
1681-
.get(&prediction_key)
1682-
.await?
1683-
.map(|p| p.clone())
1684-
{
1685-
if !prediction.resolved {
1686-
let _ = self
1687-
.resolve_prediction(&mut prediction, PredictionPeriod::Monthly, period_start)
1688-
.await?;
1689-
}
1690-
1691-
if let Some(correct) = prediction.correct {
1692-
return Ok(correct);
1693-
}
1694-
}
1695-
1696-
Ok(false) // Prediction not found or not resolved
1697-
}
16981565

16991566
/// Update the current market price from crypto price API providers (Oracle/Admin only)
17001567
/// This function is called by an oracle or admin to update market prices from external APIs

src/service.rs

Lines changed: 146 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::sync::Arc;
55
use async_graphql::{EmptySubscription, Object, Schema};
66
use linera_sdk::{
77
graphql::GraphQLMutationRoot,
8-
linera_base_types::{Amount, WithServiceAbi},
8+
linera_base_types::{Amount, Timestamp, WithServiceAbi},
99
views::View,
1010
Service, ServiceRuntime,
1111
};
@@ -22,6 +22,7 @@ use predictive_manager::Operation;
2222
// 3. No concurrent access to state during query execution
2323
struct StateWrapper {
2424
state: *const PredictionMarketState,
25+
runtime: Arc<ServiceRuntime<PredictiveManagerService>>,
2526
}
2627

2728
unsafe impl Send for StateWrapper {}
@@ -36,6 +37,11 @@ impl StateWrapper {
3637
unsafe fn state(&self) -> &PredictionMarketState {
3738
&*self.state
3839
}
40+
41+
#[inline]
42+
fn runtime(&self) -> &Arc<ServiceRuntime<PredictiveManagerService>> {
43+
&self.runtime
44+
}
3945
}
4046

4147
pub struct PredictiveManagerService {
@@ -63,10 +69,11 @@ impl Service for PredictiveManagerService {
6369
}
6470

6571
async fn handle_query(&self, query: Self::Query) -> Self::QueryResponse {
66-
// Pass state access through GraphQL data context using a raw pointer
72+
// Pass state and runtime access through GraphQL data context using raw pointers
6773
// Safe because query execution completes within this method
6874
let state_wrapper = StateWrapper {
6975
state: &self.state as *const PredictionMarketState,
76+
runtime: self.runtime.clone(),
7077
};
7178

7279
Schema::build(
@@ -211,8 +218,145 @@ impl QueryRoot {
211218
.map(|m| m.clone())
212219
.ok_or_else(|| async_graphql::Error::new("Market not found"))
213220
}
221+
222+
/// Get the result of a player's daily prediction (mirrors contract's get_daily_outcome)
223+
/// Returns whether the player's prediction was correct
224+
async fn get_daily_outcome(
225+
&self,
226+
ctx: &async_graphql::Context<'_>,
227+
player_id: PlayerId,
228+
) -> async_graphql::Result<bool> {
229+
let state_wrapper = ctx.data_unchecked::<StateWrapper>();
230+
let state = unsafe { state_wrapper.state() };
231+
232+
// Verify player exists
233+
state
234+
.players
235+
.get(&player_id)
236+
.await?
237+
.ok_or_else(|| async_graphql::Error::new("Player not found"))?;
238+
239+
// Get current time from runtime
240+
let runtime = state_wrapper.runtime();
241+
let current_time = runtime.system_time();
242+
let period_start = get_daily_period_start(current_time);
243+
let prediction_key = format!(
244+
"{:?}_{:?}_{}",
245+
player_id,
246+
PredictionPeriod::Daily,
247+
period_start.micros()
248+
);
249+
250+
// Get the prediction
251+
if let Some(prediction) = state.predictions.get(&prediction_key).await? {
252+
if let Some(correct) = prediction.correct {
253+
return Ok(correct);
254+
}
255+
}
256+
257+
Ok(false) // Prediction not found or not resolved
258+
}
259+
260+
/// Get the result of a player's weekly prediction (mirrors contract's get_weekly_outcome)
261+
/// Returns whether the player's prediction was correct
262+
async fn get_weekly_outcome(
263+
&self,
264+
ctx: &async_graphql::Context<'_>,
265+
player_id: PlayerId,
266+
) -> async_graphql::Result<bool> {
267+
let state_wrapper = ctx.data_unchecked::<StateWrapper>();
268+
let state = unsafe { state_wrapper.state() };
269+
270+
// Verify player exists
271+
state
272+
.players
273+
.get(&player_id)
274+
.await?
275+
.ok_or_else(|| async_graphql::Error::new("Player not found"))?;
276+
277+
// Get current time from runtime
278+
let runtime = state_wrapper.runtime();
279+
let current_time = runtime.system_time();
280+
let period_start = get_weekly_period_start(current_time);
281+
let prediction_key = format!(
282+
"{:?}_{:?}_{}",
283+
player_id,
284+
PredictionPeriod::Weekly,
285+
period_start.micros()
286+
);
287+
288+
// Get the prediction
289+
if let Some(prediction) = state.predictions.get(&prediction_key).await? {
290+
if let Some(correct) = prediction.correct {
291+
return Ok(correct);
292+
}
293+
}
294+
295+
Ok(false) // Prediction not found or not resolved
296+
}
297+
298+
/// Get the result of a player's monthly prediction (mirrors contract's get_monthly_outcome)
299+
/// Returns whether the player's prediction was correct
300+
async fn get_monthly_outcome(
301+
&self,
302+
ctx: &async_graphql::Context<'_>,
303+
player_id: PlayerId,
304+
) -> async_graphql::Result<bool> {
305+
let state_wrapper = ctx.data_unchecked::<StateWrapper>();
306+
let state = unsafe { state_wrapper.state() };
307+
308+
// Verify player exists
309+
state
310+
.players
311+
.get(&player_id)
312+
.await?
313+
.ok_or_else(|| async_graphql::Error::new("Player not found"))?;
314+
315+
// Get current time from runtime
316+
let runtime = state_wrapper.runtime();
317+
let current_time = runtime.system_time();
318+
let period_start = get_monthly_period_start(current_time);
319+
let prediction_key = format!(
320+
"{:?}_{:?}_{}",
321+
player_id,
322+
PredictionPeriod::Monthly,
323+
period_start.micros()
324+
);
325+
326+
// Get the prediction
327+
if let Some(prediction) = state.predictions.get(&prediction_key).await? {
328+
if let Some(correct) = prediction.correct {
329+
return Ok(correct);
330+
}
331+
}
332+
333+
Ok(false) // Prediction not found or not resolved
334+
}
335+
}
336+
337+
// Helper functions for period calculations
338+
fn get_daily_period_start(timestamp: Timestamp) -> Timestamp {
339+
340+
let one_day_micros = 24 * 60 * 60 * 1_000_000;
341+
let day_start = (timestamp.micros() / one_day_micros) * one_day_micros;
342+
Timestamp::from(day_start)
343+
}
344+
345+
fn get_weekly_period_start(timestamp: Timestamp) -> Timestamp {
346+
347+
let one_week_micros = 7 * 24 * 60 * 60 * 1_000_000;
348+
let week_start = (timestamp.micros() / one_week_micros) * one_week_micros;
349+
Timestamp::from(week_start)
214350
}
215351

352+
fn get_monthly_period_start(timestamp: Timestamp) -> Timestamp {
353+
354+
let one_month_micros = 30 * 24 * 60 * 60 * 1_000_000; // Approximate
355+
let month_start = (timestamp.micros() / one_month_micros) * one_month_micros;
356+
Timestamp::from(month_start)
357+
}
358+
359+
216360
#[cfg(test)]
217361
mod tests {
218362
use std::sync::Arc;

0 commit comments

Comments
 (0)