@xmbl/simulator 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/CHANGELOG.md +8 -0
- package/DEVNET-SEAM-FINDING.md +102 -0
- package/index.js +50 -0
- package/instructions.md +784 -0
- package/package.json +28 -0
- package/readme.md +7 -0
- package/src/capabilities.js +110 -0
- package/src/devnet-rpc.js +114 -0
- package/src/devnet-rpc.test.mjs +91 -0
- package/src/devnet-run.mjs +46 -0
- package/src/devnet.js +180 -0
- package/src/devnet.test.mjs +117 -0
- package/src/logger.js +80 -0
- package/src/simulator.js +846 -0
- package/status.md +167 -0
package/instructions.md
ADDED
|
@@ -0,0 +1,784 @@
|
|
|
1
|
+
# XSIM - XMBL System Simulator Instructions
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
XSIM is a comprehensive system simulator that runs infinitely, generating random interactions and activities across the entire XMBL ecosystem. It simulates identity creation, transaction posting, validations, storage operations, compute tasks, state machine diffs, and app-centric state assembly. The simulator is essential for end-to-end testing, stress testing, and validating system behavior under various conditions.
|
|
6
|
+
|
|
7
|
+
## Fundamentals
|
|
8
|
+
|
|
9
|
+
### Key Concepts
|
|
10
|
+
|
|
11
|
+
- **Infinite Execution**: Simulator runs continuously until stopped
|
|
12
|
+
- **Random Generation**: Random qualities for all interaction types
|
|
13
|
+
- **Full System Coverage**: Simulates all XMBL modules
|
|
14
|
+
- **Realistic Behavior**: Mimics real user and node behavior
|
|
15
|
+
- **Metrics Collection**: Tracks performance and system health
|
|
16
|
+
- **Failure Injection**: Simulates network failures and node crashes
|
|
17
|
+
|
|
18
|
+
### Dependencies
|
|
19
|
+
|
|
20
|
+
- **all XMBL modules**: xid, xn, xclt, xvsm, xpc, xsc
|
|
21
|
+
- **faker**: Generate realistic fake data
|
|
22
|
+
- **chance**: Random data generation
|
|
23
|
+
|
|
24
|
+
### Architectural Decisions
|
|
25
|
+
|
|
26
|
+
- **Event-Driven**: Uses module events for realistic simulation
|
|
27
|
+
- **Configurable**: Adjustable rates and probabilities
|
|
28
|
+
- **Observable**: Emits metrics and events for monitoring
|
|
29
|
+
- **Deterministic Option**: Can run with seed for reproducible tests
|
|
30
|
+
|
|
31
|
+
## Development Steps
|
|
32
|
+
|
|
33
|
+
### Step 1: Project Setup
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cd xsim
|
|
37
|
+
npm init -y
|
|
38
|
+
npm install faker chance
|
|
39
|
+
npm install --save-dev jest @types/jest
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Step 2: Identity Simulator (TDD)
|
|
43
|
+
|
|
44
|
+
**Test First** (`__tests__/identity-sim.test.js`):
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
import { describe, test, expect } from 'jest';
|
|
48
|
+
import { IdentitySimulator } from '../src/identity-sim';
|
|
49
|
+
|
|
50
|
+
describe('Identity Simulator', () => {
|
|
51
|
+
test('should create random identity', async () => {
|
|
52
|
+
const sim = new IdentitySimulator();
|
|
53
|
+
const identity = await sim.createRandomIdentity();
|
|
54
|
+
expect(identity).toHaveProperty('address');
|
|
55
|
+
expect(identity).toHaveProperty('publicKey');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('should create identities at specified rate', async () => {
|
|
59
|
+
const sim = new IdentitySimulator({ rate: 10 }); // 10 per second
|
|
60
|
+
const identities = [];
|
|
61
|
+
sim.on('identity:created', (id) => identities.push(id));
|
|
62
|
+
await sim.start();
|
|
63
|
+
await new Promise(resolve => setTimeout(resolve, 1100)); // 1.1 seconds
|
|
64
|
+
await sim.stop();
|
|
65
|
+
expect(identities.length).toBeGreaterThanOrEqual(10);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Implementation** (`src/identity-sim.js`):
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
import { EventEmitter } from 'events';
|
|
74
|
+
import { Identity } from 'xid';
|
|
75
|
+
|
|
76
|
+
export class IdentitySimulator extends EventEmitter {
|
|
77
|
+
constructor(options = {}) {
|
|
78
|
+
super();
|
|
79
|
+
this.rate = options.rate || 1; // identities per second
|
|
80
|
+
this.identities = [];
|
|
81
|
+
this.running = false;
|
|
82
|
+
this.interval = null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async start() {
|
|
86
|
+
if (this.running) return;
|
|
87
|
+
this.running = true;
|
|
88
|
+
|
|
89
|
+
const delay = 1000 / this.rate;
|
|
90
|
+
this.interval = setInterval(async () => {
|
|
91
|
+
const identity = await Identity.create();
|
|
92
|
+
this.identities.push(identity);
|
|
93
|
+
this.emit('identity:created', identity);
|
|
94
|
+
}, delay);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async stop() {
|
|
98
|
+
if (!this.running) return;
|
|
99
|
+
this.running = false;
|
|
100
|
+
if (this.interval) {
|
|
101
|
+
clearInterval(this.interval);
|
|
102
|
+
this.interval = null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
getIdentities() {
|
|
107
|
+
return this.identities;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Step 3: Transaction Simulator (TDD)
|
|
113
|
+
|
|
114
|
+
**Test** (`__tests__/transaction-sim.test.js`):
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
import { describe, test, expect } from 'jest';
|
|
118
|
+
import { TransactionSimulator } from '../src/transaction-sim';
|
|
119
|
+
|
|
120
|
+
describe('Transaction Simulator', () => {
|
|
121
|
+
test('should create random transaction', () => {
|
|
122
|
+
const sim = new TransactionSimulator();
|
|
123
|
+
const identities = [{ address: 'alice' }, { address: 'bob' }];
|
|
124
|
+
const tx = sim.createRandomTransaction(identities);
|
|
125
|
+
expect(tx).toHaveProperty('to');
|
|
126
|
+
expect(tx).toHaveProperty('from');
|
|
127
|
+
expect(tx).toHaveProperty('amount');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('should generate transactions at specified rate', async () => {
|
|
131
|
+
const sim = new TransactionSimulator({ rate: 5 });
|
|
132
|
+
const transactions = [];
|
|
133
|
+
sim.on('transaction:created', (tx) => transactions.push(tx));
|
|
134
|
+
await sim.start();
|
|
135
|
+
await new Promise(resolve => setTimeout(resolve, 1100));
|
|
136
|
+
await sim.stop();
|
|
137
|
+
expect(transactions.length).toBeGreaterThanOrEqual(5);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Implementation** (`src/transaction-sim.js`):
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
import { EventEmitter } from 'events';
|
|
146
|
+
import faker from 'faker';
|
|
147
|
+
|
|
148
|
+
export class TransactionSimulator extends EventEmitter {
|
|
149
|
+
constructor(options = {}) {
|
|
150
|
+
super();
|
|
151
|
+
this.rate = options.rate || 1;
|
|
152
|
+
this.transactions = [];
|
|
153
|
+
this.running = false;
|
|
154
|
+
this.interval = null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
createRandomTransaction(identities) {
|
|
158
|
+
if (identities.length < 2) {
|
|
159
|
+
throw new Error('Need at least 2 identities');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const from = faker.random.arrayElement(identities);
|
|
163
|
+
const to = faker.random.arrayElement(identities.filter(i => i.address !== from.address));
|
|
164
|
+
const amount = parseFloat(faker.finance.amount(0.1, 100, 2));
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
to: to.address,
|
|
168
|
+
from: from.address,
|
|
169
|
+
amount,
|
|
170
|
+
fee: amount * 0.1,
|
|
171
|
+
stake: amount * 0.2,
|
|
172
|
+
timestamp: Date.now()
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async start(identities) {
|
|
177
|
+
if (this.running) return;
|
|
178
|
+
this.running = true;
|
|
179
|
+
|
|
180
|
+
const delay = 1000 / this.rate;
|
|
181
|
+
this.interval = setInterval(() => {
|
|
182
|
+
const tx = this.createRandomTransaction(identities);
|
|
183
|
+
this.transactions.push(tx);
|
|
184
|
+
this.emit('transaction:created', tx);
|
|
185
|
+
}, delay);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async stop() {
|
|
189
|
+
if (!this.running) return;
|
|
190
|
+
this.running = false;
|
|
191
|
+
if (this.interval) {
|
|
192
|
+
clearInterval(this.interval);
|
|
193
|
+
this.interval = null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Step 4: Validation Simulator (TDD)
|
|
200
|
+
|
|
201
|
+
**Test** (`__tests__/validation-sim.test.js`):
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
import { describe, test, expect } from 'jest';
|
|
205
|
+
import { ValidationSimulator } from '../src/validation-sim';
|
|
206
|
+
|
|
207
|
+
describe('Validation Simulator', () => {
|
|
208
|
+
test('should simulate validation tasks', async () => {
|
|
209
|
+
const sim = new ValidationSimulator();
|
|
210
|
+
const task = { rawTxId: 'tx1', task: 'validate_sig' };
|
|
211
|
+
const result = await sim.simulateValidation(task);
|
|
212
|
+
expect(result).toHaveProperty('complete');
|
|
213
|
+
expect(result).toHaveProperty('timestamp');
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('should simulate validation delays', async () => {
|
|
217
|
+
const sim = new ValidationSimulator({ avgDelay: 100 });
|
|
218
|
+
const start = Date.now();
|
|
219
|
+
await sim.simulateValidation({});
|
|
220
|
+
const elapsed = Date.now() - start;
|
|
221
|
+
expect(elapsed).toBeGreaterThan(50); // Some delay
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Implementation** (`src/validation-sim.js`):
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
229
|
+
import { EventEmitter } from 'events';
|
|
230
|
+
import chance from 'chance';
|
|
231
|
+
|
|
232
|
+
export class ValidationSimulator extends EventEmitter {
|
|
233
|
+
constructor(options = {}) {
|
|
234
|
+
super();
|
|
235
|
+
this.avgDelay = options.avgDelay || 50; // milliseconds
|
|
236
|
+
this.successRate = options.successRate || 0.95; // 95% success
|
|
237
|
+
this.chance = new chance();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async simulateValidation(task) {
|
|
241
|
+
// Simulate validation delay
|
|
242
|
+
const delay = this.chance.normal({ mean: this.avgDelay, dev: this.avgDelay * 0.2 });
|
|
243
|
+
await new Promise(resolve => setTimeout(resolve, Math.max(0, delay)));
|
|
244
|
+
|
|
245
|
+
// Simulate success/failure
|
|
246
|
+
const success = this.chance.bool({ likelihood: this.successRate * 100 });
|
|
247
|
+
|
|
248
|
+
const result = {
|
|
249
|
+
task: task.task,
|
|
250
|
+
complete: success,
|
|
251
|
+
timestamp: Date.now(),
|
|
252
|
+
error: success ? null : 'Validation failed'
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
this.emit('validation:complete', result);
|
|
256
|
+
return result;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Step 5: Storage/Compute Simulator (TDD)
|
|
262
|
+
|
|
263
|
+
**Test** (`__tests__/storage-compute-sim.test.js`):
|
|
264
|
+
|
|
265
|
+
```javascript
|
|
266
|
+
import { describe, test, expect } from 'jest';
|
|
267
|
+
import { StorageComputeSimulator } from '../src/storage-compute-sim';
|
|
268
|
+
|
|
269
|
+
describe('Storage/Compute Simulator', () => {
|
|
270
|
+
test('should simulate storage operations', async () => {
|
|
271
|
+
const sim = new StorageComputeSimulator();
|
|
272
|
+
const operation = await sim.simulateStorageOperation();
|
|
273
|
+
expect(operation).toHaveProperty('type');
|
|
274
|
+
expect(['store', 'retrieve', 'delete']).toContain(operation.type);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test('should simulate compute operations', async () => {
|
|
278
|
+
const sim = new StorageComputeSimulator();
|
|
279
|
+
const operation = await sim.simulateComputeOperation();
|
|
280
|
+
expect(operation).toHaveProperty('functionName');
|
|
281
|
+
expect(operation).toHaveProperty('duration');
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**Implementation** (`src/storage-compute-sim.js`):
|
|
287
|
+
|
|
288
|
+
```javascript
|
|
289
|
+
import { EventEmitter } from 'events';
|
|
290
|
+
import faker from 'faker';
|
|
291
|
+
import chance from 'chance';
|
|
292
|
+
|
|
293
|
+
export class StorageComputeSimulator extends EventEmitter {
|
|
294
|
+
constructor(options = {}) {
|
|
295
|
+
super();
|
|
296
|
+
this.storageRate = options.storageRate || 0.5;
|
|
297
|
+
this.computeRate = options.computeRate || 0.5;
|
|
298
|
+
this.chance = new chance();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async simulateStorageOperation() {
|
|
302
|
+
const types = ['store', 'retrieve', 'delete'];
|
|
303
|
+
const type = this.chance.pickone(types);
|
|
304
|
+
const size = this.chance.integer({ min: 100, max: 10000 });
|
|
305
|
+
|
|
306
|
+
const operation = {
|
|
307
|
+
type,
|
|
308
|
+
size,
|
|
309
|
+
timestamp: Date.now()
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
this.emit('storage:operation', operation);
|
|
313
|
+
return operation;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async simulateComputeOperation() {
|
|
317
|
+
const functionName = faker.hacker.verb() + '_' + faker.hacker.noun();
|
|
318
|
+
const duration = this.chance.normal({ mean: 100, dev: 20 });
|
|
319
|
+
|
|
320
|
+
const operation = {
|
|
321
|
+
functionName,
|
|
322
|
+
duration: Math.max(0, duration),
|
|
323
|
+
memory: this.chance.integer({ min: 10, max: 100 }),
|
|
324
|
+
timestamp: Date.now()
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
this.emit('compute:operation', operation);
|
|
328
|
+
return operation;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Step 6: System Simulator (TDD)
|
|
334
|
+
|
|
335
|
+
**Test** (`__tests__/system-sim.test.js`):
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
import { describe, test, expect, beforeEach, afterEach } from 'jest';
|
|
339
|
+
import { SystemSimulator } from '../src/system-sim';
|
|
340
|
+
|
|
341
|
+
describe('System Simulator', () => {
|
|
342
|
+
let sim;
|
|
343
|
+
|
|
344
|
+
beforeEach(() => {
|
|
345
|
+
sim = new SystemSimulator();
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
afterEach(async () => {
|
|
349
|
+
await sim.stop();
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
test('should start simulator', async () => {
|
|
353
|
+
await sim.start();
|
|
354
|
+
expect(sim.isRunning()).toBe(true);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test('should stop simulator', async () => {
|
|
358
|
+
await sim.start();
|
|
359
|
+
await sim.stop();
|
|
360
|
+
expect(sim.isRunning()).toBe(false);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
test('should collect metrics', async () => {
|
|
364
|
+
await sim.start();
|
|
365
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
366
|
+
const metrics = sim.getMetrics();
|
|
367
|
+
expect(metrics).toHaveProperty('identitiesCreated');
|
|
368
|
+
expect(metrics).toHaveProperty('transactionsCreated');
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**Implementation** (`src/system-sim.js`):
|
|
374
|
+
|
|
375
|
+
```javascript
|
|
376
|
+
import { EventEmitter } from 'events';
|
|
377
|
+
import { IdentitySimulator } from './identity-sim';
|
|
378
|
+
import { TransactionSimulator } from './transaction-sim';
|
|
379
|
+
import { ValidationSimulator } from './validation-sim';
|
|
380
|
+
import { StorageComputeSimulator } from './storage-compute-sim';
|
|
381
|
+
|
|
382
|
+
export class SystemSimulator extends EventEmitter {
|
|
383
|
+
constructor(options = {}) {
|
|
384
|
+
super();
|
|
385
|
+
this.options = {
|
|
386
|
+
identityRate: options.identityRate || 1,
|
|
387
|
+
transactionRate: options.transactionRate || 5,
|
|
388
|
+
...options
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
this.identitySim = new IdentitySimulator({ rate: this.options.identityRate });
|
|
392
|
+
this.transactionSim = new TransactionSimulator({ rate: this.options.transactionRate });
|
|
393
|
+
this.validationSim = new ValidationSimulator();
|
|
394
|
+
this.storageComputeSim = new StorageComputeSimulator();
|
|
395
|
+
|
|
396
|
+
this.metrics = {
|
|
397
|
+
identitiesCreated: 0,
|
|
398
|
+
transactionsCreated: 0,
|
|
399
|
+
validationsCompleted: 0,
|
|
400
|
+
storageOperations: 0,
|
|
401
|
+
computeOperations: 0,
|
|
402
|
+
startTime: null
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
this.running = false;
|
|
406
|
+
this.setupEventHandlers();
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
setupEventHandlers() {
|
|
410
|
+
this.identitySim.on('identity:created', () => {
|
|
411
|
+
this.metrics.identitiesCreated++;
|
|
412
|
+
this.emit('metrics:update', this.metrics);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
this.transactionSim.on('transaction:created', () => {
|
|
416
|
+
this.metrics.transactionsCreated++;
|
|
417
|
+
this.emit('metrics:update', this.metrics);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
this.validationSim.on('validation:complete', () => {
|
|
421
|
+
this.metrics.validationsCompleted++;
|
|
422
|
+
this.emit('metrics:update', this.metrics);
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
this.storageComputeSim.on('storage:operation', () => {
|
|
426
|
+
this.metrics.storageOperations++;
|
|
427
|
+
this.emit('metrics:update', this.metrics);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
this.storageComputeSim.on('compute:operation', () => {
|
|
431
|
+
this.metrics.computeOperations++;
|
|
432
|
+
this.emit('metrics:update', this.metrics);
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async start() {
|
|
437
|
+
if (this.running) return;
|
|
438
|
+
this.running = true;
|
|
439
|
+
this.metrics.startTime = Date.now();
|
|
440
|
+
|
|
441
|
+
const identities = [];
|
|
442
|
+
this.identitySim.on('identity:created', (id) => identities.push(id));
|
|
443
|
+
|
|
444
|
+
await this.identitySim.start();
|
|
445
|
+
await this.transactionSim.start(identities);
|
|
446
|
+
|
|
447
|
+
// Start periodic storage/compute operations
|
|
448
|
+
this.storageInterval = setInterval(() => {
|
|
449
|
+
this.storageComputeSim.simulateStorageOperation();
|
|
450
|
+
}, 2000);
|
|
451
|
+
|
|
452
|
+
this.computeInterval = setInterval(() => {
|
|
453
|
+
this.storageComputeSim.simulateComputeOperation();
|
|
454
|
+
}, 2000);
|
|
455
|
+
|
|
456
|
+
this.emit('started');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
async stop() {
|
|
460
|
+
if (!this.running) return;
|
|
461
|
+
this.running = false;
|
|
462
|
+
|
|
463
|
+
await this.identitySim.stop();
|
|
464
|
+
await this.transactionSim.stop();
|
|
465
|
+
|
|
466
|
+
if (this.storageInterval) clearInterval(this.storageInterval);
|
|
467
|
+
if (this.computeInterval) clearInterval(this.computeInterval);
|
|
468
|
+
|
|
469
|
+
this.emit('stopped');
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
isRunning() {
|
|
473
|
+
return this.running;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
getMetrics() {
|
|
477
|
+
return { ...this.metrics };
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Interfaces/APIs
|
|
483
|
+
|
|
484
|
+
### Exported Classes
|
|
485
|
+
|
|
486
|
+
```javascript
|
|
487
|
+
export class SystemSimulator extends EventEmitter {
|
|
488
|
+
constructor(options?: SimulatorOptions);
|
|
489
|
+
async start(): Promise<void>;
|
|
490
|
+
async stop(): Promise<void>;
|
|
491
|
+
isRunning(): boolean;
|
|
492
|
+
getMetrics(): Metrics;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export class IdentitySimulator extends EventEmitter {
|
|
496
|
+
constructor(options?: IdentitySimOptions);
|
|
497
|
+
async start(): Promise<void>;
|
|
498
|
+
async stop(): Promise<void>;
|
|
499
|
+
async createRandomIdentity(): Promise<Identity>;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
export class TransactionSimulator extends EventEmitter {
|
|
503
|
+
constructor(options?: TransactionSimOptions);
|
|
504
|
+
async start(identities: Identity[]): Promise<void>;
|
|
505
|
+
async stop(): Promise<void>;
|
|
506
|
+
createRandomTransaction(identities: Identity[]): Transaction;
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
## Testing
|
|
511
|
+
|
|
512
|
+
### Test Scenarios
|
|
513
|
+
|
|
514
|
+
1. **Identity Generation**
|
|
515
|
+
- Random identity creation
|
|
516
|
+
- Rate control
|
|
517
|
+
- Event emission
|
|
518
|
+
|
|
519
|
+
2. **Transaction Generation**
|
|
520
|
+
- Random transaction creation
|
|
521
|
+
- Rate control
|
|
522
|
+
- Realistic amounts
|
|
523
|
+
|
|
524
|
+
3. **Validation Simulation**
|
|
525
|
+
- Validation delays
|
|
526
|
+
- Success/failure rates
|
|
527
|
+
- Task completion
|
|
528
|
+
|
|
529
|
+
4. **Storage/Compute Simulation**
|
|
530
|
+
- Operation types
|
|
531
|
+
- Resource usage
|
|
532
|
+
- Timing
|
|
533
|
+
|
|
534
|
+
5. **System Integration**
|
|
535
|
+
- Full system simulation
|
|
536
|
+
- Metrics collection
|
|
537
|
+
- Event handling
|
|
538
|
+
|
|
539
|
+
### Coverage Goals
|
|
540
|
+
|
|
541
|
+
- 90%+ code coverage
|
|
542
|
+
- All simulation types tested
|
|
543
|
+
- Rate control validation
|
|
544
|
+
- Metrics accuracy
|
|
545
|
+
|
|
546
|
+
## Integration Notes
|
|
547
|
+
|
|
548
|
+
### Module Dependencies
|
|
549
|
+
|
|
550
|
+
- **All XMBL modules**: xid, xn, xclt, xvsm, xpc, xsc
|
|
551
|
+
- **xv**: Visualizer module (consumes xsim events via bridge server)
|
|
552
|
+
|
|
553
|
+
### Integration Pattern
|
|
554
|
+
|
|
555
|
+
```javascript
|
|
556
|
+
import { SystemSimulator } from 'xsim';
|
|
557
|
+
import { XCLT } from 'xclt';
|
|
558
|
+
import { XPC } from 'xpc';
|
|
559
|
+
import { XID } from 'xid';
|
|
560
|
+
import { XN } from 'xn';
|
|
561
|
+
import { XSC } from 'xsc';
|
|
562
|
+
import { XVSM } from 'xvsm';
|
|
563
|
+
|
|
564
|
+
const sim = new SystemSimulator({
|
|
565
|
+
identityRate: 2,
|
|
566
|
+
transactionRate: 10,
|
|
567
|
+
stateDiffRate: 5
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
// Connect to real modules - xsim generates data, modules process it
|
|
571
|
+
sim.identitySim.on('identity:created', async (identity) => {
|
|
572
|
+
// Use actual xid module to create identity
|
|
573
|
+
const realIdentity = await XID.create(identity);
|
|
574
|
+
// Emit to xn for network topology
|
|
575
|
+
XN.addNode(realIdentity);
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
sim.transactionSim.on('transaction:created', async (tx) => {
|
|
579
|
+
// Submit to actual xpc module
|
|
580
|
+
await XPC.submitTransaction('leader1', tx);
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
sim.stateDiffSim.on('state:diff:created', async (diff) => {
|
|
584
|
+
// Submit to actual xvsm module
|
|
585
|
+
await XVSM.addStateDiff(diff);
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
sim.storageComputeSim.on('storage:operation', async (op) => {
|
|
589
|
+
// Submit to actual xsc module
|
|
590
|
+
await XSC.handleOperation(op);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
sim.on('metrics:update', (metrics) => {
|
|
594
|
+
console.log('Metrics:', metrics);
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
await sim.start();
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### Integration with XV Visualizer
|
|
601
|
+
|
|
602
|
+
xsim integrates with xv visualizer via the bridge server (`xv/server.js`):
|
|
603
|
+
|
|
604
|
+
1. **Bridge Server Setup**:
|
|
605
|
+
- Bridge server runs on port 3000
|
|
606
|
+
- Connects to xsim SystemSimulator
|
|
607
|
+
- Connects to xclt Ledger
|
|
608
|
+
- Bridges events to visualizer via socket.io
|
|
609
|
+
|
|
610
|
+
2. **Event Flow**:
|
|
611
|
+
```
|
|
612
|
+
xsim → bridge server → socket.io → xv visualizer
|
|
613
|
+
xclt → bridge server → socket.io → xv visualizer
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
3. **Events Bridged**:
|
|
617
|
+
- `identity:created` → `xn:node:connected` (with real activity/ping from xn)
|
|
618
|
+
- `transaction:created` → `xpc:transaction:new`
|
|
619
|
+
- `state:diff:created` → `xvsm:state:diff`
|
|
620
|
+
- `state:assembled` → `xvsm:state:assembled`
|
|
621
|
+
- `storage:operation` → `xsc:operation`
|
|
622
|
+
- `compute:operation` → `xpc:compute:operation`
|
|
623
|
+
|
|
624
|
+
### CRITICAL: Data Generation Policy
|
|
625
|
+
|
|
626
|
+
**xsim IS a simulator - it generates test data. However, it must coordinate with real modules.**
|
|
627
|
+
|
|
628
|
+
#### What xsim does:
|
|
629
|
+
- ✅ Generates test identities, transactions, state diffs, etc.
|
|
630
|
+
- ✅ Uses faker/chance for realistic test data generation
|
|
631
|
+
- ✅ Emits events that can be consumed by visualizer or real modules
|
|
632
|
+
- ✅ Provides deterministic mode for reproducible tests
|
|
633
|
+
|
|
634
|
+
#### What xsim must NOT do:
|
|
635
|
+
- ❌ Generate fake network topology data (must use xn module)
|
|
636
|
+
- ❌ Generate fake ping/latency data (must use xn module)
|
|
637
|
+
- ❌ Generate fake activity metrics (must use actual module metrics)
|
|
638
|
+
- ❌ Bypass real modules when they're available
|
|
639
|
+
|
|
640
|
+
#### Integration Requirements:
|
|
641
|
+
|
|
642
|
+
1. **When used with real modules**:
|
|
643
|
+
- xsim generates test data (identities, transactions, etc.)
|
|
644
|
+
- Real modules process the data (xid, xpc, xclt, etc.)
|
|
645
|
+
- Real modules emit their own events with actual metrics
|
|
646
|
+
- Visualizer displays data from real modules, not xsim directly
|
|
647
|
+
|
|
648
|
+
2. **When used standalone (simulation mode)**:
|
|
649
|
+
- xsim generates all test data
|
|
650
|
+
- Bridge server forwards xsim events to visualizer
|
|
651
|
+
- Visualizer displays simulated data
|
|
652
|
+
- This is acceptable for development/testing
|
|
653
|
+
|
|
654
|
+
3. **Network data**:
|
|
655
|
+
- xsim should NOT generate fake ping/latency/activity
|
|
656
|
+
- When xn module is available, use real network metrics
|
|
657
|
+
- When xn is not available, xsim can generate basic test data
|
|
658
|
+
- Bridge server should enrich with real data when available
|
|
659
|
+
|
|
660
|
+
### Required Integration Work
|
|
661
|
+
|
|
662
|
+
1. **Connect to real modules**:
|
|
663
|
+
- xsim should optionally connect to real xid, xpc, xclt, xvsm, xsc modules
|
|
664
|
+
- When modules are available, use them instead of just emitting events
|
|
665
|
+
- Real modules provide actual metrics and processing
|
|
666
|
+
|
|
667
|
+
2. **Bridge server enhancements**:
|
|
668
|
+
- Bridge server must connect to xn module for real network topology
|
|
669
|
+
- Bridge server must enrich xsim identity events with real xn node data
|
|
670
|
+
- Bridge server must use real ping/latency from xn, not generate fake values
|
|
671
|
+
|
|
672
|
+
3. **Event coordination**:
|
|
673
|
+
- xsim events should trigger real module operations
|
|
674
|
+
- Real module events should be forwarded to visualizer
|
|
675
|
+
- Visualizer should prefer real module events over xsim events
|
|
676
|
+
|
|
677
|
+
4. **Metrics collection**:
|
|
678
|
+
- Collect metrics from real modules when available
|
|
679
|
+
- Fall back to xsim metrics only when modules aren't connected
|
|
680
|
+
- Distinguish between simulated and real metrics in output
|
|
681
|
+
|
|
682
|
+
## Outstanding Requirements
|
|
683
|
+
|
|
684
|
+
Based on `status.md`, the following work is still required:
|
|
685
|
+
|
|
686
|
+
### Module Integration
|
|
687
|
+
|
|
688
|
+
- [ ] **Integrate with actual XMBL modules** (xid, xn, xclt, xvsm, xpc, xsc)
|
|
689
|
+
- Currently xsim generates data but doesn't always connect to real modules
|
|
690
|
+
- Must connect to real modules when available
|
|
691
|
+
- Must use real module metrics instead of simulated ones
|
|
692
|
+
|
|
693
|
+
- [ ] **Add failure injection** (network failures, node crashes)
|
|
694
|
+
- Currently missing failure simulation
|
|
695
|
+
- Must simulate network partitions
|
|
696
|
+
- Must simulate node crashes and recovery
|
|
697
|
+
- Must simulate validation failures
|
|
698
|
+
|
|
699
|
+
- [ ] **Add browser monitoring capabilities** (web dashboard)
|
|
700
|
+
- Currently only has terminal monitoring
|
|
701
|
+
- Must provide web interface for metrics
|
|
702
|
+
- Must integrate with xv visualizer
|
|
703
|
+
|
|
704
|
+
- [ ] **Add metrics export/visualization** (JSON, CSV, Prometheus)
|
|
705
|
+
- Currently only displays metrics in terminal
|
|
706
|
+
- Must export metrics in standard formats
|
|
707
|
+
- Must support Prometheus metrics endpoint
|
|
708
|
+
|
|
709
|
+
- [ ] **Add performance benchmarking**
|
|
710
|
+
- Currently missing performance benchmarks
|
|
711
|
+
- Must measure throughput (tx/s, identities/s)
|
|
712
|
+
- Must measure latency (validation time, state assembly time)
|
|
713
|
+
- Must measure resource usage (CPU, memory)
|
|
714
|
+
|
|
715
|
+
- [ ] **Add stress testing modes**
|
|
716
|
+
- Currently missing stress testing
|
|
717
|
+
- Must support high-rate simulation
|
|
718
|
+
- Must support large-scale simulation (many nodes)
|
|
719
|
+
- Must support long-running simulations
|
|
720
|
+
|
|
721
|
+
- [ ] **Add configuration file support**
|
|
722
|
+
- Currently only supports environment variables
|
|
723
|
+
- Must support JSON/YAML configuration files
|
|
724
|
+
- Must support per-simulator configuration
|
|
725
|
+
|
|
726
|
+
### Bridge Server Integration
|
|
727
|
+
|
|
728
|
+
- [ ] **Enhance bridge server to use real module data**
|
|
729
|
+
- Bridge server must connect to xn module for real network topology
|
|
730
|
+
- Bridge server must enrich xsim events with real module metrics
|
|
731
|
+
- Bridge server must use real ping/latency from xn, not generate fake values
|
|
732
|
+
|
|
733
|
+
- [ ] **Coordinate events between xsim and real modules**
|
|
734
|
+
- xsim events should trigger real module operations
|
|
735
|
+
- Real module events should be forwarded to visualizer
|
|
736
|
+
- Must handle both simulated and real data sources
|
|
737
|
+
|
|
738
|
+
## Terminal and Browser Monitoring
|
|
739
|
+
|
|
740
|
+
### Terminal Output
|
|
741
|
+
|
|
742
|
+
- **Simulation Status**: Log simulation state
|
|
743
|
+
```javascript
|
|
744
|
+
console.log(`Simulator running: ${sim.isRunning()}`);
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
- **Metrics**: Periodic metrics display
|
|
748
|
+
```javascript
|
|
749
|
+
console.log(`Identities: ${metrics.identitiesCreated}, Transactions: ${metrics.transactionsCreated}`);
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
- **Rates**: Current operation rates
|
|
753
|
+
```javascript
|
|
754
|
+
console.log(`Rate: ${txRate} tx/s, ${idRate} identities/s`);
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
- **Module Connections**: Log which modules are connected
|
|
758
|
+
```javascript
|
|
759
|
+
console.log(`Connected modules: ${connectedModules.join(', ')}`);
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
- **Data Source**: Distinguish between simulated and real data
|
|
763
|
+
```javascript
|
|
764
|
+
console.log(`Data source: ${isUsingRealModules ? 'real modules' : 'simulated'}`);
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
### Screenshot Requirements
|
|
768
|
+
|
|
769
|
+
Capture terminal output for:
|
|
770
|
+
- Simulation startup
|
|
771
|
+
- Real-time metrics
|
|
772
|
+
- Rate statistics
|
|
773
|
+
- Error logs
|
|
774
|
+
- Module connection status
|
|
775
|
+
- Metrics showing simulated vs real data
|
|
776
|
+
|
|
777
|
+
### Console Logging
|
|
778
|
+
|
|
779
|
+
- Log all simulation events
|
|
780
|
+
- Include timing information
|
|
781
|
+
- Log metrics updates
|
|
782
|
+
- Include error details
|
|
783
|
+
- Log module connection/disconnection events
|
|
784
|
+
- **Distinguish between simulated and real data** in logs
|