Infernet
SDK
Reference
Coordinator

Coordinator

Git Source (opens in a new tab)

Inherits: ReentrancyGuard

Coordination layer between consuming smart contracts and off-chain Infernet nodes

Implements ReentrancyGuard to prevent reentrancy in deliverCompute

Allows creating and deleting Subscription(s)

Allows any address (a node) to deliver susbcription outputs via off-chain container compute

Structs

Subscription

A subscription is the fundamental unit of Infernet

A subscription represents some request configuration for off-chain compute via containers on Infernet nodes

A subscription with frequency == 1 is a one-time subscription (a callback)

A subscription with frequency > 1 is a recurring subscription (many callbacks)

Tightly-packed struct:

  • [owner, activeAt, period, frequency]: [160, 32 32, 32] = 256
  • [redundancy, containerId, lazy, verifier]: [16, 32, 8, 160] = 216
  • [paymentAmount]: [256] = 256
  • [paymentToken]: [160] = 160
  • [wallet]: [160] = 160
struct Subscription {
    address owner;
    uint32 activeAt;
    uint32 period;
    uint32 frequency;
    uint16 redundancy;
    bytes32 containerId;
    bool lazy;
    address payable verifier;
    uint256 paymentAmount;
    address paymentToken;
    address payable wallet;
}

ProofRequest

A ProofRequest is a request made to a verifier contract to validate some proof bytes

Tightly-packed struct

  • [expiry, nodeWallet]: [32, 160] = 192
  • [consumerEscrowed]: [256] = 256
struct ProofRequest {
    uint32 expiry;
    Wallet nodeWallet;
    uint256 consumerEscrowed;
}

State Variables

FEE

Fee registry contract (used to collect protocol fee)

Fee private immutable FEE;

INBOX

Inbox contract (handles lazily storing subscription responses)

Inbox private immutable INBOX;

WALLET_FACTORY

Wallet factory contract (handles validity verification of Wallet contracts)

WalletFactory private immutable WALLET_FACTORY;

id

Current highest subscription ID

1-indexed to allow using id as a mapping value (prevent 0-indexed default from being misused)

uint32 size(4.2B) should be sufficiently large

uint32 public id = 1;

nodeResponded

hash(subscriptionId, interval, caller) => has caller responded for (sub, interval)?

mapping(bytes32 => bool) public nodeResponded;

redundancyCount

hash(subscriptionId, interval) => Number of responses for (sub, interval)?

Limited to type(Subscription.redundancy) == uint16

Technically, this is not required and we can save an SLOAD if we simply add a uint48 to the subscription struct that represents 32 bits of the interval -> 16 bits of redundancy count, reset each interval change But, this is a little over the optimization:readability line and would make Subscriptions harder to grok

mapping(bytes32 => uint16) public redundancyCount;

proofRequests

hash(subscriptionId, interval, caller) => proof request

mapping(bytes32 => ProofRequest) public proofRequests;

subscriptions

subscriptionID => Subscription

1-indexed, 0th-subscription is empty

Visibility restricted to internal because we expose an explicit getSubscription view function that returns Subscription struct

mapping(uint32 => Subscription) internal subscriptions;

Functions

constructor

Initializes new Coordinator

constructor(Registry registry);

Parameters

NameTypeDescription
registryRegistryregistry contract

_calculateFee

Given an input amount, returns the value of fee applied to it

function _calculateFee(uint256 amount, uint16 fee) internal pure returns (uint256);

Parameters

NameTypeDescription
amountuint256to calculate fee on top of
feeuint16to use in calculation

Returns

NameTypeDescription
<none>uint256fee amount

getSubscription

Returns Subscription from subscriptions mapping, indexed by subscriptionId

Useful utility view function because by default public mappings with struct values return destructured parameters

function getSubscription(uint32 subscriptionId) external view returns (Subscription memory);

Parameters

NameTypeDescription
subscriptionIduint32subscription ID to collect

createSubscription

Creates new subscription

function createSubscription(
    string memory containerId,
    uint32 frequency,
    uint32 period,
    uint16 redundancy,
    bool lazy,
    address paymentToken,
    uint256 paymentAmount,
    address wallet,
    address verifier
) external returns (uint32);

Parameters

NameTypeDescription
containerIdstringcompute container identifier used by off-chain Infernet node
frequencyuint32max number of times to process subscription (i.e, frequency == 1 is a one-time request)
perioduint32period, in seconds, at which to progress each responding interval
redundancyuint16number of unique responding Infernet nodes
lazyboolwhether to lazily store subscription responses
paymentTokenaddressIf providing payment for compute, payment token address (address(0) for ETH, else ERC20 contract address)
paymentAmountuint256If providing payment for compute, payment in paymentToken per compute request fulfillment
walletaddressIf providing payment for compute, Infernet Wallet address; msg.sender must be approved spender
verifieraddressoptional verifier contract to restrict payment based on response proof verification

Returns

NameTypeDescription
<none>uint32subscription ID

cancelSubscription

Cancel a subscription

Must be called by subscriptions[subscriptionId].owner

