Skip to content

Calibratable gas pricing for the Cadence Arch precompile #8556

Description

@janezpodhostnik

Background

The Cadence Arch precompile's gas costs are hardcoded in fvm/evm/precompiles/arch.go:39-52 (FlowBlockHeightFixedGas, ProofVerifierBaseGas, ProofVerifierGasMultiplerPerSignature, RandomSourceGas, RevertibleRandomGas). Changing any of them requires a flow-go release, which leaves no operational lever for retuning as the Cadence runtime's underlying costs evolve.

Proposal

Make the costs calibratable through the existing ExecutionEffortWeights mechanism by adding new ComputationKinds whose weight is interpreted as EVM gas per intensity rather than FVM-computation units. The precompile reads the weight inside ComputeGas; the cost still flows into the FVM via the existing meterGasUsage(res) call (fvm/evm/handler/handler.go:714-720).

New kinds (in fvm/environment/meter.go):

  • ComputationKindEVMArchFlowBlockHeight
  • ComputationKindEVMArchVerifyCOAOwnershipBase
  • ComputationKindEVMArchVerifyCOAOwnershipPerSig
  • ComputationKindEVMArchGetRandomSource
  • ComputationKindEVMArchRevertibleRandom

A banner comment documents the EVM-gas-vs-FVM-units distinction; the EVMArch* prefix flags them as a separate semantic class.

Default weights are added to MainnetExecutionEffortWeights matching today's constants (shifted by MeterExecutionInternalPrecisionBytes).

A new accessor on backends.Backend:

ComputationWeight(kind common.ComputationKind) (uint64, bool)

reads from the per-tx weights map populated by ExecutionParametersComputer.Compute (fvm/executionParameters.go:121). precompiles.ArchContract takes a closure that does the lookup, applies the precision shift, and falls back to the hardcoded constant if absent or zero. Lookups happen per-call (the handler is bound to a runtime that outlives transactions via RegisterOnSwapCallback at fvm/runtime/cadence_function_declarations.go:113).

Intensity tracking

Calibration needs per-kind invocation data. Because the precompile bypasses MeterComputation, and ExecutionState.MeterComputation is suppressed when meteringEnabled is false (fvm/storage/state/execution_state.go:224-228), the new kinds won't appear in ComputationIntensities through the existing path.

A new method is added to the meter / execution state / backend:

RecordIntensity(kind common.ComputationKind, intensity uint64)

It records the intensity unconditionally (bypassing the meteringEnabled guard) and never touches computationUsed. Each precompile's Run calls it after the work completes — proof verifier with the per-signature count, the others with intensity 1. The resulting intensities feed the existing weight-tuning pipeline.

Backward compatibility

Missing weights fall back to the current hardcoded constants, so default behavior is unchanged. On-network migration is optional via a service-account transaction following SetExecutionEffortWeightsTransaction (fvm/blueprints/fees.go:172). EVM transaction semantics don't change unless the in-state weights are explicitly updated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions