Skip to content

backport: Merge bitcoin/bitcoin#30397, 22729, 29633, 29459#7300

Open
vijaydasmp wants to merge 3 commits into
dashpay:developfrom
vijaydasmp:May_2026_04
Open

backport: Merge bitcoin/bitcoin#30397, 22729, 29633, 29459#7300
vijaydasmp wants to merge 3 commits into
dashpay:developfrom
vijaydasmp:May_2026_04

Conversation

@vijaydasmp

Copy link
Copy Markdown

bitcoin backports

@github-actions

github-actions Bot commented Apr 30, 2026

Copy link
Copy Markdown

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@vijaydasmp vijaydasmp changed the title backport: Merge bitcoin/bitcoin#26662 backport: Merge bitcoin/bitcoin#28264,30291,30397,2279,29459 May 8, 2026
@vijaydasmp vijaydasmp changed the title backport: Merge bitcoin/bitcoin#28264,30291,30397,2279,29459 backport: Merge bitcoin/bitcoin#30291,30397,2279,29459 May 8, 2026
@vijaydasmp vijaydasmp changed the title backport: Merge bitcoin/bitcoin#30291,30397,2279,29459 backport: Merge bitcoin/bitcoin#30291, 30397, 22729, 29633, 29459 May 8, 2026
@vijaydasmp vijaydasmp marked this pull request as ready for review May 18, 2026 03:03
@thepastaclaw

thepastaclaw commented May 18, 2026

Copy link
Copy Markdown

✅ Review complete (commit 955f92d)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 314e0a3b81

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 231 to 233
if extra_args is None:
extra_args = self.extra_args

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid mutating shared node args when auto-inserting binds

start() appends auto-generated -bind arguments directly into extra_args, and when extra_args is omitted this aliases self.extra_args (line 232). In the framework, add_nodes() commonly seeds node args with shared empty lists ([[]] * num_nodes), so the first node that starts can mutate the list used by other nodes; subsequent nodes then inherit the first node’s bind ports and may fail with port-collision startup errors. Copy extra_args before appending so each node gets an isolated argument list.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5e2bf247-6081-4079-9130-57825a639fe0

📥 Commits

Reviewing files that changed from the base of the PR and between bccd3eb and 955f92d.

📒 Files selected for processing (8)
  • src/init.cpp
  • src/logging.h
  • src/net.cpp
  • src/test/util/net.cpp
  • test/functional/feature_bind_extra.py
  • test/functional/test-shell.md
  • test/functional/test_framework/test_node.py
  • test/functional/test_framework/util.py
✅ Files skipped from review due to trivial changes (3)
  • test/functional/test-shell.md
  • src/test/util/net.cpp
  • src/logging.h
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/init.cpp
  • test/functional/test_framework/util.py
  • test/functional/test_framework/test_node.py
  • src/net.cpp
  • test/functional/feature_bind_extra.py

Walkthrough

This PR changes onion service target selection in node initialization to prefer the first -bind address over the default target when no onion binds are configured. CConnman::InitBinds now fails fast on the first unsuccessful bind and reports onion bind errors. Test framework port allocation adds a tor_port helper and refactors rpc_port. TestNode now auto-injects default P2P and onion bind arguments when no explicit bind is configured. feature_bind_extra.py is extended to a 3-node scenario. Minor documentation and formatting updates are also included.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant feature_bind_extra.py
  participant TestNode
  participant util.py
  participant init.cpp
  participant CConnman

  feature_bind_extra.py->>TestNode: setup_nodes(extra_args)
  TestNode->>TestNode: check has_explicit_bind / -nolisten
  TestNode->>util.py: p2p_port(n), tor_port(n)
  TestNode->>TestNode: append default -bind args (P2P, onion)
  TestNode->>init.cpp: start node with bind args
  init.cpp->>init.cpp: select onion_service_target (vBinds.front() or default)
  init.cpp->>CConnman: InitBinds(options)
  CConnman->>CConnman: bind vBinds/vWhiteBinds/onion_binds
  CConnman-->>init.cpp: return false on first failure, else continue
Loading

Suggested reviewers: thepastaclaw, kwvg, PastaPastaPasta

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the PR as a backport merge of several Bitcoin upstream changes.
Description check ✅ Passed The description is brief but clearly related to the changeset as a Bitcoin backports bundle.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
test/functional/mempool_accept.py (1)

80-86: 💤 Low value

Clarify or remove the incomplete comment.

Line 86 contains the comment # ... 0.99 passes, but the subsequent test case (lines 87-90) doesn't actually pass a maxfeerate parameter to demonstrate this. The comment may confuse readers who expect to see a positive feerate test immediately following the negative feerate test.

Consider either:

  • Removing the comment
  • Expanding it to clarify that any positive value would pass (without needing explicit demonstration here)
  • Adding an explicit test with a positive maxfeerate value
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/functional/mempool_accept.py` around lines 80 - 86, The inline comment
"# ... 0.99 passes" is misleading because no positive maxfeerate test follows;
update the test around the assert_raises_rpc_error call that uses
check_mempool_result so the comment matches reality: either remove the comment,
replace it with a clarifying note that positive maxfeerate values would pass
without an explicit test, or add an explicit passing assertion that calls
check_mempool_result with maxfeerate=0.99 (using the same raw_tx_in_block and
expected successful result_expected) to demonstrate the positive-case; reference
check_mempool_result and raw_tx_in_block when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/functional/test_framework/test_node.py`:
- Around line 94-98: The current logic only sets has_explicit_bind by checking
extra_conf for entries starting with "bind=", causing auto-injected binds to
ignore effective settings like listen, port, and whitebind; update the code in
the block that calls append_config(datadir, extra_conf) so it computes the
effective configuration after appending and derives has_explicit_bind from that
effective config: consider any explicit "bind=" or "-bind=" entries, any
whitebind entries, whether listen=0 is set, and whether a custom port is set
(i.e., port != p2p_port(self.index)); if any of those conditions apply, treat
the node as having an explicit bind and do not inject default
p2p_port(self.index). Use the existing symbols append_config, extra_conf,
has_explicit_bind, p2p_port(self.index), listen, port, whitebind to find and
change the logic.

