Technical reference for the three core CompressNode contracts on Base.

    Contract Overview

    CompressNode deploys three interdependent smart contracts on Base. They handle all on-chain logic: node registration, job escrow, and verification challenges. All contracts are written in Solidity, compiled with Foundry, and use OpenZeppelin's Ownable for access control.

    NodeRegistry

    Manages node lifecycle - registration, deactivation, and reputation tracking.

    • registerNode(endpoint, gpuTier) - register a new node (permissionless, free)
    • deactivateSelf() - operator can voluntarily deactivate their node
    • updateGpuTier(newTier) - update GPU tier after hardware upgrade
    • getActiveNodes() - returns all currently active node addresses
    • setLastChallengeAt(node) - called by VerificationEngine after challenge issuance
    • Stores: operator address, endpoint, registeredAt, reputation (0-10000), gpuTier, active status, jobsCompleted, jobsFailed, totalEarned

    JobRegistry

    Handles job submission, assignment, completion, and ETH payments.

    • submitJob(modelId, inputHash) payable - submit a job with ETH payment locked in escrow
    • assignJob(jobId, nodeAddress) - backend assigns the job to the best available node
    • completeJob(jobId, outputHash) - node completes the job, receives 95% ETH, 5% burned
    • expireJob(jobId) - requester reclaims ETH if job is unassigned after 24 hours
    • Follows CEI (Checks-Effects-Interactions) pattern to prevent reentrancy attacks

    VerificationEngine

    Issues challenges and validates node responses.

    • issueChallenge(nodeAddress, inputHash, expectedOutputHash) - restricted to authorized issuers
    • respondToChallenge(challengeId, responseHash) - called by the challenged node
    • checkTimeout(challengeId) - deactivates nodes that miss the response window
    • Uses block.prevrandao for additional entropy in challenge selection

    Security Patterns

    All contracts implement: zero-address checks on constructors and setters, CEI (Checks-Effects-Interactions) pattern for ETH transfers, access control via onlyOwner and onlyIssuer modifiers, bounded loops to prevent gas limit issues, and a receive() fallback on JobRegistry for direct ETH deposits.