Skip to content

feat(mining): operator-configurable custom extension fields - #199

Merged
arkadianet merged 3 commits into
mainfrom
feat/configurable-extension-fields
Jul 18, 2026
Merged

feat(mining): operator-configurable custom extension fields#199
arkadianet merged 3 commits into
mainfrom
feat/configurable-extension-fields

Conversation

@arkadianet

@arkadianet arkadianet commented Jul 14, 2026

Copy link
Copy Markdown
Owner

What

Adds an opt-in, operator-configurable mechanism for a miner to inject
arbitrary optional key-value fields into every block candidate's Extension
section — the general merge-mining / commitment hook.

Ergo's candidate builder currently assembles the extension from only
protocol-defined fields (NiPoPoW interlinks, and the parameter map /
validation-settings at voting-epoch boundaries). There is no way for an
operator to add a custom field, and because the extension's Merkle root is
inside the bytes Autolykos hashes, the commitment must be present at
candidate-build time (the external miner grinds a fixed msg). This PR adds
that missing hook.

It is deliberately general, not tied to any one sidechain: any commitment
use case (a merge-mined chain, an anchoring/timestamp commitment, etc.) can
configure a field. Unknown extension keys are consensus-legal, so a candidate
carrying one is a valid Ergo block regardless of whether other nodes
understand it — this never forks the chain.

How

  • ergo-mining/extension_builder.rs
    • validate_custom_extension_fields: enforces rule 404 (value ≤
      EXTENSION_FIELD_VALUE_MAX_SIZE), a reserved-namespace guard (a custom
      key's first byte may not be 0x00 params / 0x01 interlinks / 0x02
      validation, so it can never overwrite a consensus field), and rule 405
      (no duplicate keys).
    • build_candidate_extension_fields takes a custom_fields argument,
      appends the validated fields after interlinks/epoch fields, and runs a
      final duplicate-key sweep across the whole assembled extension.
  • MiningHandle::with_extension_fields — a validating, builder-style setter
    (mirrors with_rent_config), plus an accessor; threaded through
    generate_candidate and both engine call sites.
  • Config ([mining])MiningConfig.extension_fields, validated at
    startup in MiningConfig::validate so a misconfiguration refuses to boot;
    resolve_extension_fields decodes the hex form; boot.rs wires it onto the
    handle.
[mining]
enabled = true
extension_fields = [
  { key = "ae00", value = "01<32-byte commitment>" },
]

Off by default (empty), so nodes not using it are unaffected.

Test plan

  • cargo fmt --all -- --check — clean
  • cargo clippy --workspace --all-targets --all-features -- -D warnings — clean
  • cargo build --workspace — clean
  • cargo test -p ergo-mining — 129 lib + integration tests pass, including new
    coverage: custom field appended after interlinks; validate_* rejects a
    reserved namespace / oversize value / duplicate key; config resolve +
    validate round-trips and rejections.
  • cargo test -p ergo-node --lib config:: / mining — 123 + 39 pass (config load
    • mining wiring unaffected).

Notes

  • Voting-epoch-boundary candidates still require the recomputed parameter map;
    custom fields are additive and orthogonal to that path.
  • This is the reference implementation for what an equivalent Scala-node
    feature would need — Scala's CandidateGenerator has no custom-field hook
    today, so cross-implementation merge-mining depends on a matching change
    there.

Summary by CodeRabbit

  • New Features
    • Added support for operator-configured custom extension fields in mining configuration.
    • Custom fields are included in every mined candidate alongside standard extension data.
    • Added configuration decoding and validation for field keys and values.
  • Bug Fixes
    • Invalid, reserved, oversized, or duplicate extension fields are now rejected before mining starts.
  • Tests
    • Added coverage for field resolution, ordering, collisions, and validation failures.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@arkadianet, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dda19908-a67f-428f-a1be-cae51abac94d

📥 Commits

Reviewing files that changed from the base of the PR and between 2a4748d and f9511e4.

📒 Files selected for processing (7)
  • ergo-mining/src/candidate.rs
  • ergo-mining/src/config.rs
  • ergo-mining/src/engine.rs
  • ergo-mining/src/extension_builder.rs
  • ergo-mining/src/handle.rs
  • ergo-mining/tests/engine_published_parity.rs
  • ergo-node/src/node/boot/mining.rs
📝 Walkthrough

Walkthrough

Mining configuration now accepts custom extension fields, validates and resolves them, propagates them through the mining handle and candidate-generation paths, and appends them to candidate extensions with duplicate and reserved-key checks.

Changes

Custom mining extension fields

Layer / File(s) Summary
Configuration resolution and validation
ergo-mining/src/config.rs
Adds hexadecimal custom extension-field configuration, decoding into byte pairs and validating malformed, reserved, and invalid-length inputs.
Extension validation and assembly
ergo-mining/src/extension_builder.rs
Validates custom fields, appends them after interlinks and epoch fields, and rejects duplicate keys across the complete extension list.
Mining handle and candidate wiring
ergo-mining/src/handle.rs, ergo-mining/src/candidate.rs, ergo-mining/src/engine.rs, ergo-node/src/node/boot.rs, ergo-mining/tests/engine_published_parity.rs
Stores resolved fields in MiningHandle, configures them during node boot, forwards them through candidate generation, and updates parity call sites with empty defaults.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MiningConfig
  participant NodeBoot
  participant MiningHandle
  participant CandidateBuilder
  participant ExtensionBuilder
  MiningConfig->>NodeBoot: resolve_extension_fields()
  NodeBoot->>MiningHandle: with_extension_fields(fields)
  MiningHandle->>CandidateBuilder: custom_extension_fields()
  CandidateBuilder->>ExtensionBuilder: build_candidate_extension_fields(custom_fields)
  ExtensionBuilder-->>CandidateBuilder: assembled extension fields
