Skip to content

Billing: Contract + Emit Values - #2428

Merged
DylanTinianov merged 6 commits into
mainfrom
CRE-6781-emit-usage-value
Oct 6, 2026
Merged

DylanTinianov merged 6 commits into
mainfrom
CRE-6781-emit-usage-value

Conversation

@DylanTinianov

@DylanTinianov DylanTinianov commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Groundwork for capability-centric workflow billing smartcontract-it.atlassian.net/browse/CRE-6917. No behaviour change for existing producers.

What

  • ResourceManager.EmitUsageValue(ctx, identity, eventID, *big.Int, fields): METER_ACTION_USAGE from an arbitrary-precision value, so chain-write capabilities can report gas fees in wei/lamports without int64 truncation. Same event-id contract and fail-open semantics as EmitUsage.

  • resourcemanager/workflow_usage.go: the producer side of the billing contract, shared by the engine (compute) and the chain-write plugins (gas):

    • record type cre:workflow; resource types cre:workflow:compute (ms) and cre:workflow:gas:<chain_selector> (WorkflowGasResourceType)
    • Utilization.ResourceId = "<workflow_id>:<execution_id>" (WorkflowUsageResourceID, rejects : in either part)
    • emitting service names chain-write / workflow-engine; Identity.ResourcePool cre:workflow:gas / cre:workflow:compute with ResourcePoolId = fully qualified resource type (WithWorkflowUsagePool)

    Matches the consumer in billing-platform-service (#963, ConstructCapabilityUsageEventID: cre:workflow:<wf>:<exec>:<EventId>).

Usage records are gated by the existing MeterRecordsEnabled; no separate flag.

…L_CAPABILITY_USAGE_ENABLED

Groundwork for capability-centric workflow billing (CRE-6778):

- ResourceManager.EmitUsageValue emits a METER_ACTION_USAGE record from a
  *big.Int so chain-write capabilities can report gas fees in wei without
  truncation.
- resourcemanager/workflow_usage.go pins the producer side of the billing
  contract: record type cre:workflow, resource types cre:workflow:compute and
  cre:workflow:gas:<chain_selector>, ResourceId "<workflow_id>:<execution_id>",
  emitting service names and resource pool. Matches the consumer in
  billing-platform-service (ConstructCapabilityUsageEventID).
- loop.EnvConfig.CapabilityUsageEnabled (CL_CAPABILITY_USAGE_ENABLED) carries
  the new [Metering].CapabilityUsageEnabled node setting to LOOP capability
  plugins, independent of MeterRecordsEnabled.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

✅ API Diff Results - github.com/smartcontractkit/chainlink-common

✅ Compatible Changes (11)

pkg/resourcemanager (10)
  • EmittingServiceChainWrite — ➕ Added

  • EmittingServiceWorkflowEngine — ➕ Added

  • ResourceTypeWorkflowCompute — ➕ Added

  • ResourceTypeWorkflowGasPrefix — ➕ Added

  • WithWorkflowUsagePool — ➕ Added

  • WorkflowComputeResourcePool — ➕ Added

  • WorkflowGasResourcePool — ➕ Added

  • WorkflowGasResourceType — ➕ Added

  • WorkflowRecordType — ➕ Added

  • WorkflowUsageResourceID — ➕ Added

pkg/resourcemanager.(*ResourceManager) (1)
  • EmitUsageValue — ➕ Added

📄 View full apidiff report

@DylanTinianov DylanTinianov changed the title resourcemanager: EmitUsageValue, workflow usage contract, CL_CAPABILITY_USAGE_ENABLED (CRE-6778) Billing: Emit resource manager values Sep 29, 2026
@DylanTinianov
DylanTinianov requested a balanced review from Copilot September 29, 2026 18:40

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Capability usage remains blocked by MeterRecordsEnabled, contradicting the new setting’s documented independence.

Review effort: Balanced
Findings: 1 High severity

Open (1)
What changed in this PR

Adds workflow capability billing primitives and propagates capability usage configuration to LOOP plugins.

Changes:

  • Adds arbitrary-precision usage emission.
  • Defines workflow compute/gas billing identifiers.
  • Adds CL_CAPABILITY_USAGE_ENABLED configuration transport.
File Description
pkg/​resourcemanager/​workflow_usage.go Defines workflow billing identifiers and helpers.
pkg/​resourcemanager/​workflow_usage_test.go Tests workflow billing helpers.
pkg/​resourcemanager/​resourcemanager.go Adds arbitrary-precision usage emission.
pkg/​resourcemanager/​resourcemanager_test.go Tests large and nil usage values.
pkg/​loop/​config.go Adds capability usage configuration.
pkg/​loop/​config_test.go Tests configuration parsing and propagation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pkg/loop/config.go Outdated
@DylanTinianov
DylanTinianov marked this pull request as ready for review October 5, 2026 18:35
@DylanTinianov
DylanTinianov requested a review from a team as a code owner October 5, 2026 18:35
…y by CapabilityUsageEnabled

Review follow-up. ResourceManager drops every emit when its own
MeterRecordsEnabled is false, so a usage manager built from MeteringConfig
would be silently gated by the durable-metering flag. CapabilityUsageConfig
returns a Config for a dedicated usage ResourceManager: records enabled iff
CapabilityUsageEnabled, snapshots off, same emitter and deployment identity.
Producers run that manager next to the durable one, so the two settings
never share a gate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@DylanTinianov
DylanTinianov requested review from patrickhuie19 and a balanced review from Copilot October 5, 2026 18:41
@DylanTinianov DylanTinianov self-assigned this Oct 5, 2026

Copilot AI 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.

Copilot review overview

🟢 Approval recommended

The billing primitives, independent configuration gate, and associated boundary cases are consistently implemented and tested.

Review effort: Balanced
Findings: None

Resolved since last review (1)

…d contract

Identity.ResourcePool / ResourcePoolID follow the Billing <-> Decentralized
stack contract: pool "cre:workflow:gas" with pool id
"cre:workflow:gas:<chain_selector>" for gas, "cre:workflow:compute" for
both on compute. WithWorkflowUsagePool derives them from the resource type
so producers cannot drift. Replaces the single "workflow_usage" pool.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@DylanTinianov DylanTinianov changed the title Billing: Emit resource manager values Billing: Contract + Emit Values Oct 6, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment thread pkg/loop/config.go Outdated
Comment thread pkg/resourcemanager/resourcemanager.go
// WorkflowGasResourceType returns the gas resource type for a chain selector,
// e.g. "cre:workflow:gas:421614".
func WorkflowGasResourceType(chainSelector uint64) string {
return ResourceTypeWorkflowGasPrefix + strconv.FormatUint(chainSelector, 10)

@patrickhuie19 patrickhuie19 Oct 6, 2026 •

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Matches that section: ResourcePool is cre:workflow:gas / cre:workflow:compute, ResourcePoolId is the fully qualified resource type, ResourceId is <wf>:<exec>.

…abled

Per review, capability usage records (compute, gas) do not need their own
gate. The existing MeterRecordsEnabled / MeterSnapshotsEnabled knobs already
control emission per node and are sufficient for local-cre tuning, so
producers reuse EnvConfig.MeteringConfig for the usage ResourceManager.

Removes CL_CAPABILITY_USAGE_ENABLED, EnvConfig.CapabilityUsageEnabled and
EnvConfig.CapabilityUsageConfig with their tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
// EmitUsageValue is EmitUsage for quantities that do not fit an int64, such as a
// transaction fee in wei. A nil value emits "0". Same event_id contract and
// fail-open semantics as EmitUsage.
func (rm *ResourceManager) EmitUsageValue(ctx context.Context, identity ResourceIdentity, eventID string, value *big.Int, fields UtilizationFields) {

@patrickhuie19 patrickhuie19 Oct 6, 2026 •

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.

one note is that I'm not sure how the *big.Int will go across the wire in the message payload. it will need to be serialized to string, we should double check that the emitRecord call will handle this properly. we use a cloudEvent packaging, which I believe wraps OTEL

// WorkflowUsageResourceID returns the Utilization.ResourceId for a workflow
// execution: "<workflow_id>:<execution_id>". Neither component may be empty or
// contain ':', since the consumer splits on the first ':'.
func WorkflowUsageResourceID(workflowID, executionID string) (string, error) {

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.

nit: is this shared with any other components? maybe deserves its own file or even a "utils" package?

Merged via the queue into main with commit 2959452 Oct 6, 2026
37 checks passed
@DylanTinianov
DylanTinianov deleted the CRE-6781-emit-usage-value branch October 6, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants