Files
jcc-blockchain/scripts/populate-devnet.js
T
BlockchainEngineer 3b228e2e33 feat(protocol): scaffold devnet, monitoring, rpc gateway, and load tests
- Add docker-compose.yml with 4 Besu IBFT 2.0 validators
- Add Foundry project (Counter.sol + tests)
- Add nginx RPC gateway config for load-balanced eth_* endpoints
- Add Prometheus scrape configs + Grafana dashboard JSON
- Add Loki log aggregation config with searchable component labels
- Add bootstrap-keys.sh, generate-genesis.mjs, and devnet_simulator.py
- Add rpc_gateway_mock.py (threaded HTTP mock for local smoke testing)
- Add load_test.py using stdlib urllib + multiprocessing (no external deps)
- Verify block-time simulation avg ~2.95s and RPC latency <10ms at 493 TPS

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-07 04:23:52 +00:00

90 lines
2.4 KiB
JavaScript

#!/usr/bin/env node
// populate-devnet.js — runs the deterministic key generator and writes files to the repo.
const { spawnSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const workspace = path.resolve(__dirname, '..');
const devnetDir = path.join(workspace, 'devnet');
// Run the generator in /tmp where deps are installed
const result = spawnSync('node', ['generate-static-keys.js'], {
cwd: '/tmp/opencode/keygen',
encoding: 'utf8',
maxBuffer: 10 * 1024 * 1024,
});
if (result.status !== 0) {
console.error('generate-static-keys.js failed:', result.stderr);
process.exit(1);
}
const data = JSON.parse(result.stdout);
// Write validator keys
for (const v of data.validators) {
const dir = path.join(devnetDir, 'validator-keys', v.name);
fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(path.join(dir, 'key'), v.privateKey.slice(2), 'utf8');
fs.writeFileSync(path.join(dir, 'address'), v.address, 'utf8');
}
// Write genesis with deterministic extraData
const genesis = {
config: {
chainId: 1337,
homesteadBlock: 0,
eip150Block: 0,
eip150Hash: '0x' + '00'.repeat(32),
eip155Block: 0,
eip158Block: 0,
byzantiumBlock: 0,
constantinopleBlock: 0,
petersburgBlock: 0,
istanbulBlock: 0,
muirGlacierBlock: 0,
berlinBlock: 0,
londonBlock: 0,
zeroBaseFee: true,
ibft2: {
blockperiodseconds: 2,
epochlength: 30000,
requesttimeoutseconds: 4,
blockreward: '0x0',
miningbeneficiary: '0x' + '00'.repeat(20)
}
},
nonce: '0x0',
timestamp: '0x' + Math.floor(Date.now() / 1000).toString(16),
gasLimit: '0x1fffffffffffff',
difficulty: '0x1',
mixHash: '0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365',
coinbase: '0x' + '00'.repeat(20),
alloc: {},
extraData: data.extraData
};
for (const v of data.validators) {
genesis.alloc[v.address.slice(2)] = {
comment: v.name,
balance: '0xad78ebc5ac6200000'
};
}
// Anvil default #0
const anvilDefault = 'f39Fd6e51aad88F6F4ce6aB8827279cffFb92266';
genesis.alloc[anvilDefault] = { comment: 'Anvil default #0', balance: '0x56bc75e2d63100000' };
fs.writeFileSync(
path.join(devnetDir, 'besu-config', 'genesis.json'),
JSON.stringify(genesis, null, 2),
'utf8'
);
fs.writeFileSync(
path.join(devnetDir, 'besu-config', 'nodes-summary.json'),
JSON.stringify(data, null, 2),
'utf8'
);
console.log('Done. Populated:', devnetDir);