montana/Русский/Экономика/банк_времени/код/test_halving.py

250 lines
12 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
test_halving.py Unit tests для halving.py
Montana Protocol
Тестирование механизма халвинга эмиссии
"""
import unittest
from halving import halving_coefficient
class TestHalving(unittest.TestCase):
"""Тесты для механизма халвинга Montana"""
# ═══════════════════════════════════════════════════════════════════════
# BASIC HALVING
# ═══════════════════════════════════════════════════════════════════════
def test_halving_tau4_0(self):
"""τ₄ = 0: коэффициент 1.0 (первые 4 года)"""
self.assertEqual(halving_coefficient(0), 1.0)
def test_halving_tau4_1(self):
"""τ₄ = 1: коэффициент 0.5 (4-8 лет)"""
self.assertEqual(halving_coefficient(1), 0.5)
def test_halving_tau4_2(self):
"""τ₄ = 2: коэффициент 0.25 (8-12 лет)"""
self.assertEqual(halving_coefficient(2), 0.25)
def test_halving_tau4_3(self):
"""τ₄ = 3: коэффициент 0.125 (12-16 лет)"""
self.assertEqual(halving_coefficient(3), 0.125)
def test_halving_tau4_4(self):
"""τ₄ = 4: коэффициент 0.0625 (16-20 лет)"""
self.assertEqual(halving_coefficient(4), 0.0625)
# ═══════════════════════════════════════════════════════════════════════
# EXTENDED TIMELINE
# ═══════════════════════════════════════════════════════════════════════
def test_halving_tau4_10(self):
"""τ₄ = 10: коэффициент ~0.0009765625 (40-44 года)"""
expected = 1.0 / (2 ** 10)
self.assertEqual(halving_coefficient(10), expected)
self.assertAlmostEqual(halving_coefficient(10), 0.0009765625, places=10)
def test_halving_tau4_20(self):
"""τ₄ = 20: очень малый коэффициент (80-84 года)"""
expected = 1.0 / (2 ** 20)
self.assertEqual(halving_coefficient(20), expected)
self.assertAlmostEqual(halving_coefficient(20), 9.5367431640625e-07, places=15)
def test_halving_tau4_50(self):
"""τ₄ = 50: экстремально малый коэффициент (200-204 года)"""
expected = 1.0 / (2 ** 50)
self.assertEqual(halving_coefficient(50), expected)
# ═══════════════════════════════════════════════════════════════════════
# EMISSION CALCULATION
# ═══════════════════════════════════════════════════════════════════════
def test_emission_calculation_tau4_0(self):
"""Эмиссия для 100 участников, 600 сек каждый, τ₄ = 0"""
participants = 100
seconds_per_participant = 600
total_seconds = participants * seconds_per_participant
coef = halving_coefficient(0)
emission = total_seconds * coef
self.assertEqual(emission, 60_000) # 100 × 600 × 1.0
def test_emission_calculation_tau4_1(self):
"""Эмиссия для 100 участников, 600 сек каждый, τ₄ = 1"""
participants = 100
seconds_per_participant = 600
total_seconds = participants * seconds_per_participant
coef = halving_coefficient(1)
emission = total_seconds * coef
self.assertEqual(emission, 30_000) # 100 × 600 × 0.5
def test_emission_calculation_tau4_2(self):
"""Эмиссия для 100 участников, 600 сек каждый, τ₄ = 2"""
participants = 100
seconds_per_participant = 600
total_seconds = participants * seconds_per_participant
coef = halving_coefficient(2)
emission = total_seconds * coef
self.assertEqual(emission, 15_000) # 100 × 600 × 0.25
# ═══════════════════════════════════════════════════════════════════════
# COMPARISON WITH BITCOIN
# ═══════════════════════════════════════════════════════════════════════
def test_bitcoin_like_progression(self):
"""Проверка что прогрессия халвинга как у Bitcoin"""
# Bitcoin: 50 → 25 → 12.5 → 6.25 → 3.125
# Montana: 1.0 → 0.5 → 0.25 → 0.125 → 0.0625
btc_rewards = [50, 25, 12.5, 6.25, 3.125]
montana_coefs = [halving_coefficient(i) for i in range(5)]
# Нормализуем Bitcoin к Montana (делим на 50)
btc_normalized = [r / 50 for r in btc_rewards]
for btc_norm, montana in zip(btc_normalized, montana_coefs):
self.assertAlmostEqual(btc_norm, montana, places=10)
# ═══════════════════════════════════════════════════════════════════════
# PROPERTIES
# ═══════════════════════════════════════════════════════════════════════
def test_halving_monotonic_decrease(self):
"""Коэффициент монотонно убывает"""
coefficients = [halving_coefficient(i) for i in range(10)]
for i in range(len(coefficients) - 1):
self.assertGreater(coefficients[i], coefficients[i + 1])
def test_halving_never_zero(self):
"""Коэффициент никогда не равен нулю"""
for tau4 in range(100):
coef = halving_coefficient(tau4)
self.assertGreater(coef, 0)
def test_halving_never_negative(self):
"""Коэффициент никогда не отрицательный"""
for tau4 in range(100):
coef = halving_coefficient(tau4)
self.assertGreaterEqual(coef, 0)
def test_halving_approaches_zero(self):
"""Коэффициент стремится к нулю при больших τ₄"""
coef_100 = halving_coefficient(100)
self.assertLess(coef_100, 1e-30) # Очень близко к нулю
def test_halving_exact_division_by_two(self):
"""Каждый следующий коэффициент ровно в 2 раза меньше"""
for tau4 in range(10):
coef_current = halving_coefficient(tau4)
coef_next = halving_coefficient(tau4 + 1)
self.assertAlmostEqual(coef_current / 2, coef_next, places=15)
# ═══════════════════════════════════════════════════════════════════════
# PRACTICAL SCENARIOS
# ═══════════════════════════════════════════════════════════════════════
def test_single_user_emission(self):
"""Один пользователь, 600 секунд присутствия"""
seconds = 600
# τ₄ = 0
emission_0 = seconds * halving_coefficient(0)
self.assertEqual(emission_0, 600)
# τ₄ = 1
emission_1 = seconds * halving_coefficient(1)
self.assertEqual(emission_1, 300)
# τ₄ = 2
emission_2 = seconds * halving_coefficient(2)
self.assertEqual(emission_2, 150)
def test_ten_users_emission(self):
"""10 пользователей, 600 секунд каждый"""
total_seconds = 10 * 600 # 6000
# τ₄ = 0
emission_0 = total_seconds * halving_coefficient(0)
self.assertEqual(emission_0, 6_000)
# τ₄ = 1
emission_1 = total_seconds * halving_coefficient(1)
self.assertEqual(emission_1, 3_000)
def test_thousand_users_emission(self):
"""1000 пользователей, 600 секунд каждый"""
total_seconds = 1000 * 600 # 600,000
# τ₄ = 0
emission_0 = total_seconds * halving_coefficient(0)
self.assertEqual(emission_0, 600_000)
# τ₄ = 1
emission_1 = total_seconds * halving_coefficient(1)
self.assertEqual(emission_1, 300_000)
# ═══════════════════════════════════════════════════════════════════════
# EDGE CASES
# ═══════════════════════════════════════════════════════════════════════
def test_halving_float_precision(self):
"""Проверка точности float для больших tau4"""
# Для очень больших tau4 может возникнуть underflow
coef_1000 = halving_coefficient(1000)
# Должно быть очень близко к нулю, но не точно ноль из-за float precision
self.assertGreaterEqual(coef_1000, 0)
# Может быть 0.0 из-за underflow — это ожидаемо для tau4 > ~1000
if coef_1000 > 0:
self.assertLess(coef_1000, 1e-300)
def test_halving_formula_consistency(self):
"""Проверка что формула 1/(2^n) работает корректно"""
for tau4 in range(20):
coef = halving_coefficient(tau4)
expected = 1.0 / (2 ** tau4)
self.assertEqual(coef, expected)
# ═══════════════════════════════════════════════════════════════════════
# FUTURE PROJECTIONS
# ═══════════════════════════════════════════════════════════════════════
def test_100_years_projection(self):
"""Проекция на 100 лет (25 халвингов)"""
# 100 лет ÷ 4 года = 25 халвингов
tau4_100_years = 25
coef = halving_coefficient(tau4_100_years)
expected = 1.0 / (2 ** 25)
self.assertEqual(coef, expected)
self.assertAlmostEqual(coef, 2.9802322387695312e-08, places=15)
def test_200_years_projection(self):
"""Проекция на 200 лет (50 халвингов)"""
tau4_200_years = 50
coef = halving_coefficient(tau4_200_years)
expected = 1.0 / (2 ** 50)
self.assertEqual(coef, expected)
# ═══════════════════════════════════════════════════════════════════════════
# RUN TESTS
# ═══════════════════════════════════════════════════════════════════════════
if __name__ == '__main__':
# Запускаем с verbose output
unittest.main(verbosity=2)