Files
zeekayandHanzo Dev 64519916bf the corporate name is Lux Industries Inc
Lux Partners Limited is not the entity behind this work. Every place the
old name stood — copyright lines, site footers, brand config, legal and
compliance text — now names the company that actually holds it.

lux.fund is the exception and is not renamed to match: that site belongs
to Lux Assets Management LLC, a different company, and it says so.

Two kinds of line were left for a person rather than rewritten. A dated
news item recording that Lux Partners Limited was established in the Isle
of Man is a historical fact, and renaming it would falsify the record. And
a sentence asserting that the company is domiciled in the Isle of Man is a
claim about a jurisdiction, not a name — an Inc or an LLC is not an Isle
of Man company, so swapping the name there would assert something untrue.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-28 13:01:04 -07:00

559 lines
18 KiB
Go

// Copyright (c) 2025 Lux Industries Inc
// SPDX-License-Identifier: MIT
// Package achain provides the A-Chain (AI) adapter for the DAG indexer.
// Handles AI compute attestations, model hashes, and inference results.
package ai
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/luxfi/indexer/dag"
"github.com/luxfi/indexer/storage"
)
const (
// DefaultPort for A-Chain indexer API
DefaultPort = 4500
// DefaultDatabase name
DefaultDatabase = "explorer_achain"
)
// AttestationType categorizes AI attestations
type AttestationType string
const (
AttestationCompute AttestationType = "compute" // Compute job attestation
AttestationModel AttestationType = "model" // Model registration
AttestationInference AttestationType = "inference" // Inference result
AttestationTraining AttestationType = "training" // Training job
)
// ComputeAttestation represents an AI compute attestation
type ComputeAttestation struct {
ID string `json:"id"`
Type AttestationType `json:"type"`
ModelHash string `json:"modelHash,omitempty"`
InputHash string `json:"inputHash,omitempty"`
OutputHash string `json:"outputHash,omitempty"`
ComputeUnits uint64 `json:"computeUnits"`
Provider string `json:"provider"`
Requester string `json:"requester"`
Timestamp time.Time `json:"timestamp"`
Status string `json:"status"`
Metadata json.RawMessage `json:"metadata,omitempty"`
}
// ModelRegistration represents a registered AI model
type ModelRegistration struct {
ID string `json:"id"`
ModelHash string `json:"modelHash"`
Name string `json:"name"`
Version string `json:"version"`
Owner string `json:"owner"`
Framework string `json:"framework,omitempty"`
Parameters uint64 `json:"parameters,omitempty"`
Timestamp time.Time `json:"timestamp"`
Metadata json.RawMessage `json:"metadata,omitempty"`
}
// InferenceResult represents an AI inference result
type InferenceResult struct {
ID string `json:"id"`
ModelID string `json:"modelId"`
InputHash string `json:"inputHash"`
OutputHash string `json:"outputHash"`
Confidence float64 `json:"confidence,omitempty"`
Latency time.Duration `json:"latency"`
Provider string `json:"provider"`
Timestamp time.Time `json:"timestamp"`
Metadata json.RawMessage `json:"metadata,omitempty"`
}
// AIProvider represents an AI compute provider
type AIProvider struct {
ID string `json:"id"`
Address string `json:"address"`
Name string `json:"name"`
Reputation float64 `json:"reputation"`
Capacity uint64 `json:"capacity"`
Active bool `json:"active"`
Timestamp time.Time `json:"timestamp"`
Metadata json.RawMessage `json:"metadata,omitempty"`
}
// AIReceipt represents a payment receipt for AI compute services
type AIReceipt struct {
ID string `json:"id"`
AttestationID string `json:"attestationId"`
Provider string `json:"provider"`
Requester string `json:"requester"`
Amount uint64 `json:"amount"`
Currency string `json:"currency"`
Status string `json:"status"`
Timestamp time.Time `json:"timestamp"`
}
// TrainingJob represents an AI training job
type TrainingJob struct {
ID string `json:"id"`
ModelID string `json:"modelId"`
DatasetHash string `json:"datasetHash"`
Epochs int `json:"epochs"`
BatchSize int `json:"batchSize"`
LearningRate float64 `json:"learningRate"`
Provider string `json:"provider"`
Status string `json:"status"`
StartedAt time.Time `json:"startedAt,omitempty"`
CompletedAt time.Time `json:"completedAt,omitempty"`
Metadata json.RawMessage `json:"metadata,omitempty"`
}
// Adapter implements dag.Adapter for A-Chain
type Adapter struct {
rpcEndpoint string
httpClient *http.Client
}
// New creates a new A-Chain adapter
func New(rpcEndpoint string) *Adapter {
return &Adapter{
rpcEndpoint: rpcEndpoint,
httpClient: &http.Client{Timeout: 30 * time.Second},
}
}
// ParseVertex parses A-Chain vertex data from RPC response
func (a *Adapter) ParseVertex(data json.RawMessage) (*dag.Vertex, error) {
var raw struct {
ID string `json:"id"`
Type string `json:"type"`
ParentIDs []string `json:"parentIds"`
Height uint64 `json:"height"`
Epoch uint32 `json:"epoch"`
TxIDs []string `json:"txIds"`
Timestamp int64 `json:"timestamp"`
Status string `json:"status"`
Data json.RawMessage `json:"data"`
}
if err := json.Unmarshal(data, &raw); err != nil {
return nil, fmt.Errorf("unmarshal vertex: %w", err)
}
v := &dag.Vertex{
ID: raw.ID,
Type: raw.Type,
ParentIDs: raw.ParentIDs,
Height: raw.Height,
Epoch: raw.Epoch,
TxIDs: raw.TxIDs,
Status: dag.Status(raw.Status),
Data: raw.Data,
Metadata: make(map[string]interface{}),
}
if raw.Timestamp > 0 {
v.Timestamp = time.Unix(raw.Timestamp, 0)
} else {
v.Timestamp = time.Now()
}
// Parse AI-specific metadata from vertex data
if len(raw.Data) > 0 {
var aiData struct {
AttestationType string `json:"attestationType"`
ModelHash string `json:"modelHash"`
Provider string `json:"provider"`
ComputeUnits uint64 `json:"computeUnits"`
}
if err := json.Unmarshal(raw.Data, &aiData); err == nil {
if aiData.AttestationType != "" {
v.Metadata["attestation_type"] = aiData.AttestationType
}
if aiData.ModelHash != "" {
v.Metadata["model_hash"] = aiData.ModelHash
}
if aiData.Provider != "" {
v.Metadata["provider"] = aiData.Provider
}
if aiData.ComputeUnits > 0 {
v.Metadata["compute_units"] = aiData.ComputeUnits
}
}
}
return v, nil
}
// GetRecentVertices fetches recent vertices from A-Chain via RPC
func (a *Adapter) GetRecentVertices(ctx context.Context, limit int) ([]json.RawMessage, error) {
req := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"method": "aivm.getRecentVertices",
"params": map[string]interface{}{
"limit": limit,
},
}
body, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("marshal request: %w", err)
}
httpReq, err := http.NewRequestWithContext(ctx, "POST", a.rpcEndpoint, bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("create request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
resp, err := a.httpClient.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("rpc call: %w", err)
}
defer resp.Body.Close()
var result struct {
Result struct {
Vertices []json.RawMessage `json:"vertices"`
} `json:"result"`
Error *struct {
Code int `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("decode response: %w", err)
}
if result.Error != nil {
return nil, fmt.Errorf("rpc error %d: %s", result.Error.Code, result.Error.Message)
}
return result.Result.Vertices, nil
}
// GetVertexByID fetches a specific vertex by ID
func (a *Adapter) GetVertexByID(ctx context.Context, id string) (json.RawMessage, error) {
req := map[string]interface{}{
"jsonrpc": "2.0",
"id": 1,
"method": "aivm.getVertex",
"params": map[string]interface{}{
"vertexID": id,
},
}
body, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("marshal request: %w", err)
}
httpReq, err := http.NewRequestWithContext(ctx, "POST", a.rpcEndpoint, bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("create request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
resp, err := a.httpClient.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("rpc call: %w", err)
}
defer resp.Body.Close()
var result struct {
Result json.RawMessage `json:"result"`
Error *struct {
Code int `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("decode response: %w", err)
}
if result.Error != nil {
return nil, fmt.Errorf("rpc error %d: %s", result.Error.Code, result.Error.Message)
}
return result.Result, nil
}
// InitSchema creates A-Chain specific database tables
func (a *Adapter) InitSchema(ctx context.Context, store storage.Store) error {
schema := `
-- AI Compute Attestations
CREATE TABLE IF NOT EXISTS achain_attestations (
id TEXT PRIMARY KEY,
type TEXT NOT NULL,
model_hash TEXT,
input_hash TEXT,
output_hash TEXT,
compute_units BIGINT DEFAULT 0,
provider TEXT,
requester TEXT,
status TEXT DEFAULT 'pending',
vertex_id TEXT,
timestamp TIMESTAMP NOT NULL,
metadata TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_achain_attestations_type ON achain_attestations(type);
CREATE INDEX IF NOT EXISTS idx_achain_attestations_provider ON achain_attestations(provider);
CREATE INDEX IF NOT EXISTS idx_achain_attestations_model ON achain_attestations(model_hash);
-- AI Model Registry
CREATE TABLE IF NOT EXISTS achain_models (
id TEXT PRIMARY KEY,
model_hash TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
version TEXT,
owner TEXT NOT NULL,
framework TEXT,
parameters BIGINT DEFAULT 0,
vertex_id TEXT,
timestamp TIMESTAMP NOT NULL,
metadata TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_achain_models_owner ON achain_models(owner);
CREATE INDEX IF NOT EXISTS idx_achain_models_hash ON achain_models(model_hash);
-- AI Inference Results
CREATE TABLE IF NOT EXISTS achain_inferences (
id TEXT PRIMARY KEY,
model_id TEXT NOT NULL,
input_hash TEXT NOT NULL,
output_hash TEXT NOT NULL,
confidence REAL,
latency_ms BIGINT,
provider TEXT,
vertex_id TEXT,
timestamp TIMESTAMP NOT NULL,
metadata TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_achain_inferences_model ON achain_inferences(model_id);
CREATE INDEX IF NOT EXISTS idx_achain_inferences_provider ON achain_inferences(provider);
-- AI Training Jobs
CREATE TABLE IF NOT EXISTS achain_training (
id TEXT PRIMARY KEY,
model_id TEXT,
dataset_hash TEXT NOT NULL,
epochs INT,
batch_size INT,
learning_rate REAL,
provider TEXT,
status TEXT DEFAULT 'pending',
vertex_id TEXT,
started_at TIMESTAMP,
completed_at TIMESTAMP,
metadata TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_achain_training_model ON achain_training(model_id);
CREATE INDEX IF NOT EXISTS idx_achain_training_status ON achain_training(status);
-- AI Compute Providers Registry
CREATE TABLE IF NOT EXISTS achain_providers (
id TEXT PRIMARY KEY,
address TEXT UNIQUE NOT NULL,
name TEXT,
reputation REAL DEFAULT 0,
capacity BIGINT DEFAULT 0,
active BOOLEAN DEFAULT true,
vertex_id TEXT,
timestamp TIMESTAMP NOT NULL,
metadata TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_achain_providers_active ON achain_providers(active);
CREATE INDEX IF NOT EXISTS idx_achain_providers_address ON achain_providers(address);
-- AI Payment Receipts
CREATE TABLE IF NOT EXISTS achain_receipts (
id TEXT PRIMARY KEY,
attestation_id TEXT NOT NULL,
provider TEXT NOT NULL,
requester TEXT NOT NULL,
amount BIGINT NOT NULL,
currency TEXT DEFAULT 'AI',
status TEXT DEFAULT 'pending',
vertex_id TEXT,
timestamp TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_achain_receipts_attestation ON achain_receipts(attestation_id);
CREATE INDEX IF NOT EXISTS idx_achain_receipts_provider ON achain_receipts(provider);
-- A-Chain specific stats
CREATE TABLE IF NOT EXISTS achain_stats (
id INT PRIMARY KEY DEFAULT 1,
total_attestations BIGINT DEFAULT 0,
total_models BIGINT DEFAULT 0,
total_inferences BIGINT DEFAULT 0,
total_training_jobs BIGINT DEFAULT 0,
total_compute_units BIGINT DEFAULT 0,
unique_providers INT DEFAULT 0,
unique_requesters INT DEFAULT 0,
total_receipts BIGINT DEFAULT 0,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO achain_stats (id) VALUES (1) ON CONFLICT DO NOTHING;
`
if err := store.Exec(ctx, schema); err != nil {
return fmt.Errorf("init achain schema: %w", err)
}
return nil
}
// GetStats returns A-Chain specific statistics
func (a *Adapter) GetStats(ctx context.Context, store storage.Store) (map[string]interface{}, error) {
stats := make(map[string]interface{})
// Update stats first
_ = store.Exec(ctx, `
UPDATE achain_stats SET
total_attestations = (SELECT COUNT(*) FROM achain_attestations),
total_models = (SELECT COUNT(*) FROM achain_models),
total_inferences = (SELECT COUNT(*) FROM achain_inferences),
total_compute_units = (SELECT COALESCE(SUM(compute_units), 0) FROM achain_attestations),
unique_providers = (SELECT COUNT(DISTINCT provider) FROM achain_attestations WHERE provider IS NOT NULL),
unique_requesters = (SELECT COUNT(DISTINCT requester) FROM achain_attestations WHERE requester IS NOT NULL),
updated_at = CURRENT_TIMESTAMP
WHERE id = 1
`)
rows, err := store.Query(ctx, `
SELECT total_attestations, total_models, total_inferences,
total_compute_units, unique_providers, unique_requesters
FROM achain_stats WHERE id = 1
`)
if err != nil || len(rows) == 0 {
return stats, nil
}
row := rows[0]
if v, ok := row["total_attestations"].(int64); ok {
stats["total_attestations"] = v
}
if v, ok := row["total_models"].(int64); ok {
stats["total_models"] = v
}
if v, ok := row["total_inferences"].(int64); ok {
stats["total_inferences"] = v
}
if v, ok := row["total_compute_units"].(int64); ok {
stats["total_compute_units"] = v
}
if v, ok := row["unique_providers"].(int64); ok {
stats["unique_providers"] = v
}
if v, ok := row["unique_requesters"].(int64); ok {
stats["unique_requesters"] = v
}
// Get attestation breakdown by type
typeRows, err := store.Query(ctx, `
SELECT type, COUNT(*) as cnt FROM achain_attestations GROUP BY type
`)
if err == nil {
breakdown := make(map[string]int64)
for _, r := range typeRows {
if t, ok := r["type"].(string); ok {
if c, ok := r["cnt"].(int64); ok {
breakdown[t] = c
}
}
}
stats["attestations_by_type"] = breakdown
}
return stats, nil
}
// StoreAttestation stores a compute attestation
func (a *Adapter) StoreAttestation(ctx context.Context, store storage.Store, att *ComputeAttestation, vertexID string) error {
return store.Exec(ctx, `
INSERT INTO achain_attestations (id, type, model_hash, input_hash, output_hash,
compute_units, provider, requester, status, vertex_id, timestamp, metadata)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (id) DO UPDATE SET status = EXCLUDED.status
`, att.ID, att.Type, att.ModelHash, att.InputHash, att.OutputHash,
att.ComputeUnits, att.Provider, att.Requester, att.Status, vertexID, att.Timestamp, string(att.Metadata))
}
// StoreModel stores a model registration
func (a *Adapter) StoreModel(ctx context.Context, store storage.Store, model *ModelRegistration, vertexID string) error {
return store.Exec(ctx, `
INSERT INTO achain_models (id, model_hash, name, version, owner,
framework, parameters, vertex_id, timestamp, metadata)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (id) DO NOTHING
`, model.ID, model.ModelHash, model.Name, model.Version, model.Owner,
model.Framework, model.Parameters, vertexID, model.Timestamp, string(model.Metadata))
}
// StoreInference stores an inference result
func (a *Adapter) StoreInference(ctx context.Context, store storage.Store, inf *InferenceResult, vertexID string) error {
return store.Exec(ctx, `
INSERT INTO achain_inferences (id, model_id, input_hash, output_hash,
confidence, latency_ms, provider, vertex_id, timestamp, metadata)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (id) DO NOTHING
`, inf.ID, inf.ModelID, inf.InputHash, inf.OutputHash,
inf.Confidence, inf.Latency.Milliseconds(), inf.Provider, vertexID, inf.Timestamp, string(inf.Metadata))
}
// StoreTrainingJob stores a training job
func (a *Adapter) StoreTrainingJob(ctx context.Context, store storage.Store, job *TrainingJob, vertexID string) error {
return store.Exec(ctx, `
INSERT INTO achain_training (id, model_id, dataset_hash, epochs, batch_size,
learning_rate, provider, status, vertex_id, started_at, completed_at, metadata)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (id) DO UPDATE SET
status = EXCLUDED.status,
completed_at = EXCLUDED.completed_at
`, job.ID, job.ModelID, job.DatasetHash, job.Epochs, job.BatchSize,
job.LearningRate, job.Provider, job.Status, vertexID, job.StartedAt, job.CompletedAt, string(job.Metadata))
}
// StoreProvider stores or updates a provider registration
func (a *Adapter) StoreProvider(ctx context.Context, store storage.Store, provider *AIProvider, vertexID string) error {
return store.Exec(ctx, `
INSERT INTO achain_providers (id, address, name, reputation, capacity,
active, vertex_id, timestamp, metadata)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (id) DO UPDATE SET
reputation = EXCLUDED.reputation,
capacity = EXCLUDED.capacity,
active = EXCLUDED.active
`, provider.ID, provider.Address, provider.Name, provider.Reputation, provider.Capacity,
provider.Active, vertexID, provider.Timestamp, string(provider.Metadata))
}
// StoreReceipt stores a payment receipt
func (a *Adapter) StoreReceipt(ctx context.Context, store storage.Store, receipt *AIReceipt, vertexID string) error {
return store.Exec(ctx, `
INSERT INTO achain_receipts (id, attestation_id, provider, requester,
amount, currency, status, vertex_id, timestamp)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (id) DO UPDATE SET status = EXCLUDED.status
`, receipt.ID, receipt.AttestationID, receipt.Provider, receipt.Requester,
receipt.Amount, receipt.Currency, receipt.Status, vertexID, receipt.Timestamp)
}
// Verify interface compliance at compile time
var _ dag.Adapter = (*Adapter)(nil)