PR for java-tron Issue #6590 | Penn Blockchain Conference Hackathon 2026 — TRON Bounty 2
Implements Prometheus metrics for empty block detection and SR set change monitoring, addressing critical operational blind spots in java-tron's monitoring infrastructure.
| Metric Name | Type | Labels | Description |
|---|---|---|---|
tron:block_transaction_count |
Histogram | miner |
Distribution of transaction counts per block |
tron:sr_set_change_total |
Counter | witness, change_type |
SR set changes (added/removed) |
Query empty blocks using the histogram's le="0.0" bucket:
# Empty blocks count by miner
tron:block_transaction_count_bucket{le="0.0"}
# Empty block ratio
rate(tron:block_transaction_count_bucket{le="0.0"}[1h]) / rate(tron:block_transaction_count_count[1h])
[0, 10, 50, 100, 200, 500, 1000, 2000, 5000, 10000]
| Label | Value | Description |
|---|---|---|
change_type |
added |
A new SR entered the active set |
change_type |
removed |
An existing SR left the active set |
witness |
base58 address | The SR address affected |
In your node's config.conf:
node {
metricsPrometheusEnable = true
}Or via CLI flag:
java -jar FullNode.jar --metrics-prometheus-enableWhen enabled, metrics are available at:
http://localhost:9527/metrics
Add to your prometheus.yml:
scrape_configs:
- job_name: 'tron-node'
static_configs:
- targets: ['localhost:9527']
metrics_path: '/metrics'rate(tron:block_transaction_count_bucket{le="0.0"}[1m])
rate(tron:block_transaction_count_bucket{le="0.0"}[1h]) / rate(tron:block_transaction_count_count[1h])
tron:block_transaction_count_bucket{le="0.0"}
# Blocks with 0-10 transactions
tron:block_transaction_count_bucket{le="10"} - tron:block_transaction_count_bucket{le="0"}
# Average transactions per block
rate(tron:block_transaction_count_sum[5m]) / rate(tron:block_transaction_count_count[5m])
rate(tron:sr_set_change_total[5m])
# Added
sum by (change_type) (tron:sr_set_change_total{change_type="added"})
# Removed
sum by (change_type) (tron:sr_set_change_total{change_type="removed"})
rate(tron:block_transaction_count_bucket{le="0.0"}[5m]) > 10
increase(tron:sr_set_change_total[1h]) > 0
| File | Change |
|---|---|
common/src/main/java/org/tron/common/prometheus/MetricKeys.java |
Removed BLOCK_EMPTY, added BLOCK_TRANSACTION_COUNT histogram constant |
common/src/main/java/org/tron/common/prometheus/MetricsCounter.java |
Removed BLOCK_EMPTY counter registration |
common/src/main/java/org/tron/common/prometheus/MetricsHistogram.java |
Added overloaded init() for custom buckets, registered BLOCK_TRANSACTION_COUNT |
framework/src/main/java/org/tron/core/metrics/blockchain/BlockChainMetricManager.java |
Replaced counter with histogramObserve() for all blocks, kept SR counter |
framework/src/test/java/org/tron/core/metrics/prometheus/PrometheusApiServiceTest.java |
Updated tests for histogram bucket queries |
# Build without tests (fast)
./gradlew clean build -x test
# Compile modified source
./gradlew :framework:compileJava :common:compileJava
# Run Prometheus metric tests only
./gradlew :framework:test --tests \
"org.tron.core.metrics.prometheus.PrometheusApiServiceTest"
# Run all metrics tests
./gradlew :framework:test --tests "org.tron.core.metrics.*"
# Full test suite
./gradlew test
# Coverage report
./gradlew :framework:jacocoTestReport
# Report: framework/build/reports/jacoco/test/html/index.htmlRecords transaction count for all blocks (including empty blocks):
int txCount = block.getTransactions().size();
Metrics.histogramObserve(MetricKeys.Histogram.BLOCK_TRANSACTION_COUNT, txCount,
StringUtil.encode58Check(address));Benefits over simple counter:
- Rich insights: Tracks full distribution of tx counts
- Flexible queries: Percentiles, trends, specific ranges
- Empty block detection: Via
le="0.0"bucket
List<ByteString> currentSrList =
chainBaseManager.getWitnessScheduleStore().getActiveWitnesses();
Set<String> currentSrSet = currentSrList.stream()
.map(bs -> Hex.toHexString(bs.toByteArray()))
.collect(Collectors.toSet());
if (!previousSrSet.isEmpty() && !currentSrSet.equals(previousSrSet)) {
for (String sr : Sets.difference(currentSrSet, previousSrSet)) {
Metrics.counterInc(MetricKeys.Counter.SR_SET_CHANGE, 1,
sr, MetricLabels.Counter.SR_ADDED);
}
for (String sr : Sets.difference(previousSrSet, currentSrSet)) {
Metrics.counterInc(MetricKeys.Counter.SR_SET_CHANGE, 1,
sr, MetricLabels.Counter.SR_REMOVED);
}
}
previousSrSet = currentSrSet;- Purely additive — zero protocol changes, zero API changes, zero backward compatibility issues
- Uses existing
Metrics.histogramObserve()pattern for histogram - Uses existing
Metrics.counterInc()pattern for counter - All constants defined in
MetricKeys.java(no hardcoded strings) - Java 8 compatible
- No new Gradle dependencies
The histogram approach (as suggested by Sunny6889) provides richer insights:
| Approach | Pros |
|---|---|
| Counter | Simple, single-purpose |
| Histogram | Tracks distribution, enables ratio queries, supports percentiles |
Example queries enabled by histogram:
- Empty block ratio over any time window
- Transaction distribution patterns
- Block capacity utilization
- java-tron #6590 — Prometheus metrics for empty blocks and SR changes