Skip to content

Add metric to track the Flow total supply on each block - #949

Merged
m-Peter merged 3 commits into
mainfrom
mpeter/add-total-supply-metric
Jan 13, 2026
Merged

Add metric to track the Flow total supply on each block#949
m-Peter merged 3 commits into
mainfrom
mpeter/add-total-supply-metric

Conversation

@m-Peter

@m-Peter m-Peter commented Jan 9, 2026

Copy link
Copy Markdown
Collaborator

Closes: #947

Description

Tracking this field from the EVM.BlockExecuted event payload, can be useful and will allow us to create alerts for abnormal fluctuations on the totalSupply value.


For contributor use:

  • Targeted PR against master branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the standards mentioned here.
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

Summary by CodeRabbit

  • New Features
    • Added a new total-supply metric for FLOW tokens and exposed it in the metrics set.
    • The metric is automatically collected during block/event processing and published alongside existing metrics for improved supply visibility.
  • Chore
    • No-op collector updated to include the new metric method so collectors remain consistent.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 9, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a Prometheus gauge flow_total_supply, exposes FlowTotalSupply(*big.Int) on the Collector interface and implementations, and emits this metric from the ingestion engine when processing EVM block events.

Changes

Cohort / File(s) Summary
Collector interface & DefaultCollector
metrics/collector.go
Add FlowTotalSupply(totalSupply *big.Int) to Collector; introduce flowTotalSupply prometheus.Gauge and logger zerolog.Logger fields on DefaultCollector; register flow_total_supply gauge in the metrics set; implement method converting *big.Intfloat64, warn on precision loss, and set gauge.
No-op collector
metrics/nop.go
Add FlowTotalSupply(totalSupply *big.Int) no-op implementation and import math/big.
Ingestion metric emission
services/ingestion/engine.go
Emit FlowTotalSupply from processEvents after EVMHeightIndexed using totalSupply from the EVM block payload.

Sequence Diagram(s)

sequenceDiagram
    participant Ingest as Ingestion Engine
    participant Collector as Collector (interface)
    participant Default as DefaultCollector
    participant Prom as Prometheus

    Ingest->>Collector: FlowTotalSupply(totalSupply *big.Int)
    Collector->>Default: FlowTotalSupply(totalSupply)
    Default->>Default: convert big.Int -> float64 (check precision)
    Default-->>Prom: Set gauge `flow_total_supply` value
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

Suggested reviewers

  • zhangchiqing
  • peterargue
  • janezpodhostnik

Poem

🐰
I hopped through code with metrics bright,
Big ints counted in the pale moonlight,
A gauge now sings of supply so true,
Prometheus listens, carrots in view,
Hooray for metrics — hops and bytes!

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a metric to track Flow total supply on each block, which directly aligns with the PR objectives and code changes.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #947: extracts totalSupply from EVM.BlockExecuted events, records metrics via FlowTotalSupply method, and enables monitoring through Prometheus gauge.
Out of Scope Changes check ✅ Passed All changes are in-scope and directly support the metric tracking objective: Collector interface/implementation extensions, nopCollector stub, and metric emission in ingestion engine.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @metrics/collector.go:
- Around line 259-262: In DefaultCollector.FlowTotalSupply, add a nil check for
the totalSupply parameter to avoid panics and replace the blind
totalSupply.Float64() call with a safe conversion that checks the returned
Accuracy and handles overflow/precision loss: convert the *big.Int to a
big.Float (e.g., big.NewFloat(0).SetInt(totalSupply)), call bigFloat.Float64()
and inspect the accuracy (big.Exact/Above/Below) or detect +Inf; if nil or
conversion is inaccurate/overflowing, log or clamp to a sensible value (or skip
updating) instead of silently setting an imprecise metric when calling
c.flowTotalSupply.Set.

