mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-08-18 16:37:24 +02:00
155 lines
5.3 KiB
Python
155 lines
5.3 KiB
Python
"""Regression coverage for malformed market lifecycle ordering metadata."""
|
|
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from services.infonet.config import CONFIG
|
|
from services.infonet.markets import MarketStatus, compute_market_status, should_advance_phase
|
|
from services.infonet.markets.event_selection import events_for_market
|
|
from services.infonet.markets.resolution import resolve_market
|
|
from services.infonet.markets.snapshot import InvalidAuthoritativeSnapshot, find_snapshot
|
|
|
|
|
|
def _create(trigger_date: Any = 200.0) -> dict[str, Any]:
|
|
return {
|
|
"event_type": "prediction_create",
|
|
"node_id": "creator",
|
|
"timestamp": 100.0,
|
|
"sequence": 1,
|
|
"payload": {"market_id": "m1", "trigger_date": trigger_date},
|
|
}
|
|
|
|
|
|
def _snapshot(
|
|
timestamp: Any = 200.0, frozen_at: Any = 200.0, sequence: Any = 2
|
|
) -> dict[str, Any]:
|
|
return {
|
|
"event_type": "market_snapshot",
|
|
"node_id": "creator",
|
|
"timestamp": timestamp,
|
|
"sequence": sequence,
|
|
"payload": {
|
|
"market_id": "m1",
|
|
"frozen_at": frozen_at,
|
|
"frozen_predictor_ids": ["predictor"],
|
|
},
|
|
}
|
|
|
|
|
|
def _finalize(timestamp: Any = 300.0, sequence: Any = 3) -> dict[str, Any]:
|
|
return {
|
|
"event_type": "resolution_finalize",
|
|
"node_id": "creator",
|
|
"timestamp": timestamp,
|
|
"sequence": sequence,
|
|
"payload": {"market_id": "m1", "outcome": "yes"},
|
|
}
|
|
|
|
|
|
def test_malformed_non_authoritative_metadata_does_not_break_projection() -> None:
|
|
chain = [
|
|
_create(),
|
|
_snapshot(),
|
|
{
|
|
"event_type": "prediction_place",
|
|
"node_id": "peer",
|
|
"timestamp": "not-a-timestamp",
|
|
"sequence": "not-a-sequence",
|
|
"payload": {"market_id": "m1"},
|
|
},
|
|
]
|
|
|
|
assert compute_market_status("m1", chain, now=201.0) == MarketStatus.EVIDENCE
|
|
|
|
|
|
def test_market_events_preserve_canonical_hashchain_order() -> None:
|
|
first = _snapshot(timestamp=300.0, sequence=5)
|
|
second = _snapshot(timestamp=200.0, sequence=2)
|
|
|
|
events = events_for_market("m1", [_create(), first, second])
|
|
|
|
assert events[1:] == [first, second]
|
|
|
|
|
|
def test_lifecycle_and_find_snapshot_share_authoritative_append_order() -> None:
|
|
evidence_window = float(CONFIG["evidence_window_hours"]) * 3600.0
|
|
first_timestamp = 10.0 * evidence_window
|
|
first = _snapshot(timestamp=first_timestamp, frozen_at=first_timestamp, sequence=5)
|
|
second = _snapshot(timestamp=1.0, frozen_at=1.0, sequence=2)
|
|
chain = [_create(), first, second]
|
|
|
|
# Lifecycle must use the first appended snapshot. If snapshot.py re-sorted
|
|
# by timestamp/sequence, the much older second event would be selected and
|
|
# this same `now` would project RESOLVING instead of EVIDENCE.
|
|
now = first_timestamp + evidence_window / 2.0
|
|
assert compute_market_status("m1", chain, now=now) == MarketStatus.EVIDENCE
|
|
assert find_snapshot("m1", chain) == first["payload"]
|
|
|
|
|
|
def test_invalid_first_snapshot_fails_closed_without_replacement() -> None:
|
|
chain = [
|
|
_create(),
|
|
_snapshot(timestamp="bad", frozen_at=200.0, sequence="bad"),
|
|
_snapshot(timestamp=200.0, frozen_at=200.0, sequence=3),
|
|
]
|
|
|
|
assert compute_market_status("m1", chain, now=10_000.0) == MarketStatus.PREDICTING
|
|
assert should_advance_phase("m1", chain, now=10_000.0) is None
|
|
with pytest.raises(InvalidAuthoritativeSnapshot):
|
|
find_snapshot("m1", chain)
|
|
|
|
|
|
def test_invalid_first_snapshot_halts_direct_resolution() -> None:
|
|
chain = [
|
|
_create(),
|
|
_snapshot(timestamp="bad", frozen_at=200.0, sequence="bad"),
|
|
_snapshot(timestamp=200.0, frozen_at=200.0, sequence=3),
|
|
{
|
|
"event_type": "resolution_stake",
|
|
"node_id": "resolver",
|
|
"timestamp": 400.0,
|
|
"sequence": 4,
|
|
"payload": {
|
|
"market_id": "m1",
|
|
"side": "yes",
|
|
"amount": 10.0,
|
|
"rep_type": "oracle",
|
|
},
|
|
},
|
|
]
|
|
|
|
# A malformed authoritative commitment is distinct from no snapshot.
|
|
# Resolution must halt instead of treating it as an empty exclusion set.
|
|
with pytest.raises(InvalidAuthoritativeSnapshot):
|
|
resolve_market("m1", chain)
|
|
|
|
|
|
def test_nonfinite_snapshot_timestamp_does_not_fall_back_to_frozen_at() -> None:
|
|
chain = [_create(), _snapshot(timestamp=float("nan"), frozen_at=200.0)]
|
|
|
|
assert compute_market_status("m1", chain, now=201.0) == MarketStatus.PREDICTING
|
|
assert should_advance_phase("m1", chain, now=10_000.0) is None
|
|
with pytest.raises(InvalidAuthoritativeSnapshot):
|
|
find_snapshot("m1", chain)
|
|
|
|
|
|
def test_invalid_first_finalize_cannot_be_replaced_by_later_finalize() -> None:
|
|
chain = [
|
|
_create(),
|
|
_snapshot(),
|
|
_finalize(timestamp="bad", sequence="bad"),
|
|
_finalize(timestamp=300.0, sequence=4),
|
|
]
|
|
|
|
# The malformed finalize has no terminal authority, so projection stays
|
|
# in the prior snapshot-backed phase. The later finalize cannot replace it.
|
|
assert compute_market_status("m1", chain, now=201.0) == MarketStatus.EVIDENCE
|
|
assert should_advance_phase("m1", chain, now=10_000.0) is None
|
|
|
|
|
|
def test_invalid_trigger_date_cannot_authorize_phase_advance() -> None:
|
|
chain = [_create(trigger_date="not-a-date")]
|
|
|
|
assert should_advance_phase("m1", chain, now=10_000.0) is None
|