From 037f87d190de3392d9d93ca645461da82fb34b47 Mon Sep 17 00:00:00 2001 From: hopeyen Date: Fri, 23 Aug 2024 09:50:06 -0500 Subject: [PATCH] feat: script to simulate network flood --- docker-compose.yaml | 50 +- grafana/dashboards/Throughput-testing.json | 595 +++++++++++++++++++++ grafana/provisioning/dashboards/all.yml | 11 + grafana/provisioning/datasources/all.yml | 15 + prometheus/prometheus.yml | 22 + rollupcreator/Dockerfile | 2 +- scripts/config.ts | 2 + scripts/flood.ts | 143 +++++ scripts/index.ts | 4 +- test-node.bash | 23 +- 10 files changed, 851 insertions(+), 16 deletions(-) create mode 100644 grafana/dashboards/Throughput-testing.json create mode 100644 grafana/provisioning/dashboards/all.yml create mode 100644 grafana/provisioning/datasources/all.yml create mode 100644 prometheus/prometheus.yml create mode 100644 scripts/flood.ts diff --git a/docker-compose.yaml b/docker-compose.yaml index b5f33d9..aecc2e5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -156,12 +156,14 @@ services: - "127.0.0.1:8547:8547" - "127.0.0.1:8548:8548" - "127.0.0.1:9642:9642" + - "127.0.0.1:6070:6070" + - "127.0.0.1:6071:6071" volumes: - "seqdata:/home/user/.arbitrum/local/nitro" - "l1keystore:/home/user/l1keystore" - "config:/config" - "tokenbridge-data:/tokenbridge-data" - command: --conf.file /config/sequencer_config.json --node.feed.output.enable --node.feed.output.port 9642 --http.api net,web3,eth,txpool,debug --node.seq-coordinator.my-url ws://sequencer:8548 --graphql.enable --graphql.vhosts * --graphql.corsdomain * + command: --conf.file /config/sequencer_config.json --node.feed.output.enable --node.feed.output.port 9642 --http.api net,web3,eth,txpool,debug --node.seq-coordinator.my-url ws://sequencer:8548 --graphql.enable --graphql.vhosts * --graphql.corsdomain --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 depends_on: - geth @@ -175,7 +177,7 @@ services: volumes: - "seqdata_b:/home/user/.arbitrum/local/nitro" - "config:/config" - command: --conf.file /config/sequencer_config.json --node.seq-coordinator.my-url ws://sequencer_b:8548 + command: --conf.file /config/sequencer_config.json --node.seq-coordinator.my-url ws://sequencer_b:8548 --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 depends_on: - geth - redis @@ -190,7 +192,7 @@ services: volumes: - "seqdata_c:/home/user/.arbitrum/local/nitro" - "config:/config" - command: --conf.file /config/sequencer_config.json --node.seq-coordinator.my-url ws://sequencer_c:8548 + command: --conf.file /config/sequencer_config.json --node.seq-coordinator.my-url ws://sequencer_c:8548 --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 depends_on: - geth - redis @@ -205,7 +207,7 @@ services: volumes: - "seqdata_d:/home/user/.arbitrum/local/nitro" - "config:/config" - command: --conf.file /config/sequencer_config.json --node.seq-coordinator.my-url ws://sequencer_d:8548 + command: --conf.file /config/sequencer_config.json --node.seq-coordinator.my-url ws://sequencer_d:8548 --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 depends_on: - geth - redis @@ -221,7 +223,7 @@ services: - "unsafestaker-data:/home/user/.arbitrum/local/nitro" - "l1keystore:/home/user/l1keystore" - "config:/config" - command: --conf.file /config/unsafe_staker_config.json + command: --conf.file /config/unsafe_staker_config.json --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 depends_on: - sequencer - redis @@ -238,7 +240,7 @@ services: - "poster-data:/home/user/.arbitrum/local/nitro" - "l1keystore:/home/user/l1keystore" - "config:/config" - command: --conf.file /config/poster_config.json + command: --conf.file /config/poster_config.json --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 depends_on: - geth - redis @@ -254,7 +256,7 @@ services: - "poster-data-b:/home/user/.arbitrum/local/nitro" - "l1keystore:/home/user/l1keystore" - "config:/config" - command: --conf.file /config/poster_config.json + command: --conf.file /config/poster_config.json --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 depends_on: - geth - redis @@ -270,7 +272,7 @@ services: - "poster-data-c:/home/user/.arbitrum/local/nitro" - "l1keystore:/home/user/l1keystore" - "config:/config" - command: --conf.file /config/poster_config.json + command: --conf.file /config/poster_config.json --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 depends_on: - geth - redis @@ -286,7 +288,7 @@ services: - "validator-data:/home/user/.arbitrum/local/nitro" - "l1keystore:/home/user/l1keystore" - "config:/config" - command: --conf.file /config/validator_config.json --http.port 8547 --http.api net,web3,arb,debug --ws.port 8548 + command: --conf.file /config/validator_config.json --http.port 8547 --http.api net,web3,arb,debug --ws.port 8548 --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 depends_on: - sequencer - validation_node @@ -302,7 +304,7 @@ services: - "validator-data:/home/user/.arbitrum/local/nitro" - "l1keystore:/home/user/l1keystore" - "config:/config" - command: --conf.file /config/l3node_config.json --http.port 3347 --http.api net,web3,arb,debug,eth --ws.port 3348 + command: --conf.file /config/l3node_config.json --http.port 3347 --http.api net,web3,arb,debug,eth --ws.port 3348 --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 depends_on: - sequencer - validation_node @@ -315,7 +317,7 @@ services: - "127.0.0.1:8949:8549" volumes: - "config:/config" - command: --conf.file /config/validation_node_config.json + command: --conf.file /config/validation_node_config.json --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 scripts: build: scripts/ @@ -330,7 +332,7 @@ services: entrypoint: /usr/local/bin/relay ports: - "127.0.0.1:9652:9652" - command: --chain.id 412346 --node.feed.input.url ws://sequencer:9642 --node.feed.output.port 9652 + command: --chain.id 412346 --node.feed.input.url ws://sequencer:9642 --node.feed.output.port 9652 --metrics --pprof --metrics-server.addr 0.0.0.0 --pprof-cfg.addr 0.0.0.0 tokenbridge: depends_on: @@ -372,6 +374,29 @@ services: ports: - 4242:4242 + prometheus: + image: prom/prometheus:latest + container_name: prometheus + volumes: + - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml + ports: + - "9090:9090" + command: + - "--config.file=/etc/prometheus/prometheus.yml" + + grafana: + image: grafana/grafana:latest + container_name: grafana + ports: + - "127.0.0.1:3000:3000" + volumes: + - ./grafana/provisioning/:/etc/grafana/provisioning/:ro + - ./grafana/dashboards:/var/lib/grafana/dashboards + environment: + - GF_SECURITY_ADMIN_PASSWORD=admin + depends_on: + - prometheus + volumes: l1data: consensus: @@ -385,6 +410,7 @@ volumes: poster-data: poster-data-b: poster-data-c: + grafana-data: config: postgres-data: tokenbridge-data: diff --git a/grafana/dashboards/Throughput-testing.json b/grafana/dashboards/Throughput-testing.json new file mode 100644 index 0000000..6c3e5b6 --- /dev/null +++ b/grafana/dashboards/Throughput-testing.json @@ -0,0 +1,595 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__elements": {}, + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "11.1.4" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Time series", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "{__name__\"": { + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "__name__*" + }, + "properties": [ + { + "id": "displayName" + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "11.1.4", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "arb_sequencenumber_confirmed", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Confirmed", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "arb_sequencenumber_inblock", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Inblock", + "range": true, + "refId": "B", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "arb_sequencenumber_latest", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Latest", + "range": true, + "refId": "C", + "useBackend": false + } + ], + "title": "nominal SeqNum", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "sum(rate(arb_sequencenumber_latest[$__rate_interval]))", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "sum(rate(arb_sequencenumber_confirmed[$__rate_interval]))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "sum(rate(arb_sequencenumber_inblock[$__rate_interval]))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "C", + "useBackend": false + } + ], + "title": "SeqNum rate", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 6 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "arb_inbox_latest_batch_message", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "latest batch message", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "sum(avg(arb_inbox_latest_batch))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "latest batch", + "range": true, + "refId": "F", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "sum(avg(arb_block_transactions_count))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "block tx count", + "range": true, + "refId": "C", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "sum(rate(arb_sequencer_block_creation_count[$__rate_interval]))", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "arb series", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "rate(arb_batchposter_wallet_eth[$__rate_interval])", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "batch poster wallet eth rate", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "rate(arb_batchposter_estimated_batch_backlog[$__rate_interval])", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "batch poster estimated batch backlog", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Panel Title", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Throughput testing", + "uid": "advlsdpd877y8a", + "version": 4, + "weekStart": "" +} \ No newline at end of file diff --git a/grafana/provisioning/dashboards/all.yml b/grafana/provisioning/dashboards/all.yml new file mode 100644 index 0000000..36fd178 --- /dev/null +++ b/grafana/provisioning/dashboards/all.yml @@ -0,0 +1,11 @@ +apiVersion: 1 + +providers: + - name: 'default' + orgId: 1 + folder: '' + type: file + disableDeletion: true + editable: true + options: + path: /var/lib/grafana/dashboards \ No newline at end of file diff --git a/grafana/provisioning/datasources/all.yml b/grafana/provisioning/datasources/all.yml new file mode 100644 index 0000000..af7179f --- /dev/null +++ b/grafana/provisioning/datasources/all.yml @@ -0,0 +1,15 @@ +apiVersion: 1 + +deleteDatasources: +- name: 'Prometheus' + +datasources: +- access: 'proxy' + editable: true + is_default: true + name: 'Prometheus' + uid: 'ddshms3dlineoe' + org_id: 1 + type: 'prometheus' + url: 'http://prometheus:9090' + version: 1 \ No newline at end of file diff --git a/prometheus/prometheus.yml b/prometheus/prometheus.yml new file mode 100644 index 0000000..8a5097e --- /dev/null +++ b/prometheus/prometheus.yml @@ -0,0 +1,22 @@ +global: + scrape_interval: 15s + scrape_timeout: 10s + evaluation_interval: 15s + +scrape_configs: + + - job_name: 'prometheus' + scrape_interval: 5s + static_configs: + - targets: ['localhost:9090'] + + - job_name: 'sequencer' + honor_timestamps: true + metrics_path: /debug/metrics/prometheus + # scheme: http + static_configs: + - targets: ["sequencer:6070"] + + # - job_name: "eigenda_proxy" + # static_configs: + # - targets: ["127.0.0.1:4242"] \ No newline at end of file diff --git a/rollupcreator/Dockerfile b/rollupcreator/Dockerfile index 8509151..55578e0 100644 --- a/rollupcreator/Dockerfile +++ b/rollupcreator/Dockerfile @@ -9,7 +9,7 @@ RUN apt-get update && \ WORKDIR /workspace # Clone the repository and checkout the specified branch RUN git clone --no-checkout https://github.com/layr-labs/nitro-contracts.git ./ -RUN git checkout 81fa76a31bde7bc0286390ddc2ee3dce4af9f68f +RUN git checkout 6aed7ed34dc5bfdb10e2f16a60d063f00501d75d # Install Foundry RUN curl -L https://foundry.paradigm.xyz | bash diff --git a/scripts/config.ts b/scripts/config.ts index c75d7cc..b3213a6 100644 --- a/scripts/config.ts +++ b/scripts/config.ts @@ -244,6 +244,7 @@ function writeConfigs(argv: any) { "vhosts": "*", "corsdomain": "*" }, + "metrics": true, } @@ -322,6 +323,7 @@ function writeConfigs(argv: any) { "jwtsecret": valJwtSecret, "addr": "0.0.0.0", }, + "metrics": true, })) fs.writeFileSync(path.join(consts.configpath, "validation_node_config.json"), JSON.stringify(validationNodeConfig)) } diff --git a/scripts/flood.ts b/scripts/flood.ts new file mode 100644 index 0000000..e019378 --- /dev/null +++ b/scripts/flood.ts @@ -0,0 +1,143 @@ +import { runStress } from './stress'; +import { ethers } from 'ethers'; +import { namedAccount, namedAddress } from './accounts'; + +function randomInRange(maxSize: number): number { + return Math.ceil(Math.random() * maxSize); +} + +function generateRandomBytes(size: number): string { + let result = ''; + const hexChars = '0123456789abcdef'; + for (let i = 0; i < size; i++) { + const byte = Math.floor(Math.random() * 256); + result += hexChars[(byte >> 4) & 0xf] + hexChars[byte & 0xf]; // Convert byte to two hex characters + } + return result; +} + +function generateRandomHexData(size: number): string { + return '0x' + generateRandomBytes(size); +} + +async function sendTransaction(argv: any, threadId: number) { + console.log("sending tx from", argv.from, "to", argv.to) + const account = namedAccount(argv.from, threadId).connect(argv.provider) + const startNonce = await account.getTransactionCount("pending") + for (let index = 0; index < argv.times; index++) { + const response = await + account.sendTransaction({ + to: namedAddress(argv.to, threadId), + value: ethers.utils.parseEther(argv.ethamount), + data: argv.data, + nonce: startNonce + index, + }) + console.log(response) + if (argv.wait) { + const receipt = await response.wait() + console.log(receipt) + } + if (argv.delay > 0) { + await new Promise(f => setTimeout(f, argv.delay)); + } + } +} + +// flood simulation +async function simulateNetworkFlood(argv: any) { + // fund the users + console.log(`fund all users`) + const funding_argv = { + ...argv, + ethamount: "100000", + times: 1, + threads: 1, + wait: true, + from: `funnel` + } + for (let i = 0; i < argv.users; i++) { + funding_argv.to = `user_${i}` + await runStress(funding_argv, sendTransaction) + } + + console.log(`start sending transactions`) + const max_time = argv.times + const max_thread = argv.threads + for (let i = 0; i < argv.rounds; i++) { + argv.from = `user_${randomInRange(argv.users)}`; + argv.times = randomInRange(max_time) + argv.threads = randomInRange(max_thread) + argv.to = `user_${randomInRange(argv.users)}`; // don't care if sending to self + const size = randomInRange(argv.maxTxDataSize) + argv.data = generateRandomHexData(size); + + console.log(`prepared transactions`, { transaction_count: i, size: size, from: argv.from, to: argv.to}) + await runStress(argv, sendTransaction); + } +} + + +export const floodCommand = { + command: "flood", + describe: "Simulates network activity by sending arbitrary transactions among random users", + builder: { + users: { + number: true, + describe: "Number of active users", + default: 10, + }, + ethamount: { + string: true, + describe: "Amount of ETH to send in each transaction", + default: "0.1", + }, + rounds: { + number: true, + describe: "Number of rounds of transactions to send (total transactions = rounds * threads * times)", + default: 10000, + }, + avgTxDataSize: { + number: true, + describe: "Average transaction data size in bytes", + default: 100, + }, + // this is something we can read from the rollup creator + maxTxDataSize: { + number: true, + describe: "Maximum transaction data size in bytes", + default: 58982, + }, + threads: { + number: true, + describe: "Number of threads per transaction", + default: 100, + }, + times: { + number: true, + describe: "Number of transactions per thread", + default: 10, + }, + delay: { + number: true, + describe: "Delay between transactions in milliseconds", + default: 0, + }, + serial: { + boolean: true, + describe: "Run transactions serially (in sequence)", + default: false, + }, + wait: { + boolean: true, + describe: "Wait for transaction confirmations", + default: false, + }, + }, + handler: async (argv: any) => { + argv.provider = new ethers.providers.WebSocketProvider(argv.l2url); + await simulateNetworkFlood(argv); + argv.provider.destroy(); + + }, + }; + diff --git a/scripts/index.ts b/scripts/index.ts index 2fd189f..b4b8605 100644 --- a/scripts/index.ts +++ b/scripts/index.ts @@ -20,6 +20,7 @@ import { sendL3Command, sendRPCCommand, } from "./ethcommands"; +import { floodCommand } from "./flood"; async function main() { await Yargs(hideBin(process.argv)) @@ -41,8 +42,9 @@ async function main() { .command(sendL2Command) .command(sendL3Command) .command(sendRPCCommand) - .command(writeConfigCommand) + .command(floodCommand) .command(writeGethGenesisCommand) + .command(writeConfigCommand) .command(writeL2ChainConfigCommand) .command(writeL3ChainConfigCommand) .command(writePrysmCommand) diff --git a/test-node.bash b/test-node.bash index 8f7c22d..7a0a603 100755 --- a/test-node.bash +++ b/test-node.bash @@ -53,6 +53,8 @@ batchposters=1 devprivkey=b6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659 l1chainid=1337 simple=true +prometheus=true +grafana=true while [[ $# -gt 0 ]]; do case $1 in --init) @@ -172,6 +174,15 @@ while [[ $# -gt 0 ]]; do simple=false shift ;; + --prometheus) + prometheus=true + shift + ;; + --grafana) + grafana=true + shift + ;; + *) echo Usage: $0 \[OPTIONS..] echo $0 script [SCRIPT-ARGS] @@ -194,6 +205,8 @@ while [[ $# -gt 0 ]]; do echo --no-tokenbridge don\'t build or launch tokenbridge echo --no-run does not launch nodes \(useful with build or init\) echo --no-simple run a full configuration with separate sequencer/batch-poster/validator/relayer + echo --prometheus start Prometheus server + echo --grafana start Grafana server echo echo script runs inside a separate docker. For SCRIPT-ARGS, run $0 script --help exit 0 @@ -256,6 +269,12 @@ fi if $blockscout; then NODES="$NODES blockscout" fi +if $prometheus; then + NODES="$NODES prometheus" +fi +if $grafana; then + NODES="$NODES grafana" +fi if $force_build; then echo == Building.. if $dev_build_nitro; then @@ -382,8 +401,8 @@ if $force_init; then echo == Funding l2 funnel and dev key docker compose up --wait $INITIAL_SEQ_NODES - docker compose run scripts bridge-funds --ethamount 100000 --wait - docker compose run scripts send-l2 --ethamount 100 --to l2owner --wait + docker compose run scripts bridge-funds --ethamount 1000000000000000 --wait + docker compose run scripts send-l2 --ethamount 1000000000 --to l2owner --wait if $tokenbridge; then echo == Deploying L1-L2 token bridge