Added hardfork code

merge-mining
SChernykh 2024-05-14 22:48:59 +02:00
parent 21326c5103
commit 899a908409
8 changed files with 121 additions and 53 deletions

View File

@ -411,9 +411,15 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
};
uint64_t max_reward_amounts_weight = get_reward_amounts_weight();
m_poolBlockTemplate->m_merkleTreeData = PoolBlock::encode_merkle_tree_data(static_cast<uint32_t>(data.aux_chains.size() + 1), data.aux_nonce);
m_poolBlockTemplate->m_merkleTreeDataSize = 0;
writeVarint(m_poolBlockTemplate->m_merkleTreeData, [this](uint8_t) { ++m_poolBlockTemplate->m_merkleTreeDataSize; });
if (m_poolBlockTemplate->merge_mining_enabled()) {
m_poolBlockTemplate->m_merkleTreeData = PoolBlock::encode_merkle_tree_data(static_cast<uint32_t>(data.aux_chains.size() + 1), data.aux_nonce);
m_poolBlockTemplate->m_merkleTreeDataSize = 0;
writeVarint(m_poolBlockTemplate->m_merkleTreeData, [this](uint8_t) { ++m_poolBlockTemplate->m_merkleTreeDataSize; });
}
else {
m_poolBlockTemplate->m_merkleTreeData = 0;
m_poolBlockTemplate->m_merkleTreeDataSize = 0;
}
if (create_miner_tx(data, m_shares, max_reward_amounts_weight, true) < 0) {
use_old_template();
@ -705,7 +711,10 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const
}
if (pool_block_debug()) {
const size_t merkle_root_offset = m_extraNonceOffsetInTemplate + m_poolBlockTemplate->m_extraNonceSize + 2 + m_poolBlockTemplate->m_merkleTreeDataSize;
const size_t merkle_root_offset =
m_poolBlockTemplate->merge_mining_enabled()
? (m_extraNonceOffsetInTemplate + m_poolBlockTemplate->m_extraNonceSize + 2 + m_poolBlockTemplate->m_merkleTreeDataSize)
: (m_extraNonceOffsetInTemplate + m_poolBlockTemplate->m_extraNonceSize + 2);
memcpy(m_blockTemplateBlob.data() + merkle_root_offset, m_poolBlockTemplate->m_merkleRoot.h, HASH_SIZE);
memcpy(m_fullDataBlob.data() + merkle_root_offset, m_poolBlockTemplate->m_merkleRoot.h, HASH_SIZE);
@ -945,9 +954,16 @@ int BlockTemplate::create_miner_tx(const MinerData& data, const std::vector<Mine
m_poolBlockTemplate->m_extraNonceSize = corrected_extra_nonce_size;
m_minerTxExtra.push_back(TX_EXTRA_MERGE_MINING_TAG);
m_minerTxExtra.push_back(static_cast<uint8_t>(m_poolBlockTemplate->m_merkleTreeDataSize + HASH_SIZE));
writeVarint(m_poolBlockTemplate->m_merkleTreeData, m_minerTxExtra);
m_minerTxExtra.insert(m_minerTxExtra.end(), HASH_SIZE, 0);
if (!m_poolBlockTemplate->merge_mining_enabled()) {
m_minerTxExtra.push_back(HASH_SIZE);
m_minerTxExtra.insert(m_minerTxExtra.end(), HASH_SIZE, 0);
}
else {
m_minerTxExtra.push_back(static_cast<uint8_t>(m_poolBlockTemplate->m_merkleTreeDataSize + HASH_SIZE));
writeVarint(m_poolBlockTemplate->m_merkleTreeData, m_minerTxExtra);
m_minerTxExtra.insert(m_minerTxExtra.end(), HASH_SIZE, 0);
}
// TX_EXTRA end
writeVarint(m_minerTxExtra.size(), m_minerTx);
@ -1037,7 +1053,10 @@ hash BlockTemplate::calc_miner_tx_hash(uint32_t extra_nonce) const
const uint32_t aux_slot = get_aux_slot(m_sidechain->consensus_hash(), m_poolBlockTemplate->m_auxNonce, n_aux_chains);
merge_mining_root = get_root_from_proof(sidechain_id, m_poolBlockTemplate->m_merkleProof, aux_slot, n_aux_chains);
}
const size_t merkle_root_offset = extra_nonce_offset + m_poolBlockTemplate->m_extraNonceSize + 2 + m_poolBlockTemplate->m_merkleTreeDataSize;
const size_t merkle_root_offset = m_poolBlockTemplate->merge_mining_enabled()
? (extra_nonce_offset + m_poolBlockTemplate->m_extraNonceSize + 2 + m_poolBlockTemplate->m_merkleTreeDataSize)
: (extra_nonce_offset + m_poolBlockTemplate->m_extraNonceSize + 2);
// 1. Prefix (everything except vin_rct_type byte in the end)
// Apply extra_nonce in-place because we can't write to the block template here
@ -1374,7 +1393,9 @@ std::vector<uint8_t> BlockTemplate::get_block_template_blob(uint32_t template_id
const uint32_t aux_slot = get_aux_slot(m_sidechain->consensus_hash(), m_poolBlockTemplate->m_auxNonce, n_aux_chains);
merge_mining_root = get_root_from_proof(sidechain_id, m_poolBlockTemplate->m_merkleProof, aux_slot, n_aux_chains);
merkle_root_offset = m_extraNonceOffsetInTemplate + m_poolBlockTemplate->m_extraNonceSize + 2 + m_poolBlockTemplate->m_merkleTreeDataSize;
merkle_root_offset = m_poolBlockTemplate->merge_mining_enabled()
? (m_extraNonceOffsetInTemplate + m_poolBlockTemplate->m_extraNonceSize + 2 + m_poolBlockTemplate->m_merkleTreeDataSize)
: (m_extraNonceOffsetInTemplate + m_poolBlockTemplate->m_extraNonceSize + 2);
*pThis = this;

View File

@ -804,7 +804,10 @@ void P2PServer::broadcast(const PoolBlock& block, const PoolBlock* parent)
writeVarint(total_reward, data->pruned_blob);
writeVarint(outputs_blob_size, data->pruned_blob);
data->pruned_blob.insert(data->pruned_blob.end(), block.m_sidechainId.h, block.m_sidechainId.h + HASH_SIZE);
if (block.merge_mining_enabled()) {
data->pruned_blob.insert(data->pruned_blob.end(), block.m_sidechainId.h, block.m_sidechainId.h + HASH_SIZE);
}
data->pruned_blob.insert(data->pruned_blob.end(), mainchain_data.begin() + outputs_offset + outputs_blob_size, mainchain_data.end());

View File

@ -201,10 +201,18 @@ std::vector<uint8_t> PoolBlock::serialize_mainchain_data(size_t* header_size, si
}
*(p++) = TX_EXTRA_MERGE_MINING_TAG;
*(p++) = static_cast<uint8_t>(m_merkleTreeDataSize + HASH_SIZE);
writeVarint(m_merkleTreeData, [&p](const uint8_t b) { *(p++) = b; });
memcpy(p, m_merkleRoot.h, HASH_SIZE);
p += HASH_SIZE;
if (!merge_mining_enabled()) {
*(p++) = HASH_SIZE;
memcpy(p, m_sidechainId.h, HASH_SIZE);
p += HASH_SIZE;
}
else {
*(p++) = static_cast<uint8_t>(m_merkleTreeDataSize + HASH_SIZE);
writeVarint(m_merkleTreeData, [&p](const uint8_t b) { *(p++) = b; });
memcpy(p, m_merkleRoot.h, HASH_SIZE);
p += HASH_SIZE;
}
writeVarint(static_cast<size_t>(p - tx_extra), data);
data.insert(data.end(), tx_extra, p);
@ -257,12 +265,14 @@ std::vector<uint8_t> PoolBlock::serialize_sidechain_data() const
writeVarint(m_cumulativeDifficulty.lo, data);
writeVarint(m_cumulativeDifficulty.hi, data);
const uint8_t n = static_cast<uint8_t>(m_merkleProof.size());
data.push_back(n);
if (merge_mining_enabled()) {
const uint8_t n = static_cast<uint8_t>(m_merkleProof.size());
data.push_back(n);
for (uint8_t i = 0; i < n; ++i) {
const hash& h = m_merkleProof[i];
data.insert(data.end(), h.h, h.h + HASH_SIZE);
for (uint8_t i = 0; i < n; ++i) {
const hash& h = m_merkleProof[i];
data.insert(data.end(), h.h, h.h + HASH_SIZE);
}
}
const uint8_t* p = reinterpret_cast<const uint8_t*>(m_sidechainExtraBuf);
@ -401,4 +411,13 @@ hash PoolBlock::calculate_tx_key_seed() const
return result;
}
bool PoolBlock::merge_mining_enabled() const
{
#ifdef P2POOL_UNIT_TESTS
return false;
#else
return (SideChain::network_type() != NetworkType::Mainnet) || (m_timestamp >= MERGE_MINING_FORK_TIME);
#endif
}
} // namespace p2pool

View File

@ -60,6 +60,9 @@ static constexpr difficulty_type MAX_CUMULATIVE_DIFFICULTY{ 13019633956666736640
// 1000 years at 1 block/second. It should be enough for any normal use.
static constexpr uint64_t MAX_SIDECHAIN_HEIGHT = 31556952000ULL;
// Jul 01 2024 00:00:00 GMT+0000
static constexpr uint64_t MERGE_MINING_FORK_TIME = 1719792000;
struct DifficultyData
{
FORCEINLINE DifficultyData(uint64_t t, const difficulty_type& d) : m_timestamp(t), m_cumulativeDifficulty(d) {}
@ -203,6 +206,8 @@ struct PoolBlock
mm_n_aux_chains = 1U + ((k >> 3U) & ((1U << n) - 1U));
mm_nonce = static_cast<uint32_t>(m_merkleTreeData >> (3U + n));
}
bool merge_mining_enabled() const;
};
} // namespace p2pool

