| 3470 | } |
| 3471 | |
| 3472 | void PeerManagerImpl::ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const BlockTransactions& block_transactions) |
| 3473 | { |
| 3474 | std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); |
| 3475 | bool fBlockRead{false}; |
| 3476 | { |
| 3477 | LOCK(cs_main); |
| 3478 | |
| 3479 | auto range_flight = mapBlocksInFlight.equal_range(block_transactions.blockhash); |
| 3480 | size_t already_in_flight = std::distance(range_flight.first, range_flight.second); |
| 3481 | bool requested_block_from_this_peer{false}; |
| 3482 | |
| 3483 | // Multimap ensures ordering of outstanding requests. It's either empty or first in line. |
| 3484 | bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.GetId()); |
| 3485 | |
| 3486 | while (range_flight.first != range_flight.second) { |
| 3487 | auto [node_id, block_it] = range_flight.first->second; |
| 3488 | if (node_id == pfrom.GetId() && block_it->partialBlock) { |
| 3489 | requested_block_from_this_peer = true; |
| 3490 | break; |
| 3491 | } |
| 3492 | range_flight.first++; |
| 3493 | } |
| 3494 | |
| 3495 | if (!requested_block_from_this_peer) { |
| 3496 | LogDebug(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId()); |
| 3497 | return; |
| 3498 | } |
| 3499 | |
| 3500 | PartiallyDownloadedBlock& partialBlock = *range_flight.first->second.second->partialBlock; |
| 3501 | |
| 3502 | if (partialBlock.header.IsNull()) { |
| 3503 | // It is possible for the header to be empty if a previous call to FillBlock wiped the header, but left |
| 3504 | // the PartiallyDownloadedBlock pointer around (i.e. did not call RemoveBlockRequest). In this case, we |
| 3505 | // should not call LookupBlockIndex below. |
| 3506 | RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); |
| 3507 | Misbehaving(peer, "previous compact block reconstruction attempt failed"); |
| 3508 | LogDebug(BCLog::NET, "Peer %d sent compact block transactions multiple times", pfrom.GetId()); |
| 3509 | return; |
| 3510 | } |
| 3511 | |
| 3512 | // We should not have gotten this far in compact block processing unless it's attached to a known header |
| 3513 | const CBlockIndex* prev_block{Assume(m_chainman.m_blockman.LookupBlockIndex(partialBlock.header.hashPrevBlock))}; |
| 3514 | ReadStatus status = partialBlock.FillBlock(*pblock, block_transactions.txn, |
| 3515 | /*segwit_active=*/DeploymentActiveAfter(prev_block, m_chainman, Consensus::DEPLOYMENT_SEGWIT)); |
| 3516 | if (status == READ_STATUS_INVALID) { |
| 3517 | RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect |
| 3518 | Misbehaving(peer, "invalid compact block/non-matching block transactions"); |
| 3519 | return; |
| 3520 | } else if (status == READ_STATUS_FAILED) { |
| 3521 | if (first_in_flight) { |
| 3522 | // Might have collided, fall back to getdata now :( |
| 3523 | // We keep the failed partialBlock to disallow processing another compact block announcement from the same |
| 3524 | // peer for the same block. We let the full block download below continue under the same m_downloading_since |
| 3525 | // timer. |
| 3526 | std::vector<CInv> invs; |
| 3527 | invs.emplace_back(MSG_BLOCK | GetFetchFlags(peer), block_transactions.blockhash); |
| 3528 | MakeAndPushMessage(pfrom, NetMsgType::GETDATA, invs); |
| 3529 | } else { |
nothing calls this directly
no test coverage detected