Skip to content

Integration/2.0.x to main#14

Merged
andrepatta merged 32 commits into
mainfrom
integration/2.0.x-to-main
Apr 28, 2026
Merged

Integration/2.0.x to main#14
andrepatta merged 32 commits into
mainfrom
integration/2.0.x-to-main

Conversation

@andrepatta
Copy link
Copy Markdown
Member

@andrepatta andrepatta commented Apr 28, 2026

Summary

Lands the v2.0.x release work onto main. 32 commits cherry-picked from
2.0.x since the merge base, skipping 3 patches already on main
(bootnodes v2, CMDS override, dlgo 1.26.1) and the rc1/rc2 version
bumps. version.go stays on 2.1.0-unstable.

Each commit carries a (cherry picked from commit ...) trailer back to
the original on 2.0.x.

What's landing

Self-dial / self-discovery hardening

  • p2p: reject v2 self-dial and self-handshake on advertised endpoint
  • p2p/addrman: skip self endpoint in V2Iter
  • p2p/protocols/disc: drop self entries at HandlePeers ingest

Disc Hello handshake (per-startup nonce-based session abort)

  • p2p/protocols/disc: define HelloMsg struct and validation
  • p2p: generate per-startup Hello nonce in setupLocalNode
  • p2p/protocols/disc: thread Hello through AddrmanBackend
  • p2p/protocols/disc: send Hello first and gate on its receipt
  • p2p/protocols/disc: end-to-end test for self-nonce session abort
  • p2p/protocols/disc: bump ProtocolLength to cover HelloMsg
  • cmd/devp2p: send disc Hello first in parallax-disc probe / crawl
  • cmd/devp2p: default parallax-disc crawl bootnodes to MainnetBootnodesV2

Cross-dial dedupe and per-peer telemetry

  • p2p: dedupe v2 cross-dial via disclosed listen port
  • p2p: add per-peer quality telemetry fields
  • p2p: measure ping RTT for eviction telemetry
  • p2p/protocols/prl: stamp last-block / last-tx receipt timestamps
  • p2p: count payload bytes received per peer
  • p2p: cache per-peer network group at attach time

Bitcoin Core-style inbound eviction

  • p2p: implement Bitcoin Core inbound eviction algorithm
  • p2p: trigger eviction on inbound saturation

Outbound peer policy (network-group diversity, block-relay-only, feelers, anchors)

  • p2p: enforce outbound network-group diversity
  • p2p: implement block-relay-only outbound peer behavior
  • p2p: add feeler and addrfetch dial loops
  • p2p: persist block-relay-only anchors across restart

Ban / discourage subsystem

  • p2p/banman: persistent ban list and ephemeral discourage filter
  • p2p: peer misbehavior plus accept-time ban / discourage gating
  • node: setban / listbanned / clearbanned admin RPC
  • cmd/parallax-cli: setban / listbanned / clearbanned subcommands

Cleanup, CI, docs

  • chore: lint cleanups across phase 4 / 5 changes
  • docs: peer-management features and operator RPC reference
  • ci: run build / lint / unit-test on v* branches
  • ci: trigger build / lint / unit-test on N.N.x release branches
  • rpc/client: drop racy canceled-context assertion from TxInBlockInterrupted

v2 sessions derive node.ID from ephemeral X25519 keys, so the
existing self-check (c.node.ID() == localnode.ID()) cannot fire
for v2 peers. A node behind a hairpinning NAT therefore dials its
own external IP and accepts the looped-back TCP connection.

Add isSelfEndpoint helper and gate DialV2 on it. Extend the v2
branch of postHandshakeChecks with the same comparison as
defense-in-depth for paths that bypass DialV2 or for the narrow
window where localnode's IP updates mid-dial.

(cherry picked from commit 5008df1)
The disc-protocol quorum can ingest the local node's observed
external IP into addrman as a KeyType=0x00 entry. Without filter,
V2Iter re-emits it every cycle and DialV2's self-guard burns the
dial slot rejecting it.

