@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.
612 lines (530 loc) • 15.8 kB
text/typescript
/**
* Voting Mechanisms for Byzantine Consensus
* Implements various voting algorithms including weighted, quadratic, and liquid democracy
*/
import { EventEmitter } from "events";
import { createHash } from "crypto";
export interface Vote {
id: string;
voterId: string;
proposalId: string;
decision: "approve" | "reject" | "abstain";
weight: number;
strength?: number; // For quadratic voting
timestamp: Date;
signature: string;
metadata?: Record<string, any>;
}
export interface VotingProposal {
id: string;
title: string;
description: string;
content: any;
proposerId: string;
timestamp: Date;
deadline: Date;
votingType: VotingType;
minimumParticipation: number;
passingThreshold: number;
status: "active" | "passed" | "rejected" | "expired";
}
export type VotingType =
| "simple-majority"
| "weighted"
| "quadratic"
| "approval"
| "liquid-democracy"
| "stake-weighted";
export interface Voter {
id: string;
publicKey: string;
weight: number;
reputation: number;
expertise: string[];
voiceCredits: number; // For quadratic voting
delegates: Set<string>; // For liquid democracy
delegatedTo?: string;
stakes: Map<string, number>; // For stake-weighted voting
}
export interface VotingResult {
proposalId: string;
totalVotes: number;
approveVotes: number;
rejectVotes: number;
abstainVotes: number;
totalWeight: number;
approveWeight: number;
rejectWeight: number;
participationRate: number;
passed: boolean;
finalizedAt: Date;
}
export class VotingMechanisms extends EventEmitter {
private voters: Map<string, Voter> = new Map();
private proposals: Map<string, VotingProposal> = new Map();
private votes: Map<string, Vote[]> = new Map(); // proposalId -> votes
private results: Map<string, VotingResult> = new Map();
private delegationGraph: Map<string, Set<string>> = new Map(); // For liquid democracy
constructor(private consensusSystemId: string) {
super();
}
/**
* Register a voter in the system
*/
public registerVoter(voter: Voter): void {
this.voters.set(voter.id, voter);
this.delegationGraph.set(voter.id, new Set());
this.emit("voter-registered", voter);
}
/**
* Create a new voting proposal
*/
public async createProposal(
proposal: Omit<VotingProposal, "id" | "status">,
): Promise<string> {
const proposalId = this.generateProposalId(proposal);
const fullProposal: VotingProposal = {
...proposal,
id: proposalId,
status: "active",
};
this.proposals.set(proposalId, fullProposal);
this.votes.set(proposalId, []);
// Set up automatic finalization
setTimeout(() => {
this.finalizeProposal(proposalId);
}, proposal.deadline.getTime() - Date.now());
this.emit("proposal-created", fullProposal);
return proposalId;
}
/**
* Cast a vote on a proposal
*/
public async castVote(
vote: Omit<Vote, "id" | "signature">,
): Promise<boolean> {
const proposal = this.proposals.get(vote.proposalId);
if (!proposal) {
throw new Error("Proposal not found");
}
if (proposal.status !== "active") {
throw new Error("Proposal is not active");
}
if (new Date() > proposal.deadline) {
throw new Error("Voting deadline has passed");
}
const voter = this.voters.get(vote.voterId);
if (!voter) {
throw new Error("Voter not registered");
}
// Check for duplicate votes
const existingVotes = this.votes.get(vote.proposalId) || [];
if (existingVotes.some((v) => v.voterId === vote.voterId)) {
throw new Error("Voter has already voted on this proposal");
}
// Validate vote based on voting type
const isValid = await this.validateVote(vote, proposal, voter);
if (!isValid) {
return false;
}
const fullVote: Vote = {
...vote,
id: this.generateVoteId(vote),
signature: this.signVote(vote),
};
this.votes.get(vote.proposalId)!.push(fullVote);
// Handle liquid democracy delegation
if (proposal.votingType === "liquid-democracy") {
await this.processDelegatedVotes(fullVote, proposal);
}
this.emit("vote-cast", fullVote);
return true;
}
/**
* Validate a vote based on the voting mechanism
*/
private async validateVote(
vote: Omit<Vote, "id" | "signature">,
proposal: VotingProposal,
voter: Voter,
): Promise<boolean> {
switch (proposal.votingType) {
case "quadratic":
return this.validateQuadraticVote(vote, voter);
case "stake-weighted":
return this.validateStakeWeightedVote(vote, voter, proposal);
case "weighted":
return vote.weight <= voter.weight;
case "liquid-democracy":
return this.validateLiquidDemocracyVote(vote, voter);
default:
return true;
}
}
/**
* Validate quadratic voting constraints
*/
private validateQuadraticVote(
vote: Omit<Vote, "id" | "signature">,
voter: Voter,
): boolean {
if (!vote.strength) {
return false;
}
const cost = vote.strength ** 2;
return cost <= voter.voiceCredits;
}
/**
* Validate stake-weighted voting
*/
private validateStakeWeightedVote(
vote: Omit<Vote, "id" | "signature">,
voter: Voter,
proposal: VotingProposal,
): boolean {
const stakes = voter.stakes.get(proposal.id) || 0;
return vote.weight <= stakes;
}
/**
* Validate liquid democracy vote
*/
private validateLiquidDemocracyVote(
vote: Omit<Vote, "id" | "signature">,
voter: Voter,
): boolean {
// Can't vote if delegated to someone else
return !voter.delegatedTo;
}
/**
* Process delegated votes in liquid democracy
*/
private async processDelegatedVotes(
vote: Vote,
proposal: VotingProposal,
): Promise<void> {
const voter = this.voters.get(vote.voterId)!;
const delegates = voter.delegates;
for (const delegateId of delegates) {
const delegate = this.voters.get(delegateId);
if (!delegate || delegate.delegatedTo !== vote.voterId) {
continue;
}
// Create delegated vote
const delegatedVote: Vote = {
id: this.generateVoteId({ ...vote, voterId: delegateId }),
voterId: delegateId,
proposalId: vote.proposalId,
decision: vote.decision,
weight: delegate.weight,
timestamp: new Date(),
signature: this.signVote({ ...vote, voterId: delegateId }),
metadata: { delegatedFrom: vote.voterId },
};
this.votes.get(vote.proposalId)!.push(delegatedVote);
this.emit("delegated-vote-cast", delegatedVote);
}
}
/**
* Delegate voting power to another voter
*/
public delegateVote(delegatorId: string, delegateId: string): boolean {
const delegator = this.voters.get(delegatorId);
const delegate = this.voters.get(delegateId);
if (!delegator || !delegate) {
return false;
}
// Prevent circular delegation
if (this.wouldCreateCircularDelegation(delegatorId, delegateId)) {
return false;
}
delegator.delegatedTo = delegateId;
delegate.delegates.add(delegatorId);
this.emit("vote-delegated", { delegatorId, delegateId });
return true;
}
/**
* Check for circular delegation
*/
private wouldCreateCircularDelegation(
delegatorId: string,
delegateId: string,
): boolean {
const visited = new Set<string>();
let current = delegateId;
while (current && !visited.has(current)) {
visited.add(current);
const voter = this.voters.get(current);
if (!voter) break;
if (voter.delegatedTo === delegatorId) {
return true;
}
current = voter.delegatedTo || "";
}
return false;
}
/**
* Calculate voting results
*/
public calculateResults(proposalId: string): VotingResult {
const proposal = this.proposals.get(proposalId);
if (!proposal) {
throw new Error("Proposal not found");
}
const votes = this.votes.get(proposalId) || [];
let totalVotes = 0;
let approveVotes = 0;
let rejectVotes = 0;
let abstainVotes = 0;
let totalWeight = 0;
let approveWeight = 0;
let rejectWeight = 0;
for (const vote of votes) {
totalVotes++;
totalWeight += vote.weight;
switch (vote.decision) {
case "approve":
approveVotes++;
approveWeight += this.calculateVoteWeight(vote, proposal);
break;
case "reject":
rejectVotes++;
rejectWeight += this.calculateVoteWeight(vote, proposal);
break;
case "abstain":
abstainVotes++;
break;
}
}
const totalRegisteredVoters = this.voters.size;
const participationRate = totalVotes / totalRegisteredVoters;
const passed = this.determineOutcome(
proposal,
approveWeight,
rejectWeight,
totalWeight,
participationRate,
);
const result: VotingResult = {
proposalId,
totalVotes,
approveVotes,
rejectVotes,
abstainVotes,
totalWeight,
approveWeight,
rejectWeight,
participationRate,
passed,
finalizedAt: new Date(),
};
this.results.set(proposalId, result);
return result;
}
/**
* Calculate weight of a vote based on voting mechanism
*/
private calculateVoteWeight(vote: Vote, proposal: VotingProposal): number {
switch (proposal.votingType) {
case "quadratic":
return vote.strength || 1;
case "weighted":
case "stake-weighted":
return vote.weight;
case "liquid-democracy":
// Weight includes delegated votes
const voter = this.voters.get(vote.voterId)!;
return vote.weight + (vote.metadata?.delegatedWeight || 0);
default:
return 1; // Simple majority
}
}
/**
* Determine if proposal passes based on voting mechanism
*/
private determineOutcome(
proposal: VotingProposal,
approveWeight: number,
rejectWeight: number,
totalWeight: number,
participationRate: number,
): boolean {
// Check minimum participation
if (participationRate < proposal.minimumParticipation) {
return false;
}
const approvalRatio = approveWeight / (approveWeight + rejectWeight);
return approvalRatio >= proposal.passingThreshold;
}
/**
* Finalize a proposal and calculate final results
*/
public async finalizeProposal(proposalId: string): Promise<VotingResult> {
const proposal = this.proposals.get(proposalId);
if (!proposal) {
throw new Error("Proposal not found");
}
if (proposal.status !== "active") {
throw new Error("Proposal is not active");
}
const result = this.calculateResults(proposalId);
proposal.status = result.passed ? "passed" : "rejected";
// Update voter credits for quadratic voting
if (proposal.votingType === "quadratic") {
await this.updateQuadraticVotingCredits(proposalId);
}
this.emit("proposal-finalized", { proposal, result });
return result;
}
/**
* Update voice credits after quadratic voting
*/
private async updateQuadraticVotingCredits(
proposalId: string,
): Promise<void> {
const votes = this.votes.get(proposalId) || [];
for (const vote of votes) {
if (vote.strength) {
const voter = this.voters.get(vote.voterId);
if (voter) {
const cost = vote.strength ** 2;
voter.voiceCredits = Math.max(0, voter.voiceCredits - cost);
}
}
}
}
/**
* Get voting statistics
*/
public getVotingStatistics(): {
totalProposals: number;
activeProposals: number;
passedProposals: number;
rejectedProposals: number;
averageParticipation: number;
votingDistribution: Record<string, number>;
} {
const proposals = Array.from(this.proposals.values());
const results = Array.from(this.results.values());
const activeProposals = proposals.filter(
(p) => p.status === "active",
).length;
const passedProposals = proposals.filter(
(p) => p.status === "passed",
).length;
const rejectedProposals = proposals.filter(
(p) => p.status === "rejected",
).length;
const averageParticipation =
results.length > 0
? results.reduce((sum, r) => sum + r.participationRate, 0) /
results.length
: 0;
const votingDistribution: Record<string, number> = {};
proposals.forEach((p) => {
votingDistribution[p.votingType] =
(votingDistribution[p.votingType] || 0) + 1;
});
return {
totalProposals: proposals.length,
activeProposals,
passedProposals,
rejectedProposals,
averageParticipation,
votingDistribution,
};
}
/**
* Detect voting anomalies
*/
public detectVotingAnomalies(proposalId: string): {
suspiciousVotes: Vote[];
coordinatedVoting: boolean;
unusualPatterns: string[];
} {
const votes = this.votes.get(proposalId) || [];
const suspiciousVotes: Vote[] = [];
const unusualPatterns: string[] = [];
// Check for votes cast very close together (potential coordination)
const voteTimestamps = votes.map((v) => v.timestamp.getTime()).sort();
let coordinated = false;
for (let i = 1; i < voteTimestamps.length; i++) {
if (voteTimestamps[i] - voteTimestamps[i - 1] < 1000) {
// Less than 1 second apart
coordinated = true;
break;
}
}
// Check for unusual voting patterns
const votesByDecision = votes.reduce(
(acc, vote) => {
acc[vote.decision] = (acc[vote.decision] || 0) + 1;
return acc;
},
{} as Record<string, number>,
);
if (votesByDecision.approve && votesByDecision.reject) {
const ratio = votesByDecision.approve / votesByDecision.reject;
if (ratio > 10 || ratio < 0.1) {
unusualPatterns.push("Extreme voting ratio detected");
}
}
// Check for voters with suspiciously high activity
const voterActivity = new Map<string, number>();
votes.forEach((vote) => {
voterActivity.set(
vote.voterId,
(voterActivity.get(vote.voterId) || 0) + 1,
);
});
voterActivity.forEach((count, voterId) => {
if (count > votes.length * 0.1) {
// More than 10% of all votes
const suspiciousVotesByVoter = votes.filter(
(v) => v.voterId === voterId,
);
suspiciousVotes.push(...suspiciousVotesByVoter);
}
});
return {
suspiciousVotes,
coordinatedVoting: coordinated,
unusualPatterns,
};
}
private generateProposalId(
proposal: Omit<VotingProposal, "id" | "status">,
): string {
return createHash("sha256")
.update(JSON.stringify(proposal) + Date.now())
.digest("hex");
}
private generateVoteId(vote: Omit<Vote, "id" | "signature">): string {
return createHash("sha256")
.update(JSON.stringify(vote) + Date.now())
.digest("hex");
}
private signVote(vote: Omit<Vote, "id" | "signature">): string {
return createHash("sha256")
.update(JSON.stringify(vote) + this.consensusSystemId)
.digest("hex");
}
/**
* Get proposal details
*/
public getProposal(proposalId: string): VotingProposal | undefined {
return this.proposals.get(proposalId);
}
/**
* Get voting result
*/
public getResult(proposalId: string): VotingResult | undefined {
return this.results.get(proposalId);
}
/**
* Get all votes for a proposal
*/
public getVotes(proposalId: string): Vote[] {
return this.votes.get(proposalId) || [];
}
}
export default VotingMechanisms;