Cancels subscription by setting Subscription activeAt to maximum (technically, de-activating)

function cancelSubscription(uint32 subscriptionId) external;

Parameters

NameTypeDescription
subscriptionIduint32subscription ID to cancel

getSubscriptionInterval

Calculates subscription interval based on activeAt and period

function getSubscriptionInterval(uint32 activeAt, uint32 period) public view returns (uint32);

Parameters

NameTypeDescription
activeAtuint32when does a subscription start accepting callback responses
perioduint32time, in seconds, between each subscription response interval

Returns

NameTypeDescription
<none>uint32current subscription interval

deliverCompute

Allows any address (nodes) to deliver container compute responses for a subscription

Re-entering generally does not work because each node can only call deliverCompute once per subscription

But, you can call deliverCompute with a seperate msg.sender (in same delivery call) so we optimistically restrict with nonReentrant

When Subscription(s) request lazy responses, stores container output in Inbox

When Subscription(s) request eager responses, delivers container output directly via BaseConsumer.rawReceiveCompute()

function deliverCompute(
    uint32 subscriptionId,
    uint32 deliveryInterval,
    bytes calldata input,
    bytes calldata output,
    bytes calldata proof,
    address nodeWallet
) public nonReentrant;

Parameters

NameTypeDescription
subscriptionIduint32subscription ID to deliver
deliveryIntervaluint32subscription interval to deliver
inputbytesoptional off-chain input recorded by Infernet node (empty, hashed input, processed input, or both)
outputbytesoptional off-chain container output (empty, hashed output, processed output, both, or fallback: all encodeable data)
proofbytesoptional container execution proof (or arbitrary metadata)
nodeWalletaddressnode wallet (used to receive payments, and put up escrow/slashing funds); msg.sender must be authorized spender of wallet

finalizeProofVerification

Inbound counterpart to IVerifier.requestProofVerification() to process proof verification

If called by verifier, accepts valid to process payout

Else, can be called by anyone after 1 week timeout to side in favor of node by default

function finalizeProofVerification(uint32 subscriptionId, uint32 interval, address node, bool valid) external;

Parameters

NameTypeDescription
subscriptionIduint32subscription ID for which proof verification was requested
intervaluint32interval of subscription for which proof verification was requested
nodeaddressnode in said interval for which proof verification was requested
validbooltrue if proof was valid, else false

Events

SubscriptionCreated

Emitted when a new subscription is created

event SubscriptionCreated(uint32 indexed id);

Parameters

NameTypeDescription
iduint32subscription ID

SubscriptionCancelled

Emitted when a subscription is cancelled

event SubscriptionCancelled(uint32 indexed id);

Parameters

NameTypeDescription
iduint32subscription ID

SubscriptionFulfilled

Emitted when a subscription is fulfilled

event SubscriptionFulfilled(uint32 indexed id, address indexed node);

Parameters

NameTypeDescription
iduint32subscription ID
nodeaddressaddress of fulfilling node

Errors

InvalidWallet

Thrown by deliverCompute() if attempting to use an invalid wallet or one not created by WalletFactory

4-byte signature: 0x23455ba1

error InvalidWallet();

IntervalMismatch

Thrown by deliverCompute() if attempting to deliver container compute response for non-current interval

E.g submitting tx for interval < current (period elapsed) or interval > current (too early to submit)

4-byte signature: 0x4db310c3

error IntervalMismatch();

IntervalCompleted

Thrown by deliverCompute() if redundancy has been met for current interval

E.g submitting 4th output tx for a subscription with redundancy == 3

4-byte signature: 0x2f4ca85b

error IntervalCompleted();

UnauthorizedVerifier

Thrown by finalizeProofVerification() if called by a msg.sender that is unauthorized to finalize proof

When a proof request is expired, this can be any address; until then, this is the designated verifier address

4-byte signature: 0xb9857aa1

error UnauthorizedVerifier();

NodeRespondedAlready

Thrown by deliverCompute() if node has already responded this interval

4-byte signature: 0x88a21e4f

error NodeRespondedAlready();

SubscriptionNotFound

Thrown by deliverCompute() if attempting to access a subscription that does not exist

4-byte signature: 0x1a00354f

error SubscriptionNotFound();

ProofRequestNotFound

Thrown by finalizeProofVerification() if attempting to access a proof request that does not exist

4-byte signature: 0x1d68b37c

error ProofRequestNotFound();

NotSubscriptionOwner

Thrown by cancelSubscription() if attempting to modify a subscription not owned by caller

4-byte signature: 0xa7fba711

error NotSubscriptionOwner();

SubscriptionCompleted

Thrown by deliverCompute() if attempting to deliver a completed subscription

4-byte signature: 0xae6704a7

error SubscriptionCompleted();

SubscriptionNotActive

Thrown by deliverCompute() if attempting to deliver a subscription before activeAt

4-byte signature: 0xefb74efe

error SubscriptionNotActive();

UnsupportedVerifierToken

Thrown by deliverCompute if attempting to pay a IVerifier-contract in a token it does not support receiving payments in

4-byte signature: 0xe2372799

error UnsupportedVerifierToken();