diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-02 16:00:59 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-02 16:00:59 +0000 |
| commit | 2e20434e563b09c5209d0a1f6784d96ed8b18851 (patch) | |
| tree | a20d2e40b6382063145cea8de0801a1747afedd3 /src/rpc.cpp | |
| parent | 2c0410b20893383ec6f1c4c8cd5134e420513e80 (diff) | |
net: keep a block tracked until its body actually validates
The mapBlockFetch entry was erased before ProcessBlock ran, on the
reasoning that the body had arrived so the fetch was over either way.
That reasoning does not survive the fact that GetHash() covers the
80-byte header and nothing else.
Any peer that saw X announced holds X's header. It can answer our
getdata with that header and a transaction list of its own invention;
the reply still hashes to X, so the entry was erased, and CheckBlock
then rejected the body on hashMerkleRoot and stored nothing. AlreadyHave
stayed false, the mapAskFor entry had already been consumed when the
getdata went out, and nothing recreated the tracking -- so X was never
requested from anybody again unless some peer happened to re-announce
it. That is the #33 stall, reachable on demand for one message.
The erase now sits inside the success branch, beside the
mapAlreadyAskedFor erase it belongs with. ProcessBlock returns true in
exactly two cases, block accepted and block parked as an orphan, and
both store it where AlreadyHave will find it, so one erase covers both
and neither needs different treatment. Of the false cases, the two
already-have ones are cleared by the sweep's own AlreadyHave check on
its next pass, and the rest are rejections that must keep the entry.
A mismatched merkle root is also now grounds to drop the peer. Nothing
honest produces it: peer traffic rides the .btf channel, which is
XChaCha20-Poly1305, so a body that arrives at all arrived intact, and
the mismatch is the peer's own construction. Checking it in the handler
also rejects a forged body before CheckBlock spends a RandomX hash on
it. The unconditional log line fires once per connection, because
ProcessMessages keeps draining the receive buffer after fDisconnect is
set and a peer that packs many forged bodies into one buffer must not
get a line for each.
Diffstat (limited to 'src/rpc.cpp')
0 files changed, 0 insertions, 0 deletions