Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Devnet improvements #471

Merged
merged 5 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/devnet-run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ jobs:

- run: |
sleep 10 &&
npx ts-node --esm scripts/seeder.ts --rpcPort=8545 --sourceFile="./blocks200000-210000.json" --numBlocks=3 --numNodes=10
npx ts-node --esm scripts/seeder.ts --rpcPort=8545 --sourceFile="./blocks200000-210000.json" --numBlocks=3 --numNodes=10 --connectNodes=false
2 changes: 1 addition & 1 deletion .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ jobs:
name: Build and push
uses: docker/build-push-action@v5
with:
push: true
push: ${{ github.event.name == 'schedule' }}
tags: ghcr.io/${{ github.repository_owner }}/ultralight:latest

6 changes: 5 additions & 1 deletion packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,12 @@ Run a local network of CLI Ultralight clients. Test JSON-RPC calls in a termina
- Run `npm run devnet -- --numNodes=3`
- This will start 3 nodes with JSON-RPC server addresses `[8545, 8546, 8547]`
- To specify a port number to, include a `--port` variable
- `num run devnet -- --numNodes=5 --port=9009`
- `npm run devnet -- --numNodes=5 --port=9009`
- This will start 5 nodes with JSON-RPC server addresses `[9009, 9010, 9011, 9012, 9013]`
- To specify which subnetworks to support, include one or more `--networks` parameters
- `npm run devnet -- --numNodes=5 --port=9009 --networks=history --networks=beacon`

Note, all nodes are connected to each other as bootnodes for each network by default. To turn off this behavior, pass `--connectNodes=false`.

### Using the Devnet
#### command-line:
Expand Down
115 changes: 72 additions & 43 deletions packages/cli/scripts/devnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,49 @@ import { hideBin } from 'yargs/helpers'
import * as fs from 'fs'
import { spawn, ChildProcessByStdio, execSync } from 'child_process'
import { createRequire } from 'module'
import jayson from 'jayson/promise/index.js'

const { Client } = jayson
const require = createRequire(import.meta.url)

const args: any = yargs(hideBin(process.argv))
.option('pks', {
describe: 'text file containing private keys for nodes in devnet',
string: true,
optional: true,
}) .option('numNodes', {
describe: 'number of random nodes to start',
number: true,
optional: true,
}) .option('ip', {
describe: 'ip addr',
string: true,
optional: true,
}).option('promConfig', {
describe: 'create prometheus scrape_target file',
boolean: true,
default: false
}).option('port', {
describe: 'starting port number',
number: true,
default: 9000
}).option('networks', {
describe: 'supported subnetworks',
array: true,
optional: true
}).argv
.option('pks', {
describe: 'text file containing private keys for nodes in devnet',
string: true,
optional: true,
}).option('numNodes', {
describe: 'number of random nodes to start',
number: true,
optional: true,
}).option('ip', {
describe: 'ip addr',
string: true,
optional: true,
}).option('promConfig', {
describe: 'create prometheus scrape_target file',
boolean: true,
default: false
}).option('port', {
describe: 'starting port number',
number: true,
default: 9000
}).option('networks', {
describe: 'supported subnetworks',
array: true,
optional: true
}).option('connectNodes', {
describe: 'connet all nodes on network start',
boolean: true,
default: true
}).strict().argv

const main = async () => {
console.log(`starting ${args.numNodes} nodes`)

const networks = args.networks && (args.networks as Array<string>).map(network => `--networks=${network}`)
const cmd = 'hostname -I'
const pubIp = execSync(cmd).toString().split(' ')
const ip = args.ip ?? pubIp[0]

let children: ChildProcessByStdio<any, any, null>[] = []
const file = require.resolve(process.cwd() + '/dist/index.js')
if (args.pks) {
Expand All @@ -54,7 +62,7 @@ const main = async () => {
`--metrics=true`,
`--metricsPort=${18545 + idx}`,
`--bindAddress-${ip}:${args.port + idx}`,
args.networks ? `--networks=${(args.networks as Array<string>).join(' ')}` : ''
...networks
],
{ stdio: ['pipe', 'pipe', process.stderr] }
)
Expand All @@ -71,30 +79,51 @@ const main = async () => {
`--metrics=true`,
`--metricsPort=${18545 + x}`,
`--bindAddress=${ip}:${args.port + x}`,
args.networks ? `--networks=${(args.networks as Array<string>).join(' ')}` : ''
...networks
],
{ stdio: ['pipe', 'pipe', process.stderr] }
)
children.push(child)
}
}

if (args.promConfig) {
const targets:any[] = []
children.forEach((_child, idx) => targets.push(`${ip}:1${args.port + idx}`))
let targetBlob = [Object.assign({
"targets": targets,
"labels": { "env": "devnet" }
})]
fs.writeFileSync('./targets.json', JSON.stringify(targetBlob, null, 2))
// Wait for nodes to start up
await new Promise(resolve => setTimeout(() => { resolve(undefined) }, 3000))

if (args.promConfig) {
const targets: any[] = []
children.forEach((_child, idx) => targets.push(`${ip}:1${args.port + idx}`))
let targetBlob = [Object.assign({
"targets": targets,
"labels": { "env": "devnet" }
})]
fs.writeFileSync('./targets.json', JSON.stringify(targetBlob, null, 2))
}

// Connect nodes to other nodes in the network via `addBootNode`
if (args.connectNodes) {
console.log('connecting nodes')
const ultralights: jayson.HttpClient[] = []
for (let x = 0; x < 10; x++) {
ultralights.push(Client.http({ host: '127.0.0.1', port: 8545 + x }))
}
const interval = setInterval(() => {}, 1000)
console.log(`starting ${children.length} nodes`)
process.on('SIGINT', async () => {
console.log('Caught close signal, shutting down...')
children.forEach((child) => child.kill())
clearInterval(interval as NodeJS.Timeout)
})

for (let x = 0; x < args.numNodes; x++) {
const peerEnr = await ultralights[x].request('discv5_nodeInfo', [])
for (let y = 0; y < args.numNodes; y++) {
if (y === x) continue
for (const network of args.networks) {
const res = await ultralights[y].request(`portal_${network}AddBootNode`, [peerEnr.result.enr])
}

}
}
}
process.on('SIGINT', async () => {
console.log('Caught close signal, shutting down...')

children.forEach((child) => child.kill())
})
}

main()
1 change: 1 addition & 0 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ const main = async () => {
} else {
networks = [ProtocolId.HistoryNetwork]
}

if (args.trustedBlockRoot !== undefined) {
networks.push(ProtocolId.BeaconLightClientNetwork)
}
Expand Down
8 changes: 5 additions & 3 deletions packages/cli/src/rpc/modules/portal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,11 @@ export class portal {
}
async historyAddBootNode(params: [string]): Promise<boolean> {
const [enr] = params
this.logger(`portal_historyAddEnrs request received for ${enr.slice(0, 10)}...`)
this.logger(`portal_historyAddBootNode request received for ${enr.slice(0, 10)}...`)
try {
await this._history.addBootNode(enr)
} catch {
} catch (err) {
this.logger(err)
return false
}
return true
Expand Down Expand Up @@ -591,7 +592,8 @@ export class portal {
this.logger(`portal_beaconAddBootNode request received for ${enr.slice(0, 10)}...`)
try {
await this._beacon.addBootNode(enr)
} catch {
} catch (err) {
this.logger(err)
return false
}
return true
Expand Down