Plumb an IsSelfFunc through NewV2Iter and reuse Server.isSelfEndpoint
so the iterator silently skips self-matching candidates.

(cherry picked from commit 3311102)
Once our quorum-confirmed external IP propagates to peers via
sendSelfAdvertise, peers gossip it back to us. Without filtering
at the ingest boundary, AddrmanBackend.HandlePeers writes the
self entry into addrman where it persists across restarts via
addrbook.rlp.

Plumb an IsSelfFunc through NewAddrmanBackend (wired to
Server.IsSelfEndpoint at node setup) and skip matching entries
before m.AddOne. Export IsSelfEndpoint so the disc package and
node wiring can consult the same source of truth as the dial /
handshake / V2Iter guards.

Add NewPeerForTest(id, name, caps, fd) so tests in other
packages can drive code paths that depend on Peer.RemoteAddr().

(cherry picked from commit 04dc741)
Hello carries protocol version, services flags, peer's claimed
listen port, and a self-connect detection nonce. Mirrors the
role of Bitcoin Core's version message (src/protocol.h
ProtocolMessageType::VERSION). Tail uses rlp:"tail" with
[]rlp.RawValue so future fields can be appended without
breaking the existing decoder.

Wire-only commit; the handler plumbing lands separately.

(cherry picked from commit 24d1285)
helloNonce is a 64-bit value drawn from crypto/rand once per
Server lifetime, exposed via Server.HelloNonce(). The disc
handler embeds it in every outgoing Hello so a self-connected
session can recognize its own greeting on receipt. Bitcoin Core
analog: nLocalHostNonce in src/net.cpp PushNodeVersion.

Wire-only commit; the disc handler integration lands separately.

(cherry picked from commit f39a414)
NewAddrmanBackend takes an additional HelloProvider closure that
returns the local node's outgoing Hello (nonce, listen port,
services). LocalHello() forwards it; HandleHello() runs the
self-connect nonce check and stores the peer's Hello in a
peerHello map. PeerDisconnected purges the entry.

node.go wires the provider to Server.HelloNonce() plus the
LocalNode's TCP port and the standard NodeNetwork|RelayTx
service flags.

The handler send/receive integration lands separately.

(cherry picked from commit d419e92)
Both sides write Hello before YourAddr on session start. The
receive path enforces protocol-order: any non-Hello message that
arrives before our peer has sent Hello ends the session. A second
Hello on the same session is also a violation.

Backend interface gains LocalHello() and HandleHello(). The
production AddrmanBackend already had these from the Hello
plumbing commit; testBackend gains stubs that capture incoming
Hellos. drainAndOpen replaces drainGreeting in tests that send
post-Hello messages so the protocol-order gate opens properly.

Self-connect detection via Hello.Nonce flows through naturally:
AddrmanBackend.HandleHello returns an error when h.Nonce matches
LocalHello().Nonce; the handler propagates and the session ends.

(cherry picked from commit 8b54bbf)
Confirms that when AddrmanBackend.HandleHello returns
errSelfConnect (the peer echoed our own nonce), the handler
propagates the error and Run returns it. The upstream peer-run
loop tears down the session.

Backend-level tests already cover the nonce comparison; this
test pins the integration so a refactor that drops the error
propagation in handleOne would be caught.

(cherry picked from commit 67ef239)
alreadyConnectedTo now consults each peer's effective listen
address: outbound peers' RemoteAddr.Port is already the listen
port; inbound peers' is ephemeral, so substitute the listen port
disclosed via parallax-disc/1 Hello when available.

Server gains PeerListenPortLookup interface plus
SetPeerListenPortLookup setter so the disc backend can serve as
the per-peer Hello cache. peerListenAddr returns ok=false in the
pre-Hello window for inbound peers, which keeps the check
conservative; the post-Hello dedup hook in HandleHello catches
duplicates that race through.

Cross-dial dedup runs in AddrmanBackend.HandleHello: scan peers
for one whose listen-addr matches the new peer's (IP, ListenPort)
and disconnect the loser. Tie-break prefers outbound retention;
same-direction ties keep the older connection. Implements
Bitcoin Core's preference (src/net.cpp ThreadOpenConnections).

