Infernet
SDK
Reference
Coordinator

Coordinator

Git Source (opens in a new tab)

Inherits: Manager

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

Allows creating and deleting Subscription(s)

Allows nodes with Manager.NodeStatus.Active to deliver subscription outputs via off-chain container compute

State Variables

DELIVERY_OVERHEAD_WEI

Gas overhead in wei to deliver container compute responses

This is the additional cost of any validation checks performed within the Coordinator before delivering responses to consumer contracts

A uint16 is sufficient but we are not packing variables so control plane cost is higher because of type casting during operations. Thus, we can just stick to uint256

uint256 public constant DELIVERY_OVERHEAD_WEI = 56_600 wei;

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:redability line and would make Subscriptions harder to grok

mapping(bytes32 => uint16) public redundancyCount;

subscriptions

subscriptionID => Subscription

1-indexed, 0th-subscription is empty

mapping(uint32 => Subscription) public subscriptions;

Functions

_deliverComputeWithOverhead

Internal counterpart to deliverCompute() w/ ability to set custom gas overhead allowance

When called by deliverCompute(), callingOverheadWei == 0 because no additional overhead imposed

_When called by deliverComputeDelegatee(), DELEGATEE*OVERHEAD*_\_WEI is imposed*

function _deliverComputeWithOverhead(
    uint32 subscriptionId,
    uint32 deliveryInterval,
    bytes calldata input,
    bytes calldata output,
    bytes calldata proof,
    uint256 callingOverheadWei
) internal;

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)
callingOverheadWeiuint256additional overhead gas used for delivery

createSubscription

Creates new subscription

function createSubscription(
    string memory containerId,
    bytes calldata inputs,
    uint48 maxGasPrice,
    uint32 maxGasLimit,
    uint32 frequency,
    uint32 period,
    uint16 redundancy
) external returns (uint32);

Parameters

NameTypeDescription
containerIdstringcompute container identifier used by off-chain Infernet node
inputsbytesoptional container inputs
maxGasPriceuint48max gas price in wei paid by an Infernet node when fulfilling callback
maxGasLimituint32max gas limit in wei paid by an Infernet node in callback tx
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

Returns

NameTypeDescription
<none>uint32subscription ID

cancelSubscription

Cancel a subscription

Must be called by subscriptions[subscriptionId].owner

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 nodes with Manager.NodeStatus.Active to deliver container compute responses for a subscription

Re-entering does not work because only active nodes (max 1 response) can call deliverCompute

Re-entering and delivering via a seperate node msg.sender works but is ignored in favor of explicit maxGasLimit

For containers without succinctly-verifiable proofs, the proof field can be repurposed for arbitrary metadata

Enforces an overhead delivery cost of DELIVERY_OVERHEAD_WEI and 0 additional overhead

function deliverCompute(
    uint32 subscriptionId,
    uint32 deliveryInterval,
    bytes calldata input,
    bytes calldata output,
    bytes calldata proof
) external onlyActiveNode;

Parameters

NameTypeDescription
subscriptionIduint32subscription ID to deliver
deliveryIntervaluint32subscription interval to deliver
inputbytesoptional off-chain container 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 off-chain container execution proof (or arbitrary metadata)

Events

SubscriptionCreated

Emitted when a new subscription is created

event SubscriptionCreated(uint32 indexed id);

SubscriptionCancelled

Emitted when a subscription is cancelled

event SubscriptionCancelled(uint32 indexed id);

SubscriptionFulfilled

Emitted when a subscription is fulfilled

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

Errors

GasPriceExceeded

Thrown by deliverComputeWithOverhead() if delivering tx with gasPrice > subscription maxGasPrice

E.g. submitting tx with gas price 10 gwei when network basefee is 11 gwei

4-byte signature: 0x682bad5a

error GasPriceExceeded();

GasLimitExceeded

Thrown by deliverComputeWithOverhead() if delivering tx with consumed gas > subscription maxGasLimit

E.g. submitting tx with gas consumed 200_000 wei when max allowed by subscription is 175_000 wei

4-byte signature: 0xbe9179a6

error GasLimitExceeded();

IntervalMismatch

Thrown by deliverComputeWithOverhead() 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 deliverComputeWithOverhead() 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();

NodeRespondedAlready

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

4-byte signature: 0x88a21e4f

error NodeRespondedAlready();

SubscriptionNotFound

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

4-byte signature: 0x1a00354f

error SubscriptionNotFound();

NotSubscriptionOwner

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

4-byte signature: 0xa7fba711

error NotSubscriptionOwner();

SubscriptionCompleted

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

4-byte signature: 0xae6704a7

error SubscriptionCompleted();

SubscriptionNotActive

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

4-byte signature: 0xefb74efe

error SubscriptionNotActive();

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]: [32, 160, 32, 32] = 256
  • [redundancy, maxGasPrice, maxGasLimit]: [16, 48, 32] = 96*
struct Subscription {
    /// @notice Subscription owner + recipient
    /// @dev This is the address called to fulfill a subscription request and must inherit `BaseConsumer`
    /// @dev Default initializes to `address(0)`
    address owner;
    /// @notice Timestamp when subscription is first active and an off-chain Infernet node can respond
    /// @dev When `period == 0`, the subscription is immediately active
    /// @dev When `period > 0`, subscription is active at `createdAt + period`
    uint32 activeAt;
    /// @notice Time, in seconds, between each subscription interval
    /// @dev At worst, assuming subscription occurs once/year << uint32
    uint32 period;
    /// @notice Number of times a subscription is processed
    /// @dev At worst, assuming 30 req/min * 60 min * 24 hours * 365 days * 10 years << uint32
    uint32 frequency;
    /// @notice Number of unique nodes that can fulfill a subscription at each `interval`
    /// @dev uint16 allows for >255 nodes (uint8) but <65,535
    uint16 redundancy;
    /// @notice Max gas price in wei paid by an Infernet node when fulfilling callback
    /// @dev uint40 caps out at ~1099 gwei, uint48 allows up to ~281K gwei
    uint48 maxGasPrice;
    /// @notice Max gas limit in wei used by an Infernet node when fulfilling callback
    /// @dev Must be at least equal to the gas limit of your receiving function execution + DELIVERY_OVERHEAD_WEI
    /// @dev uint24 is too small at ~16.7M (<30M mainnet gas limit), but uint32 is more than enough (~4.2B wei)
    uint32 maxGasLimit;
    /// @notice Container identifier used by off-chain Infernet nodes to determine which container is used to fulfill a subscription
    /// @dev Can be used to specify a linear DAG of containers by seperating container names with a "," delimiter ("A,B,C")
    /// @dev Better represented by a string[] type but constrained to string to keep struct and functions simple
    string containerId;
    /// @notice Optional container input parameters
    /// @dev If left empty, off-chain Infernet nodes call public view fn: `BaseConsumer(owner).getContainerInputs()`
    bytes inputs;
}