Fix dev fee implementation for peer synchronization

- Add dev fee output in get_outputs_blob() for sidechain validation
- Fix extra nonce size calculation to account for dev fee weight
- Fix size estimation in busy mempool handler to account for dev fee
- Add debug logging for mainchain data serialization
- Fixes peer banning due to sidechain ID mismatch (error 502)
This commit is contained in:
Matt Hess
2025-11-12 22:26:47 +00:00
parent 78cbb8bc9f
commit 8ff12ad180
4 changed files with 54 additions and 37 deletions

View File

@@ -871,11 +871,11 @@ void BlockTemplate::select_mempool_transactions(const Mempool& mempool)
size_t k = b->serialize_mainchain_data().size() + b->serialize_sidechain_data().size() - 2;
// Add output and tx count real varints
writeVarint(m_shares.size(), [&k](uint8_t) { ++k; });
writeVarint(m_shares.size() + 1, [&k](uint8_t) { ++k; });
writeVarint(m_mempoolTxs.size(), [&k](uint8_t) { ++k; });
// Add a rough upper bound estimation of outputs' size. All outputs have <= 5 bytes for each output's reward (< 0.034359738368 XMR per output)
k += m_shares.size() * (5 /* reward */ + 1 /* tx_type */ + HASH_SIZE /* stealth address */ + 1 /* viewtag */);
k += (m_shares.size() + 1) * (5 /* reward */ + 1 /* tx_type */ + HASH_SIZE /* stealth address */ + 1 /* viewtag */); // +1 for dev fee
// >= 0.034359738368 XMR is required for a 6 byte varint, add 1 byte per each potential 6-byte varint
{
@@ -998,7 +998,7 @@ int BlockTemplate::create_miner_tx(const MinerData& data, const std::vector<Mine
m_minerTxExtra.push_back(TX_EXTRA_NONCE);
const uint64_t corrected_extra_nonce_size = EXTRA_NONCE_SIZE + max_reward_amounts_weight - reward_amounts_weight;
const uint64_t corrected_extra_nonce_size = EXTRA_NONCE_SIZE + (max_reward_amounts_weight + dev_fee_weight) - reward_amounts_weight;
if (corrected_extra_nonce_size > EXTRA_NONCE_SIZE) {
if (corrected_extra_nonce_size > EXTRA_NONCE_MAX_SIZE) {
LOGWARN(5, "create_miner_tx: corrected_extra_nonce_size (" << corrected_extra_nonce_size << ") is too large");

View File

@@ -172,6 +172,8 @@ std::vector<uint8_t> PoolBlock::serialize_mainchain_data(size_t* header_size, si
writeVarint(m_outputAmounts.size(), data);
LOGINFO(3, "serialize_mainchain_data: writing " << m_outputAmounts.size() << " outputs, offset=" << outputs_offset0);
for (size_t i = 0, n = m_outputAmounts.size(); i < n; ++i) {
const TxOutput& output = m_outputAmounts[i];

View File

@@ -184,6 +184,8 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
EXPECT_BYTE(TX_EXTRA_NONCE);
READ_VARINT(m_extraNonceSize);
LOGINFO(3, "Extra nonce size: " << m_extraNonceSize << " (valid range: " << EXTRA_NONCE_SIZE << " to " << EXTRA_NONCE_MAX_SIZE << ")");
// Sanity check
if ((m_extraNonceSize < EXTRA_NONCE_SIZE) || (m_extraNonceSize > EXTRA_NONCE_MAX_SIZE)) return __LINE__;
@@ -495,8 +497,11 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
if (m_sidechainId.empty()) {
m_sidechainId = check;
LOGINFO(3, "Calculated sidechain ID: " << check);
}
else if (m_sidechainId != check) {
LOGINFO(3, "Sidechain ID mismatch! Expected: " << m_sidechainId << " Got: " << check);
LOGINFO(3, " outputs_blob_size: " << outputs_blob_size << " actual: " << outputs_actual_blob_size << " diff: " << outputs_blob_size_diff);
return __LINE__;
}

View File

@@ -894,40 +894,50 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
});
}
blob.reserve(n * 39 + 64);
writeVarint(n, blob);
block->m_ephPublicKeys.clear();
block->m_outputAmounts.clear();
block->m_ephPublicKeys.reserve(n);
block->m_outputAmounts.reserve(n);
hash eph_public_key;
for (size_t i = 0; i < n; ++i) {
// stop helper jobs when they meet with current thread
const int c = data->counter.load();
if ((c >= 0) && (static_cast<int>(i) >= c)) {
// this will cause all helper jobs to finish immediately
data->counter = -1;
}
writeVarint(tmpRewards[i], blob);
blob.emplace_back(TXOUT_TO_TAGGED_KEY);
uint8_t view_tag;
if (!data->tmpShares[i].m_wallet->get_eph_public_key(data->txkeySec, i, eph_public_key, view_tag)) {
LOGWARN(6, "get_eph_public_key failed at index " << i);
}
blob.insert(blob.end(), eph_public_key.h, eph_public_key.h + HASH_SIZE);
blob.emplace_back(view_tag);
block->m_ephPublicKeys.emplace_back(eph_public_key);
block->m_outputAmounts.emplace_back(tmpRewards[i], view_tag);
}
blob.reserve(n * 39 + 64);
writeVarint(n + 1, blob); // +1 for dev fee
// Add dev fee output first
const uint64_t total_miner_reward = std::accumulate(tmpRewards.begin(), tmpRewards.end(), 0ULL);
const uint64_t dev_fee = static_cast<uint64_t>(total_miner_reward * (Params::DEV_FEE_PERCENTAGE / 100.0));
writeVarint(dev_fee, blob);
blob.emplace_back(TXOUT_TO_TAGGED_KEY);
hash dev_eph_public_key;
uint8_t dev_view_tag;
if (!Params::s_devFeeWallet->get_eph_public_key(data->txkeySec, 0, dev_eph_public_key, dev_view_tag)) {
LOGWARN(6, "get_eph_public_key failed for dev fee");
}
blob.insert(blob.end(), dev_eph_public_key.h, dev_eph_public_key.h + HASH_SIZE);
blob.emplace_back(dev_view_tag);
block->m_ephPublicKeys.clear();
block->m_outputAmounts.clear();
block->m_ephPublicKeys.reserve(n + 1); // +1 for dev fee
block->m_outputAmounts.reserve(n + 1); // +1 for dev fee
block->m_ephPublicKeys.emplace_back(dev_eph_public_key);
block->m_outputAmounts.emplace_back(dev_fee, dev_view_tag);
hash eph_public_key;
for (size_t i = 0; i < n; ++i) {
// stop helper jobs when they meet with current thread
const int c = data->counter.load();
if ((c >= 0) && (static_cast<int>(i) >= c)) {
// this will cause all helper jobs to finish immediately
data->counter = -1;
}
writeVarint(tmpRewards[i], blob);
blob.emplace_back(TXOUT_TO_TAGGED_KEY);
uint8_t view_tag;
if (!data->tmpShares[i].m_wallet->get_eph_public_key(data->txkeySec, i + 1, eph_public_key, view_tag)) {
LOGWARN(6, "get_eph_public_key failed at index " << i);
}
blob.insert(blob.end(), eph_public_key.h, eph_public_key.h + HASH_SIZE);
blob.emplace_back(view_tag);
block->m_ephPublicKeys.emplace_back(eph_public_key);
block->m_outputAmounts.emplace_back(tmpRewards[i], view_tag);
}
block->m_ephPublicKeys.shrink_to_fit();
block->m_outputAmounts.shrink_to_fit();