Skip to content

fix: wrong XMR blocks#7688

Merged
brianp merged 3 commits intotari-project:developmentfrom
martinserts:merge-miner-xmr-fix
Feb 27, 2026
Merged

fix: wrong XMR blocks#7688
brianp merged 3 commits intotari-project:developmentfrom
martinserts:merge-miner-xmr-fix

Conversation

@martinserts
Copy link
Contributor

@martinserts martinserts commented Feb 27, 2026

Description

This PR addresses the sporadic Monero block rejections ("spend too much money" and "incorrect miner transaction") and resolves a memory leak in the merge mining proxy.

  1. Intercepts block template requests from the miner and forces the upstream Monero node to pre-allocate the exact byte size required for the Tari merge mining data. This ensures the Monero node correctly calculates any block weight penalties and adjusts the block reward before the template is sent to the proxy.

  2. Shifts the reserved space offset reported back to the miner by the exact size of the injected Tari data. This prevents the miner's software from overwriting the Tari payload or corrupting the coinbase transaction.

  3. Detaches the block template memory cleanup process from the block submission workflow. Stale templates are now pruned via an independent background interval, preventing memory leaks when miners request templates but fail to submit solutions.

Closes #7045

Motivation and Context

When the proxy facilitates merge mining, it injects 35 bytes of Tari-specific data into the Monero block's coinbase tx_extra field.

Historically, this injection happened after monerod generated the template. As a result, the final mined block was physically heavier than monerod originally predicted. If the Monero network was under load and the block was near the median weight limit, this hidden extra weight would trigger Monero's native weight penalty. Because the block was claiming the original, un-penalized reward, the Monero network would reject it for spending too much money. By tricking the Monero node into pre-reserving this space, the node handles the complex penalty math natively.

Additionally, because the proxy prepended the Tari data into the coinbase, the empty space reserved for the miner's nonce was physically shifted. Failing to report this shift to the miner resulted in corrupted miner transactions.

Finally, the proxy previously only cleared its internal memory of old block templates when a miner successfully submitted a block. If miners disconnected or simply couldn't find a solution, the stored templates would accumulate indefinitely, leading to a slow memory leak. Moving this to an automated background lifecycle ensures stable, long-term operation of the proxy.

How Has This Been Tested?

Run monerod (regtest mode)

$ ./monerod --regtest --fixed-difficulty 1 --offline --rpc-bind-port 28081
2026-02-27 10:04:24.566 I Monero 'Fluorine Fermi' (v0.18.4.5-release)
2026-02-27 10:04:24.566 I Initializing cryptonote protocol...
2026-02-27 10:04:24.566 I Cryptonote protocol initialized OK
2026-02-27 10:04:24.566 I Initializing core...
2026-02-27 10:04:24.566 I Loading blockchain from folder /Users/martinserts/.bitmonero/fake/lmdb ...
2026-02-27 10:04:24.616 I Loading checkpoints
2026-02-27 10:04:24.616 I Core initialized OK
2026-02-27 10:04:24.616 I Initializing p2p server...
2026-02-27 10:04:24.617 I p2p server initialized OK
2026-02-27 10:04:24.617 I Initializing core RPC server...
2026-02-27 10:04:24.617 I Binding on 127.0.0.1 (IPv4):28081
2026-02-27 10:04:24.636 I core RPC server initialized OK on port: 28081
2026-02-27 10:04:24.636 I Starting core RPC server...
2026-02-27 10:04:24.636 I core RPC server started ok
2026-02-27 10:04:24.637 I Starting p2p net loop...
2026-02-27 10:04:25.638 I
2026-02-27 10:04:25.638 I **********************************************************************
2026-02-27 10:04:25.638 I The daemon is running offline and will not attempt to sync to the Monero network.
2026-02-27 10:04:25.639 I
2026-02-27 10:04:25.639 I You can set the level of process detailization through "set_log <level|categories>" command,
2026-02-27 10:04:25.639 I where <level> is between 0 (no details) and 4 (very verbose), or custom category based levels (eg, *:WARNING).
2026-02-27 10:04:25.639 I
2026-02-27 10:04:25.639 I Use the "help" command to see the list of available commands.
2026-02-27 10:04:25.639 I Use "help <command>" to see a command's documentation.
2026-02-27 10:04:25.639 I **********************************************************************

Run minotari_merge_mining_proxy

