Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Core: Other Errors (Governance, Identity, Names, Storage)

Crate: kinetic-core Stage: 8 Reading Time: 35 minutes Depends On: kinetic-core/src/error/mod.rs

What Is This?

This file provides comprehensive documentation for four highly specialized and critical error domains within the Kinetic network. These domains are:

  1. Governance execution.
  2. Identity validation.
  3. Name registration.
  4. Persistent storage. These error modules are located in kinetic-core/src/error/governance.rs, kinetic-core/src/error/identity.rs, kinetic-core/src/error/names.rs, and kinetic-core/src/error/storage.rs respectively. Rather than relying on generic, network-wide error enumerations, these modules carve out highly specific, domain-isolated taxonomies. This deep isolation ensures that when a failure occurs in a very specific subsystem, the error is perfectly tailored. For example, if the embedded Sled database fails to acquire a file lock, or a governance proposal lacks the required cryptographic signatures, the resulting error code is precise. The resulting error code, severity level, and user-facing message are perfectly tailored to that specific context. By separating these, Kinetic avoids a massive, monolithic Error enum that would require recompiling the world every time a single naming rule changes. It also allows us to implement very specific is_retryable() logic for each distinct domain.

Why Kinetic Needs This

Kinetic is designed as a fully autonomous network. This means it requires built-in sub-protocols for self-management, persistence, and human interaction. Each of these sub-protocols has unique constraints and failure conditions. These constraints simply cannot be mapped to generic “bad request” or “internal server error” paradigms.

  • Governance (KIN-GOV-NNN): The Kinetic network rules are updated dynamically via on-chain governance. This involves cryptographic thresholds, timelocks, and state machines. If a node attempts to process a proposal that doesn’t meet the required threshold of signatures, it must be rejected. If a node hasn’t waited the required timelock period, the governance engine must reject it explicitly. The network operators need to know exactly why a proposal was rejected. Was it too old? Was it improperly signed? Was it structurally invalid? These precise codes ensure operators can debug their governance CLI tools effectively. Without these specific errors, governance would be a black box of failed state transitions.

  • Identity (KIN-IDN-NNN): Every Kinetic node relies on a local, quantum-resistant ML-DSA-65 identity key. This identity is used to sign its messages. This identity is the foundational anchor of network trust. If a node boots up and cannot read, parse, or decrypt its identity file, it cannot participate in the network. It must halt immediately and alert the operator. Silently generating a new identity would result in the loss of all reputation. It would also result in the loss of routing history associated with the old key. Therefore, the daemon needs granular errors to differentiate between a bad password and a corrupted file.

  • Names (KIN-NAM-NNN): Kinetic provides a decentralized naming system. This allows human-readable apex names (like saif.kin). To maintain order and compatibility, we must strictly enforce global standards. Specifically, we enforce RFC 1035 and RFC 5891 limits. Furthermore, the network must protect reserved infrastructure names (like seed or explorer). This protects them from being squatted by early adopters. When a registration transaction violates these rules, the client needs a clear, actionable error. This allows the wallet software to present a helpful message to the end user.

  • Storage (KIN-STO-NNN): Kinetic relies on the Sled embedded B-tree database for local data persistence. Embedded databases run within the daemon process itself. This means they are highly sensitive to file locks and abrupt process termination. If a user tries to run two Kinetic daemons targeting the same storage directory, Sled will hit a file lock constraint. This needs to be trapped and bubbled up as a critical error (KIN-STO-001). This prevents catastrophic data corruption. A generic IO error would not adequately explain the severity of this lock contention.

How It Works

These four error modules implement the standard Kinetic error taxonomy traits. This means they each define specific functions to standardise network-wide errors. The required functions are code(), severity(), user_message(), error_type_uri(), and is_retryable(). However, the logic inside these implementations is deeply tied to the business rules of their respective domains.

1. Governance Validation Logic

-> See: kinetic-core/src/error/governance.rs — Lines 23 to 57

