2024-01-24 22:04:35 +00:00
|
|
|
from unittest import TestCase
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
2024-02-07 14:28:36 +00:00
|
|
|
from .cryptarchia import (
|
|
|
|
Leader,
|
|
|
|
Config,
|
|
|
|
EpochState,
|
|
|
|
LedgerState,
|
|
|
|
Coin,
|
|
|
|
phi,
|
|
|
|
TimeConfig,
|
|
|
|
Slot,
|
|
|
|
)
|
2024-03-09 13:34:08 +00:00
|
|
|
from .test_common import mk_config
|
2024-01-24 22:04:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
class TestLeader(TestCase):
|
|
|
|
def test_slot_leader_statistics(self):
|
2024-02-01 09:56:49 +00:00
|
|
|
epoch = EpochState(
|
2024-01-24 22:04:35 +00:00
|
|
|
stake_distribution_snapshot=LedgerState(
|
|
|
|
total_stake=1000,
|
|
|
|
),
|
|
|
|
nonce_snapshot=LedgerState(nonce=b"1010101010"),
|
|
|
|
)
|
|
|
|
|
|
|
|
f = 0.05
|
2024-03-09 13:34:08 +00:00
|
|
|
l = Leader(
|
|
|
|
config=mk_config().replace(active_slot_coeff=f),
|
|
|
|
coin=Coin(sk=0, value=10),
|
2024-02-01 17:33:37 +00:00
|
|
|
)
|
2024-01-24 22:04:35 +00:00
|
|
|
|
|
|
|
# We'll use the Margin of Error equation to decide how many samples we need.
|
|
|
|
# https://en.wikipedia.org/wiki/Margin_of_error
|
|
|
|
margin_of_error = 1e-4
|
|
|
|
p = phi(f=f, alpha=10 / 1000)
|
|
|
|
std = np.sqrt(p * (1 - p))
|
|
|
|
Z = 3 # we want 3 std from the mean to be within the margin of error
|
|
|
|
N = int((Z * std / margin_of_error) ** 2)
|
|
|
|
|
2024-03-09 13:34:08 +00:00
|
|
|
# After N slots, the measured leader rate should be within the
|
|
|
|
# interval `p +- margin_of_error` with high probabiltiy
|
2024-02-01 09:56:49 +00:00
|
|
|
leader_rate = (
|
2024-02-07 14:28:36 +00:00
|
|
|
sum(
|
2024-02-09 14:12:12 +00:00
|
|
|
l.try_prove_slot_leader(epoch, Slot(slot), bytes(32)) is not None
|
2024-02-07 14:28:36 +00:00
|
|
|
for slot in range(N)
|
|
|
|
)
|
2024-02-01 09:56:49 +00:00
|
|
|
/ N
|
|
|
|
)
|
2024-01-24 22:04:35 +00:00
|
|
|
assert (
|
|
|
|
abs(leader_rate - p) < margin_of_error
|
|
|
|
), f"{leader_rate} != {p}, err={abs(leader_rate - p)} > {margin_of_error}"
|