Process the next batch of headers received from our peer. * Validate and store commitments, and compare total chainwork to our target to * see if we can switch to REDOWNLOAD mode. */
| 66 | * Validate and store commitments, and compare total chainwork to our target to |
| 67 | * see if we can switch to REDOWNLOAD mode. */ |
| 68 | HeadersSyncState::ProcessingResult HeadersSyncState::ProcessNextHeaders( |
| 69 | std::span<const CBlockHeader> received_headers, const bool full_headers_message) |
| 70 | { |
| 71 | ProcessingResult ret; |
| 72 | |
| 73 | Assume(!received_headers.empty()); |
| 74 | if (received_headers.empty()) return ret; |
| 75 | |
| 76 | Assume(m_download_state != State::FINAL); |
| 77 | if (m_download_state == State::FINAL) return ret; |
| 78 | |
| 79 | if (m_download_state == State::PRESYNC) { |
| 80 | // During PRESYNC, we minimally validate block headers and |
| 81 | // occasionally add commitments to them, until we reach our work |
| 82 | // threshold (at which point m_download_state is updated to REDOWNLOAD). |
| 83 | ret.success = ValidateAndStoreHeadersCommitments(received_headers); |
| 84 | if (ret.success) { |
| 85 | if (full_headers_message || m_download_state == State::REDOWNLOAD) { |
| 86 | // A full headers message means the peer may have more to give us; |
| 87 | // also if we just switched to REDOWNLOAD then we need to re-request |
| 88 | // headers from the beginning. |
| 89 | ret.request_more = true; |
| 90 | } else { |
| 91 | Assume(m_download_state == State::PRESYNC); |
| 92 | // If we're in PRESYNC and we get a non-full headers |
| 93 | // message, then the peer's chain has ended and definitely doesn't |
| 94 | // have enough work, so we can stop our sync. |
| 95 | LogDebug(BCLog::NET, "Initial headers sync aborted with peer=%d: incomplete headers message at height=%i (presync phase)\n", m_id, m_current_height); |
| 96 | } |
| 97 | } |
| 98 | } else if (m_download_state == State::REDOWNLOAD) { |
| 99 | // During REDOWNLOAD, we compare our stored commitments to what we |
| 100 | // receive, and add headers to our redownload buffer. When the buffer |
| 101 | // gets big enough (meaning that we've checked enough commitments), |
| 102 | // we'll return a batch of headers to the caller for processing. |
| 103 | ret.success = true; |
| 104 | for (const auto& hdr : received_headers) { |
| 105 | if (!ValidateAndStoreRedownloadedHeader(hdr)) { |
| 106 | // Something went wrong -- the peer gave us an unexpected chain. |
| 107 | // We could consider looking at the reason for failure and |
| 108 | // punishing the peer, but for now just give up on sync. |
| 109 | ret.success = false; |
| 110 | break; |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | if (ret.success) { |
| 115 | // Return any headers that are ready for acceptance. |
| 116 | ret.pow_validated_headers = PopHeadersReadyForAcceptance(); |
| 117 | |
| 118 | // If we hit our target blockhash, then all remaining headers will be |
| 119 | // returned and we can clear any leftover internal state. |
| 120 | if (m_redownloaded_headers.empty() && m_process_all_remaining_headers) { |
| 121 | LogDebug(BCLog::NET, "Initial headers sync complete with peer=%d: releasing all at height=%i (redownload phase)\n", m_id, m_redownload_buffer_last_height); |
| 122 | } else if (full_headers_message) { |
| 123 | // If the headers message is full, we need to request more. |
| 124 | ret.request_more = true; |
| 125 | } else { |