"""Protocol error codes for the FablePool wire format. These codes are normative: a conforming implementation MUST reject an operation for the reason indicated by the code, and the conformance vectors (``fpcf.vectors``) assert the exact code an implementation must report. See spec/02-wire-format/05-versioning-errors-extensibility.md. Check ordering is also normative, because a defective operation may be defective in more than one way. Implementations MUST check in this order: 1. byte-level parsing -> E_JSON / E_NUMBER 2. canonical-form equality -> E_CANONICAL 3. envelope schema -> E_ENVELOPE 4. body schema (per op type) -> E_BODY 5. signature -> E_SIG 6. log context: prev existence -> E_PREV 7. log context: causality -> E_CAUSALITY 8. log context: typed references -> E_REF 9. append: duplicate op id -> E_DUP """ # -- byte level --------------------------------------------------------- E_JSON = "FP-E-JSON" # not valid UTF-8 / not valid JSON / duplicate keys E_NUMBER = "FP-E-NUMBER" # non-integer number, NaN/Infinity, or |n| > 2^53-1 # -- canonical form ----------------------------------------------------- E_CANONICAL = "FP-E-CANONICAL" # parses, but bytes are not the canonical serialization # -- schema ------------------------------------------------------------- E_ENVELOPE = "FP-E-ENVELOPE" # envelope schema violation (incl. unknown op type) E_BODY = "FP-E-BODY" # body schema violation for the declared op type # -- cryptography ------------------------------------------------------- E_SIG = "FP-E-SIG" # signature does not verify against `author` # -- log context -------------------------------------------------------- E_PREV = "FP-E-PREV" # a `prev` reference is not present in the log E_CAUSALITY = "FP-E-CAUSALITY" # `ts` is earlier than the `ts` of a `prev` op E_REF = "FP-E-REF" # a body reference is missing or of the wrong op type E_DUP = "FP-E-DUP" # operation already present in the log ALL_CODES = ( E_JSON, E_NUMBER, E_CANONICAL, E_ENVELOPE, E_BODY, E_SIG, E_PREV, E_CAUSALITY, E_REF, E_DUP, ) CODE_DESCRIPTIONS = { E_JSON: "input is not well-formed UTF-8 JSON (or contains duplicate object keys)", E_NUMBER: "input contains a number that is not an integer with |n| <= 2^53-1", E_CANONICAL: "input bytes are not the canonical serialization of the parsed value", E_ENVELOPE: "operation envelope violates the envelope schema", E_BODY: "operation body violates the body schema for its declared type", E_SIG: "signature does not verify against the author public key", E_PREV: "a prev reference does not resolve to an operation in the log", E_CAUSALITY: "operation timestamp precedes the timestamp of a prev operation", E_REF: "a body reference is missing from the log or has the wrong operation type", E_DUP: "operation id already exists in the log", } class FpcfError(Exception): """A protocol-level rejection with a normative error code.""" def __init__(self, code: str, message: str = ""): if code not in ALL_CODES: raise ValueError("unknown fpcf error code: %r" % (code,)) self.code = code super().__init__(message or CODE_DESCRIPTIONS[code]) def __str__(self) -> str: # pragma: no cover - cosmetic return "%s: %s" % (self.code, super().__str__())