_followp2p.mjs takes the peer's getheaders response and trusts it — it fetches and fully validates each block, but never validates the headers' proof-of-work or difficulty. A malicious/buggy peer could feed a fabricated header chain; block validation alone doesn't prove the chain is work-backed or is the most-work chain.
The engine already does this
HeaderEngine (codec/headers.js) validates headers:
btc:rule-header-difficulty — the header's bits match the expected target via retargeting, including testnet4's 20-minute min-difficulty exception (expectedBits walk-back),
- timestamp rule —
header.time > medianTimePast(window),
- PoW — hash meets the claimed target.
HeaderSync (src/chain/header-sync.js) already drives HeaderEngine during the download-testnet4 path.
Goal
In the follow loop, validate each new header with HeaderEngine before accepting it / fetching its block:
- PoW — block hash ≤ target(bits).
- Difficulty/retarget —
bits is the correct expected value (needs prior-header context: the epoch-first header for retarget, and the min-difficulty walk-back).
- Timestamp — header.time > MTP of the last ~11 headers.
This needs the node to keep a rolling window of recent headers (and the epoch-first header) for context. Reject headers that fail; only follow a work-backed chain.
Related (separate follow-up)
Full trustlessness also wants multi-peer + most-work selection — connect to several peers and follow the valid chain with the most accumulated work, so one peer can't stall/mislead. PoW header validation (this issue) is the prerequisite; most-work selection is the next layer.
_followp2p.mjstakes the peer'sgetheadersresponse and trusts it — it fetches and fully validates each block, but never validates the headers' proof-of-work or difficulty. A malicious/buggy peer could feed a fabricated header chain; block validation alone doesn't prove the chain is work-backed or is the most-work chain.The engine already does this
HeaderEngine(codec/headers.js) validates headers:btc:rule-header-difficulty— the header'sbitsmatch the expected target via retargeting, including testnet4's 20-minute min-difficulty exception (expectedBitswalk-back),header.time > medianTimePast(window),HeaderSync(src/chain/header-sync.js) already drivesHeaderEngineduring thedownload-testnet4path.Goal
In the follow loop, validate each new header with
HeaderEnginebefore accepting it / fetching its block:bitsis the correct expected value (needs prior-header context: the epoch-first header for retarget, and the min-difficulty walk-back).This needs the node to keep a rolling window of recent headers (and the epoch-first header) for context. Reject headers that fail; only follow a work-backed chain.
Related (separate follow-up)
Full trustlessness also wants multi-peer + most-work selection — connect to several peers and follow the valid chain with the most accumulated work, so one peer can't stall/mislead. PoW header validation (this issue) is the prerequisite; most-work selection is the next layer.