@arcanea/council 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/consensus/byzantine.d.ts +63 -0
- package/dist/consensus/byzantine.d.ts.map +1 -0
- package/dist/consensus/byzantine.js +316 -0
- package/dist/consensus/byzantine.js.map +1 -0
- package/dist/consensus/gate-quorum.d.ts +61 -0
- package/dist/consensus/gate-quorum.d.ts.map +1 -0
- package/dist/consensus/gate-quorum.js +280 -0
- package/dist/consensus/gate-quorum.js.map +1 -0
- package/dist/consensus/gossip.d.ts +69 -0
- package/dist/consensus/gossip.d.ts.map +1 -0
- package/dist/consensus/gossip.js +378 -0
- package/dist/consensus/gossip.js.map +1 -0
- package/dist/consensus/index.d.ts +59 -0
- package/dist/consensus/index.d.ts.map +1 -0
- package/dist/consensus/index.js +193 -0
- package/dist/consensus/index.js.map +1 -0
- package/dist/consensus/raft.d.ts +62 -0
- package/dist/consensus/raft.d.ts.map +1 -0
- package/dist/consensus/raft.js +324 -0
- package/dist/consensus/raft.js.map +1 -0
- package/dist/external-types.d.ts +20 -0
- package/dist/external-types.d.ts.map +1 -0
- package/dist/external-types.js +21 -0
- package/dist/external-types.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +182 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V3 Raft Consensus Implementation
|
|
3
|
+
* Leader election and log replication for distributed coordination
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { ConsensusProposal, ConsensusVote, ConsensusResult, ConsensusConfig } from '../types.js';
|
|
7
|
+
export type RaftState = 'follower' | 'candidate' | 'leader';
|
|
8
|
+
export interface RaftNode {
|
|
9
|
+
id: string;
|
|
10
|
+
state: RaftState;
|
|
11
|
+
currentTerm: number;
|
|
12
|
+
votedFor?: string;
|
|
13
|
+
log: RaftLogEntry[];
|
|
14
|
+
commitIndex: number;
|
|
15
|
+
lastApplied: number;
|
|
16
|
+
}
|
|
17
|
+
export interface RaftLogEntry {
|
|
18
|
+
term: number;
|
|
19
|
+
index: number;
|
|
20
|
+
command: unknown;
|
|
21
|
+
timestamp: Date;
|
|
22
|
+
}
|
|
23
|
+
export interface RaftConfig extends Partial<ConsensusConfig> {
|
|
24
|
+
electionTimeoutMinMs?: number;
|
|
25
|
+
electionTimeoutMaxMs?: number;
|
|
26
|
+
heartbeatIntervalMs?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare class RaftConsensus extends EventEmitter {
|
|
29
|
+
private config;
|
|
30
|
+
private node;
|
|
31
|
+
private peers;
|
|
32
|
+
private proposals;
|
|
33
|
+
private electionTimeout?;
|
|
34
|
+
private heartbeatInterval?;
|
|
35
|
+
private proposalCounter;
|
|
36
|
+
constructor(nodeId: string, config?: RaftConfig);
|
|
37
|
+
initialize(): Promise<void>;
|
|
38
|
+
shutdown(): Promise<void>;
|
|
39
|
+
addPeer(peerId: string): void;
|
|
40
|
+
removePeer(peerId: string): void;
|
|
41
|
+
propose(value: unknown): Promise<ConsensusProposal>;
|
|
42
|
+
vote(proposalId: string, vote: ConsensusVote): Promise<void>;
|
|
43
|
+
awaitConsensus(proposalId: string): Promise<ConsensusResult>;
|
|
44
|
+
getState(): RaftState;
|
|
45
|
+
getTerm(): number;
|
|
46
|
+
isLeader(): boolean;
|
|
47
|
+
getLeaderId(): string | undefined;
|
|
48
|
+
private resetElectionTimeout;
|
|
49
|
+
private randomElectionTimeout;
|
|
50
|
+
private startElection;
|
|
51
|
+
private requestVote;
|
|
52
|
+
private becomeLeader;
|
|
53
|
+
private sendHeartbeats;
|
|
54
|
+
private appendEntries;
|
|
55
|
+
private replicateToFollowers;
|
|
56
|
+
private checkConsensus;
|
|
57
|
+
private createResult;
|
|
58
|
+
handleVoteRequest(candidateId: string, term: number, lastLogIndex: number, lastLogTerm: number): boolean;
|
|
59
|
+
handleAppendEntries(leaderId: string, term: number, entries: RaftLogEntry[], leaderCommit: number): boolean;
|
|
60
|
+
}
|
|
61
|
+
export declare function createRaftConsensus(nodeId: string, config?: RaftConfig): RaftConsensus;
|
|
62
|
+
//# sourceMappingURL=raft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raft.d.ts","sourceRoot":"","sources":["../../src/consensus/raft.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,eAAe,EAEhB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,YAAY,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,UAAW,SAAQ,OAAO,CAAC,eAAe,CAAC;IAC1D,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,IAAI,CAAW;IACvB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,eAAe,CAAC,CAAiB;IACzC,OAAO,CAAC,iBAAiB,CAAC,CAAiB;IAC3C,OAAO,CAAC,eAAe,CAAa;gBAExB,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,UAAe;IAsB7C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAU/B,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAW7B,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI1B,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA2CnD,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB5D,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IA2BlE,QAAQ,IAAI,SAAS;IAIrB,OAAO,IAAI,MAAM;IAIjB,QAAQ,IAAI,OAAO;IAInB,WAAW,IAAI,MAAM,GAAG,SAAS;IASjC,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,qBAAqB;YAMf,aAAa;YAgCb,WAAW;IAezB,OAAO,CAAC,YAAY;YAkBN,cAAc;YAMd,aAAa;YAeb,oBAAoB;YAkBpB,cAAc;IAwB5B,OAAO,CAAC,YAAY;IAoBpB,iBAAiB,CACf,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,OAAO;IA6BV,mBAAmB,CACjB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,EAAE,EACvB,YAAY,EAAE,MAAM,GACnB,OAAO;CA2BX;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,aAAa,CAEtF"}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* V3 Raft Consensus Implementation
|
|
3
|
+
* Leader election and log replication for distributed coordination
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { SWARM_CONSTANTS, } from '../types.js';
|
|
7
|
+
export class RaftConsensus extends EventEmitter {
|
|
8
|
+
config;
|
|
9
|
+
node;
|
|
10
|
+
peers = new Map();
|
|
11
|
+
proposals = new Map();
|
|
12
|
+
electionTimeout;
|
|
13
|
+
heartbeatInterval;
|
|
14
|
+
proposalCounter = 0;
|
|
15
|
+
constructor(nodeId, config = {}) {
|
|
16
|
+
super();
|
|
17
|
+
this.config = {
|
|
18
|
+
threshold: config.threshold ?? SWARM_CONSTANTS.DEFAULT_CONSENSUS_THRESHOLD,
|
|
19
|
+
timeoutMs: config.timeoutMs ?? SWARM_CONSTANTS.DEFAULT_CONSENSUS_TIMEOUT_MS,
|
|
20
|
+
maxRounds: config.maxRounds ?? 10,
|
|
21
|
+
requireQuorum: config.requireQuorum ?? true,
|
|
22
|
+
electionTimeoutMinMs: config.electionTimeoutMinMs ?? 150,
|
|
23
|
+
electionTimeoutMaxMs: config.electionTimeoutMaxMs ?? 300,
|
|
24
|
+
heartbeatIntervalMs: config.heartbeatIntervalMs ?? 50,
|
|
25
|
+
};
|
|
26
|
+
this.node = {
|
|
27
|
+
id: nodeId,
|
|
28
|
+
state: 'follower',
|
|
29
|
+
currentTerm: 0,
|
|
30
|
+
log: [],
|
|
31
|
+
commitIndex: 0,
|
|
32
|
+
lastApplied: 0,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async initialize() {
|
|
36
|
+
this.resetElectionTimeout();
|
|
37
|
+
this.emit('initialized', { nodeId: this.node.id });
|
|
38
|
+
}
|
|
39
|
+
async shutdown() {
|
|
40
|
+
if (this.electionTimeout) {
|
|
41
|
+
clearTimeout(this.electionTimeout);
|
|
42
|
+
}
|
|
43
|
+
if (this.heartbeatInterval) {
|
|
44
|
+
clearInterval(this.heartbeatInterval);
|
|
45
|
+
}
|
|
46
|
+
this.emit('shutdown');
|
|
47
|
+
}
|
|
48
|
+
addPeer(peerId) {
|
|
49
|
+
this.peers.set(peerId, {
|
|
50
|
+
id: peerId,
|
|
51
|
+
state: 'follower',
|
|
52
|
+
currentTerm: 0,
|
|
53
|
+
log: [],
|
|
54
|
+
commitIndex: 0,
|
|
55
|
+
lastApplied: 0,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
removePeer(peerId) {
|
|
59
|
+
this.peers.delete(peerId);
|
|
60
|
+
}
|
|
61
|
+
async propose(value) {
|
|
62
|
+
if (this.node.state !== 'leader') {
|
|
63
|
+
throw new Error('Only leader can propose values');
|
|
64
|
+
}
|
|
65
|
+
this.proposalCounter++;
|
|
66
|
+
const proposalId = `raft_${this.node.id}_${this.proposalCounter}`;
|
|
67
|
+
const proposal = {
|
|
68
|
+
id: proposalId,
|
|
69
|
+
proposerId: this.node.id,
|
|
70
|
+
value,
|
|
71
|
+
term: this.node.currentTerm,
|
|
72
|
+
timestamp: new Date(),
|
|
73
|
+
votes: new Map(),
|
|
74
|
+
status: 'pending',
|
|
75
|
+
};
|
|
76
|
+
// Add to local log
|
|
77
|
+
const logEntry = {
|
|
78
|
+
term: this.node.currentTerm,
|
|
79
|
+
index: this.node.log.length + 1,
|
|
80
|
+
command: { proposalId, value },
|
|
81
|
+
timestamp: new Date(),
|
|
82
|
+
};
|
|
83
|
+
this.node.log.push(logEntry);
|
|
84
|
+
this.proposals.set(proposalId, proposal);
|
|
85
|
+
// Leader votes for itself
|
|
86
|
+
proposal.votes.set(this.node.id, {
|
|
87
|
+
voterId: this.node.id,
|
|
88
|
+
approve: true,
|
|
89
|
+
confidence: 1.0,
|
|
90
|
+
timestamp: new Date(),
|
|
91
|
+
});
|
|
92
|
+
// Replicate to followers
|
|
93
|
+
await this.replicateToFollowers(logEntry);
|
|
94
|
+
return proposal;
|
|
95
|
+
}
|
|
96
|
+
async vote(proposalId, vote) {
|
|
97
|
+
const proposal = this.proposals.get(proposalId);
|
|
98
|
+
if (!proposal) {
|
|
99
|
+
throw new Error(`Proposal ${proposalId} not found`);
|
|
100
|
+
}
|
|
101
|
+
if (proposal.status !== 'pending') {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
proposal.votes.set(vote.voterId, vote);
|
|
105
|
+
// Check if we have consensus
|
|
106
|
+
await this.checkConsensus(proposalId);
|
|
107
|
+
}
|
|
108
|
+
async awaitConsensus(proposalId) {
|
|
109
|
+
const startTime = Date.now();
|
|
110
|
+
return new Promise((resolve, reject) => {
|
|
111
|
+
const checkInterval = setInterval(() => {
|
|
112
|
+
const proposal = this.proposals.get(proposalId);
|
|
113
|
+
if (!proposal) {
|
|
114
|
+
clearInterval(checkInterval);
|
|
115
|
+
reject(new Error(`Proposal ${proposalId} not found`));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (proposal.status !== 'pending') {
|
|
119
|
+
clearInterval(checkInterval);
|
|
120
|
+
resolve(this.createResult(proposal, Date.now() - startTime));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (Date.now() - startTime > (this.config.timeoutMs ?? 30000)) {
|
|
124
|
+
clearInterval(checkInterval);
|
|
125
|
+
proposal.status = 'expired';
|
|
126
|
+
resolve(this.createResult(proposal, Date.now() - startTime));
|
|
127
|
+
}
|
|
128
|
+
}, 10);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
getState() {
|
|
132
|
+
return this.node.state;
|
|
133
|
+
}
|
|
134
|
+
getTerm() {
|
|
135
|
+
return this.node.currentTerm;
|
|
136
|
+
}
|
|
137
|
+
isLeader() {
|
|
138
|
+
return this.node.state === 'leader';
|
|
139
|
+
}
|
|
140
|
+
getLeaderId() {
|
|
141
|
+
if (this.node.state === 'leader') {
|
|
142
|
+
return this.node.id;
|
|
143
|
+
}
|
|
144
|
+
return this.node.votedFor;
|
|
145
|
+
}
|
|
146
|
+
// ===== PRIVATE METHODS =====
|
|
147
|
+
resetElectionTimeout() {
|
|
148
|
+
if (this.electionTimeout) {
|
|
149
|
+
clearTimeout(this.electionTimeout);
|
|
150
|
+
}
|
|
151
|
+
const timeout = this.randomElectionTimeout();
|
|
152
|
+
this.electionTimeout = setTimeout(() => {
|
|
153
|
+
this.startElection();
|
|
154
|
+
}, timeout);
|
|
155
|
+
}
|
|
156
|
+
randomElectionTimeout() {
|
|
157
|
+
const min = this.config.electionTimeoutMinMs ?? 150;
|
|
158
|
+
const max = this.config.electionTimeoutMaxMs ?? 300;
|
|
159
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
160
|
+
}
|
|
161
|
+
async startElection() {
|
|
162
|
+
this.node.state = 'candidate';
|
|
163
|
+
this.node.currentTerm++;
|
|
164
|
+
this.node.votedFor = this.node.id;
|
|
165
|
+
this.emit('election.started', {
|
|
166
|
+
term: this.node.currentTerm,
|
|
167
|
+
candidateId: this.node.id
|
|
168
|
+
});
|
|
169
|
+
// Vote for self
|
|
170
|
+
let votesReceived = 1;
|
|
171
|
+
const votesNeeded = Math.floor((this.peers.size + 1) / 2) + 1;
|
|
172
|
+
// Request votes from peers
|
|
173
|
+
for (const [peerId, peer] of this.peers) {
|
|
174
|
+
const granted = await this.requestVote(peerId);
|
|
175
|
+
if (granted) {
|
|
176
|
+
votesReceived++;
|
|
177
|
+
}
|
|
178
|
+
if (votesReceived >= votesNeeded) {
|
|
179
|
+
this.becomeLeader();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Election failed, reset to follower
|
|
184
|
+
this.node.state = 'follower';
|
|
185
|
+
this.resetElectionTimeout();
|
|
186
|
+
}
|
|
187
|
+
async requestVote(peerId) {
|
|
188
|
+
const peer = this.peers.get(peerId);
|
|
189
|
+
if (!peer)
|
|
190
|
+
return false;
|
|
191
|
+
// Local vote request - uses in-process peer state
|
|
192
|
+
// Grant vote if candidate's term is higher
|
|
193
|
+
if (this.node.currentTerm > peer.currentTerm) {
|
|
194
|
+
peer.votedFor = this.node.id;
|
|
195
|
+
peer.currentTerm = this.node.currentTerm;
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
becomeLeader() {
|
|
201
|
+
this.node.state = 'leader';
|
|
202
|
+
if (this.electionTimeout) {
|
|
203
|
+
clearTimeout(this.electionTimeout);
|
|
204
|
+
}
|
|
205
|
+
// Start sending heartbeats
|
|
206
|
+
this.heartbeatInterval = setInterval(() => {
|
|
207
|
+
this.sendHeartbeats();
|
|
208
|
+
}, this.config.heartbeatIntervalMs ?? 50);
|
|
209
|
+
this.emit('leader.elected', {
|
|
210
|
+
term: this.node.currentTerm,
|
|
211
|
+
leaderId: this.node.id
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
async sendHeartbeats() {
|
|
215
|
+
for (const [peerId, peer] of this.peers) {
|
|
216
|
+
await this.appendEntries(peerId, []);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async appendEntries(peerId, entries) {
|
|
220
|
+
const peer = this.peers.get(peerId);
|
|
221
|
+
if (!peer)
|
|
222
|
+
return false;
|
|
223
|
+
// AppendEntries - local peer state update
|
|
224
|
+
if (this.node.currentTerm >= peer.currentTerm) {
|
|
225
|
+
peer.currentTerm = this.node.currentTerm;
|
|
226
|
+
peer.state = 'follower';
|
|
227
|
+
peer.log.push(...entries);
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
async replicateToFollowers(entry) {
|
|
233
|
+
const replicationPromises = Array.from(this.peers.keys()).map(peerId => this.appendEntries(peerId, [entry]));
|
|
234
|
+
const results = await Promise.allSettled(replicationPromises);
|
|
235
|
+
const successCount = results.filter(r => r.status === 'fulfilled' && r.value).length;
|
|
236
|
+
// Check if majority replicated
|
|
237
|
+
const majority = Math.floor((this.peers.size + 1) / 2) + 1;
|
|
238
|
+
if (successCount + 1 >= majority) {
|
|
239
|
+
this.node.commitIndex = entry.index;
|
|
240
|
+
this.emit('log.committed', { index: entry.index });
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
async checkConsensus(proposalId) {
|
|
244
|
+
const proposal = this.proposals.get(proposalId);
|
|
245
|
+
if (!proposal || proposal.status !== 'pending') {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const totalVoters = this.peers.size + 1;
|
|
249
|
+
const votesReceived = proposal.votes.size;
|
|
250
|
+
const approvingVotes = Array.from(proposal.votes.values()).filter(v => v.approve).length;
|
|
251
|
+
const threshold = this.config.threshold ?? 0.66;
|
|
252
|
+
const quorum = Math.floor(totalVoters * threshold);
|
|
253
|
+
if (approvingVotes >= quorum) {
|
|
254
|
+
proposal.status = 'accepted';
|
|
255
|
+
this.emit('consensus.achieved', { proposalId, approved: true });
|
|
256
|
+
}
|
|
257
|
+
else if (votesReceived - approvingVotes > totalVoters - quorum) {
|
|
258
|
+
proposal.status = 'rejected';
|
|
259
|
+
this.emit('consensus.achieved', { proposalId, approved: false });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
createResult(proposal, durationMs) {
|
|
263
|
+
const totalVoters = this.peers.size + 1;
|
|
264
|
+
const approvingVotes = Array.from(proposal.votes.values()).filter(v => v.approve).length;
|
|
265
|
+
return {
|
|
266
|
+
proposalId: proposal.id,
|
|
267
|
+
approved: proposal.status === 'accepted',
|
|
268
|
+
approvalRate: proposal.votes.size > 0
|
|
269
|
+
? approvingVotes / proposal.votes.size
|
|
270
|
+
: 0,
|
|
271
|
+
participationRate: proposal.votes.size / totalVoters,
|
|
272
|
+
finalValue: proposal.value,
|
|
273
|
+
rounds: 1,
|
|
274
|
+
durationMs,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
// Handle vote request from another candidate
|
|
278
|
+
handleVoteRequest(candidateId, term, lastLogIndex, lastLogTerm) {
|
|
279
|
+
if (term < this.node.currentTerm) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
if (term > this.node.currentTerm) {
|
|
283
|
+
this.node.currentTerm = term;
|
|
284
|
+
this.node.state = 'follower';
|
|
285
|
+
this.node.votedFor = undefined;
|
|
286
|
+
}
|
|
287
|
+
if (this.node.votedFor === undefined || this.node.votedFor === candidateId) {
|
|
288
|
+
// Check log is at least as up-to-date
|
|
289
|
+
const lastEntry = this.node.log[this.node.log.length - 1];
|
|
290
|
+
const myLastTerm = lastEntry?.term ?? 0;
|
|
291
|
+
const myLastIndex = lastEntry?.index ?? 0;
|
|
292
|
+
if (lastLogTerm > myLastTerm ||
|
|
293
|
+
(lastLogTerm === myLastTerm && lastLogIndex >= myLastIndex)) {
|
|
294
|
+
this.node.votedFor = candidateId;
|
|
295
|
+
this.resetElectionTimeout();
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
// Handle append entries from leader
|
|
302
|
+
handleAppendEntries(leaderId, term, entries, leaderCommit) {
|
|
303
|
+
if (term < this.node.currentTerm) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
this.resetElectionTimeout();
|
|
307
|
+
if (term > this.node.currentTerm) {
|
|
308
|
+
this.node.currentTerm = term;
|
|
309
|
+
this.node.state = 'follower';
|
|
310
|
+
}
|
|
311
|
+
this.node.votedFor = leaderId;
|
|
312
|
+
// Append entries
|
|
313
|
+
this.node.log.push(...entries);
|
|
314
|
+
// Update commit index
|
|
315
|
+
if (leaderCommit > this.node.commitIndex) {
|
|
316
|
+
this.node.commitIndex = Math.min(leaderCommit, this.node.log.length);
|
|
317
|
+
}
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
export function createRaftConsensus(nodeId, config) {
|
|
322
|
+
return new RaftConsensus(nodeId, config);
|
|
323
|
+
}
|
|
324
|
+
//# sourceMappingURL=raft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raft.js","sourceRoot":"","sources":["../../src/consensus/raft.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External type re-exports for @arcanea/council.
|
|
3
|
+
*
|
|
4
|
+
* These types originate from @arcanea/guardian-memory but are
|
|
5
|
+
* inlined here to avoid workspace resolution issues before
|
|
6
|
+
* pnpm install. When the monorepo is properly linked, these
|
|
7
|
+
* can be replaced with: export type { GuardianName, Element } from '@arcanea/guardian-memory';
|
|
8
|
+
*/
|
|
9
|
+
export type GuardianName = 'shinkami' | 'lyssandria' | 'draconia' | 'lyria' | 'alera' | 'maylinn' | 'aiyami' | 'elara' | 'ino' | 'leyla';
|
|
10
|
+
export type Element = 'fire' | 'water' | 'earth' | 'wind' | 'void' | 'spirit';
|
|
11
|
+
export interface GuardianProfile {
|
|
12
|
+
name: GuardianName;
|
|
13
|
+
gate: string;
|
|
14
|
+
frequency: number;
|
|
15
|
+
element: Element;
|
|
16
|
+
vault: string;
|
|
17
|
+
godbeast: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const GUARDIANS: Record<GuardianName, GuardianProfile>;
|
|
20
|
+
//# sourceMappingURL=external-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-types.d.ts","sourceRoot":"","sources":["../src/external-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,YAAY,GACpB,UAAU,GACV,YAAY,GACZ,UAAU,GACV,OAAO,GACP,OAAO,GACP,SAAS,GACT,QAAQ,GACR,OAAO,GACP,KAAK,GACL,OAAO,CAAC;AAEZ,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,YAAY,EAAE,eAAe,CAW3D,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External type re-exports for @arcanea/council.
|
|
3
|
+
*
|
|
4
|
+
* These types originate from @arcanea/guardian-memory but are
|
|
5
|
+
* inlined here to avoid workspace resolution issues before
|
|
6
|
+
* pnpm install. When the monorepo is properly linked, these
|
|
7
|
+
* can be replaced with: export type { GuardianName, Element } from '@arcanea/guardian-memory';
|
|
8
|
+
*/
|
|
9
|
+
export const GUARDIANS = {
|
|
10
|
+
lyssandria: { name: 'lyssandria', gate: 'Foundation', frequency: 174, element: 'earth', vault: 'technical', godbeast: 'Kaelith' },
|
|
11
|
+
leyla: { name: 'leyla', gate: 'Flow', frequency: 285, element: 'water', vault: 'creative', godbeast: 'Veloura' },
|
|
12
|
+
draconia: { name: 'draconia', gate: 'Fire', frequency: 396, element: 'fire', vault: 'technical', godbeast: 'Draconis' },
|
|
13
|
+
maylinn: { name: 'maylinn', gate: 'Heart', frequency: 417, element: 'wind', vault: 'creative', godbeast: 'Laeylinn' },
|
|
14
|
+
alera: { name: 'alera', gate: 'Voice', frequency: 528, element: 'wind', vault: 'operational', godbeast: 'Otome' },
|
|
15
|
+
lyria: { name: 'lyria', gate: 'Sight', frequency: 639, element: 'water', vault: 'horizon', godbeast: 'Yumiko' },
|
|
16
|
+
aiyami: { name: 'aiyami', gate: 'Crown', frequency: 741, element: 'spirit', vault: 'wisdom', godbeast: 'Sol' },
|
|
17
|
+
elara: { name: 'elara', gate: 'Shift', frequency: 852, element: 'void', vault: 'wisdom', godbeast: 'Thessara' },
|
|
18
|
+
ino: { name: 'ino', gate: 'Unity', frequency: 963, element: 'earth', vault: 'operational', godbeast: 'Kyuro' },
|
|
19
|
+
shinkami: { name: 'shinkami', gate: 'Source', frequency: 1111, element: 'void', vault: 'strategic', godbeast: 'Amaterasu' },
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=external-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-types.js","sourceRoot":"","sources":["../src/external-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAyBH,MAAM,CAAC,MAAM,SAAS,GAA0C;IAC9D,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE;IACjI,KAAK,EAAO,EAAE,IAAI,EAAE,OAAO,EAAO,IAAI,EAAE,MAAM,EAAQ,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE;IAChI,QAAQ,EAAI,EAAE,IAAI,EAAE,UAAU,EAAI,IAAI,EAAE,MAAM,EAAQ,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAG,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE;IAClI,OAAO,EAAK,EAAE,IAAI,EAAE,SAAS,EAAK,IAAI,EAAE,OAAO,EAAO,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAG,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE;IACjI,KAAK,EAAO,EAAE,IAAI,EAAE,OAAO,EAAO,IAAI,EAAE,OAAO,EAAO,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAG,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE;IACjI,KAAK,EAAO,EAAE,IAAI,EAAE,OAAO,EAAO,IAAI,EAAE,OAAO,EAAO,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE;IAC9H,MAAM,EAAM,EAAE,IAAI,EAAE,QAAQ,EAAM,IAAI,EAAE,OAAO,EAAO,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE;IAC3H,KAAK,EAAO,EAAE,IAAI,EAAE,OAAO,EAAO,IAAI,EAAE,OAAO,EAAO,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAG,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC/H,GAAG,EAAS,EAAE,IAAI,EAAE,KAAK,EAAS,IAAI,EAAE,OAAO,EAAO,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE;IACjI,QAAQ,EAAK,EAAE,IAAI,EAAE,UAAU,EAAK,IAAI,EAAE,QAAQ,EAAO,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE;CACvI,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @arcanea/council
|
|
3
|
+
*
|
|
4
|
+
* Guardian Council consensus mechanics for the Ten Guardians.
|
|
5
|
+
* Provides four consensus protocols mapped to Arcanea's mythology:
|
|
6
|
+
*
|
|
7
|
+
* council-vote — Leader-based (Raft). One Guardian leads.
|
|
8
|
+
* shinkamis-decree — Byzantine fault tolerance. Resilient under hostile agents.
|
|
9
|
+
* whisper — Gossip protocol. Eventual consistency via propagation.
|
|
10
|
+
* gate-quorum — Arcanea-native. Frequency-weighted Guardian voting.
|
|
11
|
+
* ancient-accord — Paxos lineage. Falls back to council-vote.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { createCouncilEngine, selectCouncilProtocol } from '@arcanea/council';
|
|
16
|
+
*
|
|
17
|
+
* // Auto-select protocol by element affinity
|
|
18
|
+
* const protocol = selectCouncilProtocol('fire'); // → 'shinkamis-decree'
|
|
19
|
+
*
|
|
20
|
+
* // Create the Council Engine
|
|
21
|
+
* const council = createCouncilEngine({
|
|
22
|
+
* protocol,
|
|
23
|
+
* nodeId: 'draconia-prime',
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Add Guardian nodes
|
|
27
|
+
* council.addNode('lyssandria-node', { guardian: 'lyssandria' });
|
|
28
|
+
* council.addNode('leyla-node', { guardian: 'leyla' });
|
|
29
|
+
*
|
|
30
|
+
* // Submit a petition and await consensus
|
|
31
|
+
* await council.initialize();
|
|
32
|
+
* const petition = await council.propose({ action: 'deploy-v2' });
|
|
33
|
+
* const result = await council.awaitConsensus(petition.id);
|
|
34
|
+
* console.log(result.approved ? 'Council approves' : 'Council rejects');
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export type { CouncilProtocol, ConsensusAlgorithm, CouncilConfig, ConsensusConfig, Petition, ConsensusProposal, Seal, ConsensusVote, CouncilResult, ConsensusResult, ICouncilEngine, IConsensusEngine, TopologyType, TopologyNode, GateQuorumConfig, GateQuorumVote, GateQuorumResult, } from './types.js';
|
|
38
|
+
export { COUNCIL_CONSTANTS, SWARM_CONSTANTS } from './types.js';
|
|
39
|
+
export { CouncilEngine, createCouncilEngine, selectCouncilProtocol, type CouncilEngineOptions, } from './consensus/index.js';
|
|
40
|
+
export { ByzantineConsensus, type ByzantineConfig, } from './consensus/byzantine.js';
|
|
41
|
+
export { RaftConsensus, type RaftConfig, } from './consensus/raft.js';
|
|
42
|
+
export { GossipConsensus, type GossipConfig, } from './consensus/gossip.js';
|
|
43
|
+
export { GateQuorumConsensus, type GateQuorumOptions, } from './consensus/gate-quorum.js';
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,IAAI,EACJ,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGhE,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,kBAAkB,EAClB,KAAK,eAAe,GACrB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,aAAa,EACb,KAAK,UAAU,GAChB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,EACf,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,mBAAmB,EACnB,KAAK,iBAAiB,GACvB,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @arcanea/council
|
|
3
|
+
*
|
|
4
|
+
* Guardian Council consensus mechanics for the Ten Guardians.
|
|
5
|
+
* Provides four consensus protocols mapped to Arcanea's mythology:
|
|
6
|
+
*
|
|
7
|
+
* council-vote — Leader-based (Raft). One Guardian leads.
|
|
8
|
+
* shinkamis-decree — Byzantine fault tolerance. Resilient under hostile agents.
|
|
9
|
+
* whisper — Gossip protocol. Eventual consistency via propagation.
|
|
10
|
+
* gate-quorum — Arcanea-native. Frequency-weighted Guardian voting.
|
|
11
|
+
* ancient-accord — Paxos lineage. Falls back to council-vote.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { createCouncilEngine, selectCouncilProtocol } from '@arcanea/council';
|
|
16
|
+
*
|
|
17
|
+
* // Auto-select protocol by element affinity
|
|
18
|
+
* const protocol = selectCouncilProtocol('fire'); // → 'shinkamis-decree'
|
|
19
|
+
*
|
|
20
|
+
* // Create the Council Engine
|
|
21
|
+
* const council = createCouncilEngine({
|
|
22
|
+
* protocol,
|
|
23
|
+
* nodeId: 'draconia-prime',
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Add Guardian nodes
|
|
27
|
+
* council.addNode('lyssandria-node', { guardian: 'lyssandria' });
|
|
28
|
+
* council.addNode('leyla-node', { guardian: 'leyla' });
|
|
29
|
+
*
|
|
30
|
+
* // Submit a petition and await consensus
|
|
31
|
+
* await council.initialize();
|
|
32
|
+
* const petition = await council.propose({ action: 'deploy-v2' });
|
|
33
|
+
* const result = await council.awaitConsensus(petition.id);
|
|
34
|
+
* console.log(result.approved ? 'Council approves' : 'Council rejects');
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export { COUNCIL_CONSTANTS, SWARM_CONSTANTS } from './types.js';
|
|
38
|
+
// ── Consensus Engines ────────────────────────────────────────
|
|
39
|
+
export { CouncilEngine, createCouncilEngine, selectCouncilProtocol, } from './consensus/index.js';
|
|
40
|
+
export { ByzantineConsensus, } from './consensus/byzantine.js';
|
|
41
|
+
export { RaftConsensus, } from './consensus/raft.js';
|
|
42
|
+
export { GossipConsensus, } from './consensus/gossip.js';
|
|
43
|
+
export { GateQuorumConsensus, } from './consensus/gate-quorum.js';
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAuBH,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEhE,gEAAgE;AAChE,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,qBAAqB,GAEtB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,kBAAkB,GAEnB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,aAAa,GAEd,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,GAEhB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,mBAAmB,GAEpB,MAAM,4BAA4B,CAAC"}
|