Peer.Created accessor exposes p.created for the cross-dial age
comparison; previously private.

(cherry picked from commit 96958ea)
Atomic fields on Peer carry the telemetry the inbound eviction
algorithm consumes:
  - minPing       smallest RTT observed on ping/pong
  - lastPingSent  for RTT computation on pong receipt
  - lastBlockRx   most recent block-bearing message
  - lastTxRx      most recent transaction-bearing message
  - bytesRx/Tx    payload byte counters
  - relayTxs      mirror of Hello.Services & ServiceRelayTx
  - blockRelayOnly outbound slot-bucket flag

Mirrors NodeEvictionCandidate fields in Bitcoin Core
src/node/eviction.h:18-33.

Storage and accessors only; the actual stamping (RTT in
pingLoop, prl per-message timestamps, bytes counters) lands in
the next checkpoints. RelayTxs defaults to true so peers that
haven't disclosed Services yet are treated as tx-relayers.

(cherry picked from commit f15f894)
pingLoop stamps lastPingSent before sending pingMsg. handle()
gains an explicit pongMsg branch that calls recordPongRTT, which
computes (now - lastPingSent) and updates minPing if the new
sample improves on the running minimum. CompareAndSwap loop
keeps the update race-free under concurrent pong arrivals.

Pre-send-stamp pongs (test scaffolding, adversarial peer that
sends pong unprompted) and negative deltas (clock skew) are
ignored. Mirrors Bitcoin Core's m_min_ping_time on CNode.

(cherry picked from commit d2491b3)
Block-bearing handlers (NewBlockHashes, NewBlock, BlockHeaders,
BlockBodies) call peer.MarkBlockRx; transaction-bearing handlers
(Transactions, PooledTransactions) call peer.MarkTxRx. Each
stamp is mclock.Now() on the embedded *p2p.Peer.

These timestamps drive the eviction algorithm's "newest tx" /
"newest block" / "block-relay-only with services" protection
rounds. Mirrors Bitcoin Core's m_last_tx_time / m_last_block_time
on Peer (src/net_processing.cpp).

(cherry picked from commit 473a1df)
readLoop increments p.bytesRx by msg.Size after each successful
ReadMsg. Payload-only accounting (framing overhead excluded)
keeps the counter comparable across transports.

bytesTx is reserved as a symmetric field but not yet
instrumented — Bitcoin Core's NodeEvictionCandidate has no byte
counter, so the eviction algorithm doesn't depend on it. The
field shape is locked in now so a future admin diagnostic can
fill it without churn.

(cherry picked from commit 22889be)
NetworkGroupForIP returns canonical /16-IPv4 / /32-IPv6 prefix
bytes prepended with a network-tag byte so v4 and v6 groups can
never collide. IPv4-mapped IPv6 collapses to v4. Mirrors Bitcoin
Core's CNetAddr::GetGroup defaults (src/netaddress.cpp).

Peer caches its group via computeAndCacheNetworkGroup, called
from launchPeer once the conn's RemoteAddr is resolved. Eviction
protection passes (next checkpoint) read NetworkGroup() on every
candidate without recomputing the prefix.

SameNetworkGroup treats nil as a singleton — peers with non-TCP
RemoteAddr (test pipes) are each their own group.

(cherry picked from commit 9c32e6d)
Port of CConnman::AttemptToEvictConnection (src/net.cpp:1684)
plus SelectNodeToEvict (src/node/eviction.cpp:178). Six
protection rounds in order:

  1. Network-group diversity (4 peers, anti-eclipse)
  2. Lowest min ping (8 peers, responsiveness)
  3. Newest tx relay among tx-relayers (4 peers, conditional)
  4. Newest blocks among block-relay-only peers (8 peers,
     conditional)
  5. Newest block announce overall (4 peers)
  6. Oldest 50% by connection age

