Infernet
SDK
Consumers
Callback

CallbackConsumer

Technical reference

The CallbackConsumer is a simple, easy-to-inherit interface that developers can use in their smart contracts to create one-time reqests for off-chain output, delivered via callback.

It is best used when your contract does not need to create a recurring Subscription and instead requests off-chain compute in an asynchronous callback fashion.

Using this consumer

Install dependencies

Before getting started, ensure you have installed the Infernet SDK in your Solidity smart contract project. You can follow the installation instructions found in the introduction.

Inherit CallbackConsumer.sol

In your smart contract, you must inherit the CallbackConsumer.sol abstract contract found in infernet/core/consumers/Callback.sol:

import {CallbackConsumer} from "infernet/core/consumers/Callback.sol";
 
contract MyContract is CallbackConsumer {}

Initialize the consumer

Once inherited, you must provide the address to the Infernet coordinator contract (see: architecture: coordinator if unfamiliar) to the CallbackConsumer constructor:

import {CallbackConsumer} from "infernet/core/consumers/Callback.sol";
 
contract MyContract is CallbackConsumer {
    constructor(address infernetCoordinator) CallbackConsumer(infernetCoordinator) {}
}

Request container compute via callback

By default, the CallbackConsumer exposes a _requestCompute() function (technical reference) that allows initiating a one-time callback request for compute.

We can use this function to execute an example call to run our off-chain test-model ML container workflow with some example feature inputs abcde and request a response from a single node:

ℹ️

Keen observers will notice that, behind-the-scenes, a one-time callback request is simply implemented as a Subscription that has frequency == 1 (only processed once) and period == 0 (immediately available for response from an Infernet node).

import {CallbackConsumer} from "infernet/core/consumers/Callback.sol";
 
contract MyContract is CallbackConsumer {
    constructor(address infernetCoordinator) CallbackConsumer(infernetCoordinator) {}
 
    function callMyModel() external {
        _requestCompute(
            "test-model", // Container ID for our ML model
            bytes("abcde"), // Inputs
            100 gwei, // Max callback gas price
            100_000 wei + COORDINATOR.DELIVERY_OVERHEAD_WEI(), // Max callback gas limit
            1 // Only 1 responding node
        )
    }
}

Receive container output via callback

By default, the CallbackConsumer exposes a _receiveCompute() function (technical reference) which is called every time your smart contract receives a callback response from an Infernet node. This is where you should consume your response outputs, do proof verification, or store response data.

In our example, we will simply push the received output from our test workflow above to an outputs array for future consumption.

ℹ️

Note that the _receiveCompute() function can only be called by the Coordinator, and, in-kind, registered and active Infernet nodes. The entrypoint for the Coordinator is the authorized rawReceiveCompute function.

import {CallbackConsumer} from "infernet/core/consumers/Callback.sol";
 
contract MyContract is CallbackConsumer {
    bytes[] public outputs;
 
    constructor(address infernetCoordinator) CallbackConsumer(infernetCoordinator) {}
 
    function _receiveCompute(
        uint32 subscriptionId,
        uint32 interval,
        uint16 redundancy,
        address node,
        bytes calldata input,
        bytes calldata output,
        bytes calldata proof
    ) internal override {
        // We simply track `output` for future consumption in our callback
        outputs.push(output);
    }
 
    function callMyModel() external {
        _requestCompute(
            "test-model", // Container ID for our ML model
            bytes("abcde"), // Inputs
            100 gwei, // Max callback gas price
            100_000 wei + COORDINATOR.DELIVERY_OVERHEAD_WEI(), // Max callback gas limit
            1 // Only 1 responding node
        )
    }
}

Test your implementation

That's all it takes to get started with the CallbackConsumer! You're now ready to test your implementation with mock data (see: our testing best-practices) and deploy your contracts.