Skip to main content

Cartesi Layer Documentation

L{CORE} Specific: The Cartesi layer is L{CORE}'s contribution to the architecture—this is our code built on Cartesi's open-source rollup infrastructure. It stores IoT attestations verified by Reclaim's attestor-core.

The Cartesi layer provides deterministic state management and privacy controls for L{CORE}. It runs as a Cartesi rollup on Arbitrum Sepolia.

Overview

The Cartesi layer handles:

  • Provider Schema Registration - Storing and retrieving provider definitions
  • Attestation Storage - Encrypted storage of attestation data
  • Access Control - Granting and revoking data access permissions
  • Privacy-Preserving Queries - Querying data with encryption

Architecture

graph TB
subgraph "Cartesi Rollup"
IM[InputBox Contract] --> |advance| CM[Cartesi Machine]
CM --> |inspect| IQ[Inspect Queries]
CM --> DB[(SQLite Database)]
end

subgraph "State Tables"
DB --> PS[provider_schemas]
DB --> AT[attestations]
DB --> AC[access_grants]
end

Production Deployment

ParameterValue
Cartesi Nodehttp://${CARTESI_NODE_IP}:10000
DApp Address0xAE0863401D5B953b89cad8a5E7c98f5136E9C26d
InputBox0x59b22D57D4f067708AB0c00552767405926dc768
NetworkArbitrum Sepolia (421614)

Query Types

Inspect Queries (Read-Only)

Inspect queries are read-only and don't modify state. They're sent via HTTP GET to the Cartesi node.

URL Format

http://<node>:10000/inspect/<url-encoded-json>

Important: The payload must be URL-encoded JSON, NOT hex-encoded.

all_provider_schemas

List all registered provider schemas.

# Request
curl "http://${CARTESI_NODE_IP}:10000/inspect/$(python3 -c "import urllib.parse; print(urllib.parse.quote('{\"type\":\"all_provider_schemas\",\"params\":{}}'))")"

# Response
{
"status": "Accepted",
"reports": [{
"payload": "0x..." // Hex-encoded JSON array of schemas
}]
}

provider_schema

Get a specific provider schema by ID.

# Request
curl "http://${CARTESI_NODE_IP}:10000/inspect/$(python3 -c "import urllib.parse; print(urllib.parse.quote('{\"type\":\"provider_schema\",\"params\":{\"schema_id\":\"coingecko-btc-price\"}}'))")"

attestations_by_owner

Get all attestations for a specific owner address.

# Request
curl "http://${CARTESI_NODE_IP}:10000/inspect/$(python3 -c "import urllib.parse; print(urllib.parse.quote('{\"type\":\"attestations_by_owner\",\"params\":{\"owner\":\"0x1234...\"}}'))")"

check_access

Check if a requester has access to an owner's data.

# Request
curl "http://${CARTESI_NODE_IP}:10000/inspect/$(python3 -c "import urllib.parse; print(urllib.parse.quote('{\"type\":\"check_access\",\"params\":{\"owner\":\"0x1234...\",\"requester\":\"0x5678...\"}}'))")"

Advance Inputs (State Changes)

Advance inputs modify state and must be submitted via the InputBox contract on-chain.

Input Format

interface LCoreInput {
type: string;
params: Record<string, any>;
}

register_provider_schema

Register a new provider schema.

{
type: "register_provider_schema",
params: {
schema_id: "coingecko-btc-price",
name: "CoinGecko BTC Price",
description: "Bitcoin price from CoinGecko API",
provider_type: "http",
config: {
url: "https://api.coingecko.com/api/v3/simple/price",
method: "GET",
// ... provider-specific config
}
}
}

store_attestation

Store an attestation (called by Attestor service).

{
type: "store_attestation",
params: {
owner: "0x1234...",
schema_id: "coingecko-btc-price",
encrypted_data: "base64-encrypted-payload",
timestamp: 1704067200,
attestor_signature: "0x..."
}
}

grant_access

Grant another address access to your data.

{
type: "grant_access",
params: {
owner: "0x1234...", // Must match msg.sender
grantee: "0x5678...",
schema_id: "coingecko-btc-price", // Optional: specific schema
expires_at: 1704153600 // Optional: expiration timestamp
}
}

revoke_access

Revoke previously granted access.

{
type: "revoke_access",
params: {
owner: "0x1234...",
grantee: "0x5678...",
schema_id: "coingecko-btc-price" // Optional
}
}

Submitting Inputs via InputBox

To submit advance inputs, interact with the InputBox contract:

import { ethers } from 'ethers';

