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
| Parameter | Value |
|---|---|
| Cartesi Node | http://${CARTESI_NODE_IP}:10000 |
| DApp Address | 0xAE0863401D5B953b89cad8a5E7c98f5136E9C26d |
| InputBox | 0x59b22D57D4f067708AB0c00552767405926dc768 |
| Network | Arbitrum 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:
- No external network calls - All data comes via InputBox
- No system time - Use block timestamp from input metadata
- No randomness - Use deterministic algorithms only
- 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
| Error | Cause | Solution |
|---|---|---|
Unknown query type | Invalid type field | Check spelling, use valid query type |
Schema not found | Invalid schema_id | Verify schema exists with all_provider_schemas |
Access denied | No access grant | Owner must grant access first |
Invalid signature | Attestor signature failed | Verify attestor is registered |
Response Status
Accepted- Query successful, checkreportsarrayRejected- Query failed, checkexceptionfield
Credits
The Cartesi layer is built on Cartesi, enabling Linux-based deterministic computation on blockchain.