Files
potatium/scripts/simulate_pop_v02.py

96 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""Illustrative, non-consensus PoP fee/fairness research. All numeric values hypothetical."""
from __future__ import annotations
import argparse
import random
def progressive_example(rewards_90d: float) -> float:
"""Example marginal brackets. NEVER use floating-point for on-chain fees."""
if rewards_90d < 0:
raise ValueError('Rewards must be nonnegative')
return (min(rewards_90d, 10) * 0.00005
+ min(max(rewards_90d - 10, 0), 90) * 0.0002
+ max(rewards_90d - 100, 0) * 0.0005)
def fee_example(window: int, rewards_90d: float) -> float:
if window == 1:
return 0.0
p = progressive_example(rewards_90d)
if window == 2:
return 0.001 + p
if window == 3:
return 0.003 + 2 * p
raise ValueError('Window must be 1, 2 or 3')
def qualify(rng: random.Random, windows: int, probability: float,
rewards_90d: float) -> tuple[bool, float]:
"""One ticket at most, fees charged only after the previous window fails."""
if not 1 <= windows <= 3 or not 0 <= probability <= 1:
raise ValueError('Invalid windows/probability')
fee = 0.0
for window in range(1, windows + 1):
if window > 1:
fee += fee_example(window, rewards_90d)
if rng.random() < probability:
return True, fee
return False, fee
def simulate(miners: int, runs: int, seed: int, probability: float,
windows: int, rewards_90d: float, reward: float = 1.0) -> dict[str, float]:
"""One chosen miner vs N-1 miners always attempting window one."""
if miners < 1 or runs < 1 or reward < 0:
raise ValueError('Invalid simulation scenario')
rng = random.Random(seed)
got_ticket = wins = 0
spent = 0.0
for _ in range(runs):
qualified, fee = qualify(rng, windows, probability, rewards_90d)
spent += fee
if qualified:
got_ticket += 1
others = sum(rng.random() < probability for _ in range(miners - 1))
if qualified and rng.randrange(others + 1) == 0:
wins += 1
return {
'ticket_probability': got_ticket / runs,
'win_probability': wins / runs,
'avg_fee': spent / runs,
'max_fee': sum(fee_example(w, rewards_90d) for w in range(2, windows + 1)),
'net_expected_ptm': (wins / runs) * reward - spent / runs,
}
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--runs', type=int, default=25000)
parser.add_argument('--seed', type=int, default=20261025)
parser.add_argument('--p', type=float, default=0.70, help='Example success per full window')
parser.add_argument('--reward', type=float, default=1.0, help='Illustrative PTM per won lottery')
args = parser.parse_args()
print('FORSCHUNGSMODELL, KEINE PROTOKOLLREGEL. Float nur für Simulation, niemals On-chain.')
print(f'Parameter: runs={args.runs}, seed={args.seed}, p={args.p}, reward={args.reward} PTM')
print('Alle anderen Miner nutzen nur das kostenlose Fenster 1.')
print('N 90d-Ertrag Fenster Ticket% Gewinn% Ø Gebühr max Gebühr Netto-PTM/Runde')
for n in (5, 10, 20, 50):
for mined_90d in (0, 10, 100, 1000):
for windows in (1, 2, 3):
res = simulate(n, args.runs, args.seed + n + int(mined_90d),
args.p, windows, float(mined_90d), args.reward)
print(f'{n:<3} {mined_90d:>10} {windows:>7} '
f'{100*res["ticket_probability"]:>7.2f} '
f'{100*res["win_probability"]:>8.2f} '
f'{res["avg_fee"]:>9.6f} '
f'{res["max_fee"]:>11.6f} '
f'{res["net_expected_ptm"]:>15.6f}')
print('\nACHTUNG: Modell ohne Sybil-Effekt, Gebührenbudget, Validator-Zensur, reale Hashzeiten,')
print('endogene Teilnahmeentscheidung oder Unsicherheit der PoP-Belohnung; keine')
print('Garantie für faire Chancen oder wirtschaftlich sinnvolle Tarifwahl.')
if __name__ == '__main__':
main()