In @services/ingestion/engine.go:
- Line 215: The call passes events.Block().TotalSupply (a *big.Int) directly
into e.collector.FlowTotalSupply which can panic when TotalSupply is nil; add a
nil guard before calling FlowTotalSupply (e.g., check events.Block() != nil &&
events.Block().TotalSupply != nil) and only call e.collector.FlowTotalSupply
when TotalSupply is non-nil, or alternatively update metrics/collector.go's
FlowTotalSupply to defensively handle a nil *big.Int by treating it as zero or
returning early—modify either the call site in engine.go (around
e.collector.FlowTotalSupply) or the FlowTotalSupply method to handle nil inputs.
🧹 Nitpick comments (1)
metrics/collector.go (1)

90-93: Consider clarifying the help text.

The help text "Total supply of native EVM FLOW token at a given time" contains "native EVM FLOW token" which might be clearer as "FLOW tokens in EVM" or simply "EVM FLOW supply".

📝 Suggested help text improvement
 var flowTotalSupply = prometheus.NewGauge(prometheus.GaugeOpts{
 	Name: prefixedName("flow_total_supply"),
-	Help: "Total supply of native EVM FLOW token at a given time",
+	Help: "Total supply of FLOW tokens in EVM at a given time",
 })
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 576c361 and 1292926.

📒 Files selected for processing (3)
  • metrics/collector.go
  • metrics/nop.go
  • services/ingestion/engine.go
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-10-18T19:26:37.579Z
Learnt from: peterargue
Repo: onflow/flow-evm-gateway PR: 617
File: api/stream.go:62-67
Timestamp: 2024-10-18T19:26:37.579Z
Learning: In the `flow-evm-gateway` project, within the Go file `api/stream.go`, the `prepareBlockResponse` method includes the Bloom filter as the field `LogsBloom` in the returned `Block` struct.

Applied to files:

  • services/ingestion/engine.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test
🔇 Additional comments (2)
metrics/nop.go (1)

4-4: LGTM!

The no-op implementation correctly satisfies the updated Collector interface with the appropriate signature.

Also applies to: 28-28

metrics/collector.go (1)

111-111: LGTM!

The gauge is correctly registered in the metrics slice, added to the interface, included in the struct, and properly initialized in the constructor.

Also applies to: 129-129, 151-151, 176-176

Comment thread metrics/collector.go
Comment thread services/ingestion/engine.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
metrics/collector.go (1)

90-93: Clarify the unit of measurement in the help text.

The help text should specify whether flow_total_supply represents the smallest unit (similar to wei in Ethereum) or whole FLOW tokens. This clarity will help operators correctly interpret the metric values and set appropriate alert thresholds.

📝 Suggested help text improvement
 var flowTotalSupply = prometheus.NewGauge(prometheus.GaugeOpts{
 	Name: prefixedName("flow_total_supply"),
-	Help: "Total supply of FLOW tokens in EVM at a given time",
+	Help: "Total supply of FLOW tokens in EVM at a given time (in smallest unit)",
 })
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1292926 and 4f61e97.

📒 Files selected for processing (1)
  • metrics/collector.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test
🔇 Additional comments (6)
metrics/collector.go (6)

5-5: LGTM!

The math/big import is appropriate for handling large FLOW token supply values that may exceed standard integer types.


111-111: LGTM!

The flowTotalSupply metric is correctly added to the registration list.


129-129: LGTM!

The method signature correctly uses *big.Int to handle potentially large FLOW token supply values.


135-135: LGTM!

Adding the logger field to DefaultCollector enables proper logging of precision loss warnings in the FlowTotalSupply method. The initialization in NewCollector is correct.

Also applies to: 163-163


153-153: LGTM!

The flowTotalSupply field and its initialization follow the established pattern for metric collection in this codebase.

Also applies to: 179-179


262-273: Verify that float64 precision is sufficient for the expected total supply values.

The conversion from *big.Int to float64 will lose precision for values exceeding 2^53 (~9 × 10^15). If the total supply is measured in the smallest unit (similar to wei in Ethereum), values may frequently exceed this threshold, leading to:

  • Inaccurate absolute values in the metric
  • Potential issues detecting small fluctuations
  • Misleading data for alerting purposes