In `@test/functional/test_runner.py`:
- Line 490: Replace the bare assertion on results_filepath.parent.exists() with
explicit error handling: check if not results_filepath.parent.exists() and raise
a clear exception (e.g., ValueError or FileNotFoundError) or call the same
error-reporting helper used elsewhere in this module, using the same message
"Results file parent directory does not exist" so the check on
results_filepath.parent is enforced even when Python is run with -O; update the
code near the results_filepath usage (the results_filepath variable check) to
follow the existing pattern used around the other validations in this file.

---

Nitpick comments:
In `@test/functional/mempool_accept.py`:
- Around line 80-86: The inline comment "# ... 0.99 passes" is misleading
because no positive maxfeerate test follows; update the test around the
assert_raises_rpc_error call that uses check_mempool_result so the comment
matches reality: either remove the comment, replace it with a clarifying note
that positive maxfeerate values would pass without an explicit test, or add an
explicit passing assertion that calls check_mempool_result with maxfeerate=0.99
(using the same raw_tx_in_block and expected successful result_expected) to
demonstrate the positive-case; reference check_mempool_result and
raw_tx_in_block when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ea4c1c31-e458-42d1-b146-76c59c425be7

📥 Commits

Reviewing files that changed from the base of the PR and between 5fd84aa and 314e0a3.

📒 Files selected for processing (10)
  • src/init.cpp
  • src/logging.h
  • src/net.cpp
  • src/test/util/net.cpp
  • test/functional/feature_bind_extra.py
  • test/functional/mempool_accept.py
  • test/functional/test-shell.md
  • test/functional/test_framework/test_node.py
  • test/functional/test_framework/util.py
  • test/functional/test_runner.py

Comment thread test/functional/test_framework/test_node.py
Comment thread test/functional/test_runner.py Outdated
if args.resultsfile:
results_filepath = pathlib.Path(args.resultsfile)
# Stop early if the parent directory doesn't exist
assert results_filepath.parent.exists(), "Results file parent directory does not exist"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace assertion with explicit error handling for consistency.

Using assert for user input validation is inconsistent with the error handling pattern used elsewhere in this file (e.g., lines 497-498, 546-547), and assertions can be disabled with python -O.

