Skip to content

Commit 9b2518e

Browse files
committed
fix: handle proto conversion errors
1 parent a31f3d0 commit 9b2518e

File tree

2 files changed

+55
-37
lines changed

2 files changed

+55
-37
lines changed

crates/grpc/server/src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,13 @@ impl<P: Provider + Sync> DojoWorld<P> {
188188

189189
let mut worlds = HashMap::<Felt, Vec<proto::types::Model>>::new();
190190
for model in models {
191+
let proto_model: proto::types::Model = model
192+
.try_into()
193+
.map_err(|e| anyhow!("Failed to serialize model: {}", e))?;
191194
worlds
192195
.entry(model.world_address)
193196
.or_default()
194-
.push(model.into())
197+
.push(proto_model);
195198
}
196199

197200
Ok(worlds
@@ -218,7 +221,9 @@ impl<P: Provider + Sync> DojoWorld<P> {
218221
.await
219222
.map_err(|e| anyhow!("Failed to get model from cache: {}", e))?;
220223

221-
Ok(model.into())
224+
Ok(model
225+
.try_into()
226+
.map_err(|e| anyhow!("Failed to serialize model: {}", e))?)
222227
}
223228
}
224229

crates/proto/src/lib.rs

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,20 @@ use serde::{Deserialize, Serialize};
3434
use starknet::core::types::Felt;
3535
use strum_macros::{AsRefStr, EnumIter, FromRepr};
3636

37+
fn timestamp_to_datetime(value: u64, field: &'static str) -> Result<DateTime<Utc>, ProtoError> {
38+
DateTime::from_timestamp(value as i64, 0)
39+
.ok_or_else(|| ProtoError::MissingExpectedData(field.to_string()))
40+
}
41+
42+
fn optional_timestamp_to_datetime(
43+
value: Option<u64>,
44+
field: &'static str,
45+
) -> Result<Option<DateTime<Utc>>, ProtoError> {
46+
value
47+
.map(|timestamp| timestamp_to_datetime(timestamp, field))
48+
.transpose()
49+
}
50+
3751
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
3852
pub enum TokenId {
3953
Contract(Felt),
@@ -307,8 +321,8 @@ impl TryFrom<proto::types::Contract> for Contract {
307321
last_pending_block_tx: value
308322
.last_pending_block_tx
309323
.map(|tx| Felt::from_bytes_be_slice(&tx)),
310-
updated_at: DateTime::from_timestamp(value.updated_at as i64, 0).unwrap(),
311-
created_at: DateTime::from_timestamp(value.created_at as i64, 0).unwrap(),
324+
updated_at: timestamp_to_datetime(value.updated_at, "updated_at")?,
325+
created_at: timestamp_to_datetime(value.created_at, "created_at")?,
312326
})
313327
}
314328
}
@@ -399,7 +413,7 @@ impl TryFrom<proto::types::Controller> for Controller {
399413
Ok(Self {
400414
address: Felt::from_bytes_be_slice(&value.address),
401415
username: value.username,
402-
deployed_at: DateTime::from_timestamp(value.deployed_at_timestamp as i64, 0).unwrap(),
416+
deployed_at: timestamp_to_datetime(value.deployed_at_timestamp, "deployed_at")?,
403417
})
404418
}
405419
}
@@ -559,7 +573,7 @@ impl TryFrom<proto::types::TokenTransfer> for TokenTransfer {
559573
to_address: Felt::from_bytes_be_slice(&value.to_address),
560574
amount: U256::from_be_slice(&value.amount),
561575
token_id: value.token_id.map(|id| U256::from_be_slice(&id)),
562-
executed_at: DateTime::from_timestamp(value.executed_at as i64, 0).unwrap(),
576+
executed_at: timestamp_to_datetime(value.executed_at, "executed_at")?,
563577
event_id: value.event_id,
564578
})
565579
}
@@ -1231,9 +1245,10 @@ impl TryFrom<proto::types::Model> for Model {
12311245
}
12321246
}
12331247