The nil check and precision loss warning are good defensive measures. However, consider whether:

  1. The expected magnitude of totalSupply values will fit within float64 precision
  2. Converting to a larger unit (e.g., whole FLOW tokens) before the float64 conversion would preserve sufficient precision for your alerting needs
  3. The current precision is adequate for detecting abnormal fluctuations (the stated goal in issue #947)

Could you verify the typical range of totalSupply values and confirm that float64 precision is acceptable for your monitoring and alerting requirements?

@janezpodhostnik janezpodhostnik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

One Q: whats the mechanism behind events.Block().TotalSupply how do we get that?

@m-Peter

m-Peter commented Jan 13, 2026

Copy link
Copy Markdown
Collaborator Author

Looks good.

One Q: whats the mechanism behind events.Block().TotalSupply how do we get that?

@janezpodhostnik The TotalSupply field of EVM.BlockExecuted is the total FLOW token supply on EVM side. It tracks the movement of FLOW tokens through COAs:

  • When a COA deposits FLOW from a Flow vault, the TotalSupply on EVM side will increase.
  • When a COA withdraws FLOW to a Flow vault, the TotalSupply on EVM side will decrease.

@m-Peter
m-Peter force-pushed the mpeter/add-total-supply-metric branch from 3f59858 to 603c1b6 Compare January 13, 2026 14:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
metrics/collector.go (1)

262-273: Consider adding the value to the precision loss warning for debugging.

The implementation correctly handles nil values and logs a warning when precision is lost. However, for debugging purposes, including the actual totalSupply value in the warning would help identify when/where precision loss occurs.

💡 Suggested enhancement
 	floatTotalSupply, accuracy := totalSupply.Float64()
 	if accuracy != big.Exact {
-		c.logger.Warn().Msg("precision loss when casting total supply to float")
+		c.logger.Warn().
+			Str("totalSupply", totalSupply.String()).
+			Msg("precision loss when casting total supply to float")
 	}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f61e97 and 603c1b6.

📒 Files selected for processing (3)
  • metrics/collector.go
  • metrics/nop.go
  • services/ingestion/engine.go
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-03-07T01:35:09.751Z
Learnt from: peterargue
Repo: onflow/flow-evm-gateway PR: 772
File: services/requester/keystore/key_store.go:50-62
Timestamp: 2025-03-07T01:35:09.751Z
Learning: In the flow-evm-gateway codebase, panics are acceptable in scenarios where immediate detection of critical bugs is desired during development and testing, particularly for invariant violations that should never occur in a correctly functioning system (e.g., when a key is available but locked in the keystore implementation).

Applied to files:

  • services/ingestion/engine.go
🧬 Code graph analysis (1)
services/ingestion/engine.go (2)
eth/types/types.go (1)
  • Block (457-478)
models/block.go (1)
  • Block (45-55)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test
🔇 Additional comments (4)
metrics/nop.go (1)

4-4: LGTM!

The no-op implementation correctly satisfies the Collector interface with an empty method body, and the math/big import is properly added for the *big.Int parameter type.

Also applies to: 28-28

metrics/collector.go (2)

90-93: LGTM!

The gauge is properly defined with a clear help text indicating the unit (wei). The naming convention follows the existing pattern with the prefixedName function.


129-129: LGTM!

The interface method, struct fields, and constructor initialization are all consistent with the existing patterns in the codebase. The logger is appropriately added to support the precision warning.

Also applies to: 135-136, 153-153, 163-163, 179-179

services/ingestion/engine.go (1)

210-213: LGTM!

The TotalSupply field is properly defined on the Block model as *big.Int, and the metric implementation correctly handles nil values. The metric emission is correctly placed after successful event processing and follows the existing pattern.

@m-Peter
m-Peter merged commit 8d3654a into main Jan 13, 2026
2 checks passed
@m-Peter
m-Peter deleted the mpeter/add-total-supply-metric branch January 13, 2026 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add metric to track the totalSupply when indexing EVM blocks

2 participants