mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-05-12 11:51:35 +02:00
107 lines
3.7 KiB
Python
107 lines
3.7 KiB
Python
"""Event construction helpers for the Infonet economy.
|
|
|
|
A thin layer over ``services/infonet/schema.py``: each public function
|
|
builds a payload dict for one event type, validates it, and returns it.
|
|
The caller is responsible for signing the event and routing it through
|
|
``services/infonet/adapters/hashchain_adapter.py`` for actual append.
|
|
|
|
Sprint 1 scope: payload builders + validation. No chain writes. The
|
|
hashchain adapter's ``append_infonet_event`` is the eventual integration
|
|
point — see ``adapters/hashchain_adapter.py``.
|
|
|
|
Why a builder layer and not free-form dicts:
|
|
- Centralizes the canonical field set per event_type so callers can't
|
|
drift from the schema.
|
|
- Allows future sprints to attach deterministic computation (e.g.
|
|
``probability_at_bet`` reconstruction in Sprint 4) without changing
|
|
callers.
|
|
- Matches the "events extend, never replace" rule from the plan §3.1 —
|
|
the legacy event constructors in ``mesh_schema.py`` keep working
|
|
unchanged; new event types live here.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from services.infonet.schema import (
|
|
INFONET_ECONOMY_EVENT_TYPES,
|
|
validate_infonet_event_payload,
|
|
)
|
|
|
|
|
|
class EventConstructionError(ValueError):
|
|
"""Raised when a payload fails validation at build time.
|
|
|
|
Distinct from chain-level errors (signature, replay, sequence) —
|
|
those originate in the hashchain adapter, not here.
|
|
"""
|
|
|
|
|
|
def build_event(event_type: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
"""Validate and return a payload for ``event_type``.
|
|
|
|
The returned dict is a shallow copy — callers can attach signature,
|
|
sequence, public_key, etc. before passing it to the hashchain
|
|
adapter for append.
|
|
"""
|
|
if event_type not in INFONET_ECONOMY_EVENT_TYPES:
|
|
raise EventConstructionError(
|
|
f"event_type {event_type!r} is not in INFONET_ECONOMY_EVENT_TYPES"
|
|
)
|
|
payload = dict(payload or {})
|
|
ok, reason = validate_infonet_event_payload(event_type, payload)
|
|
if not ok:
|
|
raise EventConstructionError(f"{event_type}: {reason}")
|
|
return payload
|
|
|
|
|
|
# ─── Convenience builders ────────────────────────────────────────────────
|
|
# Sprint 1 ships only a representative slice. Full per-type builders for
|
|
# the producing modules (markets/, gates/, governance/, ...) live in
|
|
# their respective sprints — they will all funnel through ``build_event``
|
|
# so this module stays the single validation choke point.
|
|
|
|
def build_uprep(target_node_id: str, target_event_id: str) -> dict[str, Any]:
|
|
return build_event("uprep", {
|
|
"target_node_id": target_node_id,
|
|
"target_event_id": target_event_id,
|
|
})
|
|
|
|
|
|
def build_citizenship_claim(sacrifice_amount: int) -> dict[str, Any]:
|
|
return build_event("citizenship_claim", {"sacrifice_amount": sacrifice_amount})
|
|
|
|
|
|
def build_petition_file(
|
|
petition_id: str,
|
|
petition_payload: dict[str, Any],
|
|
) -> dict[str, Any]:
|
|
return build_event("petition_file", {
|
|
"petition_id": petition_id,
|
|
"petition_payload": petition_payload,
|
|
})
|
|
|
|
|
|
def build_petition_vote(petition_id: str, vote: str) -> dict[str, Any]:
|
|
return build_event("petition_vote", {"petition_id": petition_id, "vote": vote})
|
|
|
|
|
|
def build_node_register(public_key: str, public_key_algo: str, node_class: str) -> dict[str, Any]:
|
|
return build_event("node_register", {
|
|
"public_key": public_key,
|
|
"public_key_algo": public_key_algo,
|
|
"node_class": node_class,
|
|
})
|
|
|
|
|
|
__all__ = [
|
|
"EventConstructionError",
|
|
"build_citizenship_claim",
|
|
"build_event",
|
|
"build_node_register",
|
|
"build_petition_file",
|
|
"build_petition_vote",
|
|
"build_uprep",
|
|
]
|