When a Kinetic node receives a SignedGovernanceMessage, the active GovernanceEngine intercepts the message. This engine can be configured in network.json as sovereign, council, or permissionless. The engine begins a rigorous verification sequence. This sequence must pass completely before any state mutation is allowed.

  • The Missing Root Key Crisis: The network must have an anchor of trust. During initialization, the engine checks for the ROOT_PUBLIC_KEY_HEX environment variable. If this is completely missing, the node yields GovernanceError::MissingRootKey. Because a node cannot evaluate founder-level overrides or verify network genesis state without this key, this is a fatal condition. The daemon will likely log this and invoke an immediate exit.

  • Cryptographic Key Validation: Governance actions often carry public keys for rotation or delegation. Since Kinetic uses ML-DSA-65, these public keys must be exactly 1,952 bytes long. If a provided byte slice does not match this strict length requirement, KeyLengthMismatch is returned. This prevents malformed payloads from wasting CPU cycles in the signature verification engine.

  • Time Windows and Replay Protection: The engine evaluates the timestamp embedded in the governance proposal. If the timestamp is older than the globally allowed replay window, it returns StaleProposal. The network sees old proposals drifting through gossip protocols all the time. Rejecting them is routine maintenance, not a critical fault.

  • Quorum and Thresholds: For networks operating under the council engine, a proposal must accumulate a specific threshold of signatures. These signatures must come from valid, active council members. If a proposal attempts execution before hitting this threshold, the engine returns InsufficientSignatures.

  • Mandatory Timelocks: To prevent governance attacks where a malicious quorum pushes a sudden change, proposals have mandatory delay periods. If the TimelockNotExpired error occurs, the network is simply enforcing patience. The operator must wait for the timelock window to naturally expire.

  • State Machine Compliance: Governance actions flow through a strict state machine. You can only execute or veto a proposal that is currently in a pending state. Attempting to act on a hash that is already finalized or unknown yields NotPendingOrVetoed.

  • Mode Restrictions: If a node operator explicitly configures their network.json to be permissionless, they are changing the node’s behaviour. They are declaring that their node will not accept any global governance updates. Any incoming governance action is immediately rejected with GovernanceDisabled.

  • Special Naming Actions: Governance has the power to forcefully grant or revoke names. However, rules still apply even to root authorities. Premium names must be exactly 1 character long. Violating this yields InvalidPremiumNameLength. Infrastructure name grants must target a valid Category 2 list. Violating this yields InvalidInfrastructureName.

2. Node Identity Loading Sequence

-> See: kinetic-core/src/error/identity.rs — Lines 13 to 33

The node identity subsystem is the very first component that executes when the Kinetic daemon starts. It dictates whether the node has the cryptographic authorization to join the network.

  • Disk I/O and File Access: The daemon attempts to locate and open {base_dir}/identity.key. If there is a filesystem permissions issue, a missing directory, or a hardware failure, an error is generated. This is a standard library std::io::Error. It is wrapped in the IdentityError::Io variant.

  • File Integrity Checks: If the file is successfully read, the daemon evaluates its size and structure. If the byte length does not match the strict layout of an encrypted ML-DSA-65 key payload, the engine aborts. It yields CorruptedIdentityFile. This is a critical safety check to prevent parsing garbage data.

  • Decryption Protocol: Identity files are protected. If the node operator provides an incorrect password via the environment or prompt, decryption fails. Additionally, if the cryptographic Message Authentication Code (MAC) on the payload fails validation, it also fails. In either case, DecryptionFailed is triggered.

  • Missing File Scenarios: If the file is simply absent (IdentityNotFound), the daemon’s bootloader must decide how to handle it. In a fresh install, it might silently generate a new key. But if the file is expected (e.g., restarting an existing node), this error forces the daemon to halt.

  • Seed Phrase Parsing: Kinetic allows node operators to restore their identity from a human-readable BIP-39 mnemonic seed phrase. If the user provides a phrase that has an invalid word count, it fails. If it fails the dictionary lookup, it fails. If it fails the checksum validation, it fails. Any of these failures results in InvalidSeedPhrase.