Final tie-break (eviction.cpp:217): find the most-populated
network group among survivors, then evict the youngest peer in
that group.

evictionCandidates excludes trusted, static, outbound, and
peers younger than evictMinAge=30s (Bitcoin Core's
MINIMUM_CONNECT_TIME). Pure-function helpers
(protectByMin/Max/Conditional, protectByNetGroupKeyed,
protectByRatio, pickEvictionVictim) keep the algorithm
unit-testable without a running Server.

evictInbound is the entrypoint; postHandshakeChecks integration
lands in the next checkpoint.

(cherry picked from commit 8f20249)
postHandshakeChecks now invokes evictInbound when an inbound
slot is full, instead of immediately returning DiscTooManyPeers.
Successful eviction lets the new peer join optimistically; the
loser's delpeer is processed asynchronously by the run loop.
Failed eviction (everyone protected) falls through to the
existing hard-reject.

MaxPeers (total cap, system-resource ceiling) still hard-rejects
without eviction — that knob is meant to be a hard ceiling.
Inbound saturation is what the algorithm targets, mirroring
Bitcoin Core's CConnman::AcceptConnection
(src/net.cpp:1684-1731).

Phase 3 complete: per-peer quality telemetry, RTT measurement,
prl receipt timestamps, network-group cache, the full eviction
algorithm, and saturation wiring. Phase 4 (outbound diversity +
block-relay-only + feeler) is next.

(cherry picked from commit 69e29ae)
dialScheduler tracks outboundGroups, a map keyed by network
group bytes (/16 IPv4 or /32 IPv6) counting how many current
outbound peers occupy each group. checkDial returns
errOutboundGroupOccupied when a candidate's group is already
represented, preventing a single AS from monopolizing our
outbound slots.

Loopback and link-local addresses bypass the diversity check so
dev / test setups using 127.x.x.x continue to work. Mirrors
Bitcoin Core's m_is_local exemption (eviction.cpp:115) and the
outbound_ipv46_peer_netgroups guard (net.cpp:2685).

This is the highest-value piece of phase 4 — it directly
counters eclipse attacks at the dial layer. Block-relay-only
peer behavior, feeler dials, and anchor persistence are deferred
to follow-up commits.

(cherry picked from commit c094af7)
Add the blockRelayConn flag and a 2-slot reservation in the dial
scheduler for block-relay-only outbound peers. Bitcoin Core's
MAX_BLOCK_RELAY_ONLY_CONNECTIONS (src/net.h:73) — anti-eclipse
insurance over and above full-relay outbound.

Slot picking prioritizes full-relay first, then block-relay (mirrors
ThreadOpenConnections at src/net.cpp:2715-2765). Counts include
in-flight dials so a burst of concurrent picks doesn't all classify
the same way before any peer reaches addPeerCh.

Behavior on a block-relay-only peer:

* prl handlers drop TransactionsMsg, NewPooledTransactionHashesMsg,
  PooledTransactionsMsg, GetPooledTransactionsMsg before any decode
  (mirrors net_processing.cpp:3681 m_relay_txs gate).
* fullnode tx-broadcast set excludes block-relay-only peers, so we
  never push tx in their direction either.
* disc/1 Hello clears the ServiceRelayTx bit on outgoing greeting
  (mirrors PushNodeVersion fRelay=false).
* disc/1 outbound greeting skips sendSelfAdvertise + RequestPeers,
  and incoming GetPeers from block-relay-only peers is silently
  dropped — no participation in address gossip.

Block traffic is unchanged. Tests pin Hello bit clearing, the
greeting-shape skip, GetPeers drop, the tx-handler drops via a
tracking decoder, and the dial-scheduler bucket fill.

(cherry picked from commit 5bfb81a)
runFeeler probes one addrman entry every ~2 minutes (Bitcoin Core
FEELER_INTERVAL, src/net.h:61). Selection prefers SelectTriedCollision
(test-before-evict) before falling back to Select(newOnly), mirroring
src/net.cpp:2796-2810. Each tick also runs ResolveCollisions so stale
collision entries don't shadow live draws. Hits go through DialV2 →
addrmanGood at peer attach; the connection self-disconnects after a
short lifetime so the feeler doesn't squat on an outbound slot.

