# FELDMAN - Agente de Consolidación **Versión:** 5.0 **Fecha:** 2024-12-24 --- ## Resumen | Aspecto | Valor | |---------|-------| | Servidor | CORP (92.112.181.188) | | Puerto | 5054 | | Base de datos | corp | | Tablas | feldman_cola, feldman_bloques, feldman_validaciones | | Estado | Operativo | --- ## Rol en el Sistema FELDMAN es el "notario" del sistema: valida y consolida datos en bloques inmutables. ``` MASON (enriquecido) │ ▼ ┌─────────────────────────────────────────┐ │ FELDMAN │ │ │ │ 1. Recibir en feldman_cola │ │ 2. Validar reglas (M-001, M-002, M-003)│ │ 3. Calcular hash_contenido │ │ 4. Encadenar (hash_previo) │ │ 5. Crear milestone o bloque │ │ 6. Marcar como consolidado │ └─────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ milestones / bloques (inmutables) │ └─────────────────────────────────────────┘ │ ▼ SENTINEL (auditoría futura) ``` --- ## Reglas de Validación | Regla | Nombre | Descripción | Acción si falla | |-------|--------|-------------|-----------------| | M-001 | Hash único | h_bloque/h_milestone no existe previamente | Rechazar | | M-002 | Encadenamiento | hash_previo apunta a bloque existente | Rechazar | | M-003 | Integridad | hash_contenido = SHA-256(contenido) | Rechazar | ### Implementación ```python def validar_m001(h_bloque): """M-001: Hash debe ser único.""" existe = db.execute( "SELECT 1 FROM bloques WHERE h_bloque = %s", [h_bloque] ).fetchone() return existe is None def validar_m002(hash_previo, h_instancia): """M-002: hash_previo debe existir (excepto génesis).""" if hash_previo is None: # Primer bloque de la instancia (génesis) existe = db.execute( "SELECT 1 FROM bloques WHERE h_instancia = %s", [h_instancia] ).fetchone() return existe is None # OK si no hay bloques previos existe = db.execute( "SELECT 1 FROM bloques WHERE h_bloque = %s", [hash_previo] ).fetchone() return existe is not None def validar_m003(hash_contenido, contenido): """M-003: Hash debe coincidir con contenido.""" import hashlib import json contenido_serializado = json.dumps(contenido, sort_keys=True) hash_calculado = hashlib.sha256(contenido_serializado.encode()).hexdigest() return hash_contenido == hash_calculado ``` --- ## Schema de Tablas ### feldman_cola ```sql CREATE TABLE feldman_cola ( id BIGSERIAL PRIMARY KEY, tipo VARCHAR(50) NOT NULL, -- 'milestone' o 'bloque' h_entrada VARCHAR(64) NOT NULL, -- Referencia a origen h_instancia VARCHAR(64) NOT NULL, contenido JSONB NOT NULL, prioridad INTEGER DEFAULT 0, estado VARCHAR(20) DEFAULT 'pendiente', intentos INTEGER DEFAULT 0, ultimo_error TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), processed_at TIMESTAMPTZ ); CREATE INDEX idx_feldman_cola_estado ON feldman_cola(estado); CREATE INDEX idx_feldman_cola_prioridad ON feldman_cola(prioridad DESC); ``` ### feldman_bloques (alias de bloques) ```sql -- Ver 02_MODELO_DATOS/planos.md para schema completo CREATE TABLE bloques ( id BIGSERIAL PRIMARY KEY, h_bloque VARCHAR(64) UNIQUE NOT NULL, h_instancia VARCHAR(64) NOT NULL, secuencia BIGINT NOT NULL, hash_previo VARCHAR(64), hash_contenido VARCHAR(64) NOT NULL, tipo_bloque VARCHAR(50) NOT NULL, contenido JSONB NOT NULL, -- ... campos adicionales UNIQUE (h_instancia, secuencia) ); ``` ### feldman_validaciones ```sql CREATE TABLE feldman_validaciones ( id BIGSERIAL PRIMARY KEY, h_entrada VARCHAR(64) NOT NULL, tipo_destino VARCHAR(50) NOT NULL, -- 'milestone' o 'bloque' h_destino VARCHAR(64), -- h_milestone o h_bloque regla VARCHAR(50) NOT NULL, -- M-001, M-002, M-003 resultado BOOLEAN NOT NULL, mensaje TEXT, validated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_feldman_val_entrada ON feldman_validaciones(h_entrada); ``` --- ## Flujo de Consolidación ``` 1. Entrada en feldman_cola │ ▼ 2. FELDMAN procesa (poll cada N segundos) │ ├─► Validar M-001 (hash único) │ ├─ PASS → continuar │ └─ FAIL → registrar error, marcar 'rechazado' │ ├─► Validar M-002 (encadenamiento) │ ├─ PASS → continuar │ └─ FAIL → registrar error, marcar 'rechazado' │ ├─► Validar M-003 (integridad) │ ├─ PASS → continuar │ └─ FAIL → registrar error, marcar 'rechazado' │ ▼ 3. Todas las validaciones PASS │ ▼ 4. Obtener última secuencia de h_instancia │ ▼ 5. Calcular h_bloque/h_milestone │ ▼ 6. INSERT en bloques/milestones │ ▼ 7. Actualizar feldman_cola → 'consolidado' │ ▼ 8. Registrar en feldman_validaciones ``` --- ## Cálculo de Hashes ### h_bloque ```python def calcular_h_bloque(h_instancia, secuencia, hash_previo, hash_contenido): """ Calcula el hash del bloque. h_bloque = SHA-256(h_instancia:secuencia:hash_previo:hash_contenido) """ import hashlib # hash_previo puede ser None para bloque génesis previo = hash_previo or "genesis" data = f"{h_instancia}:{secuencia}:{previo}:{hash_contenido}" return hashlib.sha256(data.encode()).hexdigest() ``` ### hash_contenido ```python def calcular_hash_contenido(contenido): """ Calcula el hash del contenido. hash_contenido = SHA-256(contenido_serializado) """ import hashlib import json # Serialización determinista contenido_str = json.dumps(contenido, sort_keys=True, ensure_ascii=False) return hashlib.sha256(contenido_str.encode()).hexdigest() ``` --- ## API Endpoints ### POST /consolidar ```http POST /consolidar HTTP/1.1 Host: corp.example.com:5054 Content-Type: application/json { "tipo": "bloque", "h_entrada": "abc123...", "h_instancia": "def456...", "contenido": { "tipo_bloque": "transaccion", "monto": 1000, "descripcion": "Pago factura #123" } } ``` ### Response (éxito) ```json { "success": true, "h_bloque": "ghi789...", "secuencia": 42, "hash_contenido": "jkl012...", "validaciones": { "M-001": true, "M-002": true, "M-003": true } } ``` ### Response (error) ```json { "success": false, "error": "Validación fallida", "validaciones": { "M-001": true, "M-002": false, "M-003": true }, "mensaje": "M-002: hash_previo no existe en cadena" } ``` --- ## Configuración ### Variables de Entorno ```bash # /opt/feldman/.env DB_HOST=localhost DB_PORT=5432 DB_NAME=corp DB_USER=feldman DB_PASSWORD=**** POLL_INTERVAL=5 # Segundos entre polls MAX_BATCH=10 # Elementos por lote MAX_RETRIES=3 # Reintentos antes de rechazar ``` --- ## Estados de la Cola | Estado | Descripción | |--------|-------------| | pendiente | En espera de procesamiento | | procesando | FELDMAN está validando | | consolidado | Validado y creado bloque/milestone | | rechazado | Falló validación, no se reintentará | | error | Error técnico, puede reintentarse | --- ## Auditoría Cada validación se registra en `feldman_validaciones`: ```sql -- Consultar historial de validaciones SELECT h_entrada, regla, resultado, mensaje, validated_at FROM feldman_validaciones WHERE h_entrada = 'abc123...' ORDER BY validated_at; ``` --- ## Futuro: Blockchain FELDMAN está diseñado para evolucionar hacia blockchain: 1. **Actual:** Encadenamiento por hash_previo en PostgreSQL 2. **Fase 2:** Merkle tree para verificación eficiente 3. **Fase 3:** Smart contract en blockchain (Ethereum/Polygon) ``` Merkle Root │ ┌───────────┴───────────┐ │ │ Hash(AB) Hash(CD) │ │ ┌─────┴─────┐ ┌─────┴─────┐ │ │ │ │ Hash(A) Hash(B) Hash(C) Hash(D) │ │ │ │ Bloque A Bloque B Bloque C Bloque D ``` --- ## Monitoreo ### Logs ```bash docker logs feldman-feldman -f ``` ### Consultas de Estado ```sql -- Elementos pendientes SELECT COUNT(*) FROM feldman_cola WHERE estado = 'pendiente'; -- Últimas validaciones fallidas SELECT * FROM feldman_validaciones WHERE resultado = false ORDER BY validated_at DESC LIMIT 10; -- Bloques creados hoy SELECT COUNT(*) FROM bloques WHERE created_at >= CURRENT_DATE; ```