3. Naming System Enforcement Engine

-> See: kinetic-core/src/error/names.rs — Lines 15 to 44

The Kinetic naming system allows users to claim short, human-readable identifiers. When a user submits a registration transaction to the network, it is intercepted. It is intercepted by the is_valid_apex_name function, which enforces global standards.

  • RFC 5891 LDH Compliance: The naming engine iterates through every character in the requested name. If it finds emojis, uppercase letters, spaces, or special symbols, it instantly fails. The error yielded is InvalidCharacter. The LDH rule (Letters, Digits, Hyphens) is heavily enforced to ensure cross-platform compatibility.

  • RFC 1035 Length Constraints: To prevent network spam and ensure memory bounds, the entire name string is capped. It is capped at a maximum of 253 characters, yielding NameTooLong if exceeded. Furthermore, any single label (the word between dots, if applicable) is strictly capped. It is capped at 63 characters, yielding LabelTooLong if exceeded.

  • Hierarchy and Apex Enforcement: The global Kinetic DHT is designed to handle top-level domains and apex names, not infinite sub-trees. If a user attempts to register a deeply nested subname directly on the global network, it fails. The NotAnApexName error enforces the rule that subnames must be managed locally by the apex owner.

  • Category 1 Reserved Names: To prevent confusion with local DNS and networking standards, certain words are permanently blacklisted. Names like localhost, test, invalid, or example trigger the ReservedName error.

  • Category 2 Infrastructure Names: Kinetic reserves specific names for protocol infrastructure and internal tooling. Trying to register seed, explorer, docs, or api will fail. This triggers the InfrastructureName error. These are locked to prevent squatters from holding network infrastructure hostage.

  • TLD Enforcement: If the network enforces a specific top-level domain for all registrations (such as .kin), it checks this first. Submitting a name without it yields InvalidTLD.

4. Sled Storage Error Mapping

-> See: kinetic-core/src/error/storage.rs — Lines 13 to 24

Kinetic uses Sled, an embedded B-tree database, to persist state to the local disk. The storage error module acts as a translation layer. It maps Sled’s internal panics and errors into clean, structured Kinetic errors.

  • Lock Contention Management: Sled is strictly a single-writer database. It requires exclusive lock access to its database files. If a user accidentally runs kinetic start twice in the same terminal, it fails. The second instance will be blocked by the operating system file lock. This triggers DatabaseLocked (KIN-STO-001). This is a fatal condition that immediately kills the second process. It is the most critical error in the storage module.

  • Structural Corruption Detection: If the machine loses power abruptly and the Sled write-ahead log becomes unreadable, it corrupts. Or, if the B-tree pointers become mangled, the database detects this during the startup integrity check. It returns Corruption. This forces the node operator to intervene manually, possibly wiping the data folder.

  • Routine Operational Failures: If a standard GET, PUT, or DELETE operation fails due to transient disk issues, it yields an error. The engine yields OperationFailed. These are generally transient and safe to retry.

Key Pieces

The GovernanceError Enum Architecture

-> See: kinetic-core/src/error/governance.rs — Lines 23 to 57

This enumeration defines the entirety of the KIN-GOV-NNN taxonomy. Each variant has specific mappings for standard trait methods.

  • MissingRootKey (KIN-GOV-001): This is mapped to Severity::Critical. The user_message() clearly instructs the operator that the ROOT_PUBLIC_KEY_HEX variable is missing. It emphasizes that this is a fatal configuration error.
  • GovernanceDisabled (KIN-GOV-002): This is mapped to Severity::Warning. It informs the client that their request was rejected due to local node configuration. The node is operating in a permissionless state.
  • KeyLengthMismatch (KIN-GOV-003): This is mapped to Severity::Error. This indicates a cryptographic malformation.
  • StaleProposal (KIN-GOV-004): This is mapped to Severity::Info. The is_retryable() method returns false because an old proposal will never become valid.
  • TimelockNotExpired (KIN-GOV-005): This is mapped to Severity::Info. Crucially, is_retryable() returns true for this variant. A client simply needs to wait for the timelock window to pass and try broadcasting the execution again.
  • InsufficientSignatures (KIN-GOV-016): This is mapped to Severity::Warning. This is also is_retryable() == true, because the proposal might gather more signatures in the future.
  • Note on Skipped Codes: KIN-GOV-010, 011, and 012 are intentionally skipped. This is to allow for future expansion in the stable registry.

