Skip to content

Commit 8f99527

Browse files
committed
fix: replace panic with proper error handling in APIVersion::from_u64()
- Fixes critical bug where unsupported version numbers would panic - Now returns Result<Self, VersionError> for graceful error handling - Prevents server crashes when loading contracts with invalid versions - Resolves River invitation hanging issue BREAKING CHANGE: APIVersion::from_u64() now returns Result instead of Self
1 parent b2bd5c8 commit 8f99527

File tree

3 files changed

+35
-7
lines changed

3 files changed

+35
-7
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Changelog
2+
3+
## [0.1.8] - 2025-06-19
4+
5+
### Fixed
6+
- Fixed panic in `APIVersion::from_u64()` when encountering unsupported version numbers
7+
- Now returns proper error instead of panicking
8+
- Prevents server crashes when loading contracts with invalid version data
9+
- Critical fix for River invitation bug where requests would hang indefinitely
10+
11+
### Changed
12+
- `APIVersion::from_u64()` now returns `Result<Self, VersionError>` instead of `Self`
13+
- Added `VersionError` enum for better error handling
14+
15+
## [0.1.7] - Previous release

rust/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "freenet-stdlib"
3-
version = "0.1.5"
3+
version = "0.1.8"
44
edition = "2021"
55
rust-version = "1.71.1"
66
publish = true

rust/src/versioning.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::sync::Arc;
66

77
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
88
use serde::{Deserialize, Serialize};
9+
use thiserror::Error;
910

1011
use crate::{
1112
client_api::{TryFromFbs, WsApiError},
@@ -125,8 +126,10 @@ impl DelegateCode<'static> {
125126
// Get contract version
126127
let version = contract_data
127128
.read_u64::<BigEndian>()
128-
.map_err(|_| std::io::ErrorKind::InvalidData)
129-
.map(APIVersion::from_u64)?;
129+
.map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to read version"))?;
130+
let version = APIVersion::from_u64(version).map_err(|e| {
131+
std::io::Error::new(std::io::ErrorKind::InvalidData, format!("Version error: {}", e))
132+
})?;
130133

131134
if version == APIVersion::Version0_0_1 {
132135
let mut code_hash = [0u8; 32];
@@ -303,7 +306,9 @@ impl ContractCode<'static> {
303306
let version = contract_data.read_u64::<BigEndian>().map_err(|_| {
304307
std::io::Error::new(std::io::ErrorKind::InvalidData, "Failed to read version")
305308
})?;
306-
let version = APIVersion::from_u64(version);
309+
let version = APIVersion::from_u64(version).map_err(|e| {
310+
std::io::Error::new(std::io::ErrorKind::InvalidData, format!("Version error: {}", e))
311+
})?;
307312

308313
if version == APIVersion::Version0_0_1 {
309314
let mut code_hash = [0u8; 32];
@@ -333,16 +338,24 @@ impl ContractCode<'static> {
333338
}
334339
}
335340

341+
#[derive(Debug, Error)]
342+
pub enum VersionError {
343+
#[error("unsupported incremental API version: {0}")]
344+
UnsupportedVersion(u64),
345+
#[error("failed to read version: {0}")]
346+
IoError(#[from] std::io::Error),
347+
}
348+
336349
#[derive(PartialEq, Eq, Clone, Copy)]
337350
pub enum APIVersion {
338351
Version0_0_1,
339352
}
340353

341354
impl APIVersion {
342-
fn from_u64(version: u64) -> Self {
355+
fn from_u64(version: u64) -> Result<Self, VersionError> {
343356
match version {
344-
0 => Self::Version0_0_1,
345-
_ => panic!("unsupported incremental API version: {version}"),
357+
0 => Ok(Self::Version0_0_1),
358+
v => Err(VersionError::UnsupportedVersion(v)),
346359
}
347360
}
348361

0 commit comments

Comments
 (0)