Suggested fix
-        assert results_filepath.parent.exists(), "Results file parent directory does not exist"
+        if not results_filepath.parent.exists():
+            print("ERROR: Results file parent directory does not exist")
+            sys.exit(1)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert results_filepath.parent.exists(), "Results file parent directory does not exist"
if not results_filepath.parent.exists():
print("ERROR: Results file parent directory does not exist")
sys.exit(1)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/functional/test_runner.py` at line 490, Replace the bare assertion on
results_filepath.parent.exists() with explicit error handling: check if not
results_filepath.parent.exists() and raise a clear exception (e.g., ValueError
or FileNotFoundError) or call the same error-reporting helper used elsewhere in
this module, using the same message "Results file parent directory does not
exist" so the check on results_filepath.parent is enforced even when Python is
run with -O; update the code near the results_filepath usage (the
results_filepath variable check) to follow the existing pattern used around the
other validations in this file.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Five-PR Bitcoin Core backport (bitcoin#30291, bitcoin#30397, bitcoin#22729, bitcoin#29633, bitcoin#29459) that merges cleanly against Dash's existing extensions in src/net.cpp and src/init.cpp. The behavioral change (bitcoin#22729: fail-fast on bind failures plus per-node bind injection in the test framework) is correctly carried over. One real but latent footgun in the test framework's bind injection (shared list mutation) plus two cosmetic comment issues. No blocking issues identified — Codex's 'blocking' framing of the shared-list bug is overstated because every current call site either short-circuits via has_explicit_bind or passes its own non-shared extra_args.

Reviewed commit: 314e0a3

🟡 1 suggestion(s) | 💬 2 nitpick(s)

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `test/functional/test_framework/test_node.py`:
- [SUGGESTION] lines 231-243: start() mutates the caller's extra_args list — latent shared-reference footgun
  `start()` calls `extra_args.append(...)` directly on the list reference assigned from `self.extra_args` (or the caller-supplied list). In `BitcoinTestFramework.add_nodes`, the default path is `extra_args = [[]] * num_nodes`, which produces N references to the same empty list, all of which are stored as each node's `self.extra_args`.

In the current tree this does not blow up: with the default `bind_to_localhost_only=True`, `extra_conf` contains `bind=127.0.0.1`, so `self.has_explicit_bind` is True in `__init__` and the new injection block is skipped. The five tests that set `bind_to_localhost_only=False` (feature_discover, feature_bind_extra, feature_bind_port_discover, feature_bind_port_externalip, rpc_bind) either run a single node or supply per-node `extra_args` lists that already contain `-bind=...` (so the `any(e.startswith('-bind=')...)` short-circuit kicks in). So no test currently mutates a shared list.

But any future test that sets `bind_to_localhost_only=False` while relying on the default `extra_args` would silently get every node binding to node 0's `p2p_port`/`tor_port`, producing confusing port-collision failures. Copy the list before mutating to make the new injection block defensive against the shared-default.

Comment thread test/functional/test_framework/test_node.py
Comment thread test/functional/test_framework/test_node.py Outdated
Comment thread test/functional/mempool_accept.py Outdated
rawtxs=[raw_tx_in_block],
maxfeerate=-0.01,
))
# ... 0.99 passes

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 Nitpick: Orphaned '# ... 0.99 passes' comment from bitcoin#29459 cherry-pick

Upstream bitcoin#29459 inserts the new negative-feerate assertion immediately before a pre-existing self.check_mempool_result(..., maxfeerate=0.99) call, where the trailing # ... 0.99 passes comment naturally describes the following line. Dash's mempool_accept.py never carried the maxfeerate=1 fails / 0.99 passes pair (pre-existing divergence), so the cherry-pick leaves the comment dangling above a check_mempool_result call that has no maxfeerate=0.99. Drop the comment or replace it with one that matches what the next call actually does. Cosmetic only.

source: ['claude']

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

29459: address thepastaclaw's comment comment please

@knst knst left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good overall, but check my two actionable comments

Comment thread test/functional/test_runner.py Outdated
break

print_results(test_results, max_len_name, (int(time.time() - start_time)))
runtime = int(time.time() - start_time)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: mark 30291 as partial due to missing fix of typo on this line:

 sys.exit(f"Early exiting after test failure due to insufficient free space in {tmpdir}\n"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right moved this commit it to May_2026_05 where pre-req was present

Comment thread test/functional/test_framework/test_node.py Outdated
Comment thread test/functional/test_framework/test_node.py
Comment thread test/functional/test_framework/test_node.py
Comment thread test/functional/mempool_accept.py Outdated
rawtxs=[raw_tx_in_block],
maxfeerate=-0.01,
))
# ... 0.99 passes

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

29459: address thepastaclaw's comment comment please

@knst knst added this to the 24 milestone Jun 2, 2026
@vijaydasmp vijaydasmp changed the title backport: Merge bitcoin/bitcoin#30291, 30397, 22729, 29633, 29459 backport: Merge bitcoin/bitcoin#(partial) 30291, 30397, 22729, 29633, 29459 Jun 21, 2026
@github-actions

Copy link
Copy Markdown

This pull request has conflicts, please rebase.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 086d42e6cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

will_listen = all(e != "-nolisten" and e != "-listen=0" for e in extra_args)
has_explicit_bind = self.has_explicit_bind or any(e.startswith("-bind=") for e in extra_args)
if will_listen and not has_explicit_bind:
extra_args.append(f"-bind=0.0.0.0:{p2p_port(self.index)}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep no-bind test starts from gaining a normal bind

When a test opts out with bind_to_localhost_only = False, some scripts are explicitly exercising the daemon path where no -bind is present: feature_bind_port_discover.py node 0 expects bind_on_any to call Discover(), and feature_bind_port_externalip.py cases rely on GetListenPort() honoring -port. Appending this normal -bind=0.0.0.0:<p2p_port> makes args.GetArgs("-bind") nonempty for those starts, so discovery is suppressed and -port is ignored in favor of the injected bind port. This should be opt-in or avoided for tests that intentionally requested the no-bind path.

Useful? React with 👍 / 👎.

Comment thread src/net.cpp
Comment on lines +3956 to +3957
if (!Bind(addr_bind, BF_REPORT_ERROR | BF_DONT_ADVERTISE, NetPermissionFlags::None)) {
return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep implicit onion bind conflicts non-fatal

AppInitMain() still inserts DefaultOnionServiceTarget() into options.onion_binds when no -bind/-whitebind is supplied, even if the user sets -listenonion=0; making every onion bind failure fatal here means a conflict on the implicit 127.0.0.1 onion target port aborts startup before the later 0.0.0.0 bind can succeed. This regresses running another node with a different -port and onion listening disabled, where the implicit Tor target is occupied but normal P2P listening would otherwise work; only explicit onion binds should be fatal, or the default should be skipped when onion listening is off.

Useful? React with 👍 / 👎.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Correction: the first version of this review over-promoted duplicate carried-forward test-framework findings while applying the backport-prerequisite policy gate. I edited the duplicate inline comments as superseded; please use the corrected finding list below.

Cumulative review at 086d42e confirms the five-PR backport stack (bitcoin#30291 partial, bitcoin#30397, bitcoin#22729, bitcoin#29633, bitcoin#29459) merges cleanly with the expected Dash adaptations in InitBinds and onion-service target selection. The prior mempool_accept comment nitpick is fixed. Two prior test-framework issues still apply, one new test-runner argument edge case was found, and the policy gate keeps one missing-prerequisite finding for bitcoin#29434 as blocking.

🔴 1 blocking | 🟡 2 suggestion(s) | 💬 1 nitpick(s)

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `test/functional/test_framework/test_node.py`:
- [SUGGESTION] test/functional/test_framework/test_node.py:231-243: start() mutates caller's extra_args list — shared-reference footgun
  Carried forward from the prior review at 314e0a3b and still valid at 086d42e6. When `extra_args` is None, `start()` aliases `self.extra_args` and appends the auto-injected `-bind=...` flags onto that referenced list. `BitcoinTestFramework.add_nodes` can install shared inner lists via `[[]] * num_nodes`, so the first node/restart can leak stale bind flags into later starts. Copy the selected list before appending, e.g. `extra_args = list(self.extra_args) if extra_args is None else list(extra_args)`.
- [NITPICK] test/functional/test_framework/test_node.py:234-238: Carry-over comment references Bitcoin regtest port 18445 and bitcoind
  Still valid at 086d42e6. The comment imported with bitcoin#22729 still mentions `bitcoind`, `bitcoin.conf`, and `127.0.0.1:18445`; the port is Bitcoin Core's regtest onion-service target, while Dash's ports differ by network and the code correctly uses `tor_port(self.index)`. Prefer Dash-neutral wording.
- [SUGGESTION] test/functional/test_framework/test_node.py:239-243: Implicit -bind injection ignores --dashd-extra-args (extra_args_from_options)
  `will_listen` and `has_explicit_bind` inspect only per-node `extra_args`, but the process is launched with `self.args + self.extra_args_from_options + extra_args`. A global `--dashd-extra-args=-listen=0` or `--dashd-extra-args=-bind=...` therefore does not suppress the auto-injected binds, which can fight user-supplied global args. Base the bind/listen decision on the same combined argument set passed to dashd.

In `test/functional/mempool_accept.py`:
- [BLOCKING] test/functional/mempool_accept.py:80-85: Missing prerequisite: bitcoin#29434
  bitcoin#29459 was added upstream immediately after the maxfeerate coverage introduced by bitcoin#29434. Upstream #29434 added the 1 BTC/kvB rejection test, the 0.99 BTC/kvB passing test, and the `src/rpc/mempool.cpp` `ParseFeeRate` path that rejects fee rates >= 1 BTC/kvB. Dash's current backport of bitcoin#29459 only adds the negative maxfeerate assertion and adapts around the missing #29434 context: the following already-known check still has no `maxfeerate=0.99`, and `src/rpc/mempool.cpp` still parses maxfeerate with `CFeeRate(AmountFromValue(...))` instead of `ParseFeeRate`. Per the review policy for full upstream backports, this missing prerequisite needs either backporting or explicit PR-description documentation as an intentional exclusion.

Comment on lines +234 to +238
# If listening and no -bind is given, then bitcoind would bind P2P ports on
# 0.0.0.0:P and 127.0.0.1:18445 (for incoming Tor connections), where P is
# a unique port chosen by the test framework and configured as port=P in
# bitcoin.conf. To avoid collisions on 127.0.0.1:18445, change it to
# 127.0.0.1:tor_port().

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 Nitpick: Carry-over comment references Bitcoin regtest port 18445 and bitcoind

The block comment cherry-picked from bitcoin#22729 still mentions bitcoind, bitcoin.conf, and 127.0.0.1:18445 — the latter is Bitcoin Core's regtest OnionServiceTargetPort. Dash's onion-service target ports differ per network (9996 / 19996 / 19796 / 19896) and the code already uses the dynamic tor_port(self.index) helper, so the literal 18445 is misleading for Dash test authors. Rephrase to reference dashd / dash.conf and a generic onion-service target port instead of the Bitcoin-specific literal.

Suggested change
# If listening and no -bind is given, then bitcoind would bind P2P ports on
# 0.0.0.0:P and 127.0.0.1:18445 (for incoming Tor connections), where P is
# a unique port chosen by the test framework and configured as port=P in
# bitcoin.conf. To avoid collisions on 127.0.0.1:18445, change it to
# 127.0.0.1:tor_port().
# If listening and no -bind is given, then dashd would bind P2P ports on
# 0.0.0.0:P and 127.0.0.1:<default onion-service target port> (for incoming
# Tor connections), where P is a unique port chosen by the test framework
# and configured as port=P in dash.conf. To avoid collisions on the default
# onion target port, change it to 127.0.0.1:tor_port().

source: ['claude', 'codex']

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this update — Carry-over comment references Bitcoin regtest port 18445 and bitcoind no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

Comment on lines +239 to +243
will_listen = all(e != "-nolisten" and e != "-listen=0" for e in extra_args)
has_explicit_bind = self.has_explicit_bind or any(e.startswith("-bind=") for e in extra_args)
if will_listen and not has_explicit_bind:
extra_args.append(f"-bind=0.0.0.0:{p2p_port(self.index)}")
extra_args.append(f"-bind=127.0.0.1:{tor_port(self.index)}=onion")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: Implicit -bind injection ignores --dashd-extra-args (extra_args_from_options)

will_listen and has_explicit_bind inspect only the per-node extra_args, but on line 258 the process is launched with self.args + self.extra_args_from_options + extra_args. That means a global --dashd-extra-args=-listen=0 or --dashd-extra-args=-bind=... passed via the test runner does not influence the implicit-bind decision: the auto-injected -bind= flags get appended anyway, which can fight a user-supplied -listen=0 (dashd will warn/refuse listening with explicit binds) or duplicate a user-supplied bind. Decide based on the same combined argument set that is actually passed to dashd.

Suggested change
will_listen = all(e != "-nolisten" and e != "-listen=0" for e in extra_args)
has_explicit_bind = self.has_explicit_bind or any(e.startswith("-bind=") for e in extra_args)
if will_listen and not has_explicit_bind:
extra_args.append(f"-bind=0.0.0.0:{p2p_port(self.index)}")
extra_args.append(f"-bind=127.0.0.1:{tor_port(self.index)}=onion")
startup_args = [*self.extra_args_from_options, *extra_args]
will_listen = all(e != "-nolisten" and e != "-listen=0" for e in startup_args)
has_explicit_bind = self.has_explicit_bind or any(e.startswith("-bind=") for e in startup_args)
if will_listen and not has_explicit_bind:
extra_args.append(f"-bind=0.0.0.0:{p2p_port(self.index)}")
extra_args.append(f"-bind=127.0.0.1:{tor_port(self.index)}=onion")

source: ['codex']

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this update — Implicit -bind injection ignores --dashd-extra-args (extra_args_from_options) no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

Comment on lines 231 to +243
if extra_args is None:
extra_args = self.extra_args

# If listening and no -bind is given, then bitcoind would bind P2P ports on
# 0.0.0.0:P and 127.0.0.1:18445 (for incoming Tor connections), where P is
# a unique port chosen by the test framework and configured as port=P in
# bitcoin.conf. To avoid collisions on 127.0.0.1:18445, change it to
# 127.0.0.1:tor_port().
will_listen = all(e != "-nolisten" and e != "-listen=0" for e in extra_args)
has_explicit_bind = self.has_explicit_bind or any(e.startswith("-bind=") for e in extra_args)
if will_listen and not has_explicit_bind:
extra_args.append(f"-bind=0.0.0.0:{p2p_port(self.index)}")
extra_args.append(f"-bind=127.0.0.1:{tor_port(self.index)}=onion")

@thepastaclaw thepastaclaw Jun 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: start() mutates caller's extra_args list — shared-reference footgun

Carried forward from the prior review at 314e0a3 and still valid at 086d42e. When extra_args is None, start() aliases self.extra_args and appends the auto-injected -bind=... flags onto that referenced list. BitcoinTestFramework.add_nodes can install shared inner lists via [[]] * num_nodes, so the first node/restart can leak stale bind flags into later starts. Copy the selected list before appending, e.g. extra_args = list(self.extra_args) if extra_args is None else list(extra_args).

Correction note: this is a suggestion, not a backport-prerequisite blocker; the earlier policy-gate text on this comment was incorrect.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still present at bccd3eb.

@thepastaclaw thepastaclaw Jul 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correction: this prior finding is STILL VALID at 955f92d63b and was carried forward in the top-level review. The earlier auto-resolved reply was wrong; start() still aliases self.extra_args and appends the implicit -bind= arguments to that same list.

Updated after canonical verifier reconciliation for commit 955f92d.

Comment on lines +234 to +238
# If listening and no -bind is given, then bitcoind would bind P2P ports on
# 0.0.0.0:P and 127.0.0.1:18445 (for incoming Tor connections), where P is
# a unique port chosen by the test framework and configured as port=P in
# bitcoin.conf. To avoid collisions on 127.0.0.1:18445, change it to
# 127.0.0.1:tor_port().

@thepastaclaw thepastaclaw Jun 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superseded duplicate

This inline comment was a duplicate created by an over-broad policy-gate promotion. Please ignore this thread and use the corrected nitpick comment on the same block instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this update — Carry-over comment references Bitcoin regtest Tor port 18445 (carried from prior review) no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

Comment thread test/functional/mempool_accept.py Outdated
Comment on lines +80 to +85
# Check negative feerate
assert_raises_rpc_error(-3, "Amount out of range", lambda: self.check_mempool_result(
result_expected=None,
rawtxs=[raw_tx_in_block],
maxfeerate=-0.01,
))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: Missing prerequisite: bitcoin#29434

bitcoin#29459 was added upstream immediately after the maxfeerate coverage introduced by bitcoin#29434. In upstream, bitcoin#29434 added the 1 BTC/kvB rejection test, the 0.99 BTC/kvB passing test, and the src/rpc/mempool.cpp ParseFeeRate path that rejects fee rates >= 1 BTC/kvB. Dash's current backport of bitcoin#29459 only adds the negative maxfeerate assertion and adapts around the missing bitcoin#29434 context: the following already-known check still has no maxfeerate=0.99, and src/rpc/mempool.cpp still parses maxfeerate with CFeeRate(AmountFromValue(...)) instead of ParseFeeRate. This is a soft prerequisite gap because the new negative-feerate test is cleanly adapted and should pass, but the upstream dependency chain around this test is incomplete.


Policy gate (backport-prereq-restore): For full upstream backport PRs, a missing prerequisite is blocking unless the finding is explicitly allowlisted (e.g. intentional_exclusion: true or a matching entry in policy_overrides). The agent's original evidence above is the basis for this block; either backport the prerequisite or annotate the intentional exclusion in the PR description.

source: ['codex-backport-reviewer']

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still present at bccd3eb.

@thepastaclaw thepastaclaw Jul 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correction/clarification: this prior bitcoin#29434 prerequisite finding is OUTDATED at 955f92d63b because the bitcoin#29459 mempool_accept.py hunk it depended on is no longer present in the current stack. It is superseded by the new top-level blocker that the PR still advertises bitcoin#29459 while omitting that cherry-pick.

Updated after canonical verifier reconciliation for commit 955f92d.

Comment on lines 231 to +243
if extra_args is None:
extra_args = self.extra_args

# If listening and no -bind is given, then bitcoind would bind P2P ports on
# 0.0.0.0:P and 127.0.0.1:18445 (for incoming Tor connections), where P is
# a unique port chosen by the test framework and configured as port=P in
# bitcoin.conf. To avoid collisions on 127.0.0.1:18445, change it to
# 127.0.0.1:tor_port().
will_listen = all(e != "-nolisten" and e != "-listen=0" for e in extra_args)
has_explicit_bind = self.has_explicit_bind or any(e.startswith("-bind=") for e in extra_args)
if will_listen and not has_explicit_bind:
extra_args.append(f"-bind=0.0.0.0:{p2p_port(self.index)}")
extra_args.append(f"-bind=127.0.0.1:{tor_port(self.index)}=onion")

@thepastaclaw thepastaclaw Jun 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superseded duplicate

This inline comment duplicated the carried-forward extra_args mutation finding and incorrectly labeled it as a blocking backport-prerequisite issue. Please ignore this thread and use the corrected suggestion comment instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this update — Prior finding still valid: start() mutates caller-owned extra_args no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

Comment on lines +234 to +238
# If listening and no -bind is given, then bitcoind would bind P2P ports on
# 0.0.0.0:P and 127.0.0.1:18445 (for incoming Tor connections), where P is
# a unique port chosen by the test framework and configured as port=P in
# bitcoin.conf. To avoid collisions on 127.0.0.1:18445, change it to
# 127.0.0.1:tor_port().

@thepastaclaw thepastaclaw Jun 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superseded duplicate

This inline comment duplicated the stale-comment nitpick and incorrectly labeled it as a blocking backport-prerequisite issue. Please ignore this thread and use the corrected nitpick comment instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this update — Prior finding still valid: stale Bitcoin onion port in comment no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

@vijaydasmp vijaydasmp changed the title backport: Merge bitcoin/bitcoin#(partial) 30291, 30397, 22729, 29633, 29459 backport: Merge bitcoin/bitcoin#30397, 22729, 29633, 29459 Jul 3, 2026
@vijaydasmp vijaydasmp requested review from knst and thepastaclaw July 3, 2026 01:22

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bccd3ebc61

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +239 to +240
will_listen = all(e != "-nolisten" and e != "-listen=0" for e in extra_args)
has_explicit_bind = self.has_explicit_bind or any(e.startswith("-bind=") for e in extra_args)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor global listen-off arguments before adding binds

When -listen=0 or -nolisten is supplied globally via --dashd-arg, this check still treats the node as listening because it only inspects the per-node extra_args, even though self.extra_args_from_options is later prepended to all_args. In that scenario this branch appends two -bind options and init rejects the combination (src/init.cpp rejects any -bind/-whitebind with -listen=0), so RPC-only tests that disable listening globally fail before starting; include the global args in the listen/bind checks before synthesizing binds.

Useful? React with 👍 / 👎.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Incremental + cumulative review at bccd3eb: the latest delta fixes the prior Dash/Bitcoin carry-over comment in test_node.py, so prior-4 is resolved. Three prior findings remain carried forward on the current head: two nonblocking test-framework bind-injection footguns, plus the missing bitcoin#29434 prerequisite for the bitcoin#29459 maxfeerate test. No new latest-delta findings were found beyond the carried-forward prerequisite policy block.

Source: reviewers: opus (general), claude-sonnet-5 (general), gpt-5.5[high] (general, failed), opus (dash-core-commit-history), claude-sonnet-5 (dash-core-commit-history), gpt-5.5[high] (dash-core-commit-history, failed), opus (backport-reviewer), claude-sonnet-5 (backport-reviewer), gpt-5.5[high] (backport-reviewer, failed); verifier: opus; specialists: dash-core-commit-history, backport-reviewer

🔴 1 blocking | 🟡 2 suggestion(s)

Carried-forward findings already raised (3)

These findings were not re-posted as new inline comments because an existing review thread already covers them.

  • [BLOCKING] (deduped existing open thread) test/functional/mempool_accept.py:80-85: Missing prerequisite: bitcoin#29434 (carried forward) — STILL VALID at bccd3eb. bitcoin#29459 was written upstream immediately after bitcoin#29434, which added the >=1 BTC/kvB rejection assertion, the 0.99 BTC/kvB passing assertion, and switched src/rpc/mempool.cpp maxfeerate parsing to ParseFeeRate. Current Dash still lacks that prerequisite conte...
  • [SUGGESTION] (deduped existing open thread) test/functional/test_framework/test_node.py:231-243: start() mutates caller's extra_args list — shared-reference footgun (carried forward) — Verified still present at bccd3eb. When extra_args is None, extra_args = self.extra_args aliases the node's stored list, and lines 242-243 unconditionally .append() the auto-injected -bind=0.0.0.0:{p2p_port(self.index)} and -bind=127.0.0.1:{tor_port(self.index)}=onion flags onto that...
  • [SUGGESTION] (deduped existing open thread) test/functional/test_framework/test_node.py:239-243: Implicit -bind injection ignores extra_args_from_options (--dashd-extra-args) (carried forward) — Verified still present at bccd3eb. will_listen and has_explicit_bind inspect only the per-node extra_args, but on line 258 the process is launched with self.args + self.extra_args_from_options + extra_args. A global --dashd-extra-args=-listen=0 or --dashd-extra-args=-bind=... suppl...
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `test/functional/mempool_accept.py`:
- [BLOCKING] test/functional/mempool_accept.py:80-85: Missing prerequisite: bitcoin#29434 (carried forward)
  STILL VALID at bccd3ebc61. bitcoin#29459 was written upstream immediately after bitcoin#29434, which added the >=1 BTC/kvB rejection assertion, the 0.99 BTC/kvB passing assertion, and switched src/rpc/mempool.cpp maxfeerate parsing to ParseFeeRate. Current Dash still lacks that prerequisite context: test/functional/mempool_accept.py has only the negative maxfeerate assertion and the following already-known check, while src/rpc/mempool.cpp still parses maxfeerate through CFeeRate(AmountFromValue(...)) at both call sites and contains no ParseFeeRate call. The negative-feerate assertion is self-contained, but this is a full upstream backport PR and the missing prerequisite is blocking under the review policy unless the PR explicitly documents it as an intentional exclusion.

In `test/functional/test_framework/test_node.py`:
- [SUGGESTION] test/functional/test_framework/test_node.py:231-243: start() mutates caller's extra_args list — shared-reference footgun (carried forward)
  Verified still present at bccd3ebc61. When `extra_args` is None, `extra_args = self.extra_args` aliases the node's stored list, and lines 242-243 unconditionally `.append()` the auto-injected `-bind=0.0.0.0:{p2p_port(self.index)}` and `-bind=127.0.0.1:{tor_port(self.index)}=onion` flags onto that reference. Because `BitcoinTestFramework.add_nodes` constructs the default per-node extra_args as `[[]] * num_nodes`, every TestNode's `self.extra_args` default is the same list object. The first `start()` mutates the shared default; subsequent nodes / restarts see `-bind=` already present, causing `has_explicit_bind` to flip True and suppressing the correct implicit bind while carrying the wrong-index bind forward. The same hazard applies to callers passing their own list that they don't expect to be mutated. This is a latent bug introduced by this PR's bitcoin#22729 backport (the 15-line block was added by that merge). Defensively copy the list after the None-check.
- [SUGGESTION] test/functional/test_framework/test_node.py:239-243: Implicit -bind injection ignores extra_args_from_options (--dashd-extra-args) (carried forward)
  Verified still present at bccd3ebc61. `will_listen` and `has_explicit_bind` inspect only the per-node `extra_args`, but on line 258 the process is launched with `self.args + self.extra_args_from_options + extra_args`. A global `--dashd-extra-args=-listen=0` or `--dashd-extra-args=-bind=...` supplied to the test runner therefore does not influence the implicit-bind decision: the auto `-bind=` flags still get appended, which can fight a user-supplied `-listen=0` (dashd rejects `-listen=0` combined with explicit `-bind=`) or duplicate a user-supplied bind. Decide will_listen/has_explicit_bind from the same combined argument set that is actually passed to dashd. This is a latent bug introduced by this PR's bitcoin#22729 backport.

fanquake and others added 3 commits July 4, 2026 14:50
…l/net.cpp

e233ec0 refactor: Use designated initializer (Hodlinator)

Pull request description:

  Block was recently touched (e2d1f84) and the codebase recently switched to C++20 which allows this to improve robustness.

  Follow-up suggested in bitcoin#29625 (comment)

ACKs for top commit:
  maflcko:
    ACK e233ec0

Tree-SHA512: ce3a18f513421e923710a43c8f97db1badb7ff5c6bdbfd62d9543312d2225731db5c14bef16feb47c43b84fad4dc24485086634b680feba422d2b7b363e13fa6
…startup on bind failure

bca346a net: require P2P binds to succeed (Vasil Dimov)
af55253 net: report an error if unable to bind on the Tor listening addr:port (Vasil Dimov)
9a7e5f4 net: don't extra bind for Tor if binds are restricted (Vasil Dimov)

Pull request description:

  Make it possible to disable the Tor binding on `127.0.0.1:8334` and stop startup if any P2P bind fails instead of "if all P2P binds fail".

  Fixes bitcoin#22726
  Fixes bitcoin#22727

ACKs for top commit:
  achow101:
    ACK bca346a
  cbergqvist:
    ACK bca346a
  pinheadmz:
    ACK bca346a

Tree-SHA512: fabef89a957191eea4f3e3b6109d2b8389f27ecc74440a920b0c10f31fff00a85bcfd1eb3c91826c7169c618f4de8a8d0a260e2caf40fd854f07ea9a980d8603
d0e6564 log: Remove error() reference (Fabian Jahr)

Pull request description:

  Mini-followup to bitcoin#29236 that was just merged. Removes a reference to `error()` that was missed in a comment.

ACKs for top commit:
  ryanofsky:
    Code review ACK d0e6564. Just dropped LogPrintf reference since last review
  stickies-v:
    ACK d0e6564
  Empact:
    ACK bitcoin@d0e6564

Tree-SHA512: 8abe4895951013c2ceca9a57743aacabaf8af831d07eee9ae8372c121c16e88b7226f0e537200c3464792e19ac7e03b57ba0be31f43add8802753972b0aefc48

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 955f92d63b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/init.cpp
Comment on lines +2700 to +2701
} else if (!connOptions.vBinds.empty()) {
onion_service_target = connOptions.vBinds.front();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Warn when Tor uses a normal bind

When -listenonion=1 is used together with a normal -bind but no -bind=...=onion, this branch points the auto-created onion service at the normal bind while leaving connOptions.onion_binds empty. CConnman::Init() copies only onion_binds into m_onion_binds, and accepted peers are classified as inbound onion only when their local bind address is in that vector, so Tor peers arriving through this onion service are reported and handled as ordinary local/IP inbound peers. Please either keep a dedicated onion bind for this path or emit a startup warning requiring an explicit =onion bind for accurate onion accounting.

Useful? React with 👍 / 👎.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Correction: the first rendered body over-promoted duplicate/outdated prerequisite candidates. The canonical verified findings are below.

PR title still advertises four Bitcoin Core backports (bitcoin#30397, bitcoin#22729, bitcoin#29633, bitcoin#29459), but the commit stack at 955f92d contains only the first three. The bitcoin#29459 backport (and with it the mempool_accept.py hunk that previously depended on the missing bitcoin#29434 prerequisite) has been dropped, which resolves prior-1 but introduces a new stack-composition blocker: the PR description no longer matches the actual commits. The three present backports are faithful cherry-picks and the two prior test_node.py bind-injection footguns remain unchanged at the same lines.

Source: reviewers: opus (general), claude-sonnet-5 (general), gpt-5.5 (general), opus (dash-core-commit-history), claude-sonnet-5 (dash-core-commit-history), gpt-5.5 (dash-core-commit-history), opus (backport-reviewer), claude-sonnet-5 (backport-reviewer), gpt-5.5 (backport-reviewer); verifier: opus; specialists: dash-core-commit-history, backport-reviewer.

🔴 1 blocking | 🟡 2 suggestion(s)

Prior finding reconciliation
  • prior-1 (test/functional/mempool_accept.py:80-85, Missing prerequisite: bitcoin#29434): OUTDATED at 955f92d because bitcoin#29459 is no longer in the current stack; superseded by the new blocker that the PR still advertises bitcoin#29459 while omitting it.
  • prior-2 (test/functional/test_framework/test_node.py:231-243, shared extra_args mutation): STILL VALID and carried forward.
  • prior-3 (test/functional/test_framework/test_node.py:239-243, --dashd-extra-args ignored by implicit bind injection): STILL VALID and carried forward.
Carried-forward prior findings already raised (2)

These are still valid at 955f92d but are not re-posted as new inline comments because existing review threads already cover them.

  • [SUGGESTION] test/functional/test_framework/test_node.py:231-243: start() mutates caller's extra_args list — shared-reference footgun (carried forward) — STILL VALID at 955f92d (verified by direct read of the file). When start() is called without an explicit extra_args, line 232 aliases self.extra_args (a reference, not a copy), and lines 242-243 unconditionally append the auto-injected -bind=0.0.0.0:{p2p_port} and -bind=127.0.0.1:{tor_port}=onion flags to that same list. BitcoinTestFramework.add_nodes builds default extra_args as [[]] * num_nodes, so multiple TestNode instances can share one inner list object; the first start() mutates the shared list, leaking stale -bind= flags into other nodes' first start or into the same node's next restart. On the subsequent call has_explicit_bind becomes True (because the previously-appended -bind= is still there), so the correct implicit bind for the new port is silently skipped. The same hazard applies to any caller that passes their own list and doesn't expect it to be mutated. This is a direct import of the upstream bitcoin#22729 behavior, but it's worth defending against on the Dash side. Fix: copy the selected list before appending — extra_args = list(extra_args) after the None check.
  • [SUGGESTION] test/functional/test_framework/test_node.py:239-243: Implicit -bind injection ignores extra_args_from_options / --dashd-extra-args (carried forward) — STILL VALID at 955f92d. will_listen (line 239) and has_explicit_bind (line 240) inspect only the per-node extra_args, but the process is launched on line 258 with self.args + self.extra_args_from_options + extra_args. A user invoking test_runner.py --dashd-extra-args='-bind=127.0.0.1:xxxx' or --dashd-extra-args='-listen=0' will still get the framework's auto-injected -bind=0.0.0.0:{p2p} and -bind=127.0.0.1:{tor}=onion appended, producing conflicting/duplicate bind arguments. This is now more consequential because bitcoin#22729 (also in this stack) makes InitBinds fail fast on any bind error — a spurious duplicate -bind= from --dashd-extra-args can now abort node startup instead of being tolerated. Compute the decision from the same combined argument set that is actually launched.
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `src/init.cpp`:
- [BLOCKING] src/init.cpp:1: PR title claims bitcoin#29459 backport, but it is not in the commit stack
  The PR title is `backport: Merge bitcoin/bitcoin#30397, 22729, 29633, 29459`, but `git log upstream/develop..HEAD` at 955f92d63b shows only three merge commits: 7ea632a046 (#30397), a53fb4df0a (#22729), and 955f92d63b (#29633). The #29459 backport (negative maxfeerate assertion in test/functional/mempool_accept.py) that was present at the prior review head bccd3ebc61 has been dropped entirely from this push — `git diff 4af395d8b8..955f92d63b -- test/functional/mempool_accept.py` is empty, and mempool_accept.py is not in the PR's list of changed files. Either restore the #29459 cherry-pick (with its bitcoin#29434 prerequisite, as flagged in the prior review) or edit the PR title/description to accurately reflect the three-commit stack. Leaving the title as-is is misleading for maintainers scanning the merge queue and for anyone tracking backport coverage.