The IdentityError Enum Architecture

-> See: kinetic-core/src/error/identity.rs — Lines 13 to 33

This enumeration defines the KIN-IDN-NNN taxonomy. It has some unique trait implementations compared to the others.

  • Manual PartialEq Implementation: -> See RUST_CONCEPTS.md for why IdentityError implements PartialEq manually to handle std::io::Error.
  • Io (KIN-IDN-001): This is mapped to Severity::Error. This is an unavoidable reality of disk-based identity files.
  • CorruptedIdentityFile (KIN-IDN-002): This is mapped to Severity::Error. The user_message() warns that the file cannot be used.
  • DecryptionFailed (KIN-IDN-005): This is mapped to Severity::Error. The user_message() clearly states that either the password is incorrect or the payload is mangled.
  • InvalidSeedPhrase (KIN-IDN-004): Interestingly, this is mapped to Severity::Warning. This is because providing a bad seed phrase in a CLI recovery command is usually user error. It is not a systemic failure of the node itself.
  • Retry Logic: Every single variant in IdentityError returns false for is_retryable(). Identity failures require manual intervention. Automated polling will not fix a corrupted file.

The NamesError Enum Architecture

-> See: kinetic-core/src/error/names.rs — Lines 15 to 44

This enumeration defines the KIN-NAM-NNN taxonomy. It is purely focused on input validation.

  • Trait Derivations: This enum cleanly derives Error, Debug, PartialEq, Eq, and Clone.
  • Severity Mapping: The severity() method returns Severity::Warning for all variants. This is a specific design decision. A user submitting a bad name is a validation failure, not a node health crisis. It warrants a warning in the logs, not an alert.
  • Retry Logic: The is_retryable() method unconditionally returns false. If a name violates the RFC LDH rule once, it will violate it forever.
  • User Messages: The user_message() implementations are highly descriptive. For example, InvalidCharacter explicitly lists the allowed subset. “Only lowercase letters, digits, and internal hyphens are allowed.”

The StorageError Enum Architecture

-> See: kinetic-core/src/error/storage.rs — Lines 13 to 24

This enumeration defines the KIN-STO-NNN taxonomy. It is a bridge between third-party crates and Kinetic internal rules.

  • DatabaseLocked (KIN-STO-001): This is the only storage error mapped to Severity::Critical. The user_message() clearly explains that another instance of the Kinetic daemon is already running.
  • Corruption (KIN-STO-002): This is mapped to Severity::Error. The user_message() hints that the local database may need to be reset.
  • Retry Logic: The is_retryable() method uses a matches! macro. It returns true only if the error is OperationFailed. Lock contention and corruption are permanent dead ends. These require human intervention to fix.

How This Connects to the Rest of Kinetic

FORWARD DEPENDENCY: kinetic-storage The StorageError enum is defined in the kinetic-core crate. However, it is actually instantiated and returned by the database wrapper implementations. These implementations live inside the kinetic-storage crate. The core crate defines the abstract interface, and the storage crate fulfills it. This inversion of dependency keeps the core clean.

CROSS-CRATE: kinetic-daemon The kinetic-daemon crate’s boot sequence heavily relies on IdentityError and StorageError. If the daemon encounters DatabaseLocked during boot, it halts. If the daemon encounters MissingRootKey during governance initialization, it halts. The daemon will invoke a hard std::process::exit(1). These errors dictate the survival of the node process.