runAddrFetch is the cold-start one-shot variant: when the addrman
holds fewer than addrFetchThreshold (1000) entries on startup, dial
each BootstrapNodesV2 once. The disc-protocol outbound greeting
(GetPeers) warms the addrbook from each, then we disconnect after
addrFetchLifetime. Bitcoin Core ConnectionType::ADDR_FETCH
(src/net.cpp:2422).

Both loops are gated behind addrman + !NoDial. Tests cover the
selection ordering, the empty-addrman short-circuit, and the
NetAddr → *net.TCPAddr projection used to drive the dial API.

(cherry picked from commit b039f7c)
On clean shutdown, snapshot the (IP, listen-port) of currently-
connected block-relay-only outbound peers (capped at
MaxBlockRelayAnchors = 2) into anchors.dat. On next startup, dial
each entry as block-relay-only, then delete the file so a crash
mid-startup doesn't replay the same anchors twice. Mirrors Bitcoin
Core's m_anchors / anchors.dat (src/net.cpp:57, MAX_BLOCK_RELAY_
ONLY_ANCHORS).

Wire format is RLP with a schema-version byte and an entry list of
(network-id, addr, port). Atomic write via tmp + rename, like
addrbook.rlp. Future-schema files return errAnchorFutureSchema so a
downgrade can't crash on a newer file.

Refactor DialV2 to dialV2WithFlags so DialV2BlockRelay can request
the block-relay-only flag without duplicating the cooldown / self-
endpoint / dedup checks. The anchor-replay goroutine routes through
DialV2BlockRelay, putting recovered peers into the same outbound
slot type they were in before shutdown.

Tests cover round-trip for IPv4 / IPv6, the cap-at-MaxAnchors trim,
empty-list-removes-file behavior, future-schema rejection, and the
zero-port / nil-IP filter.

(cherry picked from commit bd8cb83)
Two storage tiers, mirroring Bitcoin Core's BanMan (src/banman.h:63):

* Banned: persistent JSON map (banlist.json), operator-controlled
  via setban / unban / clearbanned RPC. Default duration 24h
  (DEFAULT_MISBEHAVING_BANTIME, src/banman.h:19). Subnet-aware:
  "1.2.3.0/24" bans the whole /24. Atomic file writes (tmp + rename),
  schema follows Bitcoin Core's modern banned_nets format
  (src/addrdb.h:34).

* Discouraged: in-memory Bloom filter (50k cap, 1e-6 fp),
  Bitcoin Core's defaults (src/common/bloom.h). Reset on restart;
  populated automatically from peer Misbehaving() calls.

Modern Bitcoin Core (v28+) dropped the ban-score point system, so
this package follows that simpler model — no nMisbehavior accumulation,
no DISCOURAGEMENT_THRESHOLD. A single MisbehavingFor call is enough
to flag for discourage.

The Bloom uses Go's stdlib hash/maphash with k independent seeds.
Sized via standard Bloom math (m = -n*ln(p)/ln(2)^2, k = m/n*ln(2),
capped at k=32).

Banlist persistence stores Unix-second timestamps; ban durations are
ceiling'd to 1s so sub-second bans don't collapse to BannedTill ==
BanCreated. Expired entries are pruned lazily on IsBanned and
ListBanned scans, and dropped at load time.

Tests cover the full Ban / IsBanned / Unban round trip for IPv4 +
IPv6, /24 subnet membership, expiry, persistence reload, expired-on-
load drop, ClearBanned, Bloom membership semantics, and Bloom false-
positive rate (sample 5k probes after 40k inserts, assert <= 1e-3).

