Implement batch block transfer with server side ancestor fill, BLOCK_BATCH_MAX_COUNT reduced from 50 to 10 to avoid contention warnings, fix get_seed failure in add_external_block returning false
This commit is contained in:
@@ -3108,7 +3108,10 @@ bool P2PServer::P2PClient::on_block_batch_request(const uint8_t* buf, uint32_t s
|
||||
|
||||
// Collect all requested blocks
|
||||
std::vector<std::vector<uint8_t>> blobs;
|
||||
blobs.reserve(count);
|
||||
blobs.reserve(BLOCK_BATCH_MAX_COUNT);
|
||||
|
||||
hash last_parent;
|
||||
size_t total_response_size = 2; // msg id + count byte
|
||||
|
||||
const uint8_t* p = buf + 1;
|
||||
for (uint8_t i = 0; i < count; ++i) {
|
||||
@@ -3117,15 +3120,41 @@ bool P2PServer::P2PClient::on_block_batch_request(const uint8_t* buf, uint32_t s
|
||||
p += HASH_SIZE;
|
||||
|
||||
std::vector<uint8_t> blob;
|
||||
const PoolBlock* block = sidechain.get_block_blob(id, blob);
|
||||
hash parent;
|
||||
const PoolBlock* block = sidechain.get_block_blob(id, blob, &parent);
|
||||
|
||||
if (!block && !id.empty()) {
|
||||
LOGWARN(6, "batch request: block " << id << " not found");
|
||||
}
|
||||
|
||||
if (block) {
|
||||
last_parent = parent;
|
||||
}
|
||||
|
||||
total_response_size += sizeof(uint32_t) + blob.size();
|
||||
blobs.push_back(std::move(blob));
|
||||
}
|
||||
|
||||
// Fill remaining slots with ancestor blocks so the peer can sync a full chain segment per request
|
||||
while (blobs.size() < BLOCK_BATCH_MAX_COUNT && !last_parent.empty()) {
|
||||
std::vector<uint8_t> blob;
|
||||
hash parent;
|
||||
const PoolBlock* ancestor = sidechain.get_block_blob(last_parent, blob, &parent);
|
||||
|
||||
if (!ancestor || blob.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
const size_t entry_size = sizeof(uint32_t) + blob.size();
|
||||
if (total_response_size + entry_size > P2P_BUF_SIZE) {
|
||||
break;
|
||||
}
|
||||
|
||||
total_response_size += entry_size;
|
||||
blobs.push_back(std::move(blob));
|
||||
last_parent = parent;
|
||||
}
|
||||
|
||||
// Send batch response
|
||||
return server->send(this,
|
||||
[this, &blobs](uint8_t* buf, size_t buf_size) -> size_t
|
||||
@@ -4333,6 +4362,8 @@ void P2PServer::P2PClient::post_handle_incoming_block(p2pool* pool, const PoolBl
|
||||
|
||||
ReadLock lock(server->m_cachedBlocksLock);
|
||||
|
||||
// Collect non-cached missing block IDs to request
|
||||
std::vector<hash> to_request;
|
||||
for (const hash& id : missing_blocks) {
|
||||
if (server->m_cachedBlocks) {
|
||||
auto it = server->m_cachedBlocks->find(id);
|
||||
@@ -4349,30 +4380,68 @@ void P2PServer::P2PClient::post_handle_incoming_block(p2pool* pool, const PoolBl
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool send_result = server->send(this,
|
||||
[this, &id](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
LOGINFO(5, "[post_handle_incoming_block] sending BLOCK_REQUEST for id = " << id << " to " << static_cast<char*>(m_addrString));
|
||||
to_request.push_back(id);
|
||||
}
|
||||
|
||||
if (buf_size < 1 + HASH_SIZE) {
|
||||
if (to_request.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use batch requests for 1.6+ peers so the server can fill in ancestors
|
||||
if (m_protocolVersion >= PROTOCOL_VERSION_1_6) {
|
||||
const bool send_result = server->send(this,
|
||||
[this, &to_request](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
LOGINFO(5, "[post_handle_incoming_block] sending BLOCK_BATCH_REQUEST for " << to_request.size() << " block(s) to " << static_cast<char*>(m_addrString));
|
||||
|
||||
const size_t needed = 2 + to_request.size() * HASH_SIZE;
|
||||
if (buf_size < needed) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p = buf;
|
||||
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_BATCH_REQUEST);
|
||||
*(p++) = static_cast<uint8_t>(to_request.size());
|
||||
|
||||
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
|
||||
|
||||
memcpy(p, id.h, HASH_SIZE);
|
||||
p += HASH_SIZE;
|
||||
for (const hash& h : to_request) {
|
||||
memcpy(p, h.h, HASH_SIZE);
|
||||
p += HASH_SIZE;
|
||||
}
|
||||
|
||||
return p - buf;
|
||||
});
|
||||
|
||||
if (!send_result) {
|
||||
return;
|
||||
if (send_result) {
|
||||
for (const hash& h : to_request) {
|
||||
m_blockPendingRequests.push_back(*h.u64());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Legacy: individual BLOCK_REQUEST for older peers
|
||||
for (const hash& id : to_request) {
|
||||
const bool send_result = server->send(this,
|
||||
[this, &id](uint8_t* buf, size_t buf_size) -> size_t
|
||||
{
|
||||
LOGINFO(5, "[post_handle_incoming_block] sending BLOCK_REQUEST for id = " << id << " to " << static_cast<char*>(m_addrString));
|
||||
|
||||
m_blockPendingRequests.push_back(*id.u64());
|
||||
if (buf_size < 1 + HASH_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* p = buf;
|
||||
*(p++) = static_cast<uint8_t>(MessageId::BLOCK_REQUEST);
|
||||
memcpy(p, id.h, HASH_SIZE);
|
||||
p += HASH_SIZE;
|
||||
|
||||
return p - buf;
|
||||
});
|
||||
|
||||
if (!send_result) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_blockPendingRequests.push_back(*id.u64());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ static constexpr uint32_t PROTOCOL_VERSION_1_6 = 0x00010006UL;
|
||||
static constexpr uint32_t SUPPORTED_PROTOCOL_VERSION = PROTOCOL_VERSION_1_6;
|
||||
|
||||
// Batch block request limits
|
||||
static constexpr uint8_t BLOCK_BATCH_MAX_COUNT = 50;
|
||||
static constexpr uint8_t BLOCK_BATCH_MAX_COUNT = 10;
|
||||
|
||||
class P2PServer : public TCPServer
|
||||
{
|
||||
|
||||
@@ -653,8 +653,9 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& missing_
|
||||
m_pool->fetch_mainchain_block(seed_height);
|
||||
}
|
||||
// Always forget so block can be re-processed when mainchain data arrives
|
||||
// Return true: missing seed is a local problem, not the peer's fault - don't ban them
|
||||
forget_incoming_block(block);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!block.get_pow_hash(m_pool->hasher(), block.m_txinGenHeight, block.m_seed, block.m_powHash)) {
|
||||
@@ -878,7 +879,7 @@ void SideChain::watch_mainchain_block(const ChainMain& data, const hash& possibl
|
||||
m_watchBlockMerkleRoot = possible_merkle_root;
|
||||
}
|
||||
|
||||
const PoolBlock* SideChain::get_block_blob(const hash& id, std::vector<uint8_t>& blob) const
|
||||
const PoolBlock* SideChain::get_block_blob(const hash& id, std::vector<uint8_t>& blob, hash* parent_hash_out) const
|
||||
{
|
||||
ReadLock lock(m_sidechainLock);
|
||||
|
||||
@@ -908,6 +909,10 @@ const PoolBlock* SideChain::get_block_blob(const hash& id, std::vector<uint8_t>&
|
||||
const std::vector<uint8_t> sidechain_data = block->serialize_sidechain_data();
|
||||
blob.insert(blob.end(), sidechain_data.begin(), sidechain_data.end());
|
||||
|
||||
if (parent_hash_out) {
|
||||
*parent_hash_out = block->m_parent;
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
bool get_genesis_info(hash& id, uint64_t& timestamp, uint64_t& height) const;
|
||||
void purge_sidechain();
|
||||
|
||||
[[nodiscard]] const PoolBlock* get_block_blob(const hash& id, std::vector<uint8_t>& blob) const;
|
||||
[[nodiscard]] const PoolBlock* get_block_blob(const hash& id, std::vector<uint8_t>& blob, hash* parent_hash_out = nullptr) const;
|
||||
[[nodiscard]] bool get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::vector<uint8_t>& blob, uv_loop_t* loop) const;
|
||||
|
||||
void print_status(bool obtain_sidechain_lock = true) const;
|
||||
|
||||
Reference in New Issue
Block a user