Load Testing with Solo and NLG
Overview
After deploying a Block Node, you should verify it can sustain production-level traffic before connecting it to the live network. This guide uses Solo to spin up a temporary network of three Consensus Nodes (CNs) that stream blocks directly to your Block Node, then drives high-volume transaction load through those CNs using the Network Load Generator (NLG).
For a lightweight connectivity check instead of a full load test, see Testing a Deployed Block Node Using the Simulator.
Prerequisites
Before you begin, ensure you have:
A running, reachable Block Node deployed via one of:
The Block Node's external IP address or hostname and gRPC port. The default gRPC port is
40840(seeserver.portin configuration.md). Retrieve the external IP from your cluster:kubectl get svc -n block-nodeUse the
EXTERNAL-IPvalue on the Block Node service row.All Solo tool dependencies (Docker, Kind, kubectl, Helm, Node.js) satisfied. See the Solo System Readiness guide. If you install Solo via Homebrew, Node.js, kubectl, and Helm are installed automatically as Homebrew dependencies; you still need Docker and Kind separately.
Network access: The Solo test cluster must be able to reach your Block Node over the network. If the Block Node is on a cloud VM, confirm that its firewall allows inbound TCP on the gRPC port from the machine running Solo. See Network Ports and Protocols for the full port list.
Step 1: Install the Solo CLI
Homebrew (recommended for macOS/Linux/WSL2):
npm (alternative installation method):
Verify the installation:
For full installation options and troubleshooting, see the Solo Quickstart.
Step 2: Set Up a Solo Test Network and Connect to Your Block Node
The commands in this step create a temporary Kubernetes cluster, deploy a three-node Hiero network inside it, and point those CNs at your Block Node — all before the CNs start. This ensures the Block Node receives every block from block 0 onwards. All resources are local and isolated from the live network. For background on what each command does, see the Manual Deployment documentation.
Set shell variables for the values you will reuse across commands:
Consensus Node version:
v0.73.0is the default used by Solo 0.77.0. Set this to the version that matches your Block Node's peer consensus node version. To see the version your Block Node is connected to, check theblock-node-sourcesconfig in your Block Node namespace.
Create a local Kind cluster:
Connect Solo to the cluster and create a deployment:
Add Cluster to Deployment with three Consensus Nodes:
Generate gossip and TLS keys:
Set up shared cluster components (MinIO, Prometheus CRDs):
Deploy the Hiero network:
Set up the Consensus Nodes:
Point the Consensus Nodes at your Block Node (before starting them):
Replace
<BN_IP>with the external IP or hostname of your Block Node and<PORT>with the gRPC port (default40840):Start the Consensus Nodes:
Once the CNs are running, run a quick sanity check to confirm the Block Node is receiving blocks:
The firstAvailableBlock and lastAvailableBlock fields should start advancing from their initial sentinel value (18446744073709551615) once blocks arrive. For instructions on downloading the protobuf bundle into ~/bn-proto, see Testing a Deployed Block Node Using the Simulator in the prerequisite grpcurl setup section.
Step 3: Run Load Tests with NLG
rapid-fire load start deploys the Network Load Generator (NLG) Helm chart into the Solo cluster and runs a named test class against the CNs. NLG transactions flow through the CNs, which produce blocks that are streamed to your Block Node.
For a comprehensive reference on NLG configuration options, available test classes, and examples, see Using Network Load Generator with Solo.
The NLG arguments (--args) must be wrapped in two layers of quotes: the outer single quotes are for the shell, the inner double quotes are for the NLG parser.
Run a Crypto Transfer load test (a good baseline test):
Key NLG arguments:
-c
Number of concurrent clients
-a
Number of accounts to create before the test
-t
Duration of the test in seconds
Available test classes:
CryptoTransferLoadTest
HBAR transfers (good general-purpose baseline)
TokenTransferLoadTest
Fungible token transfers
NftTransferLoadTest
NFT transfers
HCSLoadTest
Hedera Consensus Service message submissions
SmartContractLoadTest
Smart contract calls
LongevityLoadTest
Extended endurance run
The command prints a summary when the test finishes, for example:
A zero-tps result means NLG could not submit transactions — check the Troubleshooting section below.
To stop a running test early:
Step 4: Monitor Block Node Performance
While the load test runs, watch the Block Node to verify it is keeping up with the incoming stream.
Check ingestion and verification via Prometheus metrics (primary check):
verification_blocks_verified
Count of blocks verified and persisted; should grow
verification_blocks_failed
Verification failures — investigate immediately if > 0
verification_blocks_error
Internal errors during verification — should stay at 0
Block ingest rate
Should track CN output rate; drops indicate lag
Subscriber backlog
High values indicate the BN is falling behind
Storage write latency
Spikes may indicate I/O saturation
Because the Block Node only persists blocks that pass verification, an advancing lastAvailableBlock confirms both ingestion and verification are working correctly.
For the full metrics reference, see configuration.md.
Check ingestion via serverStatus (quick spot-check from outside the cluster):
Poll this every few seconds. lastAvailableBlock should increase steadily during the test.
Tail Block Node logs if metrics are unavailable:
See Troubleshooting for guidance on common error patterns.
Step 5: Tear Down the Test Cluster
Once you are done testing, remove the NLG and the Solo test cluster. This does not affect your Block Node — it only removes the temporary CN infrastructure.
Firewall cleanup: If you opened inbound firewall rules to allow the Solo test cluster to reach your Block Node, close them now that the test is complete.
Remove NLG resources:
Destroy the Solo network (stops and removes all CN pods):
Delete the Kind cluster:
Step 6: Reset the Block Node
After the test, the Block Node contains test data from the Solo CNs. Before connecting to the live network (or a production BN stream for Tier 2 nodes), reset the block store to start clean.
Follow the reset procedure in Resetting and Upgrading the Block Node. For a Solo Provisioner-managed deployment, the standard path is block node reset. For a Taskfile-managed deployment, use task reset.
Troubleshooting
Solo CNs fail to start
Check that your machine has enough resources for a three-node network. Each CN requires approximately 2 CPU cores and 4 GB of RAM. If you are running on a machine with limited resources, reduce to a single CN by changing --num-consensus-nodes 1 in Step 2.
solo block node add-external fails with a connection error
Verify that <BN_IP>:<PORT> is reachable from the machine running Solo:
If the connection is refused, check that:
The Block Node pod is running (
kubectl get pods -n block-node).The Block Node service is exposing the gRPC port (
kubectl get svc -n block-node).Your cloud firewall allows inbound TCP on port
40840. See Network Ports and Protocols.
NLG reports zero-tps
This usually means NLG could not submit transactions to the CNs. Check:
CN pod logs:
kubectl logs -n $SOLO_NAMESPACE <cn-pod> --followThat the CNs are in
Runningstatus:kubectl get pods -n $SOLO_NAMESPACE
Block Node lastAvailableBlock is not advancing
The BN may not be receiving blocks, or blocks are failing verification. Check the BN logs for storage or verification errors:
Also confirm the BN has sufficient disk space — the Block Node Hardware Specifications document the minimum storage requirements for each tier.
Last updated