backport: Merge bitcoin#31718, 28857, 28825, 29361, 26533, 27302, 29034#7376
backport: Merge bitcoin#31718, 28857, 28825, 29361, 26533, 27302, 29034#7376vijaydasmp wants to merge 7 commits into
Conversation
1e5b861 test: Add test for array serialization (TheCharlatan) d49d198 refactor: Initialize magic bytes in constructor initializer (TheCharlatan) Pull request description: This is a followup-PR for bitcoin#28423 * Initialize magic bytes in constructor * Add a small unit test for serializing arrays. ACKs for top commit: sipa: utACK 1e5b861 maflcko: lgtm ACK 1e5b861 Tree-SHA512: 0f58d2332dc501ca9fd419f40ed4f977c83dce0169e9a0eee1ffc9f8daa2d2ef7e7df18205ba076f55d90ae6c4a20d2b51ab303150d38470a962bcc58a66f6e7
6a91791 fuzz: allow fake and duplicate inputs in tx_package_eval target (Greg Sanders) a0626cc fuzz: allow reaching MempoolAcceptResult::ResultType::DIFFERENT_WITNESS in tx_package_eval target (Greg Sanders) Pull request description: Exercises `DIFFERENT_WITNESS` by using "blank" WSH() and allowing witness to determine wtxid, and attempts to make invalid/duplicate inputs. ACKs for top commit: dergoegge: Coverage looks good to me ACK 6a91791 Tree-SHA512: db894f5f5b81c6b454874baf11f296462832285f41ccb09f23c0db92b9abc98f8ecacd72fc8f60dc92cb7947f543a2e55bed2fd210b0e8ca7c7d5389d90b14af
fad0faf refactor: Fix timedata includes (MarcoFalke) Pull request description: Remove unused includes. Also, fixup comments, see https://github.com/bitcoin/bitcoin/pull/28956/files#r1464827885. Also, add missing includes to `chain.h` while touching it. ACKs for top commit: achow101: ACK fad0faf dergoegge: utACK fad0faf stickies-v: ACK fad0faf Tree-SHA512: 45e86f2eb90f0e37012bd83bf30259719e0e58ede18b31f51ca8a6f6d23e6ca4d060fc0f56f821a711cbdb45792b82cf780f5ae3226680d7a966471990f352bc
…s on startup 3141eab test: add functional test for ScanAndUnlinkAlreadyPrunedFiles (Andrew Toth) e252909 test: add unit test for ScanAndUnlinkAlreadyPrunedFiles (Andrew Toth) 77557dd prune: scan and unlink already pruned block files on startup (Andrew Toth) Pull request description: There are a few cases where we can mark a block and undo file as pruned in our block index, but not actually remove the files from disk. 1. If we call `FindFilesToPrune` or `FindFilesToPruneManual` and crash before `UnlinkPrunedFiles`. 2. If on Windows there is an open file handle to the file somewhere else when calling `fs::remove` in `UnlinkPrunedFiles` (https://en.cppreference.com/w/cpp/filesystem/remove, https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-deletefilew#remarks). This could be from another process, or if we are calling `ReadBlockFromDisk`/`ReadRawBlockFromDisk` without having a lock on `cs_main` (which has been allowed since bitcoin@ccd8ef6). This PR mitigates this by scanning all pruned block files on startup after `LoadBlockIndexDB` and unlinking them again. ACKs for top commit: achow101: ACK 3141eab pablomartin4btc: re-ACK with added functional test 3141eab. furszy: Code review ACK 3141eab theStack: Code-review ACK 3141eab Tree-SHA512: 6c73bc57838ad1b7e5d441af3c4d6bf4c61c4382e2b86485e57fbb74a61240710c0ceeceb8b4834e610ecfa3175c6955c81ea4b2285fee11ca6383f472979d8d
eefe569 bugfix: Fix incorrect debug.log config file path (Ryan Ofsky) 3746f00 init: Error if ignored bitcoin.conf file is found (Ryan Ofsky) 398c371 lint: Fix lint-format-strings false positives when format specifiers have argument positions (Ryan Ofsky) Pull request description: Show an error on startup if a bitcoin datadir that is being used contains a `bitcoin.conf` file that is ignored. There are two cases where this could happen: - One case reported in [bitcoin#27246 (comment)](bitcoin#27246 (comment)) happens when a `bitcoin.conf` file in the default datadir (e.g. `$HOME/.bitcoin/bitcoin.conf`) has a `datadir=/path` line that sets different datadir containing a second `bitcoin.conf` file. Currently the second `bitcoin.conf` file is ignored with no warning. - Another way this could happen is if a `-conf=` command line argument points to a configuration file with a `datadir=/path` line and that path contains a `bitcoin.conf` file, which is currently ignored. This change only adds an error message and doesn't change anything about way settings are applied. It also doesn't trigger errors if there are redundant `-datadir` or `-conf` settings pointing at the same configuration file, only if they are pointing at different files and one file is being ignored. ACKs for top commit: pinheadmz: re-ACK eefe569 willcl-ark: re-ACK eefe569 TheCharlatan: ACK eefe569 Tree-SHA512: 939a98a4b271b5263d64a2df3054c56fcde94784edf6f010d78693a371c38aa03138ae9cebb026b6164bbd898d8fd0845a61a454fd996e328fd7bcf51c580c2b
… using `platform.system()` 878d914 doc: test: mention OS detection preferences in style guideline (Sebastian Falbesoner) 4c65ac9 test: detect OS consistently using `platform.system()` (Sebastian Falbesoner) 37324ae test: use `skip_if_platform_not_linux` helper where possible (Sebastian Falbesoner) Pull request description: There are at least three ways to detect the operating system in Python3: - `os.name` (https://docs.python.org/3.9/library/os.html#os.name) - `sys.platform` (https://docs.python.org/3.9/library/sys.html#sys.platform) - `platform.system()` (https://docs.python.org/3.9/library/platform.html#platform.system) We are currently using all of them in functional tests (both in individual tests and shared test framework code), which seems a bit messy. This PR consolidates into using `platform.system()`, as it appears to be one most consistent and easy to read (see also [IRC discussion](https://bitcoin-irc.chaincode.com/bitcoin-core-dev/2023-12-08#989301;) and table below). `sys.platform` is inconsistent as it has the major version number encoded for BSD systems, which doesn't make much sense for e.g. OpenBSD, where there is no concept of major versions, but instead the version is simply increased by 0.1 on each release. Note that `os.name` is still useful to detect whether we are running a POSIX system (see `BitcoinTestFramework.skip_if_platform_not_posix`), so for this use-case it is kept as only exception. The following table shows values for common operating systems, found via ``` $ python3 -c "import os; import sys; import platform; print(os.name, sys.platform, platform.system())" ``` | OS | os.name | sys.platform | platform.system() | |--------------|---------|--------------|--------------------| | Linux 6.2.0 | posix | linux | Linux | | MacOS* | posix | darwin | Darwin | | OpenBSD 7.4 | posix | openbsd7 | OpenBSD | | Windows* | nt | win32 | Windows | \* = I neither have a MacOS nor a Windows machine available, so I extracted the values from documentation and our current code. Also I'm relying on CI for testing the relevant code-paths. Having reviewers to this this locally would be very appreciated, if this gets Concept ACKed. ACKs for top commit: kevkevinpal: ACK [878d914](bitcoin@878d914) achow101: ACK 878d914 hebasto: ACK 878d914, I have reviewed the code and it looks OK. pablomartin4btc: tACK 878d914 Tree-SHA512: 24513d493e47f572028c843260b81c47c2c29bfb701991050255c9f9529cd19065ecbc7b3b6e15619da7f3f608b4825c345ce6fee30d8fd1eaadbd08cff400fc
|
This pull request has conflicts, please rebase. |
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dfb30988e8
ℹ️ 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".
| argsman.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS); | ||
| argsman.AddArg("-dbcache=<n>", strprintf("Maximum database cache size <n> MiB (%d to %d, default: %d). In addition, unused mempool memory is shared for this cache (see -maxmempool).", nMinDbCache, nMaxDbCache, nDefaultDbCache), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); | ||
| argsman.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); | ||
| argsman.AddArg("-allowignoredconf", strprintf("For backwards compatibility, treat an unused %s file in the datadir as a warning, not an error.", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); |
There was a problem hiding this comment.
Implement ignored-conf handling for the new option
This registers -allowignoredconf, but ArgsManager::ReadConfigFiles() still has no logic to detect an ignored datadir config file or to downgrade that error when this flag is set. In the scenario added by test_ignored_conf, -conf=<temp> points back to a datadir that already has dash.conf, but startup will succeed and silently ignore that datadir config instead of failing or warning, so the new default functional test fails and users get a no-op safety option.
Useful? React with 👍 / 👎.
| conf_path = default_datadir / "bitcoin.conf" | ||
| conf_path.write_text(f"datadir={node.datadir}\n{conf_text}") |
There was a problem hiding this comment.
Use Dash config names in default-datadir tests
Here the test writes bitcoin.conf under the helper's Bitcoin default directory, but Dash reads $HOME/.dashcore/dash.conf on Unix-like systems and ~/Library/Application Support/DashCore/dash.conf on macOS. Once the test removes -datadir, dashd ignores this file and starts from an unconfigured default datadir/RPC port, so test_config_file_log and the same pattern in test_ignored_default_conf time out instead of checking the intended config behavior.
Useful? React with 👍 / 👎.
| star, star_pos_num = re.match(r"(?:.*?(\*(?:(\d+)\$)?)|)", m.group(1)).groups() | ||
| if star_pos_num is not None: | ||
| max_pos = max(max_pos, int(star_pos_num)) | ||
| elif star is not None: | ||
| n += 1 |
There was a problem hiding this comment.
Count every dynamic width/precision argument
For non-positional format strings with both dynamic width and precision, such as %*.*f, there are two * arguments plus the value, but this regex only captures the first * in the specifier. count_format_specifiers('%*.*f') now returns 2 instead of 3, so the lint can miss calls that are missing one argument when dynamic precision is used.
Useful? React with 👍 / 👎.
WalkthroughThis PR bundles four independent tracks: (1) a new Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@src/node/miner.cpp`:
- Line 24: The include change removed timedata.h but miner.cpp calls
GetAdjustedTime() on lines 52 and 221, which is defined in timedata.h and not
available in util/time.h. Either restore the `#include` <timedata.h> directive at
the top of miner.cpp, or move the GetAdjustedTime() function definition from
timedata.h to util/time.h and update the corresponding header file to ensure
miner.cpp can resolve the symbol.
In `@test/functional/feature_config_args.py`:
- Around line 116-150: The test_config_file_log function and related tests
contain hardcoded references to "bitcoin.conf" which should be "dash.conf" since
the repository uses "dash.conf" as the configuration filename. Replace all
occurrences of "bitcoin.conf" with "dash.conf" in the conf_path path creation
(where it constructs the configuration file path using pathlib.Path), in the
start_node method call arguments (where -conf parameter is specified), and in
any file write operations that create the configuration file. Additionally,
update any assertion messages and expected_msgs parameters that reference the
configuration filename to use "dash.conf" instead of "bitcoin.conf".
In `@test/lint/run-lint-format-strings.py`:
- Around line 267-271: The regex match on line 267 only captures the first `*`
in the format specifier string, causing format specifiers with multiple `*`
characters (like `%*.*d`) to be undercounted. Replace the single re.match call
with re.finditer or re.findall to find all occurrences of the `*` pattern in
m.group(1), then iterate through each match to properly count all positional
arguments and increment n for each `*` specifier found.
🪄 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: 35f19a2a-66e5-4557-be3e-60a0c05e17ad
📒 Files selected for processing (33)
ci/README.mdcontrib/guix/README.mdcontrib/tracing/README.mdcontrib/tracing/log_raw_p2p_msgs.pydoc/release-notes-27302.mdsrc/chain.hsrc/init.cppsrc/net.cppsrc/net.hsrc/net_processing.cppsrc/node/blockstorage.cppsrc/node/blockstorage.hsrc/node/miner.cppsrc/qt/test/test_main.cppsrc/rpc/mining.cppsrc/test/blockmanager_tests.cppsrc/test/serialize_tests.cppsrc/test/util/script.hsrc/timedata.hsrc/validation.cpptest/functional/README.mdtest/functional/feature_bind_extra.pytest/functional/feature_config_args.pytest/functional/feature_init.pytest/functional/feature_notifications.pytest/functional/feature_remove_pruned_files_on_startup.pytest/functional/rpc_bind.pytest/functional/test_framework/p2p.pytest/functional/test_framework/test_node.pytest/functional/test_framework/util.pytest/functional/test_runner.pytest/functional/wallet_multiwallet.pytest/lint/run-lint-format-strings.py
💤 Files with no reviewable changes (1)
- src/timedata.h
| #include <timedata.h> | ||
| #include <util/moneystr.h> | ||
| #include <util/system.h> | ||
| #include <util/time.h> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check for orphaned timedata symbols in miner.cpp after include swap
# Search for timedata usage in miner.cpp
echo "=== Checking for timedata symbol usage in miner.cpp ==="
rg -n 'timedata|dNtpOffset' src/node/miner.cpp || echo "No timedata symbol references found"
# Verify util/time.h exports needed symbols
echo ""
echo "=== Checking util/time.h for time symbols ==="
grep -E '(GetTime|GetAdjustedTime|dNtpOffset)' src/util/time.h || echo "Time symbols may not be in util/time.h"Repository: dashpay/dash
Length of output: 282
🏁 Script executed:
#!/bin/bash
# Check what time functions miner.cpp actually uses
echo "=== Time-related function calls in miner.cpp ==="
rg -n '(GetTime|GetAdjustedTime|GetSystemTimeInSeconds|dNtpOffset)' src/node/miner.cpp
# Also check for any remaining includes that might provide time functionality
echo ""
echo "=== All includes in miner.cpp ==="
head -30 src/node/miner.cpp | grep '^`#include`'Repository: dashpay/dash
Length of output: 1009
🏁 Script executed:
#!/bin/bash
# Find GetAdjustedTime definition
echo "=== Searching for GetAdjustedTime definition ==="
rg -n 'GetAdjustedTime' --type cpp --type h | head -20
# Check full util/time.h content to see all exports
echo ""
echo "=== Full util/time.h content ==="
cat src/util/time.hRepository: dashpay/dash
Length of output: 7294
🏁 Script executed:
#!/bin/bash
# Check if timedata.h is included transitively
echo "=== Checking node/miner.h for timedata.h include ==="
rg -n 'timedata' src/node/miner.h
echo ""
echo "=== Checking validation.h for timedata.h include ==="
rg -n 'timedata' src/validation.h | head -5
echo ""
echo "=== Checking chain.h for timedata.h include ==="
rg -n 'timedata' src/chain.h
echo ""
echo "=== Full search for timedata.h includes ==="
rg '`#include`.*timedata' --type h --type cpp | grep -E '(chain\.h|validation\.h|node/miner\.h|pow\.h)'Repository: dashpay/dash
Length of output: 257
🏁 Script executed:
#!/bin/bash
# Check what headers transitively include timedata.h
echo "=== Which headers include timedata.h ==="
rg '`#include`.*timedata\.h' --type h --type cpp
echo ""
echo "=== Does pow.h include timedata ==="
cat src/pow.h | grep -E '(timedata|GetAdjustedTime)' || echo "Not found in pow.h"
echo ""
echo "=== Verify miner.cpp would have access to GetAdjustedTime ==="
# Check if any of miner's includes transitively get timedata.h
for header in consensus/consensus.h consensus/validation.h pow.h; do
if rg '`#include`.*timedata' "src/$header" > /dev/null 2>&1; then
echo "$header includes timedata.h"
fi
done
echo "Done checking transitive includes"Repository: dashpay/dash
Length of output: 1053
🏁 Script executed:
#!/bin/bash
# Check if validation.h or pow.h indirectly include timedata.h
echo "=== Check validation.h includes ==="
head -50 src/validation.h | grep '`#include`'
echo ""
echo "=== Check pow.h includes ==="
head -50 src/pow.h | grep '`#include`'
echo ""
echo "=== Comprehensive check: trace includes from miner.cpp ==="
# For key headers, check if they include timedata
for header in src/validation.h src/pow.h src/consensus/consensus.h src/chainparams.h; do
if [ -f "$header" ]; then
result=$(grep '`#include`.*timedata' "$header")
if [ -n "$result" ]; then
echo "$header INCLUDES timedata.h"
fi
fi
done
echo "Check complete"Repository: dashpay/dash
Length of output: 1050
Add timedata.h include or implement GetAdjustedTime() in util/time.h.
The include swap removes timedata.h but miner.cpp calls GetAdjustedTime() on lines 52 and 221. This function is defined in timedata.h, and util/time.h does not provide it. No transitive includes supply this symbol. Either restore #include <timedata.h> or relocate GetAdjustedTime() to util/time.h.
🧰 Tools
🪛 Cppcheck (2.21.0)
[error] 24-24: #error No known always_inline attribute for this platform.
(preprocessorErrorDirective)
🤖 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 `@src/node/miner.cpp` at line 24, The include change removed timedata.h but
miner.cpp calls GetAdjustedTime() on lines 52 and 221, which is defined in
timedata.h and not available in util/time.h. Either restore the `#include`
<timedata.h> directive at the top of miner.cpp, or move the GetAdjustedTime()
function definition from timedata.h to util/time.h and update the corresponding
header file to ensure miner.cpp can resolve the symbol.
| def test_config_file_log(self): | ||
| # Disable this test for windows currently because trying to override | ||
| # the default datadir through the environment does not seem to work. | ||
| if platform.system() == "Windows": | ||
| return | ||
|
|
||
| self.log.info('Test that correct configuration path is changed when configuration file changes the datadir') | ||
|
|
||
| # Create a temporary directory that will be treated as the default data | ||
| # directory by bitcoind. | ||
| env, default_datadir = util.get_temp_default_datadir(pathlib.Path(self.options.tmpdir, "test_config_file_log")) | ||
| default_datadir.mkdir(parents=True) | ||
|
|
||
| # Write a bitcoin.conf file in the default data directory containing a | ||
| # datadir= line pointing at the node datadir. | ||
| node = self.nodes[0] | ||
| conf_text = pathlib.Path(node.bitcoinconf).read_text() | ||
| conf_path = default_datadir / "bitcoin.conf" | ||
| conf_path.write_text(f"datadir={node.datadir}\n{conf_text}") | ||
|
|
||
| # Drop the node -datadir= argument during this test, because if it is | ||
| # specified it would take precedence over the datadir setting in the | ||
| # config file. | ||
| node_args = node.args | ||
| node.args = [arg for arg in node.args if not arg.startswith("-datadir=")] | ||
|
|
||
| # Check that correct configuration file path is actually logged | ||
| # (conf_path, not node.bitcoinconf) | ||
| with self.nodes[0].assert_debug_log(expected_msgs=[f"Config file: {conf_path}"]): | ||
| self.start_node(0, ["-allowignoredconf"], env=env) | ||
| self.stop_node(0) | ||
|
|
||
| # Restore node arguments after the test | ||
| node.args = node_args | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Core config filename and config-path wiring =="
rg -n -C2 "BITCOIN_CONF_FILENAME|GetConfigFilePath|ReadConfigFiles" src/util src/init.cpp
echo
echo "== Functional framework config filename usage =="
rg -n -C2 "bitcoinconf|dash\\.conf|bitcoin\\.conf|write_config|initialize_datadir" \
test/functional/test_framework test/functional/feature_config_args.pyRepository: dashpay/dash
Length of output: 22289
Replace hardcoded "bitcoin.conf" with "dash.conf" throughout the test.
The repository uses "dash.conf" as the configuration filename (defined in src/util/system.cpp:90 and used by the test framework in test/functional/test_framework/test_node.py:83). The new tests hardcode "bitcoin.conf" in multiple locations, which will cause them to fail:
- Line 133:
conf_path = default_datadir / "bitcoin.conf"→ should be"dash.conf" - Line 335:
self.start_node(0, [f'-conf={node.datadir}/bitcoin.conf'])→ should be"dash.conf" - Line 357:
(default_datadir / "bitcoin.conf").write_text(...)→ should be"dash.conf"
Also update the assertion messages on lines 328 and 365 to reference "dash.conf" instead of "bitcoin.conf".
🤖 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/feature_config_args.py` around lines 116 - 150, The
test_config_file_log function and related tests contain hardcoded references to
"bitcoin.conf" which should be "dash.conf" since the repository uses "dash.conf"
as the configuration filename. Replace all occurrences of "bitcoin.conf" with
"dash.conf" in the conf_path path creation (where it constructs the
configuration file path using pathlib.Path), in the start_node method call
arguments (where -conf parameter is specified), and in any file write operations
that create the configuration file. Additionally, update any assertion messages
and expected_msgs parameters that reference the configuration filename to use
"dash.conf" instead of "bitcoin.conf".
| star, star_pos_num = re.match(r"(?:.*?(\*(?:(\d+)\$)?)|)", m.group(1)).groups() | ||
| if star_pos_num is not None: | ||
| max_pos = max(max_pos, int(star_pos_num)) | ||
| elif star is not None: | ||
| n += 1 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Confirm the current single-star logic exists in the changed file
rg -n "star, star_pos_num = re.match" test/lint/run-lint-format-strings.py
# Reproduce current behavior with equivalent logic (read-only verification)
python - <<'PY'
import re
def count_like_current(format_string):
format_string = format_string.replace('%%', 'X')
n = max_pos = 0
for m in re.finditer("%(.*?)[aAcdeEfFgGinopsuxX]", format_string, re.DOTALL):
pos_num, = re.match(r"(?:(^\d+)\$)?", m.group(1)).groups()
if pos_num is not None:
max_pos = max(max_pos, int(pos_num))
else:
n += 1
star, star_pos_num = re.match(r"(?:.*?(\*(?:(\d+)\$)?)|)", m.group(1)).groups()
if star_pos_num is not None:
max_pos = max(max_pos, int(star_pos_num))
elif star is not None:
n += 1
return max(n, max_pos)
cases = [
("%*.*d", 3),
("%2$*3$.*4$d", 4),
]
for fmt, expected in cases:
got = count_like_current(fmt)
print(f"{fmt}: got={got}, expected={expected}, {'OK' if got == expected else 'MISMATCH'}")
PYRepository: dashpay/dash
Length of output: 224
Count all * argument specifiers, not just the first one.
The regex pattern on line 267 only captures the first * in a format specifier. Format specifiers like %*.*d and %2$*3$.*4$d are undercounted, producing false negatives in the lint check.
Proposed fix
- star, star_pos_num = re.match(r"(?:.*?(\*(?:(\d+)\$)?)|)", m.group(1)).groups()
- if star_pos_num is not None:
- max_pos = max(max_pos, int(star_pos_num))
- elif star is not None:
- n += 1
+ for star_match in re.finditer(r"\*(?:(\d+)\$)?", m.group(1)):
+ star_pos_num = star_match.group(1)
+ if star_pos_num is not None:
+ max_pos = max(max_pos, int(star_pos_num))
+ else:
+ n += 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.
| star, star_pos_num = re.match(r"(?:.*?(\*(?:(\d+)\$)?)|)", m.group(1)).groups() | |
| if star_pos_num is not None: | |
| max_pos = max(max_pos, int(star_pos_num)) | |
| elif star is not None: | |
| n += 1 | |
| for star_match in re.finditer(r"\*(?:(\d+)\$)?", m.group(1)): | |
| star_pos_num = star_match.group(1) | |
| if star_pos_num is not None: | |
| max_pos = max(max_pos, int(star_pos_num)) | |
| else: | |
| n += 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/lint/run-lint-format-strings.py` around lines 267 - 271, The regex match
on line 267 only captures the first `*` in the format specifier string, causing
format specifiers with multiple `*` characters (like `%*.*d`) to be
undercounted. Replace the single re.match call with re.finditer or re.findall to
find all occurrences of the `*` pattern in m.group(1), then iterate through each
match to properly count all positional arguments and increment n for each `*`
specifier found.
bitcoin backports