diff --git a/src/block_cache.cpp b/src/block_cache.cpp index a1bed33..e500856 100644 --- a/src/block_cache.cpp +++ b/src/block_cache.cpp @@ -165,8 +165,11 @@ BlockCache::~BlockCache() void BlockCache::store(const PoolBlock& block) { - const size_t n1 = block.m_mainChainData.size(); - const size_t n2 = block.m_sideChainData.size(); + const std::vector mainchain_data = block.serialize_mainchain_data(); + const std::vector sidechain_data = block.serialize_sidechain_data(); + + const size_t n1 = mainchain_data.size(); + const size_t n2 = sidechain_data.size(); if (!m_impl->m_data || (sizeof(uint32_t) + n1 + n2 > BLOCK_SIZE)) { return; @@ -175,8 +178,8 @@ void BlockCache::store(const PoolBlock& block) uint8_t* data = m_impl->m_data + (static_cast((m_storeIndex++) % NUM_BLOCKS) * BLOCK_SIZE); *reinterpret_cast(data) = static_cast(n1 + n2); - memcpy(data + sizeof(uint32_t), block.m_mainChainData.data(), n1); - memcpy(data + sizeof(uint32_t) + n1, block.m_sideChainData.data(), n2); + memcpy(data + sizeof(uint32_t), mainchain_data.data(), n1); + memcpy(data + sizeof(uint32_t) + n1, sidechain_data.data(), n2); } void BlockCache::load_all(SideChain& side_chain, P2PServer& server) diff --git a/src/block_template.cpp b/src/block_template.cpp index 8e7b48d..acf5afb 100644 --- a/src/block_template.cpp +++ b/src/block_template.cpp @@ -528,15 +528,16 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, Wallet memcpy(m_blockTemplateBlob.data() + sidechain_hash_offset, m_poolBlockTemplate->m_sidechainId.h, HASH_SIZE); memcpy(m_minerTx.data() + sidechain_hash_offset - m_minerTxOffsetInTemplate, m_poolBlockTemplate->m_sidechainId.h, HASH_SIZE); - m_poolBlockTemplate->serialize_mainchain_data(0, 0, m_poolBlockTemplate->m_sidechainId); - #if POOL_BLOCK_DEBUG - if (m_poolBlockTemplate->m_mainChainData != m_blockTemplateBlob) { + const std::vector mainchain_data = m_poolBlockTemplate->serialize_mainchain_data(); + const std::vector sidechain_data = m_poolBlockTemplate->serialize_sidechain_data(); + + if (mainchain_data != m_blockTemplateBlob) { LOGERR(1, "serialize_mainchain_data() has a bug, fix it! "); - LOGERR(1, "m_poolBlockTemplate->m_mainChainData.size() = " << m_poolBlockTemplate->m_mainChainData.size()); + LOGERR(1, "m_poolBlockTemplate->m_mainChainData.size() = " << mainchain_data.size()); LOGERR(1, "m_blockTemplateBlob.size() = " << m_blockTemplateBlob.size()); - for (size_t i = 0, n = std::min(m_poolBlockTemplate->m_mainChainData.size(), m_blockTemplateBlob.size()); i < n; ++i) { - if (m_poolBlockTemplate->m_mainChainData[i] != m_blockTemplateBlob[i]) { + for (size_t i = 0, n = std::min(mainchain_data.size(), m_blockTemplateBlob.size()); i < n; ++i) { + if (mainchain_data[i] != m_blockTemplateBlob[i]) { LOGERR(1, "m_poolBlockTemplate->m_mainChainData is different at offset " << i); break; } @@ -545,7 +546,7 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, Wallet { std::vector buf = m_blockTemplateBlob; - buf.insert(buf.end(), m_poolBlockTemplate->m_sideChainData.begin(), m_poolBlockTemplate->m_sideChainData.end()); + buf.insert(buf.end(), sidechain_data.begin(), sidechain_data.end()); PoolBlock check; const int result = check.deserialize(buf.data(), buf.size(), m_pool->side_chain(), nullptr); @@ -712,7 +713,7 @@ int BlockTemplate::create_miner_tx(const MinerData& data, const std::vectorm_outputs.emplace_back(m_rewards[i], eph_public_key, tx_type, view_tag); + m_poolBlockTemplate->m_outputs.emplace_back(m_rewards[i], eph_public_key, view_tag); } if (tx_type == TXOUT_TO_TAGGED_KEY) { @@ -784,8 +785,9 @@ hash BlockTemplate::calc_sidechain_hash() const const int blob_size = static_cast(m_blockTemplateBlob.size()); const std::vector& consensus_id = m_pool->side_chain().consensus_id(); + const std::vector sidechain_data = m_poolBlockTemplate->serialize_sidechain_data(); - keccak_custom([this, sidechain_hash_offset, blob_size, consensus_id](int offset) -> uint8_t { + keccak_custom([this, sidechain_hash_offset, blob_size, consensus_id, &sidechain_data](int offset) -> uint8_t { uint32_t k = static_cast(offset - static_cast(m_nonceOffset)); if (k < NONCE_SIZE) { return 0; @@ -806,15 +808,15 @@ hash BlockTemplate::calc_sidechain_hash() const } const int side_chain_data_offsset = offset - blob_size; - const int side_chain_data_size = static_cast(m_poolBlockTemplate->m_sideChainData.size()); + const int side_chain_data_size = static_cast(sidechain_data.size()); if (side_chain_data_offsset < side_chain_data_size) { - return m_poolBlockTemplate->m_sideChainData[side_chain_data_offsset]; + return sidechain_data[side_chain_data_offsset]; } const int consensus_id_offset = side_chain_data_offsset - side_chain_data_size; return consensus_id[consensus_id_offset]; }, - static_cast(m_blockTemplateBlob.size() + m_poolBlockTemplate->m_sideChainData.size() + consensus_id.size()), sidechain_hash.h, HASH_SIZE); + static_cast(m_blockTemplateBlob.size() + sidechain_data.size() + consensus_id.size()), sidechain_hash.h, HASH_SIZE); return sidechain_hash; } @@ -1067,15 +1069,18 @@ void BlockTemplate::submit_sidechain_block(uint32_t template_id, uint32_t nonce, if (template_id == m_templateId) { m_poolBlockTemplate->m_nonce = nonce; m_poolBlockTemplate->m_extraNonce = extra_nonce; - memcpy(m_poolBlockTemplate->m_mainChainData.data() + m_nonceOffset, &nonce, NONCE_SIZE); - memcpy(m_poolBlockTemplate->m_mainChainData.data() + m_extraNonceOffsetInTemplate, &extra_nonce, EXTRA_NONCE_SIZE); SideChain& side_chain = m_pool->side_chain(); #if POOL_BLOCK_DEBUG { - std::vector buf = m_poolBlockTemplate->m_mainChainData; - buf.insert(buf.end(), m_poolBlockTemplate->m_sideChainData.begin(), m_poolBlockTemplate->m_sideChainData.end()); + std::vector buf = m_poolBlockTemplate->serialize_mainchain_data(); + const std::vector sidechain_data = m_poolBlockTemplate->serialize_sidechain_data(); + + memcpy(buf.data() + m_nonceOffset, &nonce, NONCE_SIZE); + memcpy(buf.data() + m_extraNonceOffsetInTemplate, &extra_nonce, EXTRA_NONCE_SIZE); + + buf.insert(buf.end(), sidechain_data.begin(), sidechain_data.end()); PoolBlock check; const int result = check.deserialize(buf.data(), buf.size(), side_chain, nullptr); diff --git a/src/crypto.cpp b/src/crypto.cpp index def5e30..1b42c94 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -154,10 +154,13 @@ static FORCEINLINE void derivation_to_scalar(const hash& derivation, size_t outp hash_to_scalar(data, static_cast(p - data), res); } -class Cache +class Cache : public nocopy_nomove { public: Cache() + : derivations(new DerivationsMap()) + , public_keys(new PublicKeysMap()) + , tx_keys(new TxKeysMap()) { uv_rwlock_init_checked(&derivations_lock); uv_rwlock_init_checked(&public_keys_lock); @@ -166,6 +169,10 @@ public: ~Cache() { + delete derivations; + delete public_keys; + delete tx_keys; + uv_rwlock_destroy(&derivations_lock); uv_rwlock_destroy(&public_keys_lock); uv_rwlock_destroy(&tx_keys_lock); @@ -180,8 +187,8 @@ public: derivation = {}; { ReadLock lock(derivations_lock); - auto it = derivations.find(index); - if (it != derivations.end()) { + auto it = derivations->find(index); + if (it != derivations->end()) { const DerivationEntry& entry = it->second; derivation = entry.m_derivation; if (entry.find_view_tag(output_index, view_tag)) { @@ -210,7 +217,7 @@ public: { WriteLock lock(derivations_lock); - DerivationEntry& entry = derivations.emplace(index, DerivationEntry{ derivation, {} }).first->second; + DerivationEntry& entry = derivations->emplace(index, DerivationEntry{ derivation, {} }).first->second; const uint32_t k = static_cast(output_index << 8) | view_tag; if (std::find(entry.m_viewTags.begin(), entry.m_viewTags.end(), k) == entry.m_viewTags.end()) { @@ -230,8 +237,8 @@ public: { ReadLock lock(public_keys_lock); - auto it = public_keys.find(index); - if (it != public_keys.end()) { + auto it = public_keys->find(index); + if (it != public_keys->end()) { derived_key = it->second; return true; } @@ -257,7 +264,7 @@ public: { WriteLock lock(public_keys_lock); - public_keys.emplace(index, derived_key); + public_keys->emplace(index, derived_key); } return true; @@ -271,8 +278,8 @@ public: { ReadLock lock(tx_keys_lock); - auto it = tx_keys.find(index); - if (it != tx_keys.end()) { + auto it = tx_keys->find(index); + if (it != tx_keys->end()) { pub = it->second.first; sec = it->second.second; return; @@ -291,15 +298,27 @@ public: { WriteLock lock(tx_keys_lock); - tx_keys.emplace(index, std::pair(pub, sec)); + tx_keys->emplace(index, std::pair(pub, sec)); } } void clear() { - { WriteLock lock(derivations_lock); derivations.clear(); } - { WriteLock lock(public_keys_lock); public_keys.clear(); } - { WriteLock lock(tx_keys_lock); tx_keys.clear(); } + { + WriteLock lock(derivations_lock); + delete derivations; + derivations = new DerivationsMap(); + } + { + WriteLock lock(public_keys_lock); + delete public_keys; + public_keys = new PublicKeysMap(); + } + { + WriteLock lock(tx_keys_lock); + delete tx_keys; + tx_keys = new TxKeysMap(); + } } private: @@ -319,14 +338,18 @@ private: } }; + typedef unordered_map, DerivationEntry> DerivationsMap; + typedef unordered_map, hash> PublicKeysMap; + typedef unordered_map, std::pair> TxKeysMap; + uv_rwlock_t derivations_lock; - unordered_map, DerivationEntry> derivations; + DerivationsMap* derivations; uv_rwlock_t public_keys_lock; - unordered_map, hash> public_keys; + PublicKeysMap* public_keys; uv_rwlock_t tx_keys_lock; - unordered_map, std::pair> tx_keys; + TxKeysMap* tx_keys; }; static Cache* cache = nullptr; @@ -379,7 +402,9 @@ void destroy_crypto_cache() void clear_crypto_cache() { - cache->clear(); + if (cache) { + cache->clear(); + } } } // namespace p2pool diff --git a/src/memory_leak_debug.cpp b/src/memory_leak_debug.cpp index ed0dca7..e3c4050 100644 --- a/src/memory_leak_debug.cpp +++ b/src/memory_leak_debug.cpp @@ -32,15 +32,48 @@ namespace p2pool { static bool track_memory = false; -constexpr size_t N = 2097152; -constexpr size_t MAX_FRAMES = 30; +constexpr size_t N = 1 << 22; +constexpr size_t MAX_FRAMES = 29; struct TrackedAllocation { void* p; void* stack_trace[MAX_FRAMES]; + uint64_t allocated_size; uint32_t thread_id; - uint32_t allocated_size; + + FORCEINLINE bool operator<(const TrackedAllocation& rhs) { return memcmp(stack_trace, rhs.stack_trace, sizeof(stack_trace)) < 0; } + FORCEINLINE bool operator==(const TrackedAllocation& rhs) { return memcmp(stack_trace, rhs.stack_trace, sizeof(stack_trace)) == 0; } + + void print(HANDLE h) const + { + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {}; + PSYMBOL_INFO pSymbol = reinterpret_cast(buffer); + + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + IMAGEHLP_LINE64 line{}; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + for (size_t j = 0; j < MAX_FRAMES; ++j) { + const DWORD64 address = reinterpret_cast(stack_trace[j]); + DWORD64 t1 = 0; + DWORD t2 = 0; + if (SymFromAddr(h, address, &t1, pSymbol) && SymGetLineFromAddr64(h, address, &t2, &line)) { + const char* s = line.FileName; + const char* file_name = nullptr; + while (*s) { + if ((*s == '\\') || (*s == '/')) { + file_name = s + 1; + } + ++s; + } + printf("%-25s %s (line %lu)\n", file_name ? file_name : line.FileName, pSymbol->Name, line.LineNumber); + } + } + printf("\n"); + } }; static_assert(sizeof(TrackedAllocation) == 256, ""); @@ -51,15 +84,62 @@ uint32_t first[N]; uint32_t next[N]; TrackedAllocation allocations[N]; uint32_t num_allocations = 0; +uint64_t total_allocated = 0; uint32_t cur_allocation_index = 1; +void show_top_10() +{ + TrackedAllocation* buf = reinterpret_cast(VirtualAlloc(nullptr, sizeof(TrackedAllocation) * N, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); + if (!buf) { + return; + } + + const HANDLE h = GetCurrentProcess(); + + { + p2pool::MutexLock lock(allocation_lock); + + TrackedAllocation* end = buf; + for (size_t i = 0; i < N; ++i) { + if (allocations[i].allocated_size) { + *(end++) = allocations[i]; + } + } + + std::sort(buf, end); + + TrackedAllocation* prev = buf; + for (TrackedAllocation* p = buf + 1; p < end; ++p) { + if (*p == *prev) { + prev->allocated_size += p->allocated_size; + } + else { + ++prev; + *prev = *p; + } + } + end = prev + 1; + + std::sort(buf, end, [](const auto& a, const auto& b) { return a.allocated_size > b.allocated_size; }); + + printf("%I64u total bytes allocated\n", total_allocated); + + for (TrackedAllocation* p = buf; (p < buf + 10) && (p < end); ++p) { + printf("%I64u bytes allocated at:\n", p->allocated_size); + p->print(h); + } + } + + VirtualFree(buf, 0, MEM_RELEASE); +} + FORCEINLINE static void add_alocation(void* p, size_t size) { if (!track_memory) { return; } - void* stack_trace[MAX_FRAMES]; + void* stack_trace[MAX_FRAMES] = {}; DWORD hash; CaptureStackBackTrace(1, MAX_FRAMES, stack_trace, &hash); @@ -74,6 +154,7 @@ FORCEINLINE static void add_alocation(void* p, size_t size) // Make N two times bigger if this triggers __debugbreak(); } + total_allocated += size; for (uint64_t i = cur_allocation_index;; i = (i + 1) & (N - 1)) { if (i && !allocations[i].allocated_size) { @@ -105,6 +186,7 @@ FORCEINLINE static void remove_allocation(void* p) for (uint32_t prev = 0, k = first[index]; k != 0; prev = k, k = next[k]) { if (allocations[k].p == p) { + total_allocated -= allocations[k].allocated_size; allocations[k].allocated_size = 0; if (prev) { next[prev] = next[k]; @@ -181,6 +263,8 @@ void* calloc_hook(size_t count, size_t size) noexcept void memory_tracking_start() { + SymInitialize(GetCurrentProcess(), NULL, TRUE); + using namespace p2pool; uv_replace_allocator(malloc_hook, realloc_hook, calloc_hook, free_hook); @@ -196,7 +280,6 @@ void memory_tracking_stop() uv_mutex_destroy(&allocation_lock); const HANDLE h = GetCurrentProcess(); - SymInitialize(h, NULL, TRUE); uint64_t total_leaks = 0; @@ -205,39 +288,16 @@ void memory_tracking_stop() if (t.allocated_size) { total_leaks += t.allocated_size; - char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {}; - PSYMBOL_INFO pSymbol = reinterpret_cast(buffer); - - pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); - pSymbol->MaxNameLen = MAX_SYM_NAME; - - IMAGEHLP_LINE64 line{}; - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - - printf("Memory leak detected, %u bytes allocated at %p by thread %u:\n", t.allocated_size, t.p, t.thread_id); - for (size_t j = 0; j < MAX_FRAMES; ++j) { - const DWORD64 address = reinterpret_cast(t.stack_trace[j]); - DWORD64 t1 = 0; - DWORD t2 = 0; - if (SymFromAddr(h, address, &t1, pSymbol) && SymGetLineFromAddr64(h, address, &t2, &line)) { - const char* s = line.FileName; - const char* file_name = nullptr; - while (*s) { - if ((*s == '\\') || (*s == '/')) { - file_name = s + 1; - } - ++s; - } - printf("%-25s %s (line %lu)\n", file_name ? file_name : line.FileName, pSymbol->Name, line.LineNumber); - } - } - printf("\n"); + printf("Memory leak detected, %I64u bytes allocated at %p by thread %u:\n", t.allocated_size, t.p, t.thread_id); + t.print(h); } } if (total_leaks > 0) { printf("%I64u bytes leaked\n\n", total_leaks); } + + SymCleanup(h); } NOINLINE void* operator new(size_t n) { return p2pool::allocate(n); } diff --git a/src/p2p_server.cpp b/src/p2p_server.cpp index 8323c54..8456d90 100644 --- a/src/p2p_server.cpp +++ b/src/p2p_server.cpp @@ -747,12 +747,16 @@ void P2PServer::broadcast(const PoolBlock& block) Broadcast* data = new Broadcast(); - data->blob.reserve(block.m_mainChainData.size() + block.m_sideChainData.size()); - data->blob = block.m_mainChainData; - data->blob.insert(data->blob.end(), block.m_sideChainData.begin(), block.m_sideChainData.end()); + int outputs_offset, outputs_blob_size; + const std::vector mainchain_data = block.serialize_mainchain_data(nullptr, nullptr, &outputs_offset, &outputs_blob_size); + const std::vector sidechain_data = block.serialize_sidechain_data(); - data->pruned_blob.reserve(block.m_mainChainData.size() + block.m_sideChainData.size() + 16 - block.m_mainChainOutputsBlobSize); - data->pruned_blob.assign(block.m_mainChainData.begin(), block.m_mainChainData.begin() + block.m_mainChainOutputsOffset); + data->blob.reserve(mainchain_data.size() + sidechain_data.size()); + data->blob = mainchain_data; + data->blob.insert(data->blob.end(), sidechain_data.begin(), sidechain_data.end()); + + data->pruned_blob.reserve(mainchain_data.size() + sidechain_data.size() + 16 - outputs_blob_size); + data->pruned_blob.assign(mainchain_data.begin(), mainchain_data.begin() + outputs_offset); // 0 outputs in the pruned blob data->pruned_blob.push_back(0); @@ -764,10 +768,10 @@ void P2PServer::broadcast(const PoolBlock& block) }); writeVarint(total_reward, data->pruned_blob); - writeVarint(block.m_mainChainOutputsBlobSize, data->pruned_blob); + writeVarint(outputs_blob_size, data->pruned_blob); - data->pruned_blob.insert(data->pruned_blob.end(), block.m_mainChainData.begin() + block.m_mainChainOutputsOffset + block.m_mainChainOutputsBlobSize, block.m_mainChainData.end()); - data->pruned_blob.insert(data->pruned_blob.end(), block.m_sideChainData.begin(), block.m_sideChainData.end()); + data->pruned_blob.insert(data->pruned_blob.end(), mainchain_data.begin() + outputs_offset + outputs_blob_size, mainchain_data.end()); + data->pruned_blob.insert(data->pruned_blob.end(), sidechain_data.begin(), sidechain_data.end()); data->ancestor_hashes.reserve(block.m_uncles.size() + 1); data->ancestor_hashes = block.m_uncles; diff --git a/src/p2pool.cpp b/src/p2pool.cpp index daa9198..247497b 100644 --- a/src/p2pool.cpp +++ b/src/p2pool.cpp @@ -301,6 +301,11 @@ void p2pool::handle_miner_data(MinerData& data) "\n---------------------------------------------------------------------------------------------------------------" ); + // Tx secret keys from all miners change every block, so cache can be cleared here + if (m_sideChain->precalcFinished()) { + clear_crypto_cache(); + } + if (!is_main_thread()) { update_block_template_async(); } @@ -440,7 +445,7 @@ void p2pool::submit_block_async(uint32_t template_id, uint32_t nonce, uint32_t e } } -void p2pool::submit_block_async(const std::vector& blob) +void p2pool::submit_block_async(std::vector&& blob) { { MutexLock lock(m_submitBlockDataLock); @@ -448,7 +453,7 @@ void p2pool::submit_block_async(const std::vector& blob) m_submitBlockData.template_id = 0; m_submitBlockData.nonce = 0; m_submitBlockData.extra_nonce = 0; - m_submitBlockData.blob = blob; + m_submitBlockData.blob = std::move(blob); } // If p2pool is stopped, m_submitBlockAsync is most likely already closed @@ -1322,8 +1327,6 @@ void p2pool::cleanup_mainchain_data(uint64_t height) void p2pool::api_update_block_found(const ChainMain* data) { - clear_crypto_cache(); - if (!m_api) { return; } diff --git a/src/p2pool.h b/src/p2pool.h index 3638271..1869ab7 100644 --- a/src/p2pool.h +++ b/src/p2pool.h @@ -74,7 +74,7 @@ public: virtual void handle_chain_main(ChainMain& data, const char* extra) override; void submit_block_async(uint32_t template_id, uint32_t nonce, uint32_t extra_nonce); - void submit_block_async(const std::vector& blob); + void submit_block_async(std::vector&& blob); void submit_sidechain_block(uint32_t template_id, uint32_t nonce, uint32_t extra_nonce); void update_block_template_async(bool is_alternative_block = false); diff --git a/src/pool_block.cpp b/src/pool_block.cpp index 15710d4..6e2e5f2 100644 --- a/src/pool_block.cpp +++ b/src/pool_block.cpp @@ -29,11 +29,7 @@ static constexpr char log_category_prefix[] = "PoolBlock "; namespace p2pool { PoolBlock::PoolBlock() - : m_mainChainHeaderSize(0) - , m_mainChainMinerTxSize(0) - , m_mainChainOutputsOffset(0) - , m_mainChainOutputsBlobSize(0) - , m_majorVersion(0) + : m_majorVersion(0) , m_minorVersion(0) , m_timestamp(0) , m_prevId{} @@ -57,12 +53,6 @@ PoolBlock::PoolBlock() , m_localTimestamp(seconds_since_epoch()) { uv_mutex_init_checked(&m_lock); - - m_mainChainData.reserve(48 * 1024); - m_outputs.reserve(2048); - m_transactions.reserve(256); - m_sideChainData.reserve(512); - m_uncles.reserve(8); } PoolBlock::PoolBlock(const PoolBlock& b) @@ -83,11 +73,11 @@ PoolBlock& PoolBlock::operator=(const PoolBlock& b) LOGERR(1, "operator= uv_mutex_trylock failed. Fix the code!"); } - m_mainChainData = b.m_mainChainData; - m_mainChainHeaderSize = b.m_mainChainHeaderSize; - m_mainChainMinerTxSize = b.m_mainChainMinerTxSize; - m_mainChainOutputsOffset = b.m_mainChainOutputsOffset; - m_mainChainOutputsBlobSize = b.m_mainChainOutputsBlobSize; +#if POOL_BLOCK_DEBUG + m_mainChainDataDebug = b.m_mainChainDataDebug; + m_sideChainDataDebug = b.m_sideChainDataDebug; +#endif + m_majorVersion = b.m_majorVersion; m_minorVersion = b.m_minorVersion; m_timestamp = b.m_timestamp; @@ -99,7 +89,6 @@ PoolBlock& PoolBlock::operator=(const PoolBlock& b) m_extraNonceSize = b.m_extraNonceSize; m_extraNonce = b.m_extraNonce; m_transactions = b.m_transactions; - m_sideChainData = b.m_sideChainData; m_minerWallet = b.m_minerWallet; m_txkeySec = b.m_txkeySec; m_parent = b.m_parent; @@ -129,43 +118,58 @@ PoolBlock::~PoolBlock() uv_mutex_destroy(&m_lock); } -void PoolBlock::serialize_mainchain_data(uint32_t nonce, uint32_t extra_nonce, const hash& sidechain_hash) +std::vector PoolBlock::serialize_mainchain_data(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size) const { MutexLock lock(m_lock); + return serialize_mainchain_data_nolock(header_size, miner_tx_size, outputs_offset, outputs_blob_size); +} - m_mainChainData.clear(); +std::vector PoolBlock::serialize_mainchain_data_nolock(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size) const +{ + std::vector data; + data.reserve(128 + m_outputs.size() * 39 + m_transactions.size() * HASH_SIZE); // Header - m_mainChainData.push_back(m_majorVersion); - m_mainChainData.push_back(m_minorVersion); - writeVarint(m_timestamp, m_mainChainData); - m_mainChainData.insert(m_mainChainData.end(), m_prevId.h, m_prevId.h + HASH_SIZE); - m_mainChainData.insert(m_mainChainData.end(), reinterpret_cast(&nonce), reinterpret_cast(&nonce) + NONCE_SIZE); - - m_mainChainHeaderSize = m_mainChainData.size(); + data.push_back(m_majorVersion); + data.push_back(m_minorVersion); + writeVarint(m_timestamp, data); + data.insert(data.end(), m_prevId.h, m_prevId.h + HASH_SIZE); + data.insert(data.end(), reinterpret_cast(&m_nonce), reinterpret_cast(&m_nonce) + NONCE_SIZE); + + const size_t header_size0 = data.size(); + if (header_size) { + *header_size = header_size0; + } // Miner tx - m_mainChainData.push_back(TX_VERSION); - writeVarint(m_txinGenHeight + MINER_REWARD_UNLOCK_TIME, m_mainChainData); - m_mainChainData.push_back(1); - m_mainChainData.push_back(TXIN_GEN); - writeVarint(m_txinGenHeight, m_mainChainData); + data.push_back(TX_VERSION); + writeVarint(m_txinGenHeight + MINER_REWARD_UNLOCK_TIME, data); + data.push_back(1); + data.push_back(TXIN_GEN); + writeVarint(m_txinGenHeight, data); + + const int outputs_offset0 = static_cast(data.size()); + if (outputs_offset) { + *outputs_offset = outputs_offset0; + } - m_mainChainOutputsOffset = static_cast(m_mainChainData.size()); + writeVarint(m_outputs.size(), data); - writeVarint(m_outputs.size(), m_mainChainData); + const uint8_t tx_type = get_tx_type(); - for (TxOutput& output : m_outputs) { - writeVarint(output.m_reward, m_mainChainData); - m_mainChainData.push_back(output.m_txType); - m_mainChainData.insert(m_mainChainData.end(), output.m_ephPublicKey.h, output.m_ephPublicKey.h + HASH_SIZE); + for (const TxOutput& output : m_outputs) { + writeVarint(output.m_reward, data); + data.push_back(tx_type); + data.insert(data.end(), output.m_ephPublicKey.h, output.m_ephPublicKey.h + HASH_SIZE); - if (output.m_txType == TXOUT_TO_TAGGED_KEY) { - m_mainChainData.push_back(output.m_viewTag); + if (tx_type == TXOUT_TO_TAGGED_KEY) { + data.push_back(static_cast(output.m_viewTag)); } } - m_mainChainOutputsBlobSize = static_cast(m_mainChainData.size()) - m_mainChainOutputsOffset; + if (outputs_blob_size) { + *outputs_blob_size = static_cast(data.size()) - outputs_offset0; + } uint8_t tx_extra[128]; uint8_t* p = tx_extra; @@ -183,7 +187,6 @@ void PoolBlock::serialize_mainchain_data(uint32_t nonce, uint32_t extra_nonce, c *(p++) = TX_EXTRA_NONCE; *(p++) = static_cast(extra_nonce_size); - m_extraNonce = extra_nonce; memcpy(p, &m_extraNonce, EXTRA_NONCE_SIZE); p += EXTRA_NONCE_SIZE; if (extra_nonce_size > EXTRA_NONCE_SIZE) { @@ -193,49 +196,70 @@ void PoolBlock::serialize_mainchain_data(uint32_t nonce, uint32_t extra_nonce, c *(p++) = TX_EXTRA_MERGE_MINING_TAG; *(p++) = HASH_SIZE; - memcpy(p, sidechain_hash.h, HASH_SIZE); + memcpy(p, m_sidechainId.h, HASH_SIZE); p += HASH_SIZE; - writeVarint(static_cast(p - tx_extra), m_mainChainData); - m_mainChainData.insert(m_mainChainData.end(), tx_extra, p); + writeVarint(static_cast(p - tx_extra), data); + data.insert(data.end(), tx_extra, p); + + data.push_back(0); - m_mainChainData.push_back(0); + if (miner_tx_size) { + *miner_tx_size = data.size() - header_size0; + } + + writeVarint(m_transactions.size() - 1, data); + const uint8_t* t = reinterpret_cast(m_transactions.data()); + data.insert(data.end(), t + HASH_SIZE, t + m_transactions.size() * HASH_SIZE); - m_mainChainMinerTxSize = m_mainChainData.size() - m_mainChainHeaderSize; +#if POOL_BLOCK_DEBUG + if (!m_mainChainDataDebug.empty() && (data != m_mainChainDataDebug)) { + LOGERR(1, "serialize_mainchain_data() has a bug, fix it!"); + panic(); + } +#endif - writeVarint(m_transactions.size() - 1, m_mainChainData); - const uint8_t* data = reinterpret_cast(m_transactions.data()); - m_mainChainData.insert(m_mainChainData.end(), data + HASH_SIZE, data + m_transactions.size() * HASH_SIZE); + return data; } -void PoolBlock::serialize_sidechain_data() +std::vector PoolBlock::serialize_sidechain_data() const { + std::vector data; + MutexLock lock(m_lock); - m_sideChainData.clear(); - m_sideChainData.reserve((m_uncles.size() + 4) * HASH_SIZE + 11); + data.reserve((m_uncles.size() + 4) * HASH_SIZE + 20); const hash& spend = m_minerWallet.spend_public_key(); const hash& view = m_minerWallet.view_public_key(); - m_sideChainData.insert(m_sideChainData.end(), spend.h, spend.h + HASH_SIZE); - m_sideChainData.insert(m_sideChainData.end(), view.h, view.h + HASH_SIZE); - m_sideChainData.insert(m_sideChainData.end(), m_txkeySec.h, m_txkeySec.h + HASH_SIZE); - m_sideChainData.insert(m_sideChainData.end(), m_parent.h, m_parent.h + HASH_SIZE); + data.insert(data.end(), spend.h, spend.h + HASH_SIZE); + data.insert(data.end(), view.h, view.h + HASH_SIZE); + data.insert(data.end(), m_txkeySec.h, m_txkeySec.h + HASH_SIZE); + data.insert(data.end(), m_parent.h, m_parent.h + HASH_SIZE); - writeVarint(m_uncles.size(), m_sideChainData); + writeVarint(m_uncles.size(), data); for (const hash& id : m_uncles) { - m_sideChainData.insert(m_sideChainData.end(), id.h, id.h + HASH_SIZE); + data.insert(data.end(), id.h, id.h + HASH_SIZE); } - writeVarint(m_sidechainHeight, m_sideChainData); + writeVarint(m_sidechainHeight, data); + + writeVarint(m_difficulty.lo, data); + writeVarint(m_difficulty.hi, data); - writeVarint(m_difficulty.lo, m_sideChainData); - writeVarint(m_difficulty.hi, m_sideChainData); + writeVarint(m_cumulativeDifficulty.lo, data); + writeVarint(m_cumulativeDifficulty.hi, data); - writeVarint(m_cumulativeDifficulty.lo, m_sideChainData); - writeVarint(m_cumulativeDifficulty.hi, m_sideChainData); +#if POOL_BLOCK_DEBUG + if (!m_sideChainDataDebug.empty() && (data != m_sideChainDataDebug)) { + LOGERR(1, "serialize_sidechain_data() has a bug, fix it!"); + panic(); + } +#endif + + return data; } void PoolBlock::reset_offchain_data() @@ -274,16 +298,19 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const { MutexLock lock(m_lock); - if (!m_mainChainHeaderSize || !m_mainChainMinerTxSize || (m_mainChainData.size() < m_mainChainHeaderSize + m_mainChainMinerTxSize)) { + size_t header_size, miner_tx_size; + const std::vector mainchain_data = serialize_mainchain_data_nolock(&header_size, &miner_tx_size, nullptr, nullptr); + + if (!header_size || !miner_tx_size || (mainchain_data.size() < header_size + miner_tx_size)) { LOGERR(1, "tried to calculate PoW of uninitialized block"); return false; } - blob_size = m_mainChainHeaderSize; - memcpy(blob, m_mainChainData.data(), blob_size); + blob_size = header_size; + memcpy(blob, mainchain_data.data(), blob_size); - uint8_t* miner_tx = m_mainChainData.data() + m_mainChainHeaderSize; - keccak(miner_tx, static_cast(m_mainChainMinerTxSize) - 1, reinterpret_cast(hashes), HASH_SIZE); + const uint8_t* miner_tx = mainchain_data.data() + header_size; + keccak(miner_tx, static_cast(miner_tx_size) - 1, reinterpret_cast(hashes), HASH_SIZE); count = m_transactions.size(); uint8_t* h = reinterpret_cast(m_transactions.data()); @@ -329,11 +356,13 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const uint64_t PoolBlock::get_payout(const Wallet& w) const { + const uint8_t tx_type = get_tx_type(); + for (size_t i = 0, n = m_outputs.size(); i < n; ++i) { const TxOutput& out = m_outputs[i]; hash eph_public_key; - if (out.m_txType == TXOUT_TO_TAGGED_KEY) { + if (tx_type == TXOUT_TO_TAGGED_KEY) { if (w.get_eph_public_key_with_view_tag(m_txkeySec, i, eph_public_key, out.m_viewTag) && (eph_public_key == out.m_ephPublicKey)) { return out.m_reward; } diff --git a/src/pool_block.h b/src/pool_block.h index 8231d18..ba06155 100644 --- a/src/pool_block.h +++ b/src/pool_block.h @@ -63,13 +63,12 @@ struct PoolBlock mutable uv_mutex_t m_lock; - // Monero block template - std::vector m_mainChainData; - size_t m_mainChainHeaderSize; - size_t m_mainChainMinerTxSize; - int m_mainChainOutputsOffset; - int m_mainChainOutputsBlobSize; +#if POOL_BLOCK_DEBUG + std::vector m_mainChainDataDebug; + std::vector m_sideChainDataDebug; +#endif + // Monero block template uint8_t m_majorVersion; uint8_t m_minorVersion; uint64_t m_timestamp; @@ -81,15 +80,16 @@ struct PoolBlock struct TxOutput { - FORCEINLINE TxOutput() : m_reward(0), m_ephPublicKey(), m_txType(0), m_viewTag(0) {} - FORCEINLINE TxOutput(uint64_t r, const hash& k, uint8_t tx_type, uint8_t view_tag) : m_reward(r), m_ephPublicKey(k), m_txType(tx_type), m_viewTag(view_tag) {} + FORCEINLINE TxOutput() : m_ephPublicKey(), m_reward(0), m_viewTag(0) {} + FORCEINLINE TxOutput(uint64_t r, const hash& k, uint8_t view_tag) : m_ephPublicKey(k), m_reward(r), m_viewTag(view_tag) {} - uint64_t m_reward; hash m_ephPublicKey; - uint8_t m_txType; - uint8_t m_viewTag; + uint64_t m_reward : 56; + uint64_t m_viewTag : 8; }; + static_assert(sizeof(TxOutput) == sizeof(hash) + sizeof(uint64_t), "TxOutput bit packing didn't work with this compiler, fix the code!"); + std::vector m_outputs; hash m_txkeyPub; @@ -99,9 +99,6 @@ struct PoolBlock // All block transaction hashes including the miner transaction hash at index 0 std::vector m_transactions; - // Side-chain data - std::vector m_sideChainData; - // Miner's wallet Wallet m_minerWallet{ nullptr }; @@ -134,8 +131,9 @@ struct PoolBlock uint64_t m_localTimestamp; - void serialize_mainchain_data(uint32_t nonce, uint32_t extra_nonce, const hash& sidechain_hash); - void serialize_sidechain_data(); + std::vector serialize_mainchain_data(size_t* header_size = nullptr, size_t* miner_tx_size = nullptr, int* outputs_offset = nullptr, int* outputs_blob_size = nullptr) const; + std::vector serialize_mainchain_data_nolock(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size) const; + std::vector serialize_sidechain_data() const; int deserialize(const uint8_t* data, size_t size, const SideChain& sidechain, uv_loop_t* loop); void reset_offchain_data(); diff --git a/src/pool_block_parser.inl b/src/pool_block_parser.inl index 98f358a..3d21626 100644 --- a/src/pool_block_parser.inl +++ b/src/pool_block_parser.inl @@ -75,8 +75,6 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si const int nonce_offset = static_cast(data - data_begin); READ_BUF(&m_nonce, NONCE_SIZE); - m_mainChainHeaderSize = data - data_begin; - EXPECT_BYTE(TX_VERSION); uint64_t unlock_height; @@ -89,12 +87,13 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si if (unlock_height != m_txinGenHeight + MINER_REWARD_UNLOCK_TIME) return __LINE__; std::vector outputs_blob; - m_mainChainOutputsOffset = static_cast(data - data_begin); + const int outputs_offset = static_cast(data - data_begin); uint64_t num_outputs; READ_VARINT(num_outputs); uint64_t total_reward = 0; + int outputs_blob_size; if (num_outputs > 0) { // Outputs are in the buffer, just read them @@ -105,31 +104,32 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si if (num_outputs > std::numeric_limits::max() / MIN_OUTPUT_SIZE) return __LINE__; if (static_cast(data_end - data) < num_outputs * MIN_OUTPUT_SIZE) return __LINE__; - m_outputs.clear(); - m_outputs.reserve(num_outputs); + m_outputs.resize(num_outputs); + m_outputs.shrink_to_fit(); const uint8_t expected_tx_type = get_tx_type(); for (uint64_t i = 0; i < num_outputs; ++i) { - TxOutput t; + TxOutput& t = m_outputs[i]; - READ_VARINT(t.m_reward); - total_reward += t.m_reward; + uint64_t reward; + READ_VARINT(reward); + t.m_reward = reward; + total_reward += reward; EXPECT_BYTE(expected_tx_type); - t.m_txType = expected_tx_type; READ_BUF(t.m_ephPublicKey.h, HASH_SIZE); if (expected_tx_type == TXOUT_TO_TAGGED_KEY) { - READ_BYTE(t.m_viewTag); + uint8_t view_tag; + READ_BYTE(view_tag); + t.m_viewTag = view_tag; } - - m_outputs.emplace_back(std::move(t)); } - m_mainChainOutputsBlobSize = static_cast(data - data_begin) - m_mainChainOutputsOffset; - outputs_blob.assign(data_begin + m_mainChainOutputsOffset, data); + outputs_blob_size = static_cast(data - data_begin) - outputs_offset; + outputs_blob.assign(data_begin + outputs_offset, data); } else { // Outputs are not in the buffer and must be calculated from sidechain data @@ -144,7 +144,7 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si return __LINE__; } - m_mainChainOutputsBlobSize = static_cast(tmp); + outputs_blob_size = static_cast(tmp); } // Technically some p2pool node could keep stuffing block with transactions until reward is less than 0.6 XMR @@ -153,13 +153,12 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si return __LINE__; } - const int outputs_actual_blob_size = static_cast(data - data_begin) - m_mainChainOutputsOffset; - - if (m_mainChainOutputsBlobSize < outputs_actual_blob_size) { + const int outputs_actual_blob_size = static_cast(data - data_begin) - outputs_offset; + if (outputs_blob_size < outputs_actual_blob_size) { return __LINE__; } - const int outputs_blob_size_diff = m_mainChainOutputsBlobSize - outputs_actual_blob_size; + const int outputs_blob_size_diff = outputs_blob_size - outputs_actual_blob_size; uint64_t tx_extra_size; READ_VARINT(tx_extra_size); @@ -191,8 +190,6 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si EXPECT_BYTE(0); - m_mainChainMinerTxSize = (data - data_begin) + outputs_blob_size_diff - m_mainChainHeaderSize; - uint64_t num_transactions; READ_VARINT(num_transactions); @@ -208,12 +205,14 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si m_transactions.emplace_back(std::move(id)); } - m_mainChainData.reserve((data - data_begin) + outputs_blob_size_diff); - m_mainChainData.assign(data_begin, data_begin + m_mainChainOutputsOffset); - m_mainChainData.insert(m_mainChainData.end(), m_mainChainOutputsBlobSize, 0); - m_mainChainData.insert(m_mainChainData.end(), data_begin + m_mainChainOutputsOffset + outputs_actual_blob_size, data); +#if POOL_BLOCK_DEBUG + m_mainChainDataDebug.reserve((data - data_begin) + outputs_blob_size_diff); + m_mainChainDataDebug.assign(data_begin, data_begin + outputs_offset); + m_mainChainDataDebug.insert(m_mainChainDataDebug.end(), outputs_blob_size, 0); + m_mainChainDataDebug.insert(m_mainChainDataDebug.end(), data_begin + outputs_offset + outputs_actual_blob_size, data); const uint8_t* sidechain_data_begin = data; +#endif hash spend_pub_key; hash view_pub_key; @@ -276,16 +275,18 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si return __LINE__; } - if (static_cast(outputs_blob.size()) != m_mainChainOutputsBlobSize) { + if (static_cast(outputs_blob.size()) != outputs_blob_size) { return __LINE__; } - memcpy(m_mainChainData.data() + m_mainChainOutputsOffset, outputs_blob.data(), m_mainChainOutputsBlobSize); +#if POOL_BLOCK_DEBUG + memcpy(m_mainChainDataDebug.data() + outputs_offset, outputs_blob.data(), outputs_blob_size); +#endif hash check; const std::vector& consensus_id = sidechain.consensus_id(); keccak_custom( - [this, nonce_offset, extra_nonce_offset, sidechain_hash_offset, data_begin, data_end, &consensus_id, &outputs_blob, outputs_blob_size_diff](int offset) -> uint8_t + [nonce_offset, extra_nonce_offset, sidechain_hash_offset, data_begin, data_end, &consensus_id, &outputs_blob, outputs_blob_size_diff, outputs_offset, outputs_blob_size](int offset) -> uint8_t { uint32_t k = static_cast(offset - nonce_offset); if (k < NONCE_SIZE) { @@ -304,11 +305,11 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si const int data_size = static_cast((data_end - data_begin) + outputs_blob_size_diff); if (offset < data_size) { - if (offset < m_mainChainOutputsOffset) { + if (offset < outputs_offset) { return data_begin[offset]; } - else if (offset < m_mainChainOutputsOffset + m_mainChainOutputsBlobSize) { - const int tmp = offset - m_mainChainOutputsOffset; + else if (offset < outputs_offset + outputs_blob_size) { + const int tmp = offset - outputs_offset; return outputs_blob[tmp]; } else { @@ -325,7 +326,9 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si return __LINE__; } - m_sideChainData.assign(sidechain_data_begin, data_end); +#if POOL_BLOCK_DEBUG + m_sideChainDataDebug.assign(sidechain_data_begin, data_end); +#endif } catch (std::exception& e) { const char* msg = e.what(); diff --git a/src/side_chain.cpp b/src/side_chain.cpp index f1e9994..fb937a5 100644 --- a/src/side_chain.cpp +++ b/src/side_chain.cpp @@ -32,6 +32,7 @@ #include "stratum_server.h" #include "params.h" #include "json_parsers.h" +#include "crypto.h" #include #include #include @@ -169,7 +170,10 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name) // Use between 1 and 8 threads if (numThreads < 1) numThreads = 1; + +#ifndef _DEBUG if (numThreads > 8) numThreads = 8; +#endif LOGINFO(4, "running " << numThreads << " pre-calculation workers"); @@ -527,7 +531,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector& missing_ MinerData miner_data = m_pool->miner_data(); if ((block.m_prevId == miner_data.prev_id) && miner_data.difficulty.check_pow(pow_hash)) { LOGINFO(0, log::LightGreen() << "add_external_block: block " << block.m_sidechainId << " has enough PoW for Monero network, submitting it"); - m_pool->submit_block_async(block.m_mainChainData); + m_pool->submit_block_async(block.serialize_mainchain_data()); } else { difficulty_type diff; @@ -536,7 +540,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector& missing_ } else if (diff.check_pow(pow_hash)) { LOGINFO(0, log::LightGreen() << "add_external_block: block " << block.m_sidechainId << " has enough PoW for Monero height " << block.m_txinGenHeight << ", submitting it"); - m_pool->submit_block_async(block.m_mainChainData); + m_pool->submit_block_async(block.serialize_mainchain_data()); } } @@ -675,10 +679,10 @@ bool SideChain::get_block_blob(const hash& id, std::vector& blob) const return false; } - blob.reserve(block->m_mainChainData.size() + block->m_sideChainData.size()); + blob = block->serialize_mainchain_data(); + const std::vector sidechain_data = block->serialize_sidechain_data(); + blob.insert(blob.end(), sidechain_data.begin(), sidechain_data.end()); - blob = block->m_mainChainData; - blob.insert(blob.end(), block->m_sideChainData.begin(), block->m_sideChainData.end()); return true; } @@ -696,13 +700,15 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v blob.reserve(n * 39 + 64); writeVarint(n, blob); + const uint8_t tx_type = b->get_tx_type(); + for (const PoolBlock::TxOutput& output : b->m_outputs) { writeVarint(output.m_reward, blob); - blob.emplace_back(output.m_txType); + blob.emplace_back(tx_type); blob.insert(blob.end(), output.m_ephPublicKey.h, output.m_ephPublicKey.h + HASH_SIZE); - if (output.m_txType == TXOUT_TO_TAGGED_KEY) { - blob.emplace_back(output.m_viewTag); + if (tx_type == TXOUT_TO_TAGGED_KEY) { + blob.emplace_back(static_cast(output.m_viewTag)); } } @@ -808,9 +814,11 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v blob.emplace_back(view_tag); } - block->m_outputs.emplace_back(tmpRewards[i], eph_public_key, tx_type, view_tag); + block->m_outputs.emplace_back(tmpRewards[i], eph_public_key, view_tag); } + block->m_outputs.shrink_to_fit(); + if (loop) { // this will cause all helper jobs to finish immediately counter = -1; @@ -911,12 +919,13 @@ void SideChain::print_status(bool obtain_sidechain_lock) const } const Wallet& w = m_pool->params().m_wallet; + const uint8_t tx_type = tip->get_tx_type(); hash eph_public_key; for (size_t i = 0, n = tip->m_outputs.size(); i < n; ++i) { const PoolBlock::TxOutput& out = tip->m_outputs[i]; if (!your_reward) { - if (out.m_txType == TXOUT_TO_TAGGED_KEY) { + if (tx_type == TXOUT_TO_TAGGED_KEY) { if (w.get_eph_public_key_with_view_tag(tip->m_txkeySec, i, eph_public_key, out.m_viewTag) && (out.m_ephPublicKey == eph_public_key)) { your_reward = out.m_reward; } @@ -983,11 +992,12 @@ double SideChain::get_reward_share(const Wallet& w) const const PoolBlock* tip = m_chainTip; if (tip) { + const uint8_t tx_type = tip->get_tx_type(); hash eph_public_key; for (size_t i = 0, n = tip->m_outputs.size(); i < n; ++i) { const PoolBlock::TxOutput& out = tip->m_outputs[i]; if (!reward) { - if (out.m_txType == TXOUT_TO_TAGGED_KEY) { + if (tx_type == TXOUT_TO_TAGGED_KEY) { if (w.get_eph_public_key_with_view_tag(tip->m_txkeySec, i, eph_public_key, out.m_viewTag) && (out.m_ephPublicKey == eph_public_key)) { reward = out.m_reward; } @@ -1538,6 +1548,8 @@ void SideChain::verify(PoolBlock* block) return; } + const uint8_t tx_type = block->get_tx_type(); + for (size_t i = 0, n = rewards.size(); i < n; ++i) { const PoolBlock::TxOutput& out = block->m_outputs[i]; @@ -1561,7 +1573,7 @@ void SideChain::verify(PoolBlock* block) return; } - if ((out.m_txType == TXOUT_TO_TAGGED_KEY) && (out.m_viewTag != view_tag)) { + if ((tx_type == TXOUT_TO_TAGGED_KEY) && (out.m_viewTag != view_tag)) { LOGWARN(3, "block at height = " << block->m_sidechainHeight << ", id = " << block->m_sidechainId << ", mainchain height = " << block->m_txinGenHeight << @@ -1622,6 +1634,8 @@ void SideChain::update_chain_tip(const PoolBlock* block) if (s) { s->reset_share_counters(); } + // Also clear cache because it has data from all old blocks now + clear_crypto_cache(); LOGINFO(0, log::LightCyan() << "SYNCHRONIZED"); } } @@ -2125,6 +2139,9 @@ void SideChain::finish_precalc() LOGERR(1, "exception in finish_precalc(): " << e.what()); } + // Also clear cache because it has data from all old blocks now + clear_crypto_cache(); + #ifdef DEV_TEST_SYNC if (m_pool) { LOGINFO(0, log::LightGreen() << "[DEV] Synchronization finished successfully, stopping P2Pool now"); diff --git a/tests/src/pool_block_tests.cpp b/tests/src/pool_block_tests.cpp index 4d644c0..a34d88b 100644 --- a/tests/src/pool_block_tests.cpp +++ b/tests/src/pool_block_tests.cpp @@ -51,11 +51,16 @@ TEST(pool_block, deserialize) ASSERT_EQ(b.deserialize(buf.data(), buf.size(), sidechain, nullptr), 0); - ASSERT_EQ(b.m_mainChainData.size(), 5607); - ASSERT_EQ(b.m_mainChainHeaderSize, 43); - ASSERT_EQ(b.m_mainChainMinerTxSize, 506); - ASSERT_EQ(b.m_mainChainOutputsOffset, 54); - ASSERT_EQ(b.m_mainChainOutputsBlobSize, 420); + size_t header_size, miner_tx_size; + int outputs_offset, outputs_blob_size; + const std::vector mainchain_data = b.serialize_mainchain_data(&header_size, &miner_tx_size, &outputs_offset, &outputs_blob_size); + + ASSERT_EQ(mainchain_data.size(), 5607); + ASSERT_EQ(header_size, 43); + ASSERT_EQ(miner_tx_size, 506); + ASSERT_EQ(outputs_offset, 54); + ASSERT_EQ(outputs_blob_size, 420); + ASSERT_EQ(b.m_majorVersion, 14); ASSERT_EQ(b.m_minorVersion, 14); ASSERT_EQ(b.m_timestamp, 1630934403); @@ -65,7 +70,6 @@ TEST(pool_block, deserialize) ASSERT_EQ(b.m_extraNonceSize, 4); ASSERT_EQ(b.m_extraNonce, 28); ASSERT_EQ(b.m_transactions.size(), 159); - ASSERT_EQ(b.m_sideChainData.size(), 146); ASSERT_EQ(b.m_uncles.size(), 0); ASSERT_EQ(b.m_sidechainHeight, 53450); ASSERT_EQ(b.m_difficulty.lo, 319296691);