Posting Request to a Subnet Model

When users need to utilize a subnet model within the 2PM Network, they must engage in a multi-step process to request inference from the model. This process involves contract interactions, data submissions, and cryptographic operations to ensure secure and authorized access to the model's capabilities. Here’s a comprehensive overview of posting a request to a subnet model:

Step-by-Step Process for Posting an Inference Request to a Subnet Model

  1. Interacting with the Royalty Vault Contract:

    • Users begin by interacting with the request_Inference method of the Royalty Vault contract associated with the model's corresponding subnet. This smart contract handles the economic transactions and access permissions for the subnet's resources.

  2. Uploading Signed Inference Data and Paying Fees:

    • As part of the contract interaction, users are required to upload a signature of their inference data. This signature acts as a verification mechanism to ensure the integrity and authenticity of the data being submitted for inference.

    • Additionally, users must pay the fees as defined in the contract. These fees compensate for the computational resources and used during the inference process and contribute to the ongoing development and maintenance of the subnet.

  3. Submitting the Transaction:

    • Once the necessary fees are paid and the data is signed and submitted, the transaction is completed on the blockchain. Users receive a transaction hash, which serves as a receipt and a tracking mechanism for the submitted request.

  4. Sending the Request to the 2PM Node:

    • With the transaction completed, users must then submit several pieces of information to the corresponding subnet's 2PM Node to initiate the inference process:

      • Transaction Hash: This is used by the 2PM Node to verify that the fees have been paid and the contract interactions are valid.

      • Inference Input Data: The actual input data on which inference is to be performed.

      • Inference Data Signature: This confirms the data's authenticity, ensuring it has not been altered since the signature was applied.

      • One-Time Key Signature: At the beginning of the request process, 2PM sends a one-time key to the user, which the user must sign and submit. This signature is used to ensure that the request is being made by the rightful user and to enhance the security of the data transmission.

  5. Receiving Inference Results:

    • Once the 2PM Node has verified all the submitted details, it processes the inference request. The results are then securely sent back to the user, completing the interaction.

For users involved in Fully Homomorphic Encryption (FHE) Model Inference, an additional step is required to access the results. FHE users must utilize their private key to decrypt the received data. This decryption step ensures that the privacy of the data is maintained throughout the process, as only the user with the corresponding private key can access the actual inference results.

Tutorial

This tutorial will guide you through the steps to interact with the Royalty Vault Contract using JavaScript (specifically with Web3.js library) and how to call the 2PM Node's API using HTTP RPC to request model predictions.

Prerequisites:

  • Node.js installed on your system.

  • Web3.js library installed. If not already installed, you can add it to your project by running npm install web3.

  • Access to an Ethereum wallet with Ether for transaction fees and a private key for signing transactions.

  • The address and ABI (Application Binary Interface) of the Royalty Vault Contract.

  • The URL for the 2PM Node API.

Step 1: Setup and Initialize Web3

First, set up your JavaScript environment and initialize Web3 to interact with the Ethereum blockchain.

const Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); // Update the provider URL

// Contract details
const contractABI = [/* ABI Array here */];
const contractAddress = '0xYourContractAddress';

// Create contract instance
const royaltyVaultContract = new web3.eth.Contract(contractABI, contractAddress);

// Set up your account
const account = '0xYourWalletAddress';
const privateKey = 'YourPrivateKey';

Step 2: Interacting with the Royalty Vault Contract

To interact with the Royalty Vault Contract, we will call the request_Inference method. Ensure you have the signature of the inference data input.

async function requestInference(datasetName, datasetId) {
    const data = royaltyVaultContract.methods.request_Inference(signature).encodeABI();

    const tx = {
        from: account,
        to: contractAddress,
        gas: 2000000, // set the gas limit to a suitable amount
        data: data 
    };

    const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);
    const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
    console.log("Transaction receipt: ", receipt);
}

Step 3: Calling the 2PM Node API

After the blockchain transaction is confirmed, you can make a prediction request to the 2PM Node API. Assume you have obtained a transaction hash and other necessary details for the API call.

const axios = require('axios');
const ethUtil = require('ethereumjs-util');
const Web3 = require('web3'); // Web3.js is required for Ethereum-specific functions like signing

// Initialize Web3
const web3 = new Web3();

// Function to sign data using a private key
function signData(data, privateKey) {
    const dataBuffer = Buffer.from(JSON.stringify(data));
    const hash = ethUtil.keccak256(dataBuffer);
    const signature = ethUtil.ecsign(hash, Buffer.from(privateKey, 'hex'));
    return ethUtil.bufferToHex(signature.r) + ethUtil.bufferToHex(signature.s).slice(2) + ethUtil.bufferToHex(signature.v).slice(2);
}

async function getOneTimeKey(apiURL) {
    try {
        const response = await axios.get(`${apiURL}/requestkey`);
        return response.data.key;
    } catch (error) {
        console.error("Error retrieving the one-time key: ", error.message);
        return null;  // Handle error appropriately
    }
}

async function callNodeAPI(txHash, inferenceData, privateKey, apiURL) {
    const oneTimeKey = await getOneTimeKey(apiURL);
    if (!oneTimeKey) {
        console.log("Failed to retrieve one-time key.");
        return;
    }

    const inferenceDataSig = signData(inferenceData, privateKey);
    const keySig = signData(oneTimeKey, privateKey);  // Sign the one-time key

    const postData = {
        txHash: txHash,
        data: inferenceData,
        signature: inferenceDataSig,
        keySignature: keySig
    };

    try {
        const response = await axios.post(`${apiURL}/model/predict`, postData);
        console.log("Inference result: ", response.data);
    } catch (error) {
        console.error("Error calling the 2PM Node API: ", error.response);
    }
}

// Sample data and transaction hash
const sampleData = { /* Your inference data here as JSON, may be encrypted for FHE ML Model */ }; 
const sampleTxHash = '0xYourTransactionHash';
const privateKey = 'YourPrivateKey'; // Private key in hex format
const apiURL = 'http://xxx.xxx.xx.xx:xxx'; // Update with actual 2PM Node API URL

// Run the function
callNodeAPI(sampleTxHash, sampleData, privateKey, apiURL);

Step 4: Decrypting the Results (for FHE ML model users only)

If the data received is encrypted (in the case of FHE), use your private key to decrypt the results (Refer to ZAMA Concrete ML Docs for details).

function decryptResults(encryptedData) {
    // Assuming you have a decryption function ready
    const decryptedData = decrypt(encryptedData, privateKey);
    // Perform any post processing (dequantize_output, argmax...)
    // ================================
    const postProcessedData = post_processing(decryptedData)
    console.log("Decrypted results: ", postProcessedData);
}

Last updated