(cherry picked from commit 720edc8)
Add Peer.MisbehavingFor: idempotent flag-and-disconnect for a peer
that has just committed a protocol-discipline violation. Mirrors
Bitcoin Core's modern Misbehaving() at src/net_processing.cpp — the
post-pointscore form: one trigger is enough to flag, no nMisbehavior
accumulation. The wire DiscReason is the generic DiscProtocolError;
we don't expose a distinct "you misbehaved" code so adversaries can't
calibrate against it.

Wire BanList into Server:

* checkInboundConn rejects banned source IPs at the listener loop
  (Bitcoin Core src/net.cpp:1800 AcceptConnection ban check). Trusted
  peers don't get a backdoor here — operators who want a banned subnet
  to still reach a trusted peer should unban it.
* postHandshakeChecks rejects discouraged IPs at inbound saturation
  before falling back to eviction (src/net.cpp:1808). No point evicting
  a well-behaved peer to admit a known-bad one.
* run-loop delpeer hook adds the source IP to the discourage Bloom
  when ShouldDiscourage is set, so reconnects from the same source
  hit the rejection path.

Convert the disc/1 handler's existing protocol-discipline disconnects
to MisbehavingFor calls — oversized message, msg-before-Hello, double
Hello / YourAddr, decode and validate failures, unsolicited Peers.
The session still ends via the existing error returns; the addition
is the discourage-list flag.