In `test/functional/test_framework/test_node.py`:
- [SUGGESTION] test/functional/test_framework/test_node.py:231-243: start() mutates caller's extra_args list — shared-reference footgun (carried forward)
  STILL VALID at 955f92d63b (verified by direct read of the file). When `start()` is called without an explicit `extra_args`, line 232 aliases `self.extra_args` (a reference, not a copy), and lines 242-243 unconditionally append the auto-injected `-bind=0.0.0.0:{p2p_port}` and `-bind=127.0.0.1:{tor_port}=onion` flags to that same list. `BitcoinTestFramework.add_nodes` builds default extra_args as `[[]] * num_nodes`, so multiple TestNode instances can share one inner list object; the first `start()` mutates the shared list, leaking stale `-bind=` flags into other nodes' first start or into the same node's next restart. On the subsequent call `has_explicit_bind` becomes True (because the previously-appended `-bind=` is still there), so the correct implicit bind for the new port is silently skipped. The same hazard applies to any caller that passes their own list and doesn't expect it to be mutated. This is a direct import of the upstream #22729 behavior, but it's worth defending against on the Dash side. Fix: copy the selected list before appending — `extra_args = list(extra_args)` after the `None` check.
- [SUGGESTION] test/functional/test_framework/test_node.py:239-243: Implicit -bind injection ignores extra_args_from_options / --dashd-extra-args (carried forward)
  STILL VALID at 955f92d63b. `will_listen` (line 239) and `has_explicit_bind` (line 240) inspect only the per-node `extra_args`, but the process is launched on line 258 with `self.args + self.extra_args_from_options + extra_args`. A user invoking `test_runner.py --dashd-extra-args='-bind=127.0.0.1:xxxx'` or `--dashd-extra-args='-listen=0'` will still get the framework's auto-injected `-bind=0.0.0.0:{p2p}` and `-bind=127.0.0.1:{tor}=onion` appended, producing conflicting/duplicate bind arguments. This is now more consequential because #22729 (also in this stack) makes InitBinds fail fast on any bind error — a spurious duplicate `-bind=` from --dashd-extra-args can now abort node startup instead of being tolerated. Compute the decision from the same combined argument set that is actually launched.