$ cargo run --bin minotari_merge_mining_proxy
14:31 INFO  Starting Minotari Merge Mining Proxy version: 5.3.0-pre.1-baa3f950cc89a4540aab858c196151a22bdb88a8-debug
14:31 INFO  Configuration file loaded.
14:31 INFO  Configuration: MergeMiningProxyConfig { override_from: Some("esmeralda"), use_dynamic_fail_data: true, monero_fail_url: "https://monero.fail/?chain=monero&network=mainnet&all=true", monerod_url: ConfigList(["http://127.0.0.1:28081"]), monerod_username: "", monerod_password: "", monerod_use_auth: false, base_node_grpc_address: Some("http://127.0.0.1:18142"), p2pool_node_grpc_address: None, base_node_grpc_authentication: None, base_node_grpc_tls_domain_name: None, base_node_grpc_ca_cert_filename: "node_ca.pem", listener_address: "/ip4/127.0.0.1/tcp/18081", submit_to_origin: true, wait_for_initial_sync_at_startup: true, check_tari_difficulty_before_submit: true, max_randomx_vms: 5, coinbase_extra: "tari_merge_mining_proxy", network: Esmeralda, config_dir: "/Users/martinserts/.tari/esmeralda/config/merge_mining_proxy", wallet_payment_address: "f411111111111111111111111111111111111111111111111111111111111111114K", range_proof_type: RevealedValue, p2pool_enabled: false, monerod_connection_timeout: 2s }

Please enter 'wallet-payment-address' ('quit' or 'exit' to quit) : f411111111111111111111111111111111111111111111111111111111111111114K
14:32 INFO  👛 Connecting to base node at http://127.0.0.1:18142
14:32 INFO  Listening on 127

Run xmrig

[2026-02-27 12:04:55.740]  net      use daemon 127.0.0.1:18081  127.0.0.1
[2026-02-27 12:04:55.740]  net      new job from 127.0.0.1:18081 diff 1 algo rx/0 height 1 (1 tx)
[2026-02-27 12:04:55.740]  cpu      use argon2 implementation default
[2026-02-27 12:04:55.741]  randomx  init dataset algo rx/0 (10 threads) seed 418015bb9ae982a1...
[2026-02-27 12:04:55.741]  randomx  allocated 2336 MB (2080+256) huge pages 0% 0/1168 +JIT (0 ms)
[2026-02-27 12:04:57.033]  net      new job from 127.0.0.1:18081 diff 1 algo rx/0 height 1 (1 tx)
[2026-02-27 12:04:57.982]  net      new job from 127.0.0.1:18081 diff 1 algo rx/0 height 1 (1 tx)
[2026-02-27 12:05:00.086]  randomx  dataset ready (4346 ms)
[2026-02-27 12:05:00.086]  cpu      use profile  rx  (1 thread) scratchpad 2048 KB
[2026-02-27 12:05:00.086]  cpu      READY threads 1/1 (1) huge pages 0% 0/1 memory 2048 KB (0 ms)
[2026-02-27 12:05:03.271]  cpu      accepted (1/0) diff 1 (3098 ms)
[2026-02-27 12:05:03.271]  net      no active pools, stop mining
[2026-02-27 12:05:03.478]  cpu      accepted (2/0) diff 1 (2724 ms)
[2026-02-27 12:05:03.646]  cpu      accepted (3/0) diff 1 (3323 ms)
[2026-02-27 12:05:03.672]  cpu      accepted (4/0) diff 1 (2908 ms)

...

[2026-02-27 12:05:16.173]  cpu      accepted (82/0) diff 1 (1548 ms)
[2026-02-27 12:05:16.218]  cpu      accepted (83/0) diff 1 (1625 ms)
[2026-02-27 12:05:16.264]  cpu      accepted (84/0) diff 1 (1681 ms)
[2026-02-27 12:05:16.308]  cpu      accepted (85/0) diff 1 (1702 ms)
[2026-02-27 12:05:16.353]  cpu      accepted (86/0) diff 1 (1776 ms)
[2026-02-27 12:05:16.398]  cpu      accepted (87/0) diff 1 (1818 ms)
[2026-02-27 12:05:16.443]  cpu      accepted (88/0) diff 1 (1835 ms)
[2026-02-27 12:05:16.489]  cpu      accepted (89/0) diff 1 (1878 ms)
[2026-02-27 12:05:16.534]  cpu      accepted (90/0) diff 1 (1938 ms)
[2026-02-27 12:05:16.580]  cpu      accepted (91/0) diff 1 (1993 ms)
[2026-02-27 12:05:16.626]  cpu      accepted (92/0) diff 1 (2024 ms)
...

No errors in monerod

