Preparing for WRB Cutover
This guide walks a Tier 1 Block Node operator through the steps required to prepare a deployed Block Node for the WRB (Wrapped Record Block) streaming cutover, including pre-upgrade checks that apply to every upgrade and the additional steps specific to the WRB cutover release.
It assumes the Block Node is installed using the Solo Provisioner, either on a bare-metal server (see Bare Metal Single Node Kubernetes Deployment) or a GCP VM (see Virtual Machine Single Node Kubernetes Deployment).
The steps are organized in two sections. The common pre-upgrade checks apply before every upgrade, regardless of release. The release-specific checks contain the additional steps the WRB cutover requires; future network releases will appear as additional subsections without changing the common section.
Common pre-upgrade checks
Complete all steps in this section before every upgrade, regardless of release.
Confirm Block Node health
Before upgrading, confirm the Block Node is healthy. Do not upgrade an unhealthy node — an in-progress failure becomes a stuck rollout.
List all pods and confirm the Block Node pod is
Runningwith all containers ready:kubectl get pods -A kubectl -n block-node get pods,sts,svcExpected: the
block-node-block-node-server-0pod shows1/1ready andRunning.If the pod shows
CrashLoopBackOff,ImagePullBackOff, or0/1ready: investigate withkubectl -n block-node logs <BN_POD>andkubectl -n block-node describe pod <BN_POD>before proceeding.
Record the current block range so you can confirm it does not regress after the upgrade. Retrieve the pod name first:
BN_POD=$(kubectl -n block-node get pod \ -l app.kubernetes.io/name=block-node \ -o jsonpath='{.items[0].metadata.name}')Then call
serverStatus:grpcurl -plaintext -emit-defaults \ -import-path ~/bn-proto \ -proto block-node/api/node_service.proto \ -d '{}' \ "$BLOCK_NODE_HOST:40840" \ org.hiero.block.api.BlockNodeService/serverStatusRecord
firstAvailableBlockandlastAvailableBlock. Both should be sensible block numbers — not18446744073709551615(the sentinel for "no blocks yet") — if the Block Node has been ingesting. For instructions on downloading the protobuf bundle into~/bn-proto, see Connecting a Mirror Node to a Block Node.Confirm Alloy telemetry is shipping (if configured):
kubectl -n grafana-alloy get podsAll Alloy pods should be
Running. A non-running Alloy pod is not a blocker for the upgrade but should be investigated afterwards.
Validate hardware readiness
Run the Solo Provisioner hardware preflight check before the upgrade. This validates CPU core count, RAM, disk, OS version, and network-connectivity requirements for the target profile.
Expected: each step shows a green checkmark (✅) and "success".
If a step fails: it reports the specific requirement not met. For hardware minimums, see Block Node Hardware Specifications. The preflight counts physical CPU cores, not vCPUs.
Note: The
--profile=mainnetflag is required. Omitting it returnsprofile flag is required.
Validate required directories and free space
The Block Node uses five persistent volumes. Confirm each is mounted and has adequate free space before upgrading. The solo-provisioner block node check preflight validates storage requirements for the configured profile.
live
blockNode.persistence.live.mountPath (default /opt/hiero/block-node/data/live)
6 TB
Recent block stream and live state
archive
blockNode.persistence.archive.mountPath (default /opt/hiero/block-node/data/historic)
90 TB
Compressed historic block archive
verification
blockNode.persistence.verification.mountPath (default /opt/hiero/block-node/verification)
50 GB
Block hash state and verification data
logging
blockNode.persistence.logging.mountPath (default /opt/hiero/block-node/logs)
100 GB
Application logs
plugins
blockNode.persistence.plugins
—
Plugin JARs; always mounted but may contain no JARs until plugins are explicitly loaded
Note: The exact mount paths depend on your Helm values. Run
helm -n block-node get values <release-name>to inspect your installation's overrides.Note: In the next Block Node version,
blockNode.persistence.verification.mountPathwill be replaced byblockNode.persistence.applicationState.mountPath. Check the Helm chart release notes for your target version before running volume-size checks.
Confirm all volumes are mounted and visible inside the pod:
Expected: each path reports a filesystem with non-zero size and adequate free space.
If any path is missing: the volume is not mounted. Run
kubectl -n block-node describe pod $BN_PODand look for mount errors.
Confirm provisioner version
Upgrade Solo Provisioner to the latest release before upgrading the Block Node. Your Hashgraph PoC will confirm the supported provisioner version for the cohort.
Check the installed version:
Expected output (version varies by release):
If the version is behind the target, upgrade:
The install script downloads the latest GA release for your architecture, verifies the SHA256 checksum, and replaces the existing binary.
Back up operator-side artifacts
Before the upgrade, confirm you have current copies of the following files stored off the BN host. These cannot be reproduced from upstream if the host is lost.
block-node-values.yaml
/etc/solo-provisioner/block-node-values.yaml
Cohort-specific Helm overlay generated once at handoff
rsa-bootstrap-roster.json
Default: /opt/hiero/block-node/node/rsa-bootstrap-roster.json (configurable via app.state.rsaBootstrapFilePath)
RSA public-key roster for WRB proof verification; only needed when not using Mirror Node auto-fetch for the roster
Release-specific checks
Complete the subsection below that matches the upgrade you are preparing for. Future releases will appear here as additional subsections. If no matching subsection exists for your target release, only the common checks above are required.
WRB streaming cutover prep
Applies to: the Consensus Node release that activates Wrapped Record Block (WRB) streaming — currently scheduled for CN release 0.75.0. The exact release may change if release testing surfaces a blocker; your Hashgraph PoC will confirm the target release before the maintenance window.
For the full network cutover timeline — phases, CN-side WRB catch-up, TSS ceremony, and Jumpstart Data — see Cutover Process and Timeline.
What is changing: from the cutover release onwards, Consensus Nodes begin producing Wrapped Recordfile Blocks with aggregated RSA signature Block Proofs. The production of Record files uploaded to S3 storage will continue until the cutover to TSS and Block Streams in a later release. Any preview blocks stored by the Block Node before the cutover are invalid and must be discarded before the BN can receive and store authoritative WRB history. Do not skip the reset step even if the BN appears to be functioning normally.
Note: Before beginning the WRB cutover steps, confirm that the Consensus Nodes peered with this Block Node are no longer streaming preview blocks. Ingesting blocks from a CN that is still in preview mode will store invalid data that requires another reset to clear.
Complete the common pre-upgrade checks first, then continue here.
Clear the block store (preview-blocks reset)
Caution: This operation is destructive and cannot be undone. It scales the StatefulSet to 0, clears all files from the
live,archive,verification, andloggingstorage directories, then scales back up to 1. All block data on this node is lost. Do not run this step until your Hashgraph PoC has confirmed the maintenance window is open and your off-host artifact backups are current.
Expected output:
Wait until the pod reaches 1/1 Running, then confirm the store is empty:
Expected immediately after reset:
Both values at
18446744073709551615confirm the store is empty and the Block Node is ready to backfill.
If the reset fails, run the following to diagnose the issue and share the output with your Hashgraph PoC:
Provision the RSA bootstrap roster
The roster-bootstrap-rsa plugin must be included in your Block Node's plugin list and have the RSA public-key roster available at startup to verify SignedRecordFileProof items in incoming WRBs.
Enable the plugin
Add roster-bootstrap-rsa to your plugin list in block-node-values.yaml. Append it to your existing plugins.names value — the example below shows the full plugin list used for LFH nodes on previewnet, provided for reference:
Mirror Node auto-fetch (mainnet cohort default)
When ROSTER_BOOTSTRAP_RSA_MIRROR_NODE_BASE_URL is set in your block-node-values.yaml, the plugin fetches the roster from the Mirror Node REST API at startup and caches it locally. After block node reset, the cached copy is cleared along with the rest of the storage directories and is automatically re-fetched on the next pod start — no manual intervention is needed. Before the cutover window, confirm outbound connectivity to the Mirror Node is available from the BN host.
Set the URL in your Helm values overlay:
Mirror Node base URLs by network:
Mainnet
https://mainnet-public.mirrornode.hedera.com
Testnet
https://testnet.mirrornode.hedera.com
Previewnet
https://previewnet.mirrornode.hedera.com
Note: If the Mirror Node is unreachable, the plugin polls indefinitely — every 5 seconds until the first roster is fetched, then every 60 seconds for periodic refresh. Both intervals are configurable. WRB proof verification is non-functional until the roster is available.
Peer Block Node query
All Tier 1 Block Nodes should have at least one peer Block Node source configured; more than one is recommended for redundancy. When roster.bootstrap.rsa.blockNodeSourcesPath is set, the plugin queries configured peer Block Nodes via gRPC to retrieve the roster. This runs concurrently with the Mirror Node query; whichever responds first provides the initial roster. The peer BN query follows the same two-phase polling schedule (5-second initial interval, 60-second subsequent interval, both configurable).
This is the same file referenced by BACKFILL_BLOCK_NODE_SOURCES_PATH — configuring it once serves both the roster-bootstrap-rsa plugin and the backfill plugin. Set the path in your Helm values overlay:
The file format is a JSON object with a nodes array:
Configure this file via your Helm chart's ConfigMap or values override mechanism. Use the endpoints provided by your Hashgraph PoC.
Manual file (alternative)
If ROSTER_BOOTSTRAP_RSA_MIRROR_NODE_BASE_URL is not configured, the plugin reads the roster from app.state.rsaBootstrapFilePath (default: /opt/hiero/block-node/node/rsa-bootstrap-roster.json). The file is delivered as part of the cohort package by your Hashgraph PoC. After block node reset, confirm the file is still present and non-empty:
If the file is missing after reset: re-deliver it from your off-host backup using the mechanism in your cohort's
block-node-values.yaml.
In either case, confirm the roster loaded cleanly after the pod starts by querying serverStatusDetail — the response should contain a non-empty rosterHash field:
Expected: the response includes a non-empty
rosterHashfield, confirming the RSA roster is loaded and active.
Configure backfill sources (if required)
After the block store reset, the BN backfills WRB history automatically as long as other Block Nodes on the network already hold the relevant block range. All Tier 1 operators should have at least one Block Node source configured for both backfill and peer roster queries. Most operators do not need to manually configure a specific backfill source — once peer Block Nodes are advertising history on the network, the backfill plugin discovers them through the normal backfill path.
Enable greedy backfill
Hashgraph recommends enabling greedy backfill on all Tier 1 Block Nodes for the WRB cutover. With greedy backfill enabled, the BN proactively retrieves blocks beyond the latest acknowledged block, preventing the node from falling too far behind during the initial catch-up period.
In your Helm values overlay, set BACKFILL_GREEDY to "true", apply the change, and confirm:
Expected:
BACKFILL_GREEDY: "true"
Edge case — bootstrapping from genesis when no public BN holds the history yet:
During the initial mainnet WRB cutover, the wrapped record block history may not yet be available from public Block Nodes. In this case, a special-purpose Block Node holding the offline-wrapped WRBs serves as a temporary backfill source. Operators who need access to this node will receive the endpoint and connection details through a separate operator communication channel — it is not published in this document.
If you are directed by your Hashgraph PoC to configure a specific backfill source:
Update your Helm values overlay with the backfill source path,
BLOCK_NODE_EARLIEST_MANAGED_BLOCKset to"0"(so the BN manages from genesis), astartBlockof"0", and afetchBatchSizeof"100"for faster throughput. Apply the change:The
block-node-sources.jsonfile format is a JSON object with anodesarray. Configure the file via your Helm chart's ConfigMap or values override mechanism. Use the hostname and port provided by your Hashgraph PoC:Note: Even when backfilling from a special-purpose BN, all blocks are cryptographically verified by the BN's verification plugin before they are stored. Block legitimacy is confirmed regardless of the backfill source.
Monitor backfill progress by querying
serverStatus—lastAvailableBlockshould increase steadily as blocks are fetched and verified:Full backfill of current network history takes one to several weeks; the BN does not need to complete backfill before the cutover release, but it must be active and making progress.
Verify readiness
After completing all applicable checks, confirm the BN is ready before the maintenance window opens.
Pod is running
kubectl -n block-node get pods
1/1 Running
Hardware preflight passes
sudo solo-provisioner block node check --profile=mainnet
All steps green
Block store cleared (WRB only)
grpcurl ... BlockNodeService/serverStatus
firstAvailableBlock = uint64_max
RSA roster loaded (WRB only)
grpcurl ... BlockNodeService/serverStatusDetail
Non-empty rosterHash in response
Greedy backfill enabled (WRB only)
helm -n block-node get values <release-name> | grep BACKFILL_GREEDY
BACKFILL_GREEDY: "true"
Backfill active (WRB only, if configured)
kubectl -n block-node logs $BN_POD -c block-node-server | grep -i backfill
Fetching or completed (if BACKFILL_BLOCK_NODE_SOURCES_PATH is set)
Alloy shipping
kubectl -n grafana-alloy get pods
1/1 Running
If any check fails, resolve the issue and confirm readiness with your Hashgraph PoC before the maintenance window opens.
Troubleshooting
solo-provisioner block node check fails with "CPU does not meet requirements"
VM has fewer physical cores than the profile minimum
See Block Node Hardware Specifications. The check counts physical cores, not vCPUs.
solo-provisioner block node check fails with "profile flag is required"
--profile flag missing
Always pass --profile=mainnet.
block node reset exits with "permission denied"
Command run without sudo
Prefix with sudo.
Pod stuck in 0/1 or init containers running after reset
Init containers setting up storage and resolving plugins
Allow 2-5 minutes. Run kubectl -n block-node describe pod $BN_POD to see init-container status.
RSA roster missing or not loaded after reset
Mirror Node unreachable, or file missing (file-based delivery)
If using Mirror Node auto-fetch, confirm ROSTER_BOOTSTRAP_RSA_MIRROR_NODE_BASE_URL is set and the Mirror Node is reachable — the roster is re-fetched automatically on pod start. If using file-based delivery, re-deliver from off-host backup.
Backfill not starting
backfill.blockNodeSourcesPath is blank or points to a missing file
Confirm BACKFILL_BLOCK_NODE_SOURCES_PATH is set and the referenced JSON file exists in the pod.
firstAvailableBlock still shows old block numbers after reset
Reset did not complete successfully
Check sudo head /opt/solo/weaver/logs/solo-provisioner.log for the step that failed.
grpcurl returns connection refused on port 40840
Block Node is not yet listening
Wait for the pod to reach 1/1 Running; confirm server.port in the Block Node configuration.
For issues not covered here, see Block Node Troubleshooting. When opening a support ticket, attach:
Last updated