Response to usage of unwrap in non-test code

This commit replaces all usage of `unwrap` with `expect` within
`networks/monero`, clarifying why the panic risked is unreachable. This commit
also replaces some uses of `unwrap` with solutions which are guaranteed not to
fail.

Notably, compilation on 128-bit systems is prevented, ensuring
`u64::try_from(usize::MAX)` will never panic at runtime.

Slight breaking changes are additionally included as necessary to massage out
some avoidable panics.
This commit is contained in:
Luke Parker
2025-08-08 21:28:47 -04:00
parent 4f65a0b147
commit a5f4c450c6
31 changed files with 310 additions and 169 deletions

View File

@@ -135,35 +135,13 @@ impl SimpleRequestRpc {
};
async fn body_from_response(response: Response<'_>) -> Result<Vec<u8>, RpcError> {
/*
let length = usize::try_from(
response
.headers()
.get("content-length")
.ok_or(RpcError::InvalidNode("no content-length header"))?
.to_str()
.map_err(|_| RpcError::InvalidNode("non-ascii content-length value"))?
.parse::<u32>()
.map_err(|_| RpcError::InvalidNode("non-u32 content-length value"))?,
)
.unwrap();
// Only pre-allocate 1 MB so a malicious node which claims a content-length of 1 GB actually
// has to send 1 GB of data to cause a 1 GB allocation
let mut res = Vec::with_capacity(length.max(1024 * 1024));
let mut body = response.into_body();
while res.len() < length {
let Some(data) = body.data().await else { break };
res.extend(data.map_err(|e| RpcError::ConnectionError(format!("{e:?}")))?.as_ref());
}
*/
let mut res = Vec::with_capacity(128);
response
.body()
.await
.map_err(|e| RpcError::ConnectionError(format!("{e:?}")))?
.read_to_end(&mut res)
.unwrap();
.map_err(|e| RpcError::ConnectionError(format!("{e:?}")))?;
Ok(res)
}
@@ -219,7 +197,12 @@ impl SimpleRequestRpc {
})?
.to_header_string(),
)
.unwrap(),
.map_err(|_| {
RpcError::InternalError(
"digest-auth challenge response wasn't a valid string for an HTTP header"
.to_string(),
)
})?,
);
}
@@ -269,7 +252,7 @@ impl SimpleRequestRpc {
))?
}
} else {
body_from_response(response.unwrap()).await?
body_from_response(response.expect("no response yet also no error?")).await?
}
}
});

View File

@@ -121,7 +121,7 @@ impl FeeRate {
/// defined serialization.
pub fn serialize(&self) -> Vec<u8> {
let mut res = Vec::with_capacity(16);
self.write(&mut res).unwrap();
self.write(&mut res).expect("write failed but <Vec as io::Write> doesn't fail");
res
}
@@ -139,15 +139,22 @@ impl FeeRate {
///
/// This function may panic upon overflow.
pub fn calculate_fee_from_weight(&self, weight: usize) -> u64 {
let fee = self.per_weight * u64::try_from(weight).unwrap();
let fee =
self.per_weight * u64::try_from(weight).expect("couldn't convert weight (usize) to u64");
let fee = fee.div_ceil(self.mask) * self.mask;
debug_assert_eq!(weight, self.calculate_weight_from_fee(fee), "Miscalculated weight from fee");
debug_assert_eq!(
Some(weight),
self.calculate_weight_from_fee(fee),
"Miscalculated weight from fee"
);
fee
}
/// Calculate the weight from the fee.
pub fn calculate_weight_from_fee(&self, fee: u64) -> usize {
usize::try_from(fee / self.per_weight).unwrap()
///
/// Returns `None` if the weight would not fit within a `usize`.
pub fn calculate_weight_from_fee(&self, fee: u64) -> Option<usize> {
usize::try_from(fee / self.per_weight).ok()
}
}
@@ -272,8 +279,14 @@ pub trait Rpc: Sync + Clone {
let res = self
.post(
route,
if let Some(params) = params {
serde_json::to_string(&params).unwrap().into_bytes()
if let Some(params) = params.as_ref() {
serde_json::to_string(params)
.map_err(|e| {
RpcError::InternalError(format!(
"couldn't convert parameters ({params:?}) to JSON: {e:?}"
))
})?
.into_bytes()
} else {
vec![]
},
@@ -295,7 +308,10 @@ pub trait Rpc: Sync + Clone {
async move {
let mut req = json!({ "method": method });
if let Some(params) = params {
req.as_object_mut().unwrap().insert("params".into(), params);
req
.as_object_mut()
.expect("accessing object as object failed?")
.insert("params".into(), params);
}
Ok(self.rpc_call::<_, JsonRpcResponse<Response>>("json_rpc", Some(req)).await?.result)
}