Tests cover MisbehavingFor flag + reason capture (with idempotency),
the inbound-conn banned-IP reject, and the existing handler tests
still pass under the new MisbehavingFor calls (nil-peer guard means
fuzz-style dispatch tests don't panic).

(cherry picked from commit a564a7d)
Mirrors Bitcoin Core's setban (src/rpc/net.cpp:740), listbanned
(src/rpc/net.cpp:820), and clearbanned (src/rpc/net.cpp:868).

Argument shape on setban:

* subnet:   IP ("1.2.3.4" → /32) or CIDR ("10.0.0.0/24").
* command:  "add" or "remove".
* bantime:  seconds; 0 → DefaultBanDuration. Honored only on "add".
* absolute: when true, bantime is a Unix timestamp; when false, a
            relative offset from now. Default false.

On "add" any currently-connected peer whose RemoteAddr matches the
subnet is also disconnected (Bitcoin parity, rpc/net.cpp:808-811).
On "remove" returns an error if the subnet wasn't previously banned
(rpc/net.cpp:817).

listbanned returns the active (non-expired) entries sorted by subnet
string for stable RPC output. clearbanned wipes every entry — does
NOT touch the in-memory discourage filter, which is restart-only by
design.

Resolves the deferred parallax ban / unban / banlist tracker; the
CLI subcommand can be a thin wrapper over these RPCs.

Tests cover the subnet parser: bare IPv4 → /32, bare IPv6 → /128,
CIDR pass-through, empty / garbage rejection, malformed CIDR
rejection.

(cherry picked from commit be3a9f3)
- gofmt / goimports on banman.go, dial.go, anchors_test.go,
  disc/backend.go, server_test.go.
- Drop redundant `tc := tc` and `a := a` loop-var shadows; Go
  1.22+ already gives each iteration its own variable.
- Remove unused resolveCollisionsInterval const in feeler.go.

No behavior change. golangci-lint reports zero issues across
p2p/..., p2p/banman/..., node/...

(cherry picked from commit 6d7d07e)
ProtocolLength was 3 but HelloMsg = 0x03, so protoRW.WriteMsg
rejected every outgoing Hello with "invalid message code: not
handled" (msg.Code >= rw.Length check in p2p/peer.go). The peer
never saw our Hello, then sent YourAddr first as usual, then we
disconnected on "disc: msg 0x02 before Hello" plus flagged for
misbehavior.

Net effect: the patched build couldn't disc-handshake with any
other patched build, partitioning the v2 fleet from itself.
Symptom in the wild was peer count regression to a handful of
v1.x legacy-RLPx peers (which never run disc/1) while every
parallax/v2.0.0-rc1 inbound and outbound dropped on the same
"msg 0x02 before Hello" line.

Bump to 4 (one past the highest defined code). Add a regression
test that asserts every defined message-code constant fits under
ProtocolLength — adding a new code without bumping the length
turns the test red instead of silently dropping wire traffic.

(cherry picked from commit a3cba0d)
Thin sugar over admin_setban / admin_listbanned / admin_clearbanned.

  parallax-cli setban <subnet> <add|remove> [bantime] [absolute]
  parallax-cli listbanned
  parallax-cli clearbanned

setban accepts the same argument shape the daemon RPC takes: a plain
IP ("1.2.3.4" → /32) or a CIDR ("10.0.0.0/24"); add or remove; on add
an optional bantime (seconds, 0 = default 24h); an optional absolute
flag flipping bantime from "seconds from now" to "Unix timestamp".
Trailing optionals are only forwarded when supplied so the daemon's
*int64 / *bool parameters stay nil and its default branches fire.

listbanned prints the active entries as JSON; an empty list emits "[]"
so jq-piped scripts don't choke on null. clearbanned is silent on
success.

Tests: registration check confirms all three commands are wired into
clientSugarCommands.

(cherry picked from commit ebc471a)
Add a new networking page (peer-management.mdx) covering the disc/1
session greeting, self-connect detection, cross-dial dedup,
per-peer telemetry, outbound slot allocation across full-relay /
block-relay-only / feeler / anchor buckets, network-group diversity,
inbound eviction, addrman maintenance (feeler + addrfetch + anchor
persistence), and the discourage / ban model. Linked from
networking sidebar.

pip-0006.mdx operator-RPC list extended with the three new ban
RPCs. Cross-link added between pip-0006 and the new
peer-management page.

cli.mdx network row updated with addnode, removenode,
addrbook-status, addrbook-resetkey, dialv2, setban, listbanned,
clearbanned.

admin.mdx JSON-RPC reference gains entries for every new admin
method shipped in the v2.0 networking work: addnode,
addrbookResetKey, addrbookStatus, clearbanned, dialV2, listbanned,
removenode, setban. Inserted in the existing alphabetical order so
the page stays scannable.

(cherry picked from commit ab21434)
probeOne opened the parallax-disc/1 conversation with YourAddr,
which the daemon-side handler now rejects as "msg 0x02 before
Hello" — the same gate that protects the daemon from out-of-order
messages disconnects the crawler before it can ask for peers.

Send a single disc Hello (ProtoVersion=1, random Nonce, ListenPort
0, no services) ahead of YourAddr + GetPeers so the handler accepts
the rest of the exchange. The probe is a one-shot tool, so a
per-process random nonce is enough; we fall back to a non-zero
sentinel if crypto/rand fails on the host.

Fixes the regression in parallax-disc crawl / probe against any
daemon running the patched build.

(cherry picked from commit ee5bbab)
Workflows previously triggered only on main. Push and pull_request
events on long-lived release branches (v2.0.x, v2.1.x, …) silently
skipped CI, so regressions on those branches went undetected until
the eventual merge to main.

Add 'v*' to the branches filter on push and pull_request triggers
for all three workflows. Tag-only refs are unaffected — release.yml
still owns those.

(cherry picked from commit 74530aa)
When --bootnodes is unset and the loaded --state is empty, seed the
walker from netparams.MainnetBootnodesV2 so a fresh crawler can
cold-start without operator config. Explicit --bootnodes still wins
and a populated state file still cold-starts on its own.

(cherry picked from commit 804a8be)
…upted

Port go-ethereum 7596db5f. The canceled-context branch raced with the
in-process RPC server: select in client.send/op.wait could pick the
ready request/response over ctx.Done(), so the call sometimes succeeded
and tripped the 'transaction should be nil' assertion. Replace with
positive lookups at index 0 and 1 plus the existing not-found check.

(cherry picked from commit 8872332)
@andrepatta andrepatta marked this pull request as ready for review April 28, 2026 14:30
@andrepatta andrepatta merged commit c6f6806 into main Apr 28, 2026
3 checks passed
@andrepatta andrepatta deleted the integration/2.0.x-to-main branch April 28, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant