gizatechxyz / scarb-agent

All you need to build provable web3 Agents!
https://orion-giza.gitbook.io/scarb-agent
Apache License 2.0
4 stars 0 forks source link

Polling Implementation for Cairo-Hints #8

Closed raphaelDkhn closed 4 months ago

raphaelDkhn commented 4 months ago

Overview

Some hints can take a long time to process. This PR introduces a polling mechanism to Cairo-Hints, allowing it to handle long-running hint operations. The implementation enables Cairo programs to initiate hint requests and periodically check for results.

Key Changes

Modified execute_cheatcode function in rpc_hint_processor.rs:

The polling configuration can be writing in servers.json as follow:

{
    "oracle": {
        "server_url": "http://127.0.0.1:3000",
        "polling_config": {
            "max_attempts": 60,
            "polling_interval": 4,
            "timeout": 120
        }
    }
}

Polling parameters are set by default as follow:

 let default_polling_config = PollingConfig {
            max_attempts: 30,
            polling_interval: 2,
            timeout: 60,
        };

Server side example

In server side, you can implement the server as follow:

import express, { Request, Response } from 'express';
import crypto from 'crypto';

const app = express();
const hostname: string = '127.0.0.1';
const port: number = 3001;

app.use(express.json());

// In-memory storage for job status. (in a production env, we should use a database)
const jobs: Map<string, {status: string, result?: any}> = new Map();

app.post('/oracle', (req: Request, res: Response) => {
    const { 
        agent_id, contract, felt252_calldata, selector,
    } = req.body;

    console.log(`Agent ID: ${agent_id}`);
    console.log(`Contract: ${contract}`);
    console.log(`Calldata: ${felt252_calldata}`);
    console.log(`Selector: ${selector}`);

    // Generate a unique job ID
    const jobId = crypto.randomBytes(16).toString('hex');

    // Start the job
    jobs.set(jobId, {status: 'processing'});

    // Simulate a long-running process
    setTimeout(() => {
        const responseData = {
            tx_hash: "0x12345678909876543212"
        };
        jobs.set(jobId, {status: 'completed', result: responseData});
        console.log(`Job ${jobId} completed: ${JSON.stringify(responseData, null, 2)}`);
    }, 5000); // Simulate a 5-second process

    // Immediately return the job ID
    res.json({ jobId });
});

app.get('/status/:jobId', (req: Request, res: Response) => {
    const jobId = req.params.jobId;
    const job = jobs.get(jobId);

    if (!job) {
        return res.status(404).json({ error: 'Job not found' });
    }

    if (job.status === 'completed') {
        return res.json({ status: 'completed', result: job.result });
    } else {
        return res.json({ status: 'processing' });
    }
});

app.listen(port, hostname, () => {
    console.log(`App listening on port ${port}`);
});