Fix Carrot v1 protocol TX handling for peer synchronization

Root cause: Merkle verification failures (error 659) and peer bans occurred
because protocol TX was not consistently present in m_transactions[1].

Parser fix (pool_block_parser.inl):
- Skip dummy transactions[0] entry when populating m_transactions
- Add protocol TX computation after parsing for Carrot v1 blocks

Block template fix (block_template.cpp):
- Insert protocol TX at position [1] during block creation in update()
- Insert protocol TX during select_mempool_transactions()

get_pow_hash fix (pool_block.cpp):
- Ensure protocol TX is populated before serialize_mainchain_data()

The protocol TX must be at m_transactions[1] before ANY serialization
occurs, otherwise sender and receiver compute different merkle roots.

Tested: Multiple restart cycles with two nodes, no bans, chains stay synced.
This commit is contained in:
Matt Hess
2025-12-07 23:57:46 +00:00
parent 00fb078004
commit 728d6c2cbf
5 changed files with 121 additions and 28 deletions
+15
View File
@@ -682,6 +682,15 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
m_poolBlockTemplate->m_transactions.push_back(m_mempoolTxs[m_mempoolTxsOrder[i]].id);
}
// For Carrot v1 blocks, insert protocol TX at position 1
if (m_poolBlockTemplate->m_majorVersion >= 10) {
hash protocol_tx_hash;
calculate_protocol_tx_hash(m_poolBlockTemplate->m_txinGenHeight, protocol_tx_hash);
m_poolBlockTemplate->m_transactions.insert(
m_poolBlockTemplate->m_transactions.begin() + 1,
static_cast<indexed_hash>(protocol_tx_hash));
}
m_poolBlockTemplate->m_minerWallet = params->m_miningWallet;
// Layout: [software id, version, random number, sidechain extra_nonce]
@@ -952,6 +961,12 @@ void BlockTemplate::select_mempool_transactions(const Mempool& mempool)
PoolBlock* b = m_poolBlockTemplate;
b->m_transactions.clear();
b->m_transactions.resize(1);
// For Carrot v1 blocks, protocol TX takes a slot
if (b->m_majorVersion >= 10) {
hash protocol_tx_hash;
calculate_protocol_tx_hash(b->m_txinGenHeight, protocol_tx_hash);
b->m_transactions.push_back(static_cast<indexed_hash>(protocol_tx_hash));
}
b->m_ephPublicKeys.clear();
b->m_outputAmounts.clear();
b->m_viewTags.clear();