diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.cpp | 50 |
1 files changed, 45 insertions, 5 deletions
diff --git a/src/main.cpp b/src/main.cpp index d9fe713..8926d57 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -3293,16 +3293,56 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 3293 | CInv inv(MSG_BLOCK, pblock->GetHash()); | 3293 | CInv inv(MSG_BLOCK, pblock->GetHash()); |
| 3294 | pfrom->AddInventoryKnown(inv); | 3294 | pfrom->AddInventoryKnown(inv); |
| 3295 | 3295 | ||
| 3296 | // The body is here, so the fetch is over whatever validation says | 3296 | // GetHash() covers the 80-byte header and nothing else, so the hash |
| 3297 | // next -- unlike the mapAlreadyAskedFor erase below, which stays | 3297 | // coming out right does not make this the block we asked for. Every |
| 3298 | // conditional on acceptance so a peer feeding us garbage does not | 3298 | // peer that saw X announced holds X's header, and can answer our |
| 3299 | // cancel the scheduled retries for the real thing. | 3299 | // getdata with that header bolted onto a transaction list of its own |
| 3300 | mapBlockFetch.erase(inv.hash); | 3300 | // invention -- the reply still hashes to X. hashMerkleRoot is the only |
| 3301 | // thing binding the header to the body, so check it here, before the | ||
| 3302 | // mapBlockFetch entry is touched and before CheckBlock spends a | ||
| 3303 | // RandomX hash on a body already known to be forged. | ||
| 3304 | // | ||
| 3305 | // There is no honest way to arrive here. Peer traffic rides the .btf | ||
| 3306 | // channel, which is XChaCha20-Poly1305, so a body that arrives at all | ||
| 3307 | // arrived intact: a mismatch is the peer's own construction, not line | ||
| 3308 | // noise. Drop the peer and leave the fetch outstanding so the failover | ||
| 3309 | // sweep asks somebody else for the real X, rather than recording X as | ||
| 3310 | // delivered on the strength of a header anyone could copy. | ||
| 3311 | if (pblock->hashMerkleRoot != pblock->BuildMerkleTree()) | ||
| 3312 | { | ||
| 3313 | if (LogAcceptsCategory("net")) | ||
| 3314 | printf("peer %s served a forged body for %s\n", | ||
| 3315 | pfrom->addr.ToString().c_str(), inv.ToString().c_str()); | ||
| 3316 | // One line per connection: ProcessMessages keeps draining the | ||
| 3317 | // receive buffer after fDisconnect is set, so a peer that packs | ||
| 3318 | // many forged bodies into one buffer must not get one log line | ||
| 3319 | // for each of them. | ||
| 3320 | if (!pfrom->fDisconnect) | ||
| 3321 | printf("block fetch: a peer answered the request for %s with a body that is not " | ||
| 3322 | "that block -- dropping it\n", inv.hash.ToString().substr(0,14).c_str()); | ||
| 3323 | pfrom->fDisconnect = true; | ||
| 3324 | return error("ProcessMessage() : forged block body for %s", | ||
| 3325 | inv.hash.ToString().substr(0,14).c_str()); | ||
| 3326 | } | ||
| 3301 | 3327 | ||
| 3302 | if (ProcessBlock(pfrom, pblock.release())) | 3328 | if (ProcessBlock(pfrom, pblock.release())) |
| 3303 | { | 3329 | { |
| 3304 | mapAlreadyAskedFor.erase(inv); | 3330 | mapAlreadyAskedFor.erase(inv); |
| 3305 | 3331 | ||
| 3332 | // The body arrived and validated, so the fetch really is over: | ||
| 3333 | // the block is now in mapBlockIndex, or parked in mapOrphanBlocks, | ||
| 3334 | // and either way AlreadyHave answers for it from here on. | ||
| 3335 | // | ||
| 3336 | // This has to stay inside the success branch, next to the erase | ||
| 3337 | // above. When validation rejects a body nothing is stored, | ||
| 3338 | // AlreadyHave stays false, and the mapAskFor entry was already | ||
| 3339 | // consumed when the getdata went out -- so erasing the tracking | ||
| 3340 | // here would leave the block requested from nobody at all until | ||
| 3341 | // some peer happened to re-announce it. That is exactly the stall | ||
| 3342 | // of #33, and erasing before ProcessBlock made it reachable on | ||
| 3343 | // demand. | ||
| 3344 | mapBlockFetch.erase(inv.hash); | ||
| 3345 | |||
| 3306 | // A peer that just handed us a block is demonstrably at least at | 3346 | // A peer that just handed us a block is demonstrably at least at |
| 3307 | // that block's height. Without this, nStartingHeight is a snapshot | 3347 | // that block's height. Without this, nStartingHeight is a snapshot |
| 3308 | // taken once during the version handshake and never touched again, | 3348 | // taken once during the version handshake and never touched again, |