Skip to content

Commit 47c092a

Browse files
apollo_consensus_orchestrator: add SNIP-35 module tests
1 parent ae638b6 commit 47c092a

2 files changed

Lines changed: 147 additions & 0 deletions

File tree

crates/apollo_consensus_orchestrator/src/snip35/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
use ethnum::U256;
1313
use starknet_api::block::GasPrice;
1414

15+
#[cfg(test)]
16+
mod test;
17+
1518
/// Scale factor for 18-decimal fixed-point conversion (1 STRK = 10^18 FRI).
1619
const FRI_DECIMALS_SCALE: u128 = 10u128.pow(18);
1720

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
use starknet_api::block::GasPrice;
2+
3+
use crate::snip35::{compute_fee_actual, compute_fee_proposal, compute_fee_target};
4+
5+
#[test]
6+
fn test_compute_fee_actual_with_10_identical_values() {
7+
let proposals: Vec<GasPrice> = vec![GasPrice(1000); 10];
8+
assert_eq!(compute_fee_actual(&proposals, 10), Some(GasPrice(1000)));
9+
}
10+
11+
#[test]
12+
fn test_compute_fee_actual_with_ascending_values() {
13+
let proposals: Vec<GasPrice> = (1..=10).map(|i| GasPrice(i * 100)).collect();
14+
// Sorted: 100,200,300,400,500,600,700,800,900,1000. Median = (500+600)/2 = 550.
15+
assert_eq!(compute_fee_actual(&proposals, 10), Some(GasPrice(550)));
16+
}
17+
18+
#[test]
19+
fn test_compute_fee_actual_with_descending_values() {
20+
let proposals: Vec<GasPrice> = (1..=10).rev().map(|i| GasPrice(i * 100)).collect();
21+
// Same sorted order, same median.
22+
assert_eq!(compute_fee_actual(&proposals, 10), Some(GasPrice(550)));
23+
}
24+
25+
#[test]
26+
fn test_compute_fee_actual_with_outliers() {
27+
let mut proposals: Vec<GasPrice> = vec![GasPrice(100); 8];
28+
proposals.push(GasPrice(1)); // Low outlier
29+
proposals.push(GasPrice(1_000_000)); // High outlier
30+
// Sorted: 1,100,100,100,100,100,100,100,100,1000000. Median = (100+100)/2 = 100.
31+
assert_eq!(compute_fee_actual(&proposals, 10), Some(GasPrice(100)));
32+
}
33+
34+
#[test]
35+
fn test_compute_fee_actual_fewer_than_window_returns_none() {
36+
let proposals: Vec<GasPrice> = vec![GasPrice(100); 9];
37+
assert_eq!(compute_fee_actual(&proposals, 10), None);
38+
}
39+
40+
#[test]
41+
fn test_compute_fee_actual_empty_returns_none() {
42+
assert_eq!(compute_fee_actual(&[], 10), None);
43+
}
44+
45+
#[test]
46+
fn test_compute_fee_actual_custom_window_size() {
47+
let proposals: Vec<GasPrice> = vec![GasPrice(200); 4];
48+
assert_eq!(compute_fee_actual(&proposals, 4), Some(GasPrice(200)));
49+
assert_eq!(compute_fee_actual(&proposals, 5), None);
50+
}
51+
52+
#[test]
53+
fn test_compute_fee_actual_zero_median_returns_none() {
54+
// All zeros → median is 0 → returns None (triggers l2_gas_price fallback).
55+
let proposals: Vec<GasPrice> = vec![GasPrice(0); 10];
56+
assert_eq!(compute_fee_actual(&proposals, 10), None);
57+
}
58+
59+
#[test]
60+
fn test_compute_fee_actual_uses_only_last_window_entries() {
61+
// 12 entries: first 2 are outliers, last 10 are 500.
62+
let mut proposals: Vec<GasPrice> = vec![GasPrice(999_999); 2];
63+
proposals.extend(vec![GasPrice(500); 10]);
64+
// With window_size=10, the outliers should be ignored (only last 10 used).
65+
assert_eq!(compute_fee_actual(&proposals, 10), Some(GasPrice(500)));
66+
}
67+
68+
#[test]
69+
fn test_compute_fee_target_normal() {
70+
// Target: $3e-9/gas = 3_000_000_000 atto-USD. STRK at $0.50 = 500_000_000_000_000_000.
71+
// floor = 3_000_000_000 * 10^18 / 500_000_000_000_000_000 = 6_000_000_000.
72+
let target = compute_fee_target(3_000_000_000, 500_000_000_000_000_000, 0, u128::MAX);
73+
assert_eq!(target, GasPrice(6_000_000_000));
74+
}
75+
76+
#[test]
77+
fn test_compute_fee_target_clamp_min() {
78+
let target = compute_fee_target(1, 10u128.pow(18), 100, u128::MAX);
79+
// floor = 1 * 10^18 / 10^18 = 1, but clamped to min 100.
80+
assert_eq!(target, GasPrice(100));
81+
}
82+
83+
#[test]
84+
fn test_compute_fee_target_clamp_max() {
85+
// Very low STRK price → very high floor, clamped to max.
86+
let target = compute_fee_target(10u128.pow(18), 1, 0, 1000);
87+
assert_eq!(target, GasPrice(1000));
88+
}
89+
90+
#[test]
91+
fn test_compute_fee_target_zero_rate() {
92+
let target = compute_fee_target(100, 0, 0, 999);
93+
assert_eq!(target, GasPrice(999));
94+
}
95+
96+
#[test]
97+
fn test_compute_fee_proposal_oracle_failure_freezes() {
98+
let proposal = compute_fee_proposal(None, GasPrice(1000), 2);
99+
assert_eq!(proposal, GasPrice(1000));
100+
}
101+
102+
#[test]
103+
fn test_compute_fee_proposal_target_above_actual() {
104+
// fee_target=2000, fee_actual=1000, margin=2ppt. Upper bound = 1000*1002/1000 = 1002.
105+
let proposal = compute_fee_proposal(Some(GasPrice(2000)), GasPrice(1000), 2);
106+
assert_eq!(proposal, GasPrice(1002));
107+
}
108+
109+
#[test]
110+
fn test_compute_fee_proposal_target_below_actual() {
111+
// fee_target=500, fee_actual=1000, margin=2ppt. Lower bound = 1000*1000/1002 = 998.
112+
let proposal = compute_fee_proposal(Some(GasPrice(500)), GasPrice(1000), 2);
113+
assert_eq!(proposal, GasPrice(998));
114+
}
115+
116+
#[test]
117+
fn test_compute_fee_proposal_target_within_bounds() {
118+
// fee_target=1001, fee_actual=1000, margin=2ppt. 1001 is within [998, 1002].
119+
let proposal = compute_fee_proposal(Some(GasPrice(1001)), GasPrice(1000), 2);
120+
assert_eq!(proposal, GasPrice(1001));
121+
}
122+
123+
#[test]
124+
fn test_compute_fee_proposal_fee_actual_zero_clamps_to_zero() {
125+
// When fee_actual=0, both bounds are 0, so fee_proposal is always 0.
126+
let proposal = compute_fee_proposal(Some(GasPrice(1000)), GasPrice(0), 2);
127+
assert_eq!(proposal, GasPrice(0));
128+
}
129+
130+
#[test]
131+
fn test_compute_fee_actual_window_size_below_minimum_returns_none() {
132+
let proposals: Vec<GasPrice> = vec![GasPrice(100); 10];
133+
assert_eq!(compute_fee_actual(&proposals, 0), None);
134+
assert_eq!(compute_fee_actual(&proposals, 1), None);
135+
}
136+
137+
#[test]
138+
fn test_compute_fee_proposal_custom_margin() {
139+
// margin=10ppt (1%). fee_actual=10000. Upper=10000*1010/1000=10100. Lower=10000*1000/1010=9900.
140+
let proposal_up = compute_fee_proposal(Some(GasPrice(99999)), GasPrice(10000), 10);
141+
assert_eq!(proposal_up, GasPrice(10100));
142+
let proposal_down = compute_fee_proposal(Some(GasPrice(1)), GasPrice(10000), 10);
143+
assert_eq!(proposal_down, GasPrice(9900));
144+
}

0 commit comments

Comments
 (0)