Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RP for plugin-tee-verifiable-log #1331

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"@ai16z/plugin-multiversx": "workspace:*",
"@ai16z/plugin-near": "workspace:*",
"@ai16z/plugin-zksync-era": "workspace:*",
"@ai16z/plugin-tee-verifiable-log": "workspace:*",
"readline": "1.3.0",
"ws": "8.18.0",
"yargs": "17.7.2"
Expand Down
5 changes: 5 additions & 0 deletions agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ import { suiPlugin } from "@ai16z/plugin-sui";
import { TEEMode, teePlugin } from "@ai16z/plugin-tee";
import { tonPlugin } from "@ai16z/plugin-ton";
import { zksyncEraPlugin } from "@ai16z/plugin-zksync-era";
import { verifiableLogPlugin } from "@ai16z/plugin-tee-verifiable-log";

import Database from "better-sqlite3";
import fs from "fs";
import path from "path";
Expand Down Expand Up @@ -562,6 +564,9 @@ export async function createAgent(
getSecret(character, "TON_PRIVATE_KEY") ? tonPlugin : null,
getSecret(character, "SUI_PRIVATE_KEY") ? suiPlugin : null,
getSecret(character, "STORY_PRIVATE_KEY") ? storyPlugin : null,
(teeMode !== TEEMode.OFF && walletSecretSalt &&getSecret(character,"VLOG")
? verifiableLogPlugin
: null)
].filter(Boolean),
providers: [],
actions: [],
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,7 @@ export enum ServiceType {
AWS_S3 = "aws_s3",
BUTTPLUG = "buttplug",
SLACK = "slack",
VERIFIABLE_LOGGING = "verifiable_logging",
}