Loading

Possibly related PRs

  • arkadianet/ergo#88: Modifies the same mining candidate-generation wiring for live voting-target updates.
  • arkadianet/ergo#142: Extends the same generate_candidate API and engine call sites with a different candidate-generation input.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely matches the main change: operator-configurable custom extension fields for mining.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/configurable-extension-fields

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.

@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.

🧹 Nitpick comments (1)
ergo-mining/tests/engine_published_parity.rs (1)

475-475: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exercise a non-empty custom field through the engine path.

Every updated call passes &[]. Add a build_and_publish test using MiningHandle::with_extension_fields(...) and assert the published candidate contains the field. This protects the handle → engine → candidate wiring, not just the builder.

Also applies to: 813-813, 949-949, 1046-1046, 1104-1104, 1123-1123, 1292-1292, 1311-1311, 1399-1399, 1527-1527, 1559-1559

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ergo-mining/tests/engine_published_parity.rs` at line 475, Update the
engine-path tests around build_and_publish so at least one test uses
MiningHandle::with_extension_fields(...) with a non-empty custom field instead
of &[]. Assert that the published candidate contains that field, covering
handle-to-engine-to-candidate propagation while preserving the existing
empty-field cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@ergo-mining/tests/engine_published_parity.rs`:
- Line 475: Update the engine-path tests around build_and_publish so at least
one test uses MiningHandle::with_extension_fields(...) with a non-empty custom
field instead of &[]. Assert that the published candidate contains that field,
covering handle-to-engine-to-candidate propagation while preserving the existing
empty-field cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3a604d34-7673-48fc-8019-b1e5d774376f

📥 Commits

Reviewing files that changed from the base of the PR and between e4bc154 and 2a4748d.

📒 Files selected for processing (7)
  • ergo-mining/src/candidate.rs
  • ergo-mining/src/config.rs
  • ergo-mining/src/engine.rs
  • ergo-mining/src/extension_builder.rs
  • ergo-mining/src/handle.rs
  • ergo-mining/tests/engine_published_parity.rs
  • ergo-node/src/node/boot.rs

A general, opt-in mechanism for a miner to inject arbitrary optional
extension key-values into every block candidate — the merge-mining /
commitment hook (e.g. an Aegis 0xAE00 block commitment). Deliberately
general, not sidechain-specific: this is the reference for what the
Scala node would need, since Scala's CandidateGenerator has no such hook.

- extension_builder: validate_custom_extension_fields enforces rule 404
  (value <= 64B), a reserved-namespace guard (first key byte not in
  {0x00 params, 0x01 interlinks, 0x02 validation}), and rule 405 (no
  dup keys); build_candidate_extension_fields appends validated custom
  fields after interlinks/epoch and does a final all-field dup sweep.
- MiningHandle::with_extension_fields (validating, builder-style like
  with_rent_config) + accessor; threaded through generate_candidate and
  both engine call sites.
- Unknown extension keys are consensus-legal, so this never forks Ergo.

fmt + clippy -D clean; ergo-mining 127 lib + integration tests green.
Operator-facing config for the custom-extension-field mechanism, so it
is configurable via ergo-node.toml (not just the Rust builder):

  [mining]
  extension_fields = [ { key = "ae00", value = "01<32-byte aegis id>" } ]

- MiningConfig.extension_fields (Vec<CustomExtensionField> of hex
  key/value), validated in MiningConfig::validate at startup (hex-
  decodable, 2-byte key, then the consensus checks via
  validate_custom_extension_fields) so a misconfig refuses to boot.
- resolve_extension_fields() decodes to (key, value) byte pairs.
- boot wires them onto the handle via .with_extension_fields(...)?.

ergo-mining: fmt + clippy -D clean, 129 lib + integration tests green.

Note: ergo-node lib does not build on this local checkout due to a
PRE-EXISTING ApiNodeEvent field mismatch (snapshot_emit.rs vs
ergo-api::types) reproducible on pristine main and unrelated to this
change; the full ergo-node gate needs a consistent main base.
…propagation

Adds an engine-path test that configures a non-empty custom field via
MiningHandle::with_extension_fields, runs build_and_publish, and proves
the published candidate carries it: the served work msg commits to the
extension_root, so it must equal the on-loop oracle built WITH the same
field (whose candidate is asserted to contain it directly) and differ
from a no-field build. New on_loop_build_with_fields helper; existing
empty-field on_loop_build cases unchanged.
@arkadianet
arkadianet force-pushed the feat/configurable-extension-fields branch from aa8b017 to f9511e4 Compare July 18, 2026 22:05
@arkadianet
arkadianet merged commit f147a5c into main Jul 18, 2026
9 checks passed
@arkadianet
arkadianet deleted the feat/configurable-extension-fields branch July 18, 2026 22:22
@arkadianet arkadianet mentioned this pull request Jul 18, 2026
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.

1 participant