View File

@ -148,7 +148,9 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
outputs_blob_size = static_cast<int>(tmp);
// Required by sidechain.get_outputs_blob() to speed up repeated broadcasts from different peers
READ_BUF(m_sidechainId.h, HASH_SIZE);
if (merge_mining_enabled()) {
READ_BUF(m_sidechainId.h, HASH_SIZE);
}
}
// Technically some p2pool node could keep stuffing block with transactions until reward is less than 0.6 XMR
@ -186,23 +188,39 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
EXPECT_BYTE(TX_EXTRA_MERGE_MINING_TAG);
uint64_t mm_field_size;
READ_VARINT(mm_field_size);
const uint8_t* const mm_field_begin = data;
READ_VARINT(m_merkleTreeData);
m_merkleTreeDataSize = static_cast<uint32_t>(data - mm_field_begin);
int mm_root_hash_offset;
uint32_t mm_n_aux_chains, mm_nonce;
decode_merkle_tree_data(mm_n_aux_chains, mm_nonce);
const int mm_root_hash_offset = static_cast<int>((data - data_begin) + outputs_blob_size_diff);
READ_BUF(m_merkleRoot.h, HASH_SIZE);
if (!merge_mining_enabled()) {
EXPECT_BYTE(HASH_SIZE);
if (static_cast<uint64_t>(data - mm_field_begin) != mm_field_size) {
return __LINE__;
mm_root_hash_offset = static_cast<int>((data - data_begin) + outputs_blob_size_diff);
READ_BUF(m_sidechainId.h, HASH_SIZE);
mm_n_aux_chains = 1;
mm_nonce = 0;
m_merkleRoot = static_cast<root_hash&>(m_sidechainId);
m_merkleTreeDataSize = 0;
}
else {
uint64_t mm_field_size;
READ_VARINT(mm_field_size);
const uint8_t* const mm_field_begin = data;
READ_VARINT(m_merkleTreeData);
m_merkleTreeDataSize = static_cast<uint32_t>(data - mm_field_begin);
decode_merkle_tree_data(mm_n_aux_chains, mm_nonce);
mm_root_hash_offset = static_cast<int>((data - data_begin) + outputs_blob_size_diff);
READ_BUF(m_merkleRoot.h, HASH_SIZE);
if (static_cast<uint64_t>(data - mm_field_begin) != mm_field_size) {
return __LINE__;
}
}
if (static_cast<uint64_t>(data - tx_extra_begin) != tx_extra_size) return __LINE__;
@ -340,20 +358,23 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si
return __LINE__;
}
uint8_t merkle_proof_size;
READ_BYTE(merkle_proof_size);
if (merkle_proof_size > 7) {
return __LINE__;
}
m_merkleProof.clear();
m_merkleProof.reserve(merkle_proof_size);
for (uint8_t i = 0; i < merkle_proof_size; ++i) {
hash h;
READ_BUF(h.h, HASH_SIZE);
m_merkleProof.emplace_back(h);
if (merge_mining_enabled()) {
uint8_t merkle_proof_size;
READ_BYTE(merkle_proof_size);
if (merkle_proof_size > 8) {
return __LINE__;
}
m_merkleProof.reserve(merkle_proof_size);
for (uint8_t i = 0; i < merkle_proof_size; ++i) {
hash h;
READ_BUF(h.h, HASH_SIZE);
m_merkleProof.emplace_back(h);
}
}
READ_BUF(m_sidechainExtraBuf, sizeof(m_sidechainExtraBuf));

View File

@ -42,7 +42,7 @@
LOG_CATEGORY(SideChain)
static constexpr uint64_t MIN_DIFFICULTY = 1000;
static constexpr uint64_t MIN_DIFFICULTY = 100000;
static constexpr size_t UNCLE_BLOCK_DEPTH = 3;
static_assert(1 <= UNCLE_BLOCK_DEPTH && UNCLE_BLOCK_DEPTH <= 10, "Invalid UNCLE_BLOCK_DEPTH");
@ -63,7 +63,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
, m_poolName(pool_name ? pool_name : "default")
, m_targetBlockTime(10)
, m_minDifficulty(MIN_DIFFICULTY, 0)
, m_chainWindowSize(216)
, m_chainWindowSize(2160)
, m_unclePenalty(20)
, m_precalcFinished(false)
#ifdef DEV_TEST_SYNC
@ -103,8 +103,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
// cppcheck-suppress uninitvar
log::Stream s(buf);
s << "mm" << '\0'
<< s_networkType << '\0'
s << s_networkType << '\0'
<< m_poolName << '\0'
<< m_poolPassword << '\0'
<< m_targetBlockTime << '\0'

View File

@ -26,7 +26,7 @@
namespace p2pool {
TEST(block_template, DISABLED_update)
TEST(block_template, update)
{
init_crypto_cache();

View File

@ -25,7 +25,7 @@
namespace p2pool {
TEST(pool_block, DISABLED_deserialize)
TEST(pool_block, deserialize)
{
init_crypto_cache();
@ -132,7 +132,7 @@ TEST(pool_block, DISABLED_deserialize)
destroy_crypto_cache();
}
TEST(pool_block, DISABLED_verify)
TEST(pool_block, verify)
{
init_crypto_cache();