Comment thread src/test/util/net.cpp
.fRelevantServices=random_context.randbool(),
.m_relay_txs=random_context.randbool(),
.fBloomFilter=random_context.randbool(),
.nKeyedNetGroup=random_context.randrange(100),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: Missing prerequisite: bitcoin#29625

bitcoin#30397 was applied on top of upstream's bitcoin#29625 pre-state. Upstream bitcoin#30397 changes .nKeyedNetGroup=random_context.randrange(100u), while Dash's cherry-pick keeps .nKeyedNetGroup=random_context.randrange(100). The 100u change traces to upstream commit e2d1f84 in merge 5c0cd20 (bitcoin#29625). This is a soft prerequisite/workaround: the current code is functionally harmless, but it diverges because the upstream pre-state for the modified initializer is missing.


Policy gate (backport-prereq-restore): For full upstream backport PRs, a missing prerequisite is blocking unless the finding is explicitly allowlisted (e.g. intentional_exclusion: true or a matching entry in policy_overrides). The agent's original evidence above is the basis for this block; either backport the prerequisite or annotate the intentional exclusion in the PR description.

Suggested change
.nKeyedNetGroup=random_context.randrange(100),
Backport bitcoin#29625 or include the small `100u` pre-state hunk if the larger prerequisite is intentionally deferred.

