fix(p2p): 路由评分分母 u32 溢出

rtt > 约39s 时 rtt * (10000 + loss_v * 10) 超出 u32 范围,
debug 构建下直接 panic,release 下评分错误。

改用 u64 计算并钳制回 u32。

测试:test_get_channel_score_large_rtt_no_overflow 覆盖 u32::MAX rtt
与正常大小关系。
This commit is contained in:
lbl
2026-08-21 01:55:02 +08:00
parent d49b7e6651
commit ed6f61ea2a
+23 -3
View File
@@ -87,13 +87,14 @@ pub fn get_channel_score(rtt: u32, loss_v: u32, is_relay: bool) -> u32 {
let weight = if is_relay { 100 } else { 120 };
let k_adj = 10; // 丢包惩罚系数
// 用 u64 计算避免溢出:分母最大 rtt * 110000rtt > 约39s 时 u32 溢出
// 分子:代表"有效做功"的放大值
let numerator = weight * (10000 - loss_v) * 100;
let numerator = weight as u64 * (10000 - loss_v) as u64 * 100;
// 分母:代表"链路阻力"
let denominator = rtt * (10000 + loss_v * k_adj);
let denominator = rtt as u64 * (10000 + loss_v * k_adj) as u64;
numerator / denominator
(numerator / denominator).min(u32::MAX as u64) as u32
}
#[derive(Clone)]
@@ -319,3 +320,22 @@ impl RouteTableInner {
expired_keys
}
}
#[cfg(test)]
mod tests {
use super::*;
/// rtt 极大(>39s)时分母不能 u32 溢出(debug 构建下溢出会 panic
#[test]
fn test_get_channel_score_large_rtt_no_overflow() {
let score = get_channel_score(u32::MAX, 0, false);
assert_eq!(score, 0);
let score = get_channel_score(u32::MAX, 10000, true);
assert_eq!(score, 0);
// 正常值结果与预期一致:低 rtt 零丢包得分高
let good = get_channel_score(10, 0, false);
let bad = get_channel_score(1000, 5000, true);
assert!(good > bad);
}
}