From 3fedbc4774ba84713fe677e6c182d4e36c857d6c Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Sun, 15 Mar 2026 05:45:44 +0000 Subject: [PATCH] fix: Update imports for consensus-service integration - Inline types instead of separate types package - Add Redis initialization in start() - Use actual Ed25519 signing from crypto module - Fix null safety on Redis client Co-Authored-By: Claude Opus 4.6 --- src/simpleton/simpleton-client.ts | 10 +++- src/sync/braid-state-sync.ts | 2 +- src/transport/braid-peer-manager.ts | 85 +++++++++++++++++++++-------- 3 files changed, 72 insertions(+), 25 deletions(-) diff --git a/src/simpleton/simpleton-client.ts b/src/simpleton/simpleton-client.ts index e4f62f4..98b8eff 100644 --- a/src/simpleton/simpleton-client.ts +++ b/src/simpleton/simpleton-client.ts @@ -17,10 +17,16 @@ import { EventEmitter } from 'events'; import pino from 'pino'; -import type { SimpletonClientConfig } from '../types/index.js'; - const logger = pino({ name: 'simpleton-client' }); +/** Configuration for the Simpleton light client */ +export interface SimpletonClientConfig { + endpoint: string; + statePath?: string; + balancePath?: string; + reconnectDelayMs?: number; +} + /** * Events emitted by SimpletonClient */ diff --git a/src/sync/braid-state-sync.ts b/src/sync/braid-state-sync.ts index d138246..5831384 100644 --- a/src/sync/braid-state-sync.ts +++ b/src/sync/braid-state-sync.ts @@ -11,7 +11,7 @@ import * as Automerge from '@automerge/automerge'; import pino from 'pino'; -import type { BraidPeerManager } from '../transport/braid-peer-manager.js'; +import type { BraidPeerManager } from './braid-peer-manager.js'; const logger = pino({ name: 'braid-state-sync' }); diff --git a/src/transport/braid-peer-manager.ts b/src/transport/braid-peer-manager.ts index a702591..e2879a2 100644 --- a/src/transport/braid-peer-manager.ts +++ b/src/transport/braid-peer-manager.ts @@ -15,15 +15,47 @@ import { EventEmitter } from 'events'; import { Router, Request, Response } from 'express'; import pino from 'pino'; -import type { - BraidPeerManagerConfig, - BraidPeerInfo, - ConsensusMessageEnvelope, - BraidVersion, -} from '../types/index.js'; +import Redis from 'ioredis'; +import type { ConsensusMessage } from '@rspace/common'; +import { signMessage, verifyMessage } from '../crypto/ed25519.js'; const logger = pino({ name: 'braid-peer-manager' }); +/** Braid version identifier */ +type BraidVersion = string; + +/** Peer info stored in Redis */ +export interface BraidPeerInfo { + nodeId: string; + publicKey: string; + endpoint: string; + lastSeen: number; +} + +/** Configuration for BraidPeerManager */ +export interface BraidPeerManagerConfig { + nodeId: string; + publicKey: string; + privateKey: Uint8Array; + port: number; + host: string; + redisUrl: string; + syncPath?: string; + consensusPath?: string; + heartbeatIntervalMs?: number; + peerTimeoutMs?: number; + reconnectIntervalMs?: number; +} + +/** Consensus message envelope */ +interface ConsensusMessageEnvelope { + type: string; + nodeId: string; + timestamp: number; + payload: unknown; + signature?: string; +} + /** * Events emitted by BraidPeerManager — matches PeerManager's interface * so ConsensusService can wire up identically. @@ -124,8 +156,8 @@ export class BraidPeerManager extends EventEmitter { private discoveryTimer: NodeJS.Timeout | null = null; private isRunning = false; - // Redis clients (lazy — injected via setRedis) - private redis: any = null; + // Redis client for peer discovery + private redis: Redis | null = null; constructor(config: BraidPeerManagerConfig) { super(); @@ -141,13 +173,11 @@ export class BraidPeerManager extends EventEmitter { } /** - * Inject Redis clients for peer discovery. + * Inject Redis client for peer discovery. * Call this before start() if using Redis-based discovery. */ - setRedis(redis: any, redisSub: any): void { + setRedis(redis: Redis): void { this.redis = redis; - // Note: redisSub for pub/sub not needed in HTTP mode — - // we discover peers via polling Redis hash } /** @@ -350,13 +380,15 @@ export class BraidPeerManager extends EventEmitter { 'Starting Braid peer manager' ); - // Register ourselves in Redis - if (this.redis) { - await this.registerSelf(); - this.startHeartbeat(); - this.startDiscovery(); + // Initialize Redis if not injected + if (!this.redis) { + this.redis = new Redis(this.config.redisUrl); } + await this.registerSelf(); + this.startHeartbeat(); + this.startDiscovery(); + this.isRunning = true; logger.info( @@ -399,6 +431,8 @@ export class BraidPeerManager extends EventEmitter { if (this.redis) { await this.redis.hdel('consensus:peers', this.config.nodeId); + await this.redis.quit(); + this.redis = null; } this.isRunning = false; @@ -556,7 +590,7 @@ export class BraidPeerManager extends EventEmitter { lastSeen: Date.now(), }; - await this.redis.hset( + await this.redis!.hset( 'consensus:peers', this.config.nodeId, JSON.stringify(peerInfo) @@ -624,10 +658,17 @@ export class BraidPeerManager extends EventEmitter { // --- Helpers --- private signMessage(message: Omit): ConsensusMessageEnvelope { - // Signing is delegated to the caller (ConsensusService) in the existing - // architecture. Here we just pass through — the message is already structured - // the same way as the WebSocket version. - return message as ConsensusMessageEnvelope; + const payload = { + type: message.type, + nodeId: message.nodeId, + timestamp: message.timestamp, + payload: message.payload, + }; + + const messageBytes = new TextEncoder().encode(JSON.stringify(payload)); + const signature = signMessage(messageBytes, this.config.privateKey); + + return { ...message, signature }; } private nextVersion(): BraidVersion {