UNPKG

@clduab11/gemini-flow

Version:

Revolutionary AI agent swarm coordination platform with Google Services integration, multimedia processing, and production-ready monitoring. Features 8 Google AI services, quantum computing capabilities, and enterprise-grade security.

1,108 lines (922 loc) 36.6 kB
/** * Comprehensive Test Suite for Byzantine Consensus * Tests quorum configuration, fault tolerance, and consensus mechanisms */ import { ByzantineConsensus, Agent, ConsensusMessage, ConsensusProposal, ConsensusState, } from "../byzantine-consensus.js"; describe("ByzantineConsensus", () => { let consensus: ByzantineConsensus; let testAgents: Agent[]; beforeEach(() => { consensus = new ByzantineConsensus("test-agent", 4); // Setup test agents testAgents = [ { id: "agent-1", publicKey: "key1", isLeader: false, reputation: 1.0, lastActiveTime: new Date(), }, { id: "agent-2", publicKey: "key2", isLeader: false, reputation: 0.9, lastActiveTime: new Date(), }, { id: "agent-3", publicKey: "key3", isLeader: false, reputation: 0.8, lastActiveTime: new Date(), }, { id: "malicious-agent", publicKey: "key4", isLeader: false, isMalicious: true, reputation: 0.5, lastActiveTime: new Date(), }, ]; // Register agents testAgents.forEach((agent) => consensus.registerAgent(agent)); }); afterEach(() => { consensus?.removeAllListeners(); }); describe("Initialization and Configuration", () => { it("should initialize with correct quorum parameters", () => { const state = consensus.getState(); expect(state.currentView).toBe(0); expect(state.sequenceNumber).toBe(0); expect(state.phase).toBe("pre-prepare"); expect(state.activeAgents.size).toBe(4); }); it("should calculate fault threshold correctly", () => { // For 4 agents, fault threshold should be floor((4-1)/3) = 1 const consensus4 = new ByzantineConsensus("test", 4); expect(consensus4.canReachConsensus()).toBe(true); // For 7 agents, fault threshold should be floor((7-1)/3) = 2 const consensus7 = new ByzantineConsensus("test", 7); expect(consensus7.canReachConsensus()).toBe(true); // For 10 agents, fault threshold should be floor((10-1)/3) = 3 const consensus10 = new ByzantineConsensus("test", 10); expect(consensus10.canReachConsensus()).toBe(true); }); it("should handle minimum node requirements for Byzantine fault tolerance", () => { // Need at least 3f + 1 nodes to tolerate f faults const consensus1 = new ByzantineConsensus("test", 1); expect(consensus1.canReachConsensus()).toBe(false); const consensus3 = new ByzantineConsensus("test", 3); expect(consensus3.canReachConsensus()).toBe(false); // No agents registered const consensus4 = new ByzantineConsensus("test", 4); // Register enough honest agents for (let i = 0; i < 4; i++) { consensus4.registerAgent({ id: `agent-${i}`, publicKey: `key${i}`, isLeader: false, reputation: 1.0, lastActiveTime: new Date(), }); } expect(consensus4.canReachConsensus()).toBe(true); }); it("should select leader correctly using round-robin", () => { const state = consensus.getState(); // Initial leader should be first agent (view 0 % 4 = 0) const activeAgents = Array.from(state.activeAgents); expect(state.leader).toBe(activeAgents[0]); }); }); describe("Quorum Configuration", () => { describe("Quorum Size Calculations", () => { it("should calculate correct quorum sizes for different network sizes", () => { const testCases = [ { totalNodes: 4, expectedQuorum: 2, faultTolerance: 1 }, { totalNodes: 7, expectedQuorum: 4, faultTolerance: 2 }, { totalNodes: 10, expectedQuorum: 6, faultTolerance: 3 }, { totalNodes: 13, expectedQuorum: 8, faultTolerance: 4 }, ]; testCases.forEach(({ totalNodes, expectedQuorum, faultTolerance }) => { const testConsensus = new ByzantineConsensus("test", totalNodes); // Quorum size is 2f for prepare/commit phases in PBFT const calculatedQuorum = 2 * Math.floor((totalNodes - 1) / 3); expect(calculatedQuorum).toBe(expectedQuorum); // Can tolerate up to f malicious nodes expect(Math.floor((totalNodes - 1) / 3)).toBe(faultTolerance); }); }); it("should validate quorum requirements for consensus phases", async () => { const proposal: ConsensusProposal = { id: "test-proposal", content: { data: "test" }, proposerId: "agent-1", timestamp: new Date(), hash: "test-hash", }; // Mock leader selection to make agent-1 the leader const state = consensus.getState(); state.leader = "agent-1"; let prepareCount = 0; let commitCount = 0; consensus.on("broadcast-message", (message: ConsensusMessage) => { if (message.type === "prepare") { prepareCount++; } else if (message.type === "commit") { commitCount++; } }); // Start consensus - should require 2f responses (2 for 4 nodes) const result = await consensus.startConsensus(proposal); // In a real scenario, we'd need to simulate message handling // For now, just verify the structure is correct expect(result).toBeDefined(); }); it("should handle dynamic quorum adjustments", () => { // Start with 4 agents expect(consensus.canReachConsensus()).toBe(true); // Remove an agent - should still work with 3 honest agents consensus.removeAgent("malicious-agent"); expect(consensus.canReachConsensus()).toBe(true); // Remove another agent - now only 2 agents, cannot reach consensus consensus.removeAgent("agent-3"); expect(consensus.canReachConsensus()).toBe(false); }); }); describe("Fault Tolerance Validation", () => { it("should detect when network cannot tolerate faults", () => { // With 4 total agents and 1 malicious, should still work expect(consensus.canReachConsensus()).toBe(true); // Add more malicious agents consensus.registerAgent({ id: "malicious-2", publicKey: "key5", isLeader: false, isMalicious: true, reputation: 0.3, lastActiveTime: new Date(), }); // Now have 2 malicious out of 5 total - should fail expect(consensus.canReachConsensus()).toBe(false); }); it("should validate minimum network size requirements", () => { const smallConsensus = new ByzantineConsensus("test", 2); // Register agents smallConsensus.registerAgent({ id: "agent-1", publicKey: "key1", isLeader: false, reputation: 1.0, lastActiveTime: new Date(), }); smallConsensus.registerAgent({ id: "agent-2", publicKey: "key2", isLeader: false, reputation: 1.0, lastActiveTime: new Date(), }); // Cannot reach Byzantine consensus with only 2 nodes expect(smallConsensus.canReachConsensus()).toBe(false); }); it("should handle edge cases in fault calculations", () => { // Test boundary conditions const testCases = [ { nodes: 3, malicious: 0, canConsensus: false }, // 3 < 3*0 + 1, but still too small { nodes: 4, malicious: 1, canConsensus: true }, // 4 >= 3*1 + 1 { nodes: 6, malicious: 1, canConsensus: true }, // 6 >= 3*1 + 1 { nodes: 7, malicious: 2, canConsensus: true }, // 7 >= 3*2 + 1 { nodes: 7, malicious: 3, canConsensus: false }, // 7 < 3*3 + 1 ]; testCases.forEach(({ nodes, malicious, canConsensus }, index) => { const testConsensus = new ByzantineConsensus(`test-${index}`, nodes); // Register honest agents for (let i = 0; i < nodes - malicious; i++) { testConsensus.registerAgent({ id: `honest-${i}`, publicKey: `key-${i}`, isLeader: false, reputation: 1.0, lastActiveTime: new Date(), }); } // Register malicious agents for (let i = 0; i < malicious; i++) { testConsensus.registerAgent({ id: `malicious-${i}`, publicKey: `bad-key-${i}`, isLeader: false, isMalicious: true, reputation: 0.1, lastActiveTime: new Date(), }); } expect(testConsensus.canReachConsensus()).toBe(canConsensus); }); }); }); describe("Quorum Formation and Validation", () => { it("should validate quorum formation for prepare phase", async () => { const proposal: ConsensusProposal = { id: "quorum-test", content: { action: "test" }, proposerId: "agent-1", timestamp: new Date(), hash: "quorum-hash", }; // Simulate prepare phase quorum collection const requiredPrepareResponses = 2; // 2f for 4 nodes let prepareResponses = 0; // Mock the internal prepare collection mechanism const collectPrepareResponses = consensus["collectPrepareResponses"].bind(consensus); // Simulate receiving prepare messages const prepareMessage: ConsensusMessage = { type: "prepare", viewNumber: 0, sequenceNumber: 1, digest: proposal.hash, payload: null, timestamp: new Date(), signature: "test-sig", senderId: "agent-2", }; // Add multiple prepare messages to reach quorum const state = consensus.getState(); state.proposals.set(proposal.id, proposal); state.messages.set(proposal.hash, [prepareMessage, prepareMessage]); // Test quorum validation expect(state.messages.get(proposal.hash)).toHaveLength(2); }); it("should validate quorum formation for commit phase", async () => { const proposal: ConsensusProposal = { id: "commit-test", content: { action: "commit" }, proposerId: "agent-1", timestamp: new Date(), hash: "commit-hash", }; const requiredCommitResponses = 2; // 2f for 4 nodes // Simulate commit phase messages const commitMessages = [ { type: "commit" as const, viewNumber: 0, sequenceNumber: 1, digest: proposal.hash, payload: null, timestamp: new Date(), signature: "sig1", senderId: "agent-2", }, { type: "commit" as const, viewNumber: 0, sequenceNumber: 1, digest: proposal.hash, payload: null, timestamp: new Date(), signature: "sig2", senderId: "agent-3", }, ]; const state = consensus.getState(); state.proposals.set(proposal.id, proposal); state.messages.set(proposal.hash, commitMessages); const commitCount = state.messages .get(proposal.hash)! .filter((m) => m.type === "commit" && m.viewNumber === 0).length; expect(commitCount).toBe(requiredCommitResponses); }); it("should handle partial quorum scenarios", () => { const proposal: ConsensusProposal = { id: "partial-test", content: { action: "partial" }, proposerId: "agent-1", timestamp: new Date(), hash: "partial-hash", }; // Only 1 prepare message (need 2 for quorum) const partialMessages = [ { type: "prepare" as const, viewNumber: 0, sequenceNumber: 1, digest: proposal.hash, payload: null, timestamp: new Date(), signature: "sig1", senderId: "agent-2", }, ]; const state = consensus.getState(); state.proposals.set(proposal.id, proposal); state.messages.set(proposal.hash, partialMessages); const prepareCount = state.messages .get(proposal.hash)! .filter((m) => m.type === "prepare" && m.viewNumber === 0).length; expect(prepareCount).toBeLessThan(2); // Insufficient for quorum }); }); }); describe("Consensus Protocol Flow", () => { describe("Three-Phase Commit Protocol", () => { it("should execute complete consensus flow successfully", async () => { const proposal: ConsensusProposal = { id: "flow-test", content: { operation: "update", value: 42 }, proposerId: "agent-1", timestamp: new Date(), hash: "flow-hash", }; // Track phases const phases: string[] = []; consensus.on("broadcast-message", (message: ConsensusMessage) => { phases.push(`${message.type}-sent`); }); consensus.on( "consensus-reached", (acceptedProposal: ConsensusProposal) => { phases.push("consensus-complete"); expect(acceptedProposal.id).toBe(proposal.id); }, ); // Mock leader status const state = consensus.getState(); state.leader = "test-agent"; // Start consensus const result = await consensus.startConsensus(proposal); // In a full implementation, we would simulate message exchanges // For now, verify the proposal was added to state expect(state.proposals.has(proposal.id)).toBe(true); expect(state.sequenceNumber).toBe(1); }); it("should handle pre-prepare phase correctly", async () => { const proposal: ConsensusProposal = { id: "pre-prepare-test", content: { data: "pre-prepare" }, proposerId: "test-agent", timestamp: new Date(), hash: "pre-prepare-hash", }; let prePrepareMessage: ConsensusMessage | null = null; consensus.on("broadcast-message", (message: ConsensusMessage) => { if (message.type === "pre-prepare") { prePrepareMessage = message; } }); const state = consensus.getState(); state.leader = "test-agent"; // Start consensus to trigger pre-prepare await consensus.startConsensus(proposal); // Verify pre-prepare was sent expect(prePrepareMessage).toBeDefined(); expect(prePrepareMessage!.type).toBe("pre-prepare"); expect(prePrepareMessage!.digest).toBe(proposal.hash); expect(state.phase).toBe("pre-prepare"); }); it("should validate prepare phase responses", async () => { const prepareMessage: ConsensusMessage = { type: "prepare", viewNumber: 0, sequenceNumber: 1, digest: "test-digest", payload: null, timestamp: new Date(), signature: "test-signature", senderId: "agent-2", }; let prepareHandled = false; consensus.on("message-received", () => { prepareHandled = true; }); await consensus.processMessage(prepareMessage); expect(prepareHandled).toBe(true); const state = consensus.getState(); const messages = state.messages.get("test-digest") || []; expect(messages.some((m) => m.type === "prepare")).toBe(true); }); it("should validate commit phase responses", async () => { const commitMessage: ConsensusMessage = { type: "commit", viewNumber: 0, sequenceNumber: 1, digest: "commit-digest", payload: null, timestamp: new Date(), signature: "commit-signature", senderId: "agent-3", }; await consensus.processMessage(commitMessage); const state = consensus.getState(); const messages = state.messages.get("commit-digest") || []; expect(messages.some((m) => m.type === "commit")).toBe(true); }); }); describe("Message Validation and Security", () => { it("should validate message authenticity", async () => { const validMessage: ConsensusMessage = { type: "prepare", viewNumber: 0, sequenceNumber: 1, digest: "valid-digest", payload: null, timestamp: new Date(), signature: "valid-signature", senderId: "agent-1", }; const invalidMessage: ConsensusMessage = { type: "prepare", viewNumber: 0, sequenceNumber: 1, digest: "invalid-digest", payload: null, timestamp: new Date(), signature: "", // Invalid signature senderId: "unknown-agent", // Unknown sender }; let invalidMessageCount = 0; consensus.on("invalid-message", () => { invalidMessageCount++; }); await consensus.processMessage(validMessage); await consensus.processMessage(invalidMessage); expect(invalidMessageCount).toBe(1); }); it("should detect malicious behavior", async () => { const maliciousMessage: ConsensusMessage = { type: "pre-prepare", viewNumber: 0, sequenceNumber: 1, digest: "malicious-digest", payload: null, timestamp: new Date(), signature: "malicious-signature", senderId: "agent-2", // Not the leader }; let maliciousBehaviorDetected = false; consensus.on("malicious-behavior", (event) => { maliciousBehaviorDetected = true; expect(event.type).toBe("unauthorized-pre-prepare"); expect(event.agentId).toBe("agent-2"); }); await consensus.processMessage(maliciousMessage); expect(maliciousBehaviorDetected).toBe(true); }); it("should filter messages from malicious agents", async () => { const messageFromMalicious: ConsensusMessage = { type: "prepare", viewNumber: 0, sequenceNumber: 1, digest: "mal-digest", payload: null, timestamp: new Date(), signature: "mal-signature", senderId: "malicious-agent", }; let processedCount = 0; consensus.on("message-received", () => { processedCount++; }); await consensus.processMessage(messageFromMalicious); // Message should be rejected due to malicious sender expect(processedCount).toBe(0); }); }); }); describe("View Change and Leader Election", () => { describe("View Change Mechanism", () => { it("should initiate view change on consensus failure", async () => { let viewChangeInitiated = false; consensus.on("view-change-initiated", (newView) => { viewChangeInitiated = true; expect(newView).toBe(1); }); const initialState = consensus.getState(); const initialView = initialState.currentView; // Trigger view change manually await (consensus as any).initiateViewChange(); expect(viewChangeInitiated).toBe(true); const newState = consensus.getState(); expect(newState.currentView).toBe(initialView + 1); }); it("should elect new leader during view change", async () => { const initialState = consensus.getState(); const initialLeader = initialState.leader; await (consensus as any).initiateViewChange(); const newState = consensus.getState(); const newLeader = newState.leader; // Leader should change in round-robin fashion expect(newLeader).not.toBe(initialLeader); }); it("should handle view change messages correctly", async () => { const viewChangeMessage: ConsensusMessage = { type: "view-change", viewNumber: 1, sequenceNumber: 0, digest: "", payload: { lastCommitted: [], messageLog: [], }, timestamp: new Date(), signature: "vc-signature", senderId: "agent-2", }; // Need multiple view change messages for quorum const messages = Array.from({ length: 3 }, (_, i) => ({ ...viewChangeMessage, senderId: `agent-${i + 1}`, })); // Process view change messages for (const message of messages) { await consensus.processMessage(message); } // Should trigger new view if this agent is the new leader const state = consensus.getState(); expect(state.currentView).toBeGreaterThanOrEqual(1); }); it("should validate new view messages", async () => { const newViewMessage: ConsensusMessage = { type: "new-view", viewNumber: 1, sequenceNumber: 0, digest: "", payload: { viewChangeMessages: [], }, timestamp: new Date(), signature: "nv-signature", senderId: "agent-1", }; let newViewAccepted = false; consensus.on("new-view-accepted", (viewNumber) => { newViewAccepted = true; expect(viewNumber).toBe(1); }); // Mock that agent-1 is the new leader for view 1 jest.spyOn(consensus as any, "selectLeader").mockReturnValue("agent-1"); await consensus.processMessage(newViewMessage); expect(newViewAccepted).toBe(true); }); }); describe("Leader Election Algorithm", () => { it("should select leader deterministically", () => { const selectLeader = (consensus as any).selectLeader.bind(consensus); // Should always return same leader for same view const leader1 = selectLeader(0); const leader2 = selectLeader(0); expect(leader1).toBe(leader2); // Different views should potentially have different leaders const leader3 = selectLeader(1); expect(typeof leader3).toBe("string"); }); it("should rotate leadership fairly", () => { const selectLeader = (consensus as any).selectLeader.bind(consensus); const state = consensus.getState(); const agentCount = state.activeAgents.size; const leaders = new Set(); for (let view = 0; view < agentCount * 2; view++) { leaders.add(selectLeader(view)); } // Should have used all agents as leaders over multiple rounds expect(leaders.size).toBe(agentCount); }); it("should handle leadership validation", () => { const state = consensus.getState(); const originalLeader = state.leader; // Test leader validation const isLeader1 = (consensus as any).isLeader(); // Change leader state.leader = "test-agent"; const isLeader2 = (consensus as any).isLeader(); // Restore original state.leader = originalLeader; const isLeader3 = (consensus as any).isLeader(); expect(isLeader2).toBe(true); }); }); }); describe("Network Partitions and Recovery", () => { describe("Partition Simulation", () => { it("should handle network partition gracefully", () => { const initialAgentCount = consensus.getState().activeAgents.size; // Simulate partition by removing agents consensus.simulatePartition(["agent-1", "agent-2"]); const state = consensus.getState(); expect(state.activeAgents.size).toBe(initialAgentCount - 2); expect(state.activeAgents.has("agent-1")).toBe(false); expect(state.activeAgents.has("agent-2")).toBe(false); }); it("should detect when consensus becomes impossible due to partition", () => { // Start with 4 agents, can tolerate 1 fault expect(consensus.canReachConsensus()).toBe(true); // Partition 2 agents - now only 2 remain, cannot reach consensus consensus.simulatePartition(["agent-1", "agent-2"]); expect(consensus.canReachConsensus()).toBe(false); }); it("should recover from partition when network heals", () => { // Simulate partition consensus.simulatePartition(["agent-1", "agent-2"]); expect(consensus.canReachConsensus()).toBe(false); // Heal partition consensus.healPartition(["agent-1", "agent-2"]); const state = consensus.getState(); expect(state.activeAgents.has("agent-1")).toBe(true); expect(state.activeAgents.has("agent-2")).toBe(true); expect(consensus.canReachConsensus()).toBe(true); }); it("should emit appropriate events for partition scenarios", () => { let partitionEvent: string[] = []; let healEvent: string[] = []; consensus.on("network-partition", (agentIds) => { partitionEvent = agentIds; }); consensus.on("network-healed", (agentIds) => { healEvent = agentIds; }); const partitionedAgents = ["agent-1", "agent-3"]; consensus.simulatePartition(partitionedAgents); expect(partitionEvent).toEqual(partitionedAgents); consensus.healPartition(partitionedAgents); expect(healEvent).toEqual(partitionedAgents); }); }); describe("Partition Recovery Scenarios", () => { it("should handle majority partition scenarios", () => { // With 4 agents, partition into 3 vs 1 consensus.simulatePartition(["agent-1"]); // Remove 1, keep 3 // Majority partition (3 agents) should be able to continue expect(consensus.canReachConsensus()).toBe(true); }); it("should handle minority partition scenarios", () => { // Partition into 2 vs 2 (both are minorities for Byzantine consensus) consensus.simulatePartition(["agent-1", "agent-2"]); // Remove 2, keep 2 // Neither partition can reach consensus expect(consensus.canReachConsensus()).toBe(false); }); it("should handle agents rejoining after partition", () => { const agent1Data = testAgents.find((a) => a.id === "agent-1")!; // Remove agent consensus.removeAgent("agent-1"); expect(consensus.getState().activeAgents.has("agent-1")).toBe(false); // Re-register agent (simulating rejoin) consensus.registerAgent(agent1Data); expect(consensus.getState().activeAgents.has("agent-1")).toBe(true); }); }); }); describe("Performance Metrics and Monitoring", () => { describe("Consensus Performance Tracking", () => { it("should track consensus round metrics", () => { const initialMetrics = consensus.getPerformanceMetrics(); expect(initialMetrics.consensusRounds).toBe(0); expect(initialMetrics.averageLatency).toBe(0); expect(initialMetrics.successRate).toBe(0); }); it("should update performance metrics after consensus", async () => { // Mock successful consensus const updatePerformance = (consensus as any).updatePerformance.bind( consensus, ); const startTime = Date.now() - 1000; // 1 second ago updatePerformance(startTime, true); const metrics = consensus.getPerformanceMetrics(); expect(metrics.consensusRounds).toBe(1); expect(metrics.averageLatency).toBeGreaterThan(0); expect(metrics.successRate).toBe(1.0); }); it("should track fault detection metrics", async () => { const maliciousMessage: ConsensusMessage = { type: "prepare", viewNumber: 0, sequenceNumber: 1, digest: "test-digest", payload: null, timestamp: new Date(), signature: "invalid-signature", senderId: "malicious-agent", }; await consensus.processMessage(maliciousMessage); const metrics = consensus.getPerformanceMetrics(); expect(metrics.faultsDetected).toBeGreaterThan(0); }); it("should calculate success rates accurately", async () => { const updatePerformance = (consensus as any).updatePerformance.bind( consensus, ); // Simulate mixed results updatePerformance(Date.now(), true); // Success updatePerformance(Date.now(), false); // Failure updatePerformance(Date.now(), true); // Success const metrics = consensus.getPerformanceMetrics(); expect(metrics.consensusRounds).toBe(3); expect(metrics.successRate).toBeCloseTo(2 / 3); }); }); describe("Latency and Throughput Metrics", () => { it("should measure consensus latency correctly", async () => { const updatePerformance = (consensus as any).updatePerformance.bind( consensus, ); // Simulate different latencies const baseTime = Date.now(); updatePerformance(baseTime - 100, true); // 100ms updatePerformance(baseTime - 200, true); // 200ms const metrics = consensus.getPerformanceMetrics(); expect(metrics.averageLatency).toBe(150); // (100 + 200) / 2 }); it("should track consensus throughput over time", () => { const updatePerformance = (consensus as any).updatePerformance.bind( consensus, ); // Simulate multiple consensus rounds for (let i = 0; i < 10; i++) { updatePerformance(Date.now() - 100, true); } const metrics = consensus.getPerformanceMetrics(); expect(metrics.consensusRounds).toBe(10); expect(metrics.successRate).toBe(1.0); }); }); }); describe("Edge Cases and Error Handling", () => { describe("Malicious Behavior Detection", () => { it("should detect double-spend attempts", async () => { // Simulate conflicting proposals from same agent const proposal1: ConsensusProposal = { id: "conflict-1", content: { account: "A", balance: -100 }, proposerId: "agent-1", timestamp: new Date(), hash: "hash1", }; const proposal2: ConsensusProposal = { id: "conflict-2", content: { account: "A", balance: -150 }, proposerId: "agent-1", timestamp: new Date(), hash: "hash2", }; // Both proposals from same agent in same view should be suspicious const state = consensus.getState(); state.leader = "agent-1"; // In real implementation, this would detect conflicting proposals expect(proposal1.proposerId).toBe(proposal2.proposerId); }); it("should handle message replay attacks", async () => { const message: ConsensusMessage = { type: "prepare", viewNumber: 0, sequenceNumber: 1, digest: "replay-digest", payload: null, timestamp: new Date(Date.now() - 60000), // 1 minute old signature: "replay-signature", senderId: "agent-2", }; // Process same message twice await consensus.processMessage(message); await consensus.processMessage(message); // Should only be processed once (duplicate detection) const state = consensus.getState(); const messages = state.messages.get("replay-digest") || []; // In a full implementation, would check for duplicate filtering expect(messages.length).toBeGreaterThanOrEqual(1); }); it("should validate message timing", async () => { const oldMessage: ConsensusMessage = { type: "prepare", viewNumber: 0, sequenceNumber: 1, digest: "old-digest", payload: null, timestamp: new Date(Date.now() - 3600000), // 1 hour old signature: "old-signature", senderId: "agent-2", }; const futureMessage: ConsensusMessage = { type: "prepare", viewNumber: 0, sequenceNumber: 1, digest: "future-digest", payload: null, timestamp: new Date(Date.now() + 3600000), // 1 hour in future signature: "future-signature", senderId: "agent-2", }; // In a full implementation, would validate timestamp bounds await consensus.processMessage(oldMessage); await consensus.processMessage(futureMessage); // Should handle timing validation appropriately expect(true).toBe(true); // Placeholder }); }); describe("Resource Exhaustion Scenarios", () => { it("should handle large numbers of concurrent proposals", async () => { const proposals = Array.from({ length: 100 }, (_, i) => ({ id: `proposal-${i}`, content: { data: `data-${i}` }, proposerId: "test-agent", timestamp: new Date(), hash: `hash-${i}`, })); const state = consensus.getState(); state.leader = "test-agent"; // Add all proposals proposals.forEach((proposal) => { state.proposals.set(proposal.id, proposal); }); expect(state.proposals.size).toBe(100); }); it("should handle message flooding", async () => { const messages = Array.from({ length: 1000 }, (_, i) => ({ type: "prepare" as const, viewNumber: 0, sequenceNumber: i, digest: `digest-${i}`, payload: null, timestamp: new Date(), signature: `sig-${i}`, senderId: "agent-2", })); let processedCount = 0; consensus.on("message-received", () => { processedCount++; }); // Process all messages for (const message of messages.slice(0, 10)) { // Limit for test performance await consensus.processMessage(message); } // Should handle gracefully without crashing expect(processedCount).toBeLessThanOrEqual(10); }); }); describe("State Consistency Validation", () => { it("should maintain consistent state across operations", async () => { const initialState = consensus.getState(); const initialView = initialState.currentView; const initialSequence = initialState.sequenceNumber; // Perform various operations consensus.registerAgent({ id: "new-agent", publicKey: "new-key", isLeader: false, reputation: 1.0, lastActiveTime: new Date(), }); await (consensus as any).initiateViewChange(); // State should remain consistent const finalState = consensus.getState(); expect(finalState.currentView).toBeGreaterThan(initialView); expect(finalState.sequenceNumber).toBeGreaterThanOrEqual( initialSequence, ); }); it("should validate state transitions", () => { const state = consensus.getState(); const validPhases = ["pre-prepare", "prepare", "commit", "view-change"]; expect(validPhases).toContain(state.phase); expect(state.currentView).toBeGreaterThanOrEqual(0); expect(state.sequenceNumber).toBeGreaterThanOrEqual(0); }); it("should handle concurrent state modifications safely", async () => { // Simulate concurrent operations const operations = [ () => consensus.registerAgent({ id: "concurrent-1", publicKey: "key1", isLeader: false, reputation: 1.0, lastActiveTime: new Date(), }), () => consensus.registerAgent({ id: "concurrent-2", publicKey: "key2", isLeader: false, reputation: 1.0, lastActiveTime: new Date(), }), () => consensus.removeAgent("agent-1"), ]; // Execute concurrently await Promise.all(operations.map((op) => op())); // State should remain consistent const state = consensus.getState(); expect(state.activeAgents.size).toBeGreaterThan(0); }); }); }); });