const INPUT_BOX_ADDRESS = '0x59b22D57D4f067708AB0c00552767405926dc768';
const DAPP_ADDRESS = '0xAE0863401D5B953b89cad8a5E7c98f5136E9C26d';

const INPUT_BOX_ABI = [
'function addInput(address _dapp, bytes calldata _input) external returns (bytes32)'
];

async function submitInput(signer: ethers.Signer, input: object) {
const inputBox = new ethers.Contract(INPUT_BOX_ADDRESS, INPUT_BOX_ABI, signer);

// Encode input as bytes
const payload = ethers.toUtf8Bytes(JSON.stringify(input));

// Submit to InputBox
const tx = await inputBox.addInput(DAPP_ADDRESS, payload);
await tx.wait();

return tx.hash;
}

// Example: Grant access
await submitInput(signer, {
type: 'grant_access',
params: {
owner: await signer.getAddress(),
grantee: '0x5678...',
schema_id: 'coingecko-btc-price'
}
});

Database Schema

The Cartesi layer uses SQLite for deterministic state storage.

provider_schemas

CREATE TABLE provider_schemas (
schema_id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
provider_type TEXT NOT NULL,
config TEXT NOT NULL, -- JSON
created_at INTEGER NOT NULL,
created_by TEXT NOT NULL
);

attestations

CREATE TABLE attestations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
owner TEXT NOT NULL,
schema_id TEXT NOT NULL,
encrypted_data TEXT NOT NULL, -- Base64 NaCl box
timestamp INTEGER NOT NULL,
attestor_address TEXT NOT NULL,
attestor_signature TEXT NOT NULL,
FOREIGN KEY (schema_id) REFERENCES provider_schemas(schema_id)
);
CREATE INDEX idx_attestations_owner ON attestations(owner);
CREATE INDEX idx_attestations_schema ON attestations(schema_id);

access_grants

CREATE TABLE access_grants (
id INTEGER PRIMARY KEY AUTOINCREMENT,
owner TEXT NOT NULL,
grantee TEXT NOT NULL,
schema_id TEXT, -- NULL = all schemas
expires_at INTEGER, -- NULL = never expires
created_at INTEGER NOT NULL,
UNIQUE(owner, grantee, schema_id)
);
CREATE INDEX idx_access_owner ON access_grants(owner);
CREATE INDEX idx_access_grantee ON access_grants(grantee);

Encryption

All sensitive attestation data is encrypted using NaCl box (X25519-XSalsa20-Poly1305).

Key Generation

node -e "
const nacl = require('tweetnacl');
const keypair = nacl.box.keyPair();
console.log('Public:', Buffer.from(keypair.publicKey).toString('base64'));
console.log('Private:', Buffer.from(keypair.secretKey).toString('base64'));
"

Encryption Flow

sequenceDiagram
participant User
participant Attestor
participant Cartesi

User->>Attestor: Request attestation
Attestor->>Attestor: Generate proof
Attestor->>Attestor: Encrypt with admin public key
Attestor->>Cartesi: Store encrypted attestation
Cartesi->>Cartesi: Verify & store

Note over User,Cartesi: Later - Data Access

User->>Cartesi: check_access query
Cartesi->>User: Access granted/denied
User->>Attestor: Request decryption (if granted)
Attestor->>Attestor: Decrypt with admin private key
Attestor->>User: Decrypted data

Determinism Requirements

The Cartesi layer must be fully deterministic:

  1. No external network calls - All data comes via InputBox
  2. No system time - Use block timestamp from input metadata
  3. No randomness - Use deterministic algorithms only
  4. SQLite only - No external databases

This ensures all Cartesi nodes produce identical state transitions.


Decoding Responses

Cartesi returns hex-encoded payloads. To decode:

function decodeReport(report: { payload: string }): any {
// Remove '0x' prefix and decode hex to UTF-8
const hex = report.payload.slice(2);
const bytes = Buffer.from(hex, 'hex');
return JSON.parse(bytes.toString('utf-8'));
}

// Example
const response = await fetch('http://${CARTESI_NODE_IP}:10000/inspect/...');
const data = await response.json();

if (data.reports && data.reports.length > 0) {
const result = decodeReport(data.reports[0]);
console.log(result);
}

Error Handling

Common Errors

ErrorCauseSolution
Unknown query typeInvalid type fieldCheck spelling, use valid query type
Schema not foundInvalid schema_idVerify schema exists with all_provider_schemas
Access deniedNo access grantOwner must grant access first
Invalid signatureAttestor signature failedVerify attestor is registered

Response Status

  • Accepted - Query successful, check reports array
  • Rejected - Query failed, check exception field

Credits

The Cartesi layer is built on Cartesi, enabling Linux-based deterministic computation on blockchain.