CROSS-CRATE: kinetic-rpc When a wallet client submits a name registration via the JSON-RPC interface, it is verified. The RPC server will invoke is_valid_apex_name. If that function returns a NamesError, the RPC server intercepts it. It extracts the user_message(), and serializes it into a JSON-RPC error response. This ensures the wallet UI displays a clean, human-readable reason for the rejection.

FORWARD DEPENDENCY: Governance Execution Engines The actual business logic that yields GovernanceError variants lives in the specialized execution engines. These are the sovereign, council, and permissionless modules. They implement the traits defined in core.

Quick Reference

  • KIN-GOV-001: MissingRootKey.
    • Severity: Critical.
    • Action: The node cannot initialize governance without the founder root.
  • KIN-GOV-003: KeyLengthMismatch.
    • Severity: Error.
    • Action: Ensure the key byte slice is exactly 1,952 bytes (ML-DSA-65).
  • KIN-GOV-004: StaleProposal.
    • Severity: Info.
    • Action: The proposal is too old. Non-retryable.
  • KIN-GOV-005: TimelockNotExpired.
    • Severity: Info.
    • Action: The waiting period is active. Retryable later.
  • KIN-GOV-016: InsufficientSignatures.
    • Severity: Warning.
    • Action: Proposal lacks quorum. Retryable later.
  • KIN-IDN-001: Io.
    • Severity: Error.
    • Action: Check filesystem permissions on the identity key directory.
  • KIN-IDN-002: CorruptedIdentityFile.
    • Severity: Error.
    • Action: The ML-DSA-65 key payload is structurally invalid.
  • KIN-IDN-004: InvalidSeedPhrase.
    • Severity: Warning.
    • Action: The BIP-39 mnemonic failed dictionary or checksum validation.
  • KIN-IDN-005: DecryptionFailed.
    • Severity: Error.
    • Action: Incorrect password or failed MAC check.
  • KIN-NAM-003: InvalidCharacter.
    • Severity: Warning.
    • Action: Ensure strict compliance with the RFC 5891 LDH rule.
  • KIN-NAM-007: NotAnApexName.
    • Severity: Warning.
    • Action: Subnames cannot be registered directly on the global network.
  • KIN-STO-001: DatabaseLocked.
    • Severity: Critical.
    • Action: Kill any ghost daemon processes competing for the Sled file lock.
  • KIN-STO-002: Corruption.
    • Severity: Error.
    • Action: The Sled write-ahead log is mangled. Requires manual database wipe.

Open Questions / Things to Revisit

  • Identity Key Format Flexibility: Currently, IdentityError::CorruptedIdentityFile expects a very specific and rigid ML-DSA-65 format length. If Kinetic ever expands to support hardware security modules (HSMs), this must change. If we support different quantum-resistant signature schemes in the future, it must also change. The corruption logic will need to parse version headers rather than relying on raw byte length checks.
  • Name TLD Hardcoding: The InvalidTLD error implies a hardcoded list of allowed TLDs (most likely just .kin). Should this list be adjustable via on-chain governance in the future? If so, the validator needs dynamic state access, not just static regex checks.
  • Sled Recovery Tooling: StorageError::Corruption is a dead end right now. Could we implement a standalone recovery tool? Or an auto-compaction mechanism that attempts to salvage key-value pairs from a corrupted Sled log? This would be better than forcing the user to wipe their node state.
  • Manual PartialEq Overhead: We should ensure manual equality checking for std::io::Error doesn’t lead to false positives if two distinct IO errors happen to share the same .kind().
  • Skipped Error Codes: The governance module intentionally skips KIN-GOV-010, KIN-GOV-011, and KIN-GOV-012. We should ensure that when new features are added, developers know these specific codes are reserved. They should be documented elsewhere to prevent collisions. These skipped blocks might suggest that features were removed or planned and never finished.