In this commit, we make the pre-verack lifecycle test count only peers that
btcd has admitted and processed through version exchange.
The source handshake limit can close a rapid follow-up socket while the
previous disconnect is still unwinding. This made the client-side version
write fail with EPIPE before the intended lifecycle path ran. We now wait for
a version response from btcd, retry rejected attempts under a deadline, and
still disconnect without sending verack.
This preserves all 50 peerDone without peerAdd cycles while removing the
scheduler-dependent admission race from the test.
In this commit, we make each stress wave establish its full set of peers
before disconnecting them together. A ping/pong barrier proves the server
processed each verack, while RPC connection-count barriers prove
registration and removal completed before the next wave starts.
We bound concurrent handshakes from the shared source, drain every worker on
failure, and wait for server-side cleanup. This keeps the test compatible
with the admission limits it exercises and makes a passing run evidence of
the intended NewPeer/DonePeer ordering.
In this commit, we introduce a server-wide admission policy for
incomplete inbound handshakes and the CPU-bound portion of v2 responder
setup. Source accounting uses normalized IPv4 and IPv6 prefixes, while
global, per-source, and concurrent v2 budgets remain independent and
bounded.
Peer construction passes the policy through a small interface only for
inbound v2 responders. Handshake slots release on verack or disconnect,
and the connection manager reserves MaxPeers capacity for automatic
outbound peers.
Two pieces of rpctest's global state silently aliased across concurrent
test processes (which is what `go test ./...` does by default, so any
`make unit` that exercises -tags=rpctest hit this):
- btcdExecutablePath compiled to a fixed path /tmp/btcd/rpctest/btcd.
Two `go build` invocations would race on the same file, occasionally
yielding a truncated or stale binary and downstream "tls: certificate
signed by unknown authority" failures when the harness tried to talk
to the resulting node.
- lastPort started at the same defaultNodePort in every process. The
bind-test in NextAvailablePort closes the listener before returning,
so two processes climbing from the same base would frequently hand
out the same port and one harness would die with "connection refused"
when btcd failed to bind.
Suffix the executable with a random uint32 and seed lastPort with a
random offset into a 50k-port window so each process climbs through
its own range.
p2a_test.go calls btcutil.NewAddressPayToAnchor, but the
NewAddressPayToAnchor constructor lives in the address/v2 module's
address package. Import that package and call it through there so the
integration package builds when -tags=rpctest is set.
Address review feedback on the peer add/done race fix:
Add three direct unit tests in server_test.go that exercise the fix
without the full server or rpctest harness:
- TestOnVerAckDoubleCall: call OnVerAck twice on the same serverPeer,
assert no panic and verAckCh remains closed.
- TestPeerLifecycleOrdering: verack before disconnect emits peerAdd
then peerDone in order.
- TestPeerLifecycleSimultaneousReady: both verAckCh and Peer.Done()
ready before the handler runs; assert peerDone always arrives and
peerAdd, if emitted, precedes it (100 iterations).
Harden integration tests in sync_race_test.go:
- Check fakePeerConn errors via require.NoError instead of discarding.
- Extract dialAndSendVersion helper for TestPreVerackDisconnect;
check all errors instead of silently continuing.
- Fix comment wording ("produces" -> "is expected to produce").
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.
Address review feedback on the peer add/done race fix:
- Make peerLifecycleHandler (renamed from peerDoneHandler) the sole
sender of both peerAdd and peerDone events for each peer. OnVerAck
now closes a signal channel (verAckCh) instead of sending directly,
and peerLifecycleHandler selects on verAckCh vs peer.Done() to
decide whether to send peerAdd before peerDone. This guarantees
ordering by construction: a single goroutine sends both events
sequentially, eliminating the negotiateTimeout race window.
- Add Done() method to peer.Peer exposing the quit channel read-only,
enabling select-based disconnect detection from server code.
- Remove the now-unused AddPeer method.
- Address style feedback: 80-char line limit, empty lines between
switch cases, break long function calls, use require.GreaterOrEqualf
instead of if+Fatalf, bump syncRaceConcurrency to 300 for
backpressure testing, add TestPreVerackDisconnect for disconnect
prior to verack.
peerDoneHandler ran as a separate goroutine per peer and independently
notified both peerHandler (via donePeers channel) and the sync manager
(via syncManager.DonePeer) about a peer disconnect. Because these two
sends were unsynchronized, the sync manager could observe DonePeer
before NewPeer when a peer connected and disconnected quickly. This
caused the sync manager to log "unknown peer", then later register the
already-dead peer as a sync candidate that was never cleaned up,
potentially leaving it stuck with a dead sync peer.
Two structural changes eliminate the race:
1. Merge the newPeers and donePeers channels into a single
peerLifecycle channel. Since OnVerAck (add) always fires before
WaitForDisconnect returns (done), a single FIFO channel guarantees
peerHandler always processes add before done for a given peer,
removing the select-ambiguity where Go could pick done first.
2. Move the syncManager.DonePeer call and orphan eviction from
peerDoneHandler into handleDonePeerMsg, which runs inside
peerHandler. All sync manager peer lifecycle notifications now
originate from the single peerHandler goroutine and flow into
sm.msgChan in guaranteed add-before-done order.
Set regtest buried heights to match Core: BIP34/65/66 at height 1 and make
CSV/SegWit/Taproot always active. Added regtest coverage for header version
floors, coinbase height enforcement, and deployment state to ensure we now
reject the blocks Core rejects and accept the ones Core accepts.
Updated package fullblocktests to generate BIP34-compliant blocks.
Test helpers now set prev block height to 0 (not the default -1) so generated
blocks start at height 1 and satisfy coinbase height rules.
This commit introduces the concept of `AlwaysActiveHeight` to the
deployment mechanism, allowing a deployment to be forced into the active
state if the next block's height meets or exceeds this threshold.
This is intended primarily to be used alongside the new Testnet4
deployment, as the past major soft forks are meant to be active from the
very first block height.
This commit adds a new NextAvailablePortForProcess function that takes a
process ID and then assures unique (non-occupied) port numbers are
returned per process.
This uses a temporary file that contains the latest used port and a
secondary temporary lock file to assure only a single goroutine can
request a new port at a time.
The GenerateProcessUniqueListenerAddresses is intened to be used as a
package-level override for the ListenAddressGenerator variable. We don't
use it by default to make sure we don't break any existing assumptions.
rpcclient now support calling the getchaintips rpc call.
getchaintips_test.go adds test for the getchaintips rpc call. The test
includes hard-coded blocks which the test will feed the node via rpc and
it'll check that the returned chain tips from the getchaintips call
are chaintips that we expect to be returned.
The doc formatting changes introduced in the recent go version is
increasing the diff for all of the new commits. Formatting it all in
this commit will help the readability of future PRs by reducing the
diff.
In this commit, we extend the existing version bits state machine to add
support for the new minimum activation height and custom block threshold
for activation. We then extend the existing BIP 9 tests (tho this isn't
really BIP 9 anymore...) to exercise the new min activation height
logic.
In this commit, we update all the btcutil imports to point to the new
sub-module.
In the same commit, we also modify the recently added `btcutil/go.mod`
file as we need to continue pointing to the _old_ version of btcd, until
we merge this PR and push a new tag.
To allow using a custom btcd executable, we allow specifying a path to a
file. If the path is empty, the harness will fall back to compiling one
from scratch.
With the use of go modules, the btcdPkgPath will no longer be `github.com/btcsuite/btcd`, but end with a version string (e.g. btcd@v0.0.0-20181129140220-beb77e89572a).
This trips up build.ImportDir, which will return a ImportPath of ".", since this package cannot be found in the go path.
There are probably several ways of fixing this, by clever string magic, but seems easiest to just hardcode the btcd package name.