Skip to content

Commit 2883569

Browse files
committed
Add real-life scenario test when 7 TAO was lost due to precision loss in the share pool
1 parent 22e2538 commit 2883569

File tree

1 file changed

+41
-0
lines changed
  • primitives/share-pool/src

1 file changed

+41
-0
lines changed

primitives/share-pool/src/lib.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,4 +1203,45 @@ mod tests {
12031203
assert_abs_diff_eq!(actual, expected, epsilon = epsilon);
12041204
});
12051205
}
1206+
1207+
/// This is a real-life scenario test when someone lost 7 TAO on Chutes (SN64)
1208+
/// when paying fees in Alpha. The scenario occured because the update of share value
1209+
/// of one coldkey (update_value_for_one) hit the scenario of full unstake.
1210+
///
1211+
/// Specifically, the following condition was triggered:
1212+
///
1213+
/// `(shared_value + 2_628_000_000_000_000_u64).checked_div(new_denominator)`
1214+
///
1215+
/// returned None because new_denominator was too low and division of
1216+
/// `shared_value + 2_628_000_000_000_000_u64` by new_denominator has overflown U64F64.
1217+
///
1218+
/// This test fails on the old version of share pool (with much lower tolerances).
1219+
///
1220+
/// cargo test --package share-pool --lib -- tests::test_loss_due_to_precision --exact --nocapture
1221+
#[test]
1222+
fn test_loss_due_to_precision() {
1223+
let mock_ops = MockSharePoolDataOperations::new();
1224+
let mut pool = SharePool::<u16, MockSharePoolDataOperations>::new(mock_ops);
1225+
1226+
// Setup pool so that initial coldkey's alpha is 10% of 1e12 = 1e11 rao.
1227+
let low_denominator = SafeFloat::new(SafeInt::from(1), -14).unwrap();
1228+
let low_share = SafeFloat::new(SafeInt::from(1), -15).unwrap();
1229+
pool.state_ops.set_denominator(low_denominator);
1230+
pool.state_ops.set_shared_value(1_000_000_000_000_u64);
1231+
pool.state_ops.set_share(&1, low_share);
1232+
1233+
let value_before = pool.get_value(&1) as i128;
1234+
assert_abs_diff_eq!(value_before as f64, 100_000_000_000., epsilon = 0.1);
1235+
1236+
// Remove a little stake
1237+
let unstake_amount = 1000i64;
1238+
pool.update_value_for_one(&1, unstake_amount.neg());
1239+
1240+
let value_after = pool.get_value(&1) as i128;
1241+
assert_abs_diff_eq!(
1242+
(value_before - value_after) as f64,
1243+
unstake_amount as f64,
1244+
epsilon = unstake_amount as f64 / 1_000_000_000.
1245+
);
1246+
}
12061247
}

0 commit comments

Comments
 (0)