mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-08-10 04:30:36 +02:00
211 lines
7.9 KiB
Python
211 lines
7.9 KiB
Python
"""Sprint 7 — petition state machine + constitutional challenge.
|
|
|
|
Maps to IMPLEMENTATION_PLAN §7.1 Sprint 7 row:
|
|
"Constitutional challenge can void passed petition."
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from services.infonet.config import CONFIG
|
|
from services.infonet.governance import (
|
|
compute_challenge_state,
|
|
compute_petition_state,
|
|
)
|
|
from services.infonet.tests._chain_factory import make_event, make_market_chain
|
|
|
|
|
|
_DAY_S = 86400.0
|
|
_HOUR_S = 3600.0
|
|
|
|
|
|
def _file_petition(filer: str, petition_id: str, *, ts: float, seq: int,
|
|
payload: dict | None = None) -> dict:
|
|
return make_event(
|
|
"petition_file", filer,
|
|
{"petition_id": petition_id,
|
|
"petition_payload": payload or {
|
|
"type": "UPDATE_PARAM",
|
|
"key": "vote_decay_days",
|
|
"value": 60,
|
|
}},
|
|
timestamp=ts, sequence=seq,
|
|
)
|
|
|
|
|
|
def _sign(signer: str, petition_id: str, *, ts: float, seq: int) -> dict:
|
|
return make_event(
|
|
"petition_sign", signer,
|
|
{"petition_id": petition_id},
|
|
timestamp=ts, sequence=seq,
|
|
)
|
|
|
|
|
|
def _vote(voter: str, petition_id: str, vote: str, *, ts: float, seq: int) -> dict:
|
|
return make_event(
|
|
"petition_vote", voter,
|
|
{"petition_id": petition_id, "vote": vote},
|
|
timestamp=ts, sequence=seq,
|
|
)
|
|
|
|
|
|
def _challenge_file(filer: str, petition_id: str, *, ts: float, seq: int) -> dict:
|
|
return make_event(
|
|
"challenge_file", filer,
|
|
{"petition_id": petition_id, "reason": "constitutional violation"},
|
|
timestamp=ts, sequence=seq,
|
|
)
|
|
|
|
|
|
def _challenge_vote(voter: str, petition_id: str, vote: str, *,
|
|
ts: float, seq: int) -> dict:
|
|
return make_event(
|
|
"challenge_vote", voter,
|
|
{"petition_id": petition_id, "vote": vote},
|
|
timestamp=ts, sequence=seq,
|
|
)
|
|
|
|
|
|
def _seed_oracle(node_id: str, base_ts: float, market_id: str,
|
|
stake: float = 100.0) -> list[dict]:
|
|
return make_market_chain(
|
|
market_id, "creator", outcome="yes",
|
|
predictions=[
|
|
{"node_id": node_id, "side": "yes", "stake_amount": stake},
|
|
{"node_id": f"{node_id}-loser", "side": "no", "stake_amount": stake},
|
|
],
|
|
base_ts=base_ts, participants=5, total_stake=stake * 2,
|
|
)
|
|
|
|
|
|
def test_unknown_petition_is_not_found():
|
|
state = compute_petition_state("nope", [], now=1.0)
|
|
assert state.status == "not_found"
|
|
|
|
|
|
def test_just_filed_is_in_signatures_phase():
|
|
base = 1_000_000.0
|
|
chain = [_file_petition("alice", "p1", ts=base, seq=1)]
|
|
state = compute_petition_state("p1", chain, now=base + 1)
|
|
assert state.status == "signatures"
|
|
|
|
|
|
def test_signatures_below_threshold_failed_after_window():
|
|
base = 1_000_000.0
|
|
chain = [_file_petition("alice", "p1", ts=base, seq=1)]
|
|
sig_window = float(CONFIG["petition_signature_window_days"]) * _DAY_S
|
|
state = compute_petition_state("p1", chain, now=base + sig_window + 1)
|
|
assert state.status == "failed_signatures"
|
|
|
|
|
|
def test_petition_advances_to_voting_when_signatures_meet_threshold():
|
|
"""Build enough oracle rep into a single signer that 25% threshold
|
|
is satisfied."""
|
|
base = 1_000_000.0
|
|
chain = []
|
|
chain += _seed_oracle("alice", base, "m1", stake=500.0)
|
|
chain.append(_file_petition("alice", "p1", ts=base + 100_000, seq=200))
|
|
chain.append(_sign("alice", "p1", ts=base + 100_100, seq=201))
|
|
state = compute_petition_state("p1", chain, now=base + 100_500)
|
|
# alice has nearly all the network's oracle rep → her single
|
|
# signature satisfies the 25% threshold.
|
|
assert state.status == "voting"
|
|
|
|
|
|
def test_petition_fails_vote_when_quorum_not_met():
|
|
base = 1_000_000.0
|
|
chain = []
|
|
chain += _seed_oracle("alice", base, "m1", stake=500.0)
|
|
chain.append(_file_petition("alice", "p1", ts=base + 100_000, seq=200))
|
|
chain.append(_sign("alice", "p1", ts=base + 100_100, seq=201))
|
|
# No votes cast.
|
|
sig_ts = base + 100_100
|
|
vote_window = float(CONFIG["petition_vote_window_days"]) * _DAY_S
|
|
after = sig_ts + vote_window + 1
|
|
state = compute_petition_state("p1", chain, now=after)
|
|
assert state.status == "failed_vote"
|
|
|
|
|
|
def test_petition_passes_vote_with_supermajority_and_quorum():
|
|
base = 1_000_000.0
|
|
chain = []
|
|
chain += _seed_oracle("alice", base, "m1", stake=500.0)
|
|
chain.append(_file_petition("alice", "p1", ts=base + 100_000, seq=200))
|
|
chain.append(_sign("alice", "p1", ts=base + 100_100, seq=201))
|
|
chain.append(_vote("alice", "p1", "for", ts=base + 100_500, seq=202))
|
|
sig_ts = base + 100_100
|
|
vote_window = float(CONFIG["petition_vote_window_days"]) * _DAY_S
|
|
after = sig_ts + vote_window + 1
|
|
state = compute_petition_state("p1", chain, now=after)
|
|
# Vote passed → enters challenge phase.
|
|
assert state.status == "challenge"
|
|
|
|
|
|
def test_constitutional_challenge_can_void_passed_petition():
|
|
"""The Sprint 7 marquee adversarial test."""
|
|
base = 1_000_000.0
|
|
chain = []
|
|
chain += _seed_oracle("alice", base, "m1", stake=500.0)
|
|
chain += _seed_oracle("bob", base + 50_000, "m2", stake=10.0)
|
|
chain.append(_file_petition("alice", "p1", ts=base + 100_000, seq=200))
|
|
chain.append(_sign("alice", "p1", ts=base + 100_100, seq=201))
|
|
chain.append(_vote("alice", "p1", "for", ts=base + 100_500, seq=202))
|
|
|
|
sig_ts = base + 100_100
|
|
vote_window = float(CONFIG["petition_vote_window_days"]) * _DAY_S
|
|
challenge_filed_at = sig_ts + vote_window + 60.0
|
|
chain.append(_challenge_file("bob", "p1", ts=challenge_filed_at, seq=300))
|
|
# alice (high oracle rep) votes UPHOLD the challenge.
|
|
chain.append(_challenge_vote("alice", "p1", "uphold",
|
|
ts=challenge_filed_at + 60, seq=301))
|
|
|
|
challenge_window = float(CONFIG["challenge_window_hours"]) * _HOUR_S
|
|
after = challenge_filed_at + challenge_window + 1
|
|
cstate = compute_challenge_state("p1", chain, now=after)
|
|
assert cstate.outcome == "voided"
|
|
pstate = compute_petition_state("p1", chain, now=after)
|
|
assert pstate.status == "voided_challenge"
|
|
|
|
|
|
def test_unupheld_challenge_does_not_void_petition():
|
|
base = 1_000_000.0
|
|
chain = []
|
|
chain += _seed_oracle("alice", base, "m1", stake=500.0)
|
|
chain += _seed_oracle("bob", base + 50_000, "m2", stake=10.0)
|
|
chain.append(_file_petition("alice", "p1", ts=base + 100_000, seq=200))
|
|
chain.append(_sign("alice", "p1", ts=base + 100_100, seq=201))
|
|
chain.append(_vote("alice", "p1", "for", ts=base + 100_500, seq=202))
|
|
|
|
sig_ts = base + 100_100
|
|
vote_window = float(CONFIG["petition_vote_window_days"]) * _DAY_S
|
|
challenge_filed_at = sig_ts + vote_window + 60.0
|
|
chain.append(_challenge_file("bob", "p1", ts=challenge_filed_at, seq=300))
|
|
# alice (high oracle rep) votes VOID the challenge → petition stands.
|
|
chain.append(_challenge_vote("alice", "p1", "void",
|
|
ts=challenge_filed_at + 60, seq=301))
|
|
|
|
challenge_window = float(CONFIG["challenge_window_hours"]) * _HOUR_S
|
|
after = challenge_filed_at + challenge_window + 1
|
|
pstate = compute_petition_state("p1", chain, now=after)
|
|
assert pstate.status == "passed"
|
|
|
|
|
|
def test_petition_executed_after_petition_execute_event():
|
|
base = 1_000_000.0
|
|
chain = []
|
|
chain += _seed_oracle("alice", base, "m1", stake=500.0)
|
|
chain.append(_file_petition("alice", "p1", ts=base + 100_000, seq=200))
|
|
chain.append(_sign("alice", "p1", ts=base + 100_100, seq=201))
|
|
chain.append(_vote("alice", "p1", "for", ts=base + 100_500, seq=202))
|
|
|
|
sig_ts = base + 100_100
|
|
vote_window = float(CONFIG["petition_vote_window_days"]) * _DAY_S
|
|
challenge_window = float(CONFIG["challenge_window_hours"]) * _HOUR_S
|
|
execute_at = sig_ts + vote_window + challenge_window + 100.0
|
|
chain.append(make_event(
|
|
"petition_execute", "alice",
|
|
{"petition_id": "p1"},
|
|
timestamp=execute_at, sequence=400,
|
|
))
|
|
state = compute_petition_state("p1", chain, now=execute_at + 1)
|
|
assert state.status == "executed"
|