1234-
impl From<Model> for proto::types::Model {
1235-
fn from(value: Model) -> Self {
1236-
Self {
1248+
impl TryFrom<Model> for proto::types::Model {
1249+
type Error = ProtoError;
1250+
fn try_from(value: Model) -> Result<Self, Self::Error> {
1251+
Ok(Self {
12371252
selector: value.selector.to_bytes_be().to_vec(),
12381253
namespace: value.namespace,
12391254
name: value.name,
@@ -1242,10 +1257,10 @@ impl From<Model> for proto::types::Model {
12421257
use_legacy_store: value.use_legacy_store,
12431258
class_hash: value.class_hash.to_bytes_be().to_vec(),
12441259
contract_address: value.contract_address.to_bytes_be().to_vec(),
1245-
layout: serde_json::to_vec(&value.layout).unwrap(),
1246-
schema: serde_json::to_vec(&value.schema).unwrap(),
1260+
layout: serde_json::to_vec(&value.layout).map_err(ProtoError::FromJson)?,
1261+
schema: serde_json::to_vec(&value.schema).map_err(ProtoError::FromJson)?,
12471262
world_address: value.world_address.to_bytes_be().to_vec(),
1248-
}
1263+
})
12491264
}
12501265
}
12511266

@@ -1739,7 +1754,7 @@ impl TryFrom<proto::types::Transaction> for Transaction {
17391754
nonce: Felt::from_bytes_be_slice(&value.nonce),
17401755
block_number: value.block_number,
17411756
transaction_type: value.transaction_type,
1742-
block_timestamp: DateTime::from_timestamp(value.block_timestamp as i64, 0).unwrap(),
1757+
block_timestamp: timestamp_to_datetime(value.block_timestamp, "block_timestamp")?,
17431758
calls: value
17441759
.calls
17451760
.into_iter()
@@ -1869,11 +1884,11 @@ impl TryFrom<proto::types::Activity> for Activity {
18691884
world_address: Felt::from_bytes_be_slice(&value.world_address),
18701885
namespace: value.namespace,
18711886
caller_address: Felt::from_bytes_be_slice(&value.caller_address),
1872-
session_start: DateTime::from_timestamp(value.session_start as i64, 0).unwrap(),
1873-
session_end: DateTime::from_timestamp(value.session_end as i64, 0).unwrap(),
1887+
session_start: timestamp_to_datetime(value.session_start, "session_start")?,
1888+
session_end: timestamp_to_datetime(value.session_end, "session_end")?,
18741889
action_count: value.action_count,
18751890
actions: value.actions,
1876-
updated_at: DateTime::from_timestamp(value.updated_at as i64, 0).unwrap(),
1891+
updated_at: timestamp_to_datetime(value.updated_at, "updated_at")?,
18771892
})
18781893
}
18791894
}
@@ -1924,12 +1939,8 @@ impl TryFrom<proto::types::ActivityQuery> for ActivityQuery {
19241939
.into_iter()
19251940
.map(|a| Felt::from_bytes_be_slice(&a))
19261941
.collect(),
1927-
from_time: value
1928-
.from_time
1929-
.map(|t| DateTime::from_timestamp(t as i64, 0).unwrap()),
1930-
to_time: value
1931-
.to_time
1932-
.map(|t| DateTime::from_timestamp(t as i64, 0).unwrap()),
1942+
from_time: optional_timestamp_to_datetime(value.from_time, "from_time")?,
1943+
to_time: optional_timestamp_to_datetime(value.to_time, "to_time")?,
19331944
pagination: value.pagination.map(|p| p.into()).unwrap_or_default(),
19341945
})
19351946
}
@@ -1985,8 +1996,8 @@ impl TryFrom<proto::types::Achievement> for Achievement {
19851996
data: value.data,
19861997
total_completions: value.total_completions,
19871998
completion_rate: value.completion_rate,
1988-
created_at: DateTime::from_timestamp(value.created_at as i64, 0).unwrap(),
1989-
updated_at: DateTime::from_timestamp(value.updated_at as i64, 0).unwrap(),
1999+
created_at: timestamp_to_datetime(value.created_at, "created_at")?,
2000+
updated_at: timestamp_to_datetime(value.updated_at, "updated_at")?,
19902001
})
19912002
}
19922003
}
@@ -2010,7 +2021,7 @@ impl TryFrom<proto::types::AchievementTask> for AchievementTask {
20102021
total: value.total,
20112022
total_completions: value.total_completions,
20122023
completion_rate: value.completion_rate,
2013-
created_at: DateTime::from_timestamp(value.created_at as i64, 0).unwrap(),
2024+
created_at: timestamp_to_datetime(value.created_at, "created_at")?,
20142025
})
20152026
}
20162027
}
@@ -2042,11 +2053,9 @@ impl TryFrom<proto::types::AchievementProgression> for AchievementProgression {
20422053
player_id: Felt::from_bytes_be_slice(&value.player_id),
20432054
count: value.count,
20442055
completed: value.completed,
2045-
completed_at: value
2046-
.completed_at
2047-
.map(|t| DateTime::from_timestamp(t as i64, 0).unwrap()),
2048-
created_at: DateTime::from_timestamp(value.created_at as i64, 0).unwrap(),
2049-
updated_at: DateTime::from_timestamp(value.updated_at as i64, 0).unwrap(),
2056+
completed_at: optional_timestamp_to_datetime(value.completed_at, "completed_at")?,
2057+
created_at: timestamp_to_datetime(value.created_at, "created_at")?,
2058+
updated_at: timestamp_to_datetime(value.updated_at, "updated_at")?,
20502059
})
20512060
}
20522061
}
@@ -2070,11 +2079,12 @@ impl TryFrom<proto::types::PlayerAchievementStats> for PlayerAchievementStats {
20702079
completed_achievements: value.completed_achievements,
20712080
total_achievements: value.total_achievements,
20722081
completion_percentage: value.completion_percentage,
2073-
last_achievement_at: value
2074-
.last_achievement_at
2075-
.map(|t| DateTime::from_timestamp(t as i64, 0).unwrap()),
2076-
created_at: DateTime::from_timestamp(value.created_at as i64, 0).unwrap(),
2077-
updated_at: DateTime::from_timestamp(value.updated_at as i64, 0).unwrap(),
2082+
last_achievement_at: optional_timestamp_to_datetime(
2083+
value.last_achievement_at,
2084+
"last_achievement_at",
2085+
)?,
2086+
created_at: timestamp_to_datetime(value.created_at, "created_at")?,
2087+
updated_at: timestamp_to_datetime(value.updated_at, "updated_at")?,
20782088
})
20792089
}
20802090
}
@@ -2108,7 +2118,10 @@ impl TryFrom<proto::types::PlayerAchievementEntry> for PlayerAchievementEntry {
21082118
fn try_from(value: proto::types::PlayerAchievementEntry) -> Result<Self, Self::Error> {
21092119
Ok(Self {
21102120
player_address: Felt::from_bytes_be_slice(&value.player_address),
2111-
stats: value.stats.expect("stats is required").try_into()?,
2121+
stats: value
2122+
.stats
2123+
.ok_or_else(|| ProtoError::MissingExpectedData("stats".to_string()))?
2124+
.try_into()?,
21122125
achievements: value
21132126
.achievements
21142127
.into_iter()
@@ -2132,7 +2145,7 @@ impl TryFrom<proto::types::PlayerAchievementProgress> for PlayerAchievementProgr
21322145
Ok(Self {
21332146
achievement: value
21342147
.achievement
2135-
.expect("achievement is required")
2148+
.ok_or_else(|| ProtoError::MissingExpectedData("achievement".to_string()))?
21362149
.try_into()?,
21372150
task_progress: value.task_progress.into_iter().map(|t| t.into()).collect(),
21382151
completed: value.completed,

0 commit comments

Comments
 (0)