git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
259 lines
9.9 KiB
JavaScript
259 lines
9.9 KiB
JavaScript
/**
|
|
* Network State Management
|
|
* Manages the P2P network state and phase transitions
|
|
*/
|
|
import { Cell, CellType, CellState } from './cell.js';
|
|
export var NetworkPhase;
|
|
(function (NetworkPhase) {
|
|
NetworkPhase["GENESIS"] = "genesis";
|
|
NetworkPhase["GROWTH"] = "growth";
|
|
NetworkPhase["MATURATION"] = "maturation";
|
|
NetworkPhase["INDEPENDENCE"] = "independence";
|
|
})(NetworkPhase || (NetworkPhase = {}));
|
|
export class Network {
|
|
cells;
|
|
currentPhase;
|
|
currentTick;
|
|
config;
|
|
genesisCells;
|
|
taskQueue;
|
|
constructor(config) {
|
|
this.cells = new Map();
|
|
this.currentPhase = NetworkPhase.GENESIS;
|
|
this.currentTick = 0;
|
|
this.genesisCells = new Set();
|
|
this.taskQueue = [];
|
|
this.config = {
|
|
genesisNodeCount: config?.genesisNodeCount ?? 100,
|
|
targetNodeCount: config?.targetNodeCount ?? 120000,
|
|
nodesPerTick: config?.nodesPerTick ?? 10,
|
|
taskGenerationRate: config?.taskGenerationRate ?? 5,
|
|
baseTaskReward: config?.baseTaskReward ?? 1.0,
|
|
connectionCost: config?.connectionCost ?? 0.5,
|
|
maxConnectionsPerNode: config?.maxConnectionsPerNode ?? 50,
|
|
};
|
|
}
|
|
/**
|
|
* Initialize network with genesis nodes
|
|
*/
|
|
initialize() {
|
|
console.log(`Initializing network with ${this.config.genesisNodeCount} genesis nodes...`);
|
|
for (let i = 0; i < this.config.genesisNodeCount; i++) {
|
|
const cell = new Cell(CellType.GENESIS, this.currentTick, {
|
|
computePower: 0.8 + Math.random() * 0.2, // Genesis nodes are powerful
|
|
bandwidth: 0.8 + Math.random() * 0.2,
|
|
reliability: 0.9 + Math.random() * 0.1,
|
|
storage: 0.8 + Math.random() * 0.2,
|
|
});
|
|
this.cells.set(cell.id, cell);
|
|
this.genesisCells.add(cell.id);
|
|
}
|
|
// Connect genesis nodes to each other (mesh topology)
|
|
this.connectGenesisNodes();
|
|
}
|
|
/**
|
|
* Connect all genesis nodes to each other
|
|
*/
|
|
connectGenesisNodes() {
|
|
const genesisArray = Array.from(this.genesisCells);
|
|
for (let i = 0; i < genesisArray.length; i++) {
|
|
for (let j = i + 1; j < genesisArray.length; j++) {
|
|
const cell1 = this.cells.get(genesisArray[i]);
|
|
const cell2 = this.cells.get(genesisArray[j]);
|
|
cell1.connectTo(cell2.id);
|
|
cell2.connectTo(cell1.id);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Add new regular nodes to the network
|
|
*/
|
|
spawnNodes(count) {
|
|
for (let i = 0; i < count; i++) {
|
|
const cell = new Cell(CellType.REGULAR, this.currentTick);
|
|
this.cells.set(cell.id, cell);
|
|
// Connect to random existing nodes (preferential attachment)
|
|
this.connectNewNode(cell);
|
|
}
|
|
}
|
|
/**
|
|
* Connect a new node to the network
|
|
*/
|
|
connectNewNode(newCell) {
|
|
const connectionCount = Math.min(5 + Math.floor(Math.random() * 5), this.config.maxConnectionsPerNode);
|
|
const potentialTargets = Array.from(this.cells.values())
|
|
.filter(c => c.id !== newCell.id)
|
|
.filter(c => {
|
|
// In Phase 2+, genesis nodes don't accept new connections
|
|
if (this.currentPhase !== NetworkPhase.GENESIS && c.type === CellType.GENESIS) {
|
|
return false;
|
|
}
|
|
return c.state === CellState.ACTIVE && c.connectedCells.size < this.config.maxConnectionsPerNode;
|
|
});
|
|
// Preferential attachment: higher fitness = more likely to connect
|
|
const selectedTargets = this.selectPreferentialTargets(potentialTargets, connectionCount);
|
|
for (const target of selectedTargets) {
|
|
newCell.connectTo(target.id);
|
|
target.connectTo(newCell.id);
|
|
// Connection costs energy
|
|
newCell.spendEnergy(this.config.connectionCost);
|
|
target.spendEnergy(this.config.connectionCost);
|
|
}
|
|
}
|
|
/**
|
|
* Select targets using preferential attachment
|
|
*/
|
|
selectPreferentialTargets(candidates, count) {
|
|
if (candidates.length <= count) {
|
|
return candidates;
|
|
}
|
|
const selected = [];
|
|
const weights = candidates.map(c => c.getFitnessScore() * (1 + c.connectedCells.size));
|
|
const totalWeight = weights.reduce((sum, w) => sum + w, 0);
|
|
for (let i = 0; i < count && candidates.length > 0; i++) {
|
|
let random = Math.random() * totalWeight;
|
|
let selectedIndex = 0;
|
|
for (let j = 0; j < weights.length; j++) {
|
|
random -= weights[j];
|
|
if (random <= 0) {
|
|
selectedIndex = j;
|
|
break;
|
|
}
|
|
}
|
|
selected.push(candidates[selectedIndex]);
|
|
candidates.splice(selectedIndex, 1);
|
|
weights.splice(selectedIndex, 1);
|
|
}
|
|
return selected;
|
|
}
|
|
/**
|
|
* Generate tasks for the network
|
|
*/
|
|
generateTasks() {
|
|
const tasksToGenerate = Math.floor(this.cells.size * this.config.taskGenerationRate * Math.random());
|
|
for (let i = 0; i < tasksToGenerate; i++) {
|
|
// Task complexity between 0.1 and 1.0
|
|
this.taskQueue.push(0.1 + Math.random() * 0.9);
|
|
}
|
|
}
|
|
/**
|
|
* Distribute tasks to capable cells
|
|
*/
|
|
distributeTasks() {
|
|
const activeCells = Array.from(this.cells.values())
|
|
.filter(c => c.state === CellState.ACTIVE);
|
|
while (this.taskQueue.length > 0 && activeCells.length > 0) {
|
|
const task = this.taskQueue.shift();
|
|
// Select cell based on fitness and availability
|
|
const selectedCell = activeCells[Math.floor(Math.random() * activeCells.length)];
|
|
selectedCell.processTask(task, this.config.baseTaskReward);
|
|
}
|
|
}
|
|
/**
|
|
* Update network phase based on node count
|
|
*/
|
|
updatePhase() {
|
|
const nodeCount = this.cells.size;
|
|
const oldPhase = this.currentPhase;
|
|
if (nodeCount >= 100000) {
|
|
this.currentPhase = NetworkPhase.INDEPENDENCE;
|
|
}
|
|
else if (nodeCount >= 50000) {
|
|
this.currentPhase = NetworkPhase.MATURATION;
|
|
}
|
|
else if (nodeCount >= 10000) {
|
|
this.currentPhase = NetworkPhase.GROWTH;
|
|
}
|
|
else {
|
|
this.currentPhase = NetworkPhase.GENESIS;
|
|
}
|
|
if (oldPhase !== this.currentPhase) {
|
|
console.log(`\n🔄 PHASE TRANSITION: ${oldPhase} → ${this.currentPhase} (${nodeCount} nodes)`);
|
|
this.onPhaseTransition();
|
|
}
|
|
}
|
|
/**
|
|
* Handle phase transition events
|
|
*/
|
|
onPhaseTransition() {
|
|
// Update all cells based on new phase
|
|
this.cells.forEach(cell => cell.updateState(this.cells.size));
|
|
// Phase-specific actions
|
|
switch (this.currentPhase) {
|
|
case NetworkPhase.GROWTH:
|
|
console.log(' → Genesis nodes reducing 10x multiplier...');
|
|
break;
|
|
case NetworkPhase.MATURATION:
|
|
console.log(' → Genesis nodes entering READ-ONLY mode...');
|
|
break;
|
|
case NetworkPhase.INDEPENDENCE:
|
|
console.log(' → Genesis nodes RETIRED. Network is independent!');
|
|
break;
|
|
}
|
|
}
|
|
/**
|
|
* Simulate one tick of the network
|
|
*/
|
|
tick() {
|
|
this.currentTick++;
|
|
// Spawn new nodes (if not at target)
|
|
if (this.cells.size < this.config.targetNodeCount) {
|
|
const nodesToSpawn = Math.min(this.config.nodesPerTick, this.config.targetNodeCount - this.cells.size);
|
|
this.spawnNodes(nodesToSpawn);
|
|
}
|
|
// Generate and distribute tasks
|
|
this.generateTasks();
|
|
this.distributeTasks();
|
|
// Update all cells
|
|
this.cells.forEach(cell => {
|
|
cell.tick();
|
|
cell.updateState(this.cells.size);
|
|
});
|
|
// Check for phase transitions
|
|
this.updatePhase();
|
|
}
|
|
/**
|
|
* Get network statistics
|
|
*/
|
|
getStats() {
|
|
const cells = Array.from(this.cells.values());
|
|
const genesisCells = cells.filter(c => c.type === CellType.GENESIS);
|
|
const regularCells = cells.filter(c => c.type === CellType.REGULAR);
|
|
const totalEnergy = cells.reduce((sum, c) => sum + c.energy, 0);
|
|
const totalEarned = cells.reduce((sum, c) => sum + c.metrics.energyEarned, 0);
|
|
const totalSpent = cells.reduce((sum, c) => sum + c.metrics.energySpent, 0);
|
|
const totalTasks = cells.reduce((sum, c) => sum + c.metrics.tasksCompleted, 0);
|
|
return {
|
|
tick: this.currentTick,
|
|
phase: this.currentPhase,
|
|
nodeCount: this.cells.size,
|
|
genesisNodes: {
|
|
count: genesisCells.length,
|
|
active: genesisCells.filter(c => c.state === CellState.ACTIVE).length,
|
|
readOnly: genesisCells.filter(c => c.state === CellState.READ_ONLY).length,
|
|
retired: genesisCells.filter(c => c.state === CellState.RETIRED).length,
|
|
avgMultiplier: genesisCells.reduce((sum, c) => sum + c.genesisMultiplier, 0) / genesisCells.length,
|
|
},
|
|
regularNodes: {
|
|
count: regularCells.length,
|
|
},
|
|
economy: {
|
|
totalEnergy,
|
|
totalEarned,
|
|
totalSpent,
|
|
netEnergy: totalEarned - totalSpent,
|
|
avgEnergyPerNode: totalEnergy / this.cells.size,
|
|
},
|
|
tasks: {
|
|
completed: totalTasks,
|
|
queued: this.taskQueue.length,
|
|
avgPerNode: totalTasks / this.cells.size,
|
|
},
|
|
network: {
|
|
avgConnections: cells.reduce((sum, c) => sum + c.connectedCells.size, 0) / this.cells.size,
|
|
avgSuccessRate: cells.reduce((sum, c) => sum + c.metrics.successRate, 0) / this.cells.size,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
//# sourceMappingURL=network.js.map
|