2026-02-27 10:05:00.359 I ----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT 1
2026-02-27 10:05:00.359 I id:   <50cf9302a87f2a0074a780af3875b2611ff548beb8849a702c53878a4fac3234>
2026-02-27 10:05:00.359 I PoW:  <b3c8263ae59892f1cb740ffdf0ae2fc947007800fd50ad448763ca8b4494d57a>
2026-02-27 10:05:00.359 I difficulty:   1
2026-02-27 10:05:03.314 I ----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT 1
2026-02-27 10:05:03.314 I id:   <281b4663d5bf3c16042fd0356a72678071dadce973d69eda6962f0e7cfc91040>
2026-02-27 10:05:03.315 I PoW:  <0834449bc6d011dac3d62f90f1baade7bbb7f6e6f6b0f53ba995dad99b9db2b4>
2026-02-27 10:05:03.315 I difficulty:   1
2026-02-27 10:05:03.349 I ----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT 1
2026-02-27 10:05:03.349 I id:   <0a3d1631a302b0498d5e79c3de271354b7f541fabb2b6f766aa3ab875df30f96>
2026-02-27 10:05:03.349 I PoW:  <9e014de75ca8af944165514665c3cd046fbef9c859d4b943ff0f0537470bfb5a>
2026-02-27 10:05:03.349 I difficulty:   1

...

2026-02-27 10:05:22.053 I ----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT 2
2026-02-27 10:05:22.054 I id:   <ed3eee9892b6a23be6003789073bdd6105d24476dc0aab8fea9a4350c36d0008>
2026-02-27 10:05:22.054 I PoW:  <12cf2f1d8b67df85332d8756e0b210117e82f08ace1ec0f80d4fa3957958e35b>
2026-02-27 10:05:22.054 I difficulty:   1
2026-02-27 10:05:22.086 I ----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT 2
2026-02-27 10:05:22.086 I id:   <c1a0f4ca5738c3e2a0d05277a1ed85a1741335d7728b416dc54d91aef6d2a0c8>
2026-02-27 10:05:22.086 I PoW:  <573c7cf393bc759f7aea4f8455c61932f97c5214840c69813ad3d8e6219d108c>
2026-02-27 10:05:22.086 I difficulty:   1
2026-02-27 10:05:22.120 I ----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT 2
2026-02-27 10:05:22.120 I id:   <fa689b0bd028218f6715cdf89d910b0bd4484c31b2aa82ca86ea67b2ed314152>
2026-02-27 10:05:22.120 I PoW:  <d1d228e773e131fe6ff013cbba9bc23929f59d4b2b2cad0946d548f97b73bf64>
2026-02-27 10:05:22.120 I difficulty:   1

What process can a PR reviewer use to test or verify this change?

Breaking Changes

  • None
  • Requires data directory on base node to be deleted
  • Requires hard fork
  • Other - Please specify

@martinserts martinserts self-assigned this Feb 27, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on improving the stability and correctness of the Monero merge mining proxy. It resolves issues related to block rejections, memory leaks, and coinbase transaction corruption by correctly handling Tari data injection and memory management.

Highlights

  • Monero Block Rejections: Addresses sporadic Monero block rejections due to 'spend too much money' and 'incorrect miner transaction' errors.
  • Memory Leak Fix: Resolves a memory leak in the merge mining proxy by detaching block template memory cleanup from the block submission workflow.
  • Tari Data Injection: Ensures correct block weight penalties and adjusts the block reward by forcing the Monero node to pre-allocate space for Tari merge mining data.
  • Reserved Space Offset: Shifts the reserved space offset reported back to the miner, preventing the miner's software from overwriting the Tari payload or corrupting the coinbase transaction.
Changelog
  • applications/minotari_merge_mining_proxy/docs/Architecture.md
    • Added a sequence diagram to illustrate the interactions between the miner, proxy, Monerod, and Tari base node during merge mining operations.
  • applications/minotari_merge_mining_proxy/src/proxy/inner.rs
    • Added a constant for the Tari merge mining data size.
    • Removed outdated block template cleanup from the block submission workflow.
    • Shifted the reserved offset in the Monero block template to prevent coinbase corruption.
    • Modified the Monero getblocktemplate request to reserve space for the Minotari merge mining tag.
  • applications/minotari_merge_mining_proxy/src/run_merge_miner.rs
    • Added a constant for the block template cleanup interval.
    • Spawned a background task to periodically remove outdated block templates.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@martinserts martinserts changed the title Fix wrong XMR blocks fix: wrong XMR blocks Feb 27, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request effectively addresses the Monero block rejection issues and the memory leak in the merge mining proxy. The approach of pre-reserving space in the Monero block template is a clever solution to ensure correct weight penalty calculations. Adjusting the reserved_offset is also a crucial fix to prevent coinbase corruption. Finally, moving the template cleanup to a dedicated background task is a solid architectural improvement for long-term stability. I have one suggestion to improve the robustness of the new background task.

@brianp brianp merged commit 0d5a8f2 into tari-project:development Feb 27, 2026
16 of 17 checks passed
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.

Merge mining proxy sometimes create wrong XMR blocks

2 participants