export enum LoggingLevel {
Expand Down
6 changes: 6 additions & 0 deletions packages/plugin-tee-verifiable-log/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*

!dist/**
!package.json
!readme.md
!tsup.config.ts
35 changes: 35 additions & 0 deletions packages/plugin-tee-verifiable-log/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## Build
Execute the following command to build the code.
```
pnpm clean
pnpm install or pnpm install --no-frozen-lockfile
pnpm build
```

## Configuration
This plugin depends on plugin-tee.
To get a TEE simulator for local testing, use the following commands:
```shell
docker pull phalanetwork/tappd-simulator:latest
# by default the simulator is available in localhost:8090
docker run --rm -p 8090:8090 phalanetwork/tappd-simulator:latest
```

When using the provider through the runtime environment, ensure the following settings are configured:
```shell
# Optional, for simulator purposes if testing on mac or windows. Leave empty for Linux x86 machines.
TEE_MODE="DOCKER" # LOCAL | DOCKER | PRODUCTION
WALLET_SECRET_SALT= "<your-secret-salt>" # ONLY define if you want to use TEE Plugin, otherwise it will throw errors

VLOG="true"
```
For detailed configuration of plugin-tee, see the documentation.[docs/docs/advanced/eliza-in-tee.md](/docs/docs/advanced/eliza-in-tee.md)

## Test

Test files are located in the `test` folder. To run the tests, execute the following command:

```shell
pnpm test

```
3 changes: 3 additions & 0 deletions packages/plugin-tee-verifiable-log/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import eslintGlobalConfig from "../../eslint.config.mjs";

export default [...eslintGlobalConfig];
30 changes: 30 additions & 0 deletions packages/plugin-tee-verifiable-log/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@ai16z/plugin-tee-verifiable-log",
"version": "0.1.4-alpha.3",
"main": "dist/index.js",
"type": "module",
"types": "dist/index.d.ts",
"dependencies": {
"@ai16z/eliza": "workspace:*",
"@ai16z/plugin-tee": "workspace:*",
"dompurify": "3.2.2",
"elliptic": "^6.6.1",
"ethereum-cryptography": "^3.0.0",
"tsup": "8.3.5",
"uuid": "11.0.3",
"vitest": "2.1.5"
},
"scripts": {
"build": "tsup --format esm --dts",
"test": "vitest run",
"test:watch": "vitest",
"lint": "eslint . --fix"
},
"devDependencies": {
"@types/dompurify": "3.2.0",
"ts-node": "^10.9.2"
},
"peerDependencies": {
"whatwg-url": "7.1.0"
}
}
209 changes: 209 additions & 0 deletions packages/plugin-tee-verifiable-log/src/adapters/sqliteVerifiableDAO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import { Database } from "better-sqlite3";
import { v4 as uuidv4 } from "uuid";
import {
VerifiableLog,
VerifiableAgent,
VerifiableDAO,
VerifiableLogQuery,
PageQuery,
} from "../types/logTypes.ts";

export class SQLite3VerifiableDAO extends VerifiableDAO<Database> {
constructor(db: Database) {
super();
this.db = db;
// load(db);
// check if the tables exist, if not create them
const tables = db
.prepare(
"SELECT name FROM sqlite_master WHERE type='table' AND name IN ('verifiable-logs', 'verifiable-agents');"
)
.all();
if (tables.length !== 2) {
this.initializeSchema();
}
}

async initializeSchema(): Promise<void> {
this.db.exec(`
CREATE TABLE IF NOT EXISTS "tee_verifiable_logs"
(
"id" TEXT PRIMARY KEY,
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
"agent_id" TEXT NOT NULL,
"room_id" TEXT NOT NULL,
"user_id" TEXT,
"type" TEXT,
"content" TEXT NOT NULL,
"signature" TEXT NOT NULL
);
`);

this.db.exec(`
CREATE TABLE IF NOT EXISTS "tee_verifiable_agents"
(
"id" TEXT PRIMARY KEY,
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
"agent_id" TEXT NOT NULL,
"agent_name" TEXT,
"agent_keypair_path" TEXT NOT NULL,
"agent_keypair_vlog_pk" TEXT NOT NULL,
UNIQUE ("agent_id")
);
`);
}

async addLog(log: VerifiableLog): Promise<boolean> {
const sql = `
INSERT INTO "tee_verifiable_logs" ("id", "created_at", "agent_id", "room_id", "user_id", "type", "content",
"signature")
VALUES (?, ?, ?, ?, ?, ?, ?, ?);
`;
try {
this.db
.prepare(sql)
.run(
log.id || uuidv4(),
log.created_at || new Date().getTime(),
log.agent_id,
log.room_id,
log.user_id,
log.type,
log.content,
log.signature
);
return true;
} catch (error) {
console.error("SQLite3 Error adding log:", error);
return false;
}
}

async pageQueryLogs(
query: VerifiableLogQuery,
page: number,
pageSize: number
): Promise<PageQuery<VerifiableLog[]>> {
const conditions: string[] = [];
const params: any[] = [];

if (query.idEq) {
conditions.push(`id = ?`);
params.push(query.idEq);
}
if (query.agentIdEq) {
conditions.push(`agent_id = ?`);
params.push(query.agentIdEq);
}
if (query.roomIdEq) {
conditions.push(`room_id = ?`);
params.push(query.roomIdEq);
}
if (query.userIdEq) {
conditions.push(`user_id = ?`);
params.push(query.userIdEq);
}
if (query.typeEq) {
conditions.push(`type = ?`);
params.push(query.typeEq);
}
if (query.contLike) {
conditions.push(`content LIKE ?`);
params.push(`%${query.contLike}%`);
}
if (query.signatureEq) {
conditions.push(`signature = ?`);
params.push(query.signatureEq);
}

const whereClause =
conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";

if (page < 1) {
page = 1;
}
const offset = (page - 1) * pageSize;
const limit = pageSize;


try {
const totalQuery = `SELECT COUNT(*) AS total
FROM tee_verifiable_logs ${whereClause}`;
const stmt = this.db.prepare(totalQuery);
const totalResult = stmt.get(params);
const total = totalResult.total;

const dataQuery = `
SELECT *
FROM tee_verifiable_logs ${whereClause}
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`;
const dataResult = this.db
.prepare(dataQuery)
.all(...params, limit, offset);

return {
page: page,
pageSize: pageSize,
total: total,
data: dataResult,
} as PageQuery<VerifiableLog[]>;
} catch (error) {
console.error("Error querying tee_verifiable_logs:", error);
throw error;
}
}

async addAgent(agent: VerifiableAgent): Promise<boolean> {
const sql = `
INSERT INTO "tee_verifiable_agents" ("id", "created_at", "agent_id","agent_name","agent_keypair_path", "agent_keypair_vlog_pk")
VALUES (?, ?, ?, ?, ?,?);
`;
try {
this.db
.prepare(sql)
.run(
agent.id || uuidv4(),
agent.created_at || new Date().getTime(),
agent.agent_id,
agent.agent_name||"agent bot",
agent.agent_keypair_path,
agent.agent_keypair_vlog_pk
);
return true;
} catch (error) {
console.error("SQLite3 Error adding agent:", error);
return false;
}
}

async getAgent(agentId: string): Promise<VerifiableAgent> {
const sql = `SELECT *
FROM "tee_verifiable_agents"
WHERE agent_id = ?`;
try {
const agent = this.db.prepare(sql).get(agentId);
if (agent) {
return agent as VerifiableAgent;
} else {
return null;
}
} catch (error) {
console.error("SQLite3 Error getting agent:", error);
throw error;
}
}

async listAgent(): Promise<VerifiableAgent[]> {
const sql = `SELECT *
FROM "tee_verifiable_agents"`;
try {
const agents = this.db.prepare(sql).all();
return agents as VerifiableAgent[];
} catch (error) {
console.error("SQLite3 Error listing agent:", error);
throw error;
}
}
}
Loading
Loading