In this commit, we remove the localhost-only restriction for sync peer
candidates on regtest and simnet. Previously, isSyncCandidate rejected
any regtest peer not on 127.0.0.1 or localhost, which prevented IBD
when nodes run in Docker containers on bridge networks (e.g. 172.18.0.x).
We also replace fragile pointer-equality checks against global chaincfg
params with value-based Name field comparisons, and extend the exception
to simnet since it has the same local-only usage pattern.
In this commit, we fix `IsRoutable` to correctly reject IPv6 addresses
whose first 16-bit group is zero (i.e., in the `0000::/16` reserved
block per RFC 4291). Differential fuzzing between btcd and Bitcoin Core
revealed that addresses like `0:9881:8181:8181:fe00🅰️9e:9801` were
slipping through as routable when they shouldn't be.
We add a new `zero6Net` (`0000::/16`) definition alongside the existing
`zero4Net`, and introduce an `IsZero` helper that checks both. The /16
prefix width is intentional: the broader /8 reservation would
incorrectly catch allocated sub-ranges like `0064:ff9b::/96` (RFC 6052,
NAT64). We also carve out an exception for RFC 6145 translated IPv4
addresses (`::ffff:0:0:0/96`), which live within `0000::/16` but are
valid for routing.
Test coverage includes the original bug report address, various
zero-prefix IPv6 addresses, the RFC 6145 exclusion, and corresponding
`GroupKey` entries to confirm they land in the "unroutable" bucket.
Fixes#2431
html/template automatically HTML-escapes special characters to prevent
XSS, which can silently corrupt arbitrary script data. Since the output
is binary script bytes and not HTML, this escaping provides no benefit
and might breaks correctness.
Add a recoverFromPanic method that catches panics in peer goroutines,
logs the error with a stack trace, and disconnects the offending peer
instead of crashing the entire node. This provides defense-in-depth
against future unknown panics in message parsing or handling.
Protect two goroutine boundaries:
- The negotiation goroutine in start(), which handles pre-handshake
message decoding via BtcDecode.
- The inHandler goroutine, which processes all post-handshake messages.
Refactor inHandler cleanup from manual end-of-function calls to
defer-based cleanup, ensuring close(p.inQuit) always runs even on
panic, which prevents stallHandler from hanging.
Add a bounds check against the remaining slab capacity so oversized
witness items return a decode error. Add a regression test for witness
items that overflow the decode slab.
This issue was discovered through differential fuzzing between btcd and
Bitcoin Core.
IPv4-mapped IPv6 addresses (::ffff:0:0/96, RFC 4291) sent with networkID
0x02 (IPv6) in addrv2 messages are now properly rejected. Per BIP155,
these addresses should use networkID 0x01 (IPv4) instead. This aligns
btcd's behavior with Bitcoin Core's addrv2 handling.
Changes:
- Add ipv4MappedPrefix constant for the ::ffff:0:0/96 prefix
- Add isIPv4Mapped() helper function to detect these addresses
- Update readNetAddressV2() to skip IPv4-mapped addresses with IPv6 networkID
- Add comprehensive test coverage for IPv4-mapped address detection
This issue was discovered through differential fuzzing between btcd and
Bitcoin Core.
Add detection and filtering of IPv6 ORCHIDv2 addresses as defined by
RFC7343 (2001:20::/28). These addresses are overlay routable
cryptographic hash identifiers and should not be treated as routable
peer addresses, consistent with Bitcoin Core's behavior.
Changes:
- Add rfc7343Net variable for the 2001:20::/28 address block
- Add IsRFC7343() function to detect ORCHIDv2 addresses
- Update IsRoutable() to exclude RFC7343 addresses
- Add comprehensive test coverage for RFC7343 detection
- Fix incorrect error message in TestIPTypes (IsRFC1918 -> IsRFC6145)
Verify that startSync skips header download and directly requests
blocks when the header chain is already caught up to the peer's
height but the block chain lags behind.
ince we now utilize ProcessBlockHeaders, we change the startSync
function to utilize the block index for downloading blocks/headers
instead of using the headerList in SyncManager.
This tests that after two nodes diverge and reconnect, the shorter
node downloads blocks starting from the fork point rather than its
current height. It verifies the reorg completes, both nodes
converge, and the orphaned fork appears as a side chain via
getchaintips.
Refactor fetchHeaderBlocks and buildBlockRequest to take an explicit
peer parameter instead of implicitly using sm.syncPeer. This makes the
caller responsible for choosing which peer to fetch from and adds a nil
guard to prevent a panic if the sync peer has been cleared.
headers
We introduce buildBlockRequest that'll create a getdata message based
off of the block index instead of the headerList in SyncManager.
The new fetchHeaderBlocks utilizes buildBlockRequest and now will create
fetch requests based on the processed block headers.
isInIBDMode returns if the SyncManager needs to download blocks and sync
to the latest chain tip.
It determines if it's in ibd mode by checking if the blockchain thinks
we're current and if we don't have peers that are at higher advertised
blocks.
In block processing and block downloading, HaveBlock is used to check if
the block data already exists. It was ok to just check for the
existence of the blockNode but we now we also need to check if the data
exists as the blockNode may be present for just the block header.
On flushes to the database, we check that the blockNodes we have for
the downloaded block headers are not flushed to the disk unless the
block data is stored as well for backwards compatibility.
With older btcd clients, they rely on the fact that the blockNode is
present to check if the block data is also present. Since we now
store blockNodes for just the block headers, this is no longer true.
Because of this, we don't flush the blockNodes if there's no
accompanying block data for it. This results in downloading and
verifying the headers again if the node were to restart but since the
header data is small and the verification is quick, it's not a big
downside.
As an optimization, flushToDB now skips opening a write transaction
entirely when every dirty node is header-only. This avoids a no-op
write transaction on every ProcessBlockHeader call during header sync.
maybeAcceptBlock unconditionally created a new blockNode, overwriting the
index entry. If maybeAcceptBlockHeader had already processed the header,
the pointer held by bestHeader's chainView became orphaned, breaking
bestHeader.Contains and downstream checks like IsValidHeader.
Check for an existing node first and upgrade its status to
statusDataStored rather than replacing it.
ProcessBlockHeader performs chain selection and context-free &
contextual validation for the given block header. The function allows
a header-first downloading of blocks even without checkpoints.
maybeAcceptHeader performs checks to accept block headers into the
header chain. This function allows for a true headers-first download
where we only accept block headers for downloading new blocks.
We add a chainview of bestHeaders so that we'll be able to keep track of
headers separately from the bestChain. This is needed as we're getting
headers for new block annoucements instead of invs.
The comments in schnorrSign and Sign incorrectly stated that CustomNonce
triggers RFC6979 nonce generation. The actual behavior is the opposite:
- With CustomNonce: BIP-340 compliant nonce derivation (steps 6-8)
- Without CustomNonce (default): RFC6979 deterministic nonce generation
Also fixes typo "set 14" -> "step 14".
Previously, the Put() function took in a single key-value pair,
resulting in memory allocation overhead as the intermediary treapNodes
got allocated and immediately garbage collected, resulting in
performance loss due to the garbage collection overhead.
We're able to recycle the intermediary treapNodes allocated by taking in
multiple key-value pairs. This results in better performance of the
node especially during UTXO cache flushes.