Support multiple coinbase outputs#55
Conversation
|
Thanks, it would be good to have some tests for this, maybe in https://github.com/Sjors/sv2-tp/blob/master/src/test/sv2_messages_tests.cpp |
Let me work on that, thank you for the feedback. |
Adds Sv2NewTemplate_MultipleOutputs_test which verifies that all coinbase outputs are serialized correctly, not just the first one. The test creates a NewTemplate message with 3 different outputs (100, 200, and 300 sats) and checks that the serialized bytes match the expected format with all three outputs included. Requested by maintainer in PR stratum-mining#55.
3d24164 to
1adcfcf
Compare
|
@Sjors I have pushed some test updates, looking forward to hear what you think. |
|
Thanks! Will review in more detail soon. I assume the test fails if you omit the first commit? It would be nice to also (manually) test this in a Bitcoin Core + sv2_tp + SRI integration. I guess we'd need a patch or Bitcoin Core to actually add a second output, it can just be nonsense, on e.g. signet. |
I think it should work, the only time it failed is when I did 3 commits so I was forced to squash one and test passed, do you want me to make it one commit instead of two? I will try do a manual simulation as you have advised and then share my findings, hopefully today or latest tomorrow. |
No, two is fine. I'll try it.
Thanks, please share the steps. I haven't worked on merge mining ever, so not sure what the easiest way is. |
Let me share the steps once I've figured out the merge mining and patch needed for bitcoin core |
b202a40 to
b8363fc
Compare
|
CI is finding test failures: |
b8363fc to
3ccbe50
Compare
working on a fix to solve the ci fail |
3ccbe50 to
820bd71
Compare
|
@Sjors I've pushed the new update, here's are the steps I used to test with https://gist.github.com/xyephy/13aff2a54c6286316ce7f8f089862c7f . Let me know if changes are now working. |
There was a problem hiding this comment.
Thanks for the elaborate testing instructions!
It made me realise there's a problem: the node always adds a dummy output script (typically OP_TRUE) with the full coinbase reward. We need to exclude that (or the pool will make an invalid block because it tries to spend that amount again).
I think the most robust solution is to filter the coinbase outputs for OP_RETURN. That includes SegWit and (hopefully) all merge mining schemes.
A cleaner solution would require an update to Bitcoin Core to either:
- Stop adding the dummy output; or
- Add a method similar to
getWitnessCommitmentIndex()to indicate which other inputs are commitments that need to be included.
src/sv2/messages.h
Outdated
| VectorWriter{outputs_bytes, outputs_bytes.size(), output}; | ||
| } | ||
|
|
||
| LogPrintLevel(BCLog::SV2, BCLog::Level::Debug, "Serialized %zu coinbase output(s), total size: %zu bytes\n", |
There was a problem hiding this comment.
nit: maybe downgrade to trace?
| 4 + // coinbase_tx_outputs_count (0) | ||
| 2 + // B0_64K length for outputs array (0) | ||
| 4 + // coinbase_tx_outputs_count (1 - mock creates 1 output) | ||
| 2 + 10 + // B0_64K: length(10) + 1 output (8 bytes nValue + 2 bytes script) |
There was a problem hiding this comment.
I was initially confused why this changed, but it's because we're now including all coinbase outputs.
Let's make the mock more realistic add give it:
- a dummy anyone-can-spend output, e.g. OP_TRUE with 50BTC
- a (fake) segwit commitment rather than the current
OP_RETURN, and have the mockgetWitnessCommitmentIndexreturn that position. - a (fake) merge mining commitment
| // U32 ffffffff coinbase tx input sequence | ||
| // U64 0040075af0750700 coinbase tx value remaining | ||
| // U32 03000000 coinbase tx outputs count (3 outputs) | ||
| // B0_64K 2100 coinbase_tx_outputs (33 bytes total) |
There was a problem hiding this comment.
Let's add an anyone-can-spend output here, because the node will provide one and we need to omit it.
src/sv2/messages.cpp
Outdated
| if (witness_commitment_index != NO_WITNESS_COMMITMENT) { | ||
| m_coinbase_tx_outputs_count = 1; | ||
| m_coinbase_tx_outputs = {coinbase_tx->vout[witness_commitment_index]}; | ||
| // Extract ALL coinbase outputs to support merge mining and other use cases |
There was a problem hiding this comment.
I think we need to filter this to cover only OP_RETURNs, otherwise we include the dummy output added by the node and since the spends the full reward, the pool would make an invalid block.
|
@Sjors thank you for the detailed review, let me look into it and add the recommendations you've made so as to have a much better solution. |
Implement PR stratum-mining#55 review feedback from Sjors: - Changed NewTemplate to only include OP_RETURN outputs instead of all coinbase outputs. Bitcoin Core adds a dummy output with the full block reward that must be filtered out, otherwise pools would create invalid blocks trying to spend that amount again. - Removed unused witness_commitment_index parameter from Sv2NewTemplateMsg constructor. - Changed output serialization log from Debug to Trace level to reduce log noise. - Updated test mocks to create realistic coinbase transactions with multiple outputs (1 reward + 2 OP_RETURN) to properly test filtering. - Updated all test expectations to reflect filtered OP_RETURN behavior. Testing: - All 19 unit tests pass - End-to-end tested with SRI mining-device: 397 blocks mined successfully - Zero coinbase validation errors across all mined blocks
|
Thanks, that looks better at first glance. Can you squash both commits? |
|
@Sjors I have pushed new fixes as you recommended, I've managed to solo mine with Sri mining-device without getting any invalid blocks. Let me know if this works on your end and if there are any further changes I need to add, thank you. |
let me do that |
This change enables sv2-tp to handle block templates with multiple coinbase outputs, which is required for merge mining and other use cases where additional coinbase outputs are needed. Implementation: - Changed NewTemplate to only include OP_RETURN outputs instead of all coinbase outputs. Bitcoin Core adds a dummy output with the full block reward that must be filtered out, otherwise pools would create invalid blocks trying to spend that amount again. - Removed unused witness_commitment_index parameter from Sv2NewTemplateMsg constructor. - Changed output serialization log from Debug to Trace level to reduce log noise. - Updated test mocks to create realistic coinbase transactions with multiple outputs (1 reward + 2 OP_RETURN) to properly test filtering. - Updated all test expectations to reflect filtered OP_RETURN behavior. Testing: - All 19 unit tests pass - End-to-end tested with SRI mining-device: 397 blocks mined successfully - Zero coinbase validation errors across all mined blocks Fixes: stratum-mining#18
36a7ed1 to
9e68692
Compare
|
Looks great, thanks! |
|
It would be good to round-trip test this in SRI: stratum-mining/sv2-apps#58 |
let me do that. |
Previously only the first coinbase output was serialized, breaking merge mining and multi-payout pool scenarios.
This change iterates through all outputs in m_coinbase_tx_outputs and serializes them sequentially using VectorWriter.
Also adds debug logging to track the number of outputs and total size for observability.
Fixes #18