source: ['codex-backport-reviewer']

Comment thread src/test/util/net.cpp
Comment on lines 118 to 119
std::vector<NodeEvictionCandidate> candidates;
for (int id = 0; id < n_candidates; ++id) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: Missing prerequisite: bitcoin#26642

Upstream's pre-bitcoin#30397 helper had candidates.reserve(n_candidates); immediately after constructing the vector. Dash's current helper still goes directly from std::vector<NodeEvictionCandidate> candidates; to the loop. That missing line traces to upstream merge 3963067 (bitcoin#26642, commit 7e975e6). This is a soft missing prerequisite: it is only a test-helper allocation optimization and bitcoin#30397 does not depend on it, but the modified section is not at the same upstream pre-state.


Policy gate (backport-prereq-restore): For full upstream backport PRs, a missing prerequisite is blocking unless the finding is explicitly allowlisted (e.g. intentional_exclusion: true or a matching entry in policy_overrides). The agent's original evidence above is the basis for this block; either backport the prerequisite or annotate the intentional exclusion in the PR description.

Suggested change
std::vector<NodeEvictionCandidate> candidates;
for (int id = 0; id < n_candidates; ++id) {
Add the missing `candidates.reserve(n_candidates);` line or document bitcoin#26642 as intentionally deferred.

source: ['codex-backport-reviewer']

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.

5 participants