"""DTN custody header and simple custody policy helpers. This module provides a minimal CustodyHeader dataclass used by DTN custody holders to make decisions about storing/transferring PlanDelta payloads. It also exposes a small helper that decides whether to accept custody based on priority, remaining lifetime, and a node reputation score. The implementation is intentionally small and deterministic for unit testing. """ from dataclasses import dataclass, field from typing import List, Optional import time @dataclass class CustodyHeader: delta_id: str created_at: float = field(default_factory=time.time) lifetime_secs: int = 3600 # how long the custody is expected to be valid custody_chain: List[str] = field(default_factory=list) priority_key: int = 0 # combined urgency/impact key (0..127) def is_expired(self, now: Optional[float] = None) -> bool: if now is None: now = time.time() return now > (self.created_at + self.lifetime_secs) def add_holder(self, node_id: str): # append to custody chain (no dedupe to keep deterministic append-only) self.custody_chain.append(node_id) def should_accept_custody(header: CustodyHeader, node_reputation: float, min_reputation: float = 0.2, now: Optional[float] = None) -> bool: """Decide whether a node should accept custody for a delta. Decision factors (simple heuristic): - If the header is already expired, refuse custody. - Prefer accepting higher priority_key values. - Gate acceptance by a minimum reputation threshold. Returns True if the node should accept custody. """ if header.is_expired(now=now): return False # Enforce a minimum reputation gate: nodes below min_reputation refuse custody if node_reputation < min_reputation: return False # decode urgency and impact from priority_key (urgency<<4)|impact urgency = (header.priority_key >> 4) & 0x07 impact = header.priority_key & 0x0F # compute a simple desirability score score = urgency * 2 + impact + (node_reputation * 4) # threshold depends on min_reputation; higher min_reputation raises bar threshold = 5.0 + (1.0 - min_reputation) * 3.0 return score >= threshold