{
 "number": 32993,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/32993",
 "title": "fuzz: wallet: add target for tx scanning",
 "author": "brunoerg",
 "author_association": "CONTRIBUTOR",
 "created_at": "2025-07-16T13:15:08Z",
 "updated_at": "2026-06-12T19:46:55Z",
 "age_days": 428,
 "draft": true,
 "labels": [
  "Tests",
  "Fuzzing"
 ],
 "milestone": null,
 "base": "master",
 "head_sha": "fbeba67512b32a6a516905b01db661da39ab7340",
 "head_ref": "2025-06-fuzz-wallet-scan",
 "head_repo": "brunoerg/bitcoin",
 "head_history": [
  {
   "t": "2025-07-16T16:38:07Z",
   "sha": "747d0942413b26f0260126dfecf4f960a5e53a38"
  },
  {
   "t": "2026-06-12T18:16:03Z",
   "sha": "904edfc10a72d5cd9cb44ed06129f59ea8d7ee4f"
  },
  {
   "t": "2026-06-12T18:43:37Z",
   "sha": "fbeba67512b32a6a516905b01db661da39ab7340"
  }
 ],
 "additions": 111,
 "deletions": 0,
 "changed_files": 2,
 "commit_count": 1,
 "size_bucket": "M",
 "mergeable_state": "blocked",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "stale_ack": [
     {
      "login": "Chand-ra",
      "url": "https://github.com/bitcoin/bitcoin/pull/32993#issuecomment-3619800359"
     }
    ]
   },
   "conflicts": []
  }
 },
 "acks_parsed": {},
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 0,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "Chand-ra",
   "ekzyis",
   "fanquake"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "blocked",
  "last_author_activity": "2026-06-12T18:53:43Z",
  "last_reviewer_activity": "2026-06-12T17:04:42Z",
  "last_reviewer": "ekzyis",
  "author_silent_days": 96,
  "waiting_on_author_days": 0,
  "days_since_update": 96
 },
 "refs": {
  "mentioned": [
   29901,
   31474
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 29901,
    "type": "issue",
    "state": "open",
    "merged": false,
    "merged_at": null,
    "title": "Wallet fuzzing tracking issue"
   },
   {
    "number": 31474,
    "type": "issue",
    "state": "closed",
    "merged": false,
    "merged_at": null,
    "title": "Potential crash (assert) rescanning wallet"
   }
  ],
  "conflicts": []
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/wallet/test/fuzz/scan.cpp"
 ],
 "body": "Tracking issue (#29901)\n\nThis PR adds a fuzz target for wallet tx scanning (`ScanForWalletTransactions`). Unfortunately, it's not a regression test for the issue #31474 since it would require a more complex scenario/async operations.",
 "commits": [
  {
   "sha": "fbeba67512b32a6a516905b01db661da39ab7340",
   "date": "2026-06-12T18:41:33Z",
   "message": "fuzz: add target for wallet tx scanning"
  }
 ],
 "timeline": [
  {
   "t": "2025-07-16T15:38:48Z",
   "kind": "comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "text": "https://cirrus-ci.com/task/4897452429410304?logs=ci#L6267:\n```bash\n[10:48:30.374] Run wallet_scan with args ['/ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/bin/fuzz', '-max_total_time=60']INFO: Running with entropic power schedule (0xFF, 100).\n[10:48:30.374] INFO: Seed: 1927962085\n[10:48:30.374] INFO: Loaded 1 modules   (634026 inline 8-bit counters): 634026 [0x5573df666fb8, 0x5573df701c62),\n[10:48:30.374] INFO: Loaded 1 PC tables (634026 PCs): 634026 [0x5573df701c68,0x5573e00ae708),\n[10:48:30.374] INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes\n[10:48:30.374] /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/chrono.h:225:38: runtime error: signed integer overflow: -9223372036854775808 * 1000000000 cannot be represented in type 'long'\n[10:48:30.374]     #0 0x5573dc9108bd in std::chrono::duration<long, std::ratio<1l, 1000000000l>> std::chrono::__duration_cast_impl<std::chrono::duration<long, std::ratio<1l, 1000000000l>>, std::ratio<1000000000l, 1l>, long, false, true>::__cast<long, std::ratio<1l, 1l>>(std::chrono::duration<long, std::ratio<1l, 1l>> const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/chrono.h:225:38\n[10:48:30.374]     #1 0x5573dc9108bd in std::enable_if<__is_duration<std::chrono::duration<long, std::ratio<1l, 1000000000l>>>::value, std::chrono::duration<long, std::ratio<1l, 1000000000l>>>::type std::chrono::duration_cast<std::chrono::duration<long, std::ratio<1l, 1000000000l>>, long, std::ratio<1l, 1l>>(std::chrono::duration<long, std::ratio<1l, 1l>> const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/chrono.h:287:11\n[10:48:30.374]     #2 0x5573dc9108bd in std::chrono::duration<long, std::ratio<1l, 1000000000l>>::duration<long, std::ratio<1l, 1l>, void>(std::chrono::duration<long, std::ratio<1l, 1l>> const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/chrono.h:582:10\n[10:48:30.374]     #3 0x5573dc9108bd in std::common_type<std::chrono::duration<long, std::ratio<1l, 1000000000l>>, std::chrono::duration<long, std::ratio<1l, 1l>>>::type std::chrono::operator+<long, std::ratio<1l, 1000000000l>, long, std::ratio<1l, 1l>>(std::chrono::duration<long, std::ratio<1l, 1000000000l>> const&, std::chrono::duration<long, std::ratio<1l, 1l>> const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/chrono.h:702:36\n[10:48:30.374]     #4 0x5573dc9108bd in std::chrono::time_point<std::chrono::_V2::steady_clock, std::common_type<std::chrono::duration<long, std::ratio<1l, 1000000000l>>, std::chrono::duration<long, std::ratio<1l, 1l>>>::type> std::chrono::operator+<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>, long, std::ratio<1l, 1l>>(std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>> const&, std::chrono::duration<long, std::ratio<1l, 1l>> const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/chrono.h:1107:47\n[10:48:30.374]     #5 0x5573dc9108bd in wallet::(anonymous namespace)::wallet_scan_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1::operator()() const /ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/src/test/fuzz/./wallet/test/fuzz/scan.cpp:66:44\n[10:48:30.374]     #6 0x5573dc9108bd in std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>> std::__invoke_impl<std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>>, wallet::(anonymous namespace)::wallet_scan_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1&>(std::__invoke_other, wallet::(anonymous namespace)::wallet_scan_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/invoke.h:61:14\n[10:48:30.374]     #7 0x5573dc9108bd in std::enable_if<is_invocable_r_v<std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>>, wallet::(anonymous namespace)::wallet_scan_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1&>, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>>>::type std::__invoke_r<std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>>, wallet::(anonymous namespace)::wallet_scan_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1&>(wallet::(anonymous namespace)::wallet_scan_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/invoke.h:114:9\n[10:48:30.374]     #8 0x5573dc9108bd in std::_Function_handler<std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>> (), wallet::(anonymous namespace)::wallet_scan_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>)::$_1>::_M_invoke(std::_Any_data const&) /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/std_function.h:290:9\n[10:48:30.374]     #9 0x5573dd067392 in std::function<std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>> ()>::operator()() const /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/std_function.h:591:9\n[10:48:30.374]     #10 0x5573dd067392 in wallet::WalletRescanReserver::now() const /ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/src/wallet/./wallet/wallet.h:1110:52\n[10:48:30.374]     #11 0x5573dd067392 in wallet::CWallet::ScanForWalletTransactions(uint256 const&, int, std::optional<int>, wallet::WalletRescanReserver const&, bool, bool) /ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/src/wallet/./wallet/wallet.cpp:1781:32\n[10:48:30.374]     #12 0x5573dc907a87 in wallet::(anonymous namespace)::wallet_scan_fuzz_target(std::span<unsigned char const, 18446744073709551615ul>) /ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/src/test/fuzz/./wallet/test/fuzz/scan.cpp:108:33\n[10:48:30.374]     #13 0x5573dc949cee in std::function<void (std::span<unsigned char const, 18446744073709551615ul>)>::operator()(std::span<unsigned char const, 18446744073709551615ul>) const /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/std_function.h:591:9\n[10:48:30.374]     #14 0x5573dc949cee in test_one_input(std::span<unsigned char const, 18446744073709551615ul>) /ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/src/test/fuzz/util/./test/fuzz/fuzz.cpp:88:5\n[10:48:30.374]     #15 0x5573dc949cee in LLVMFuzzerTestOneInput /ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/src/test/fuzz/util/./test/fuzz/fuzz.cpp:216:5\n[10:48:30.374]     #16 0x5573dbf4e75f in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (/ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/bin/fuzz+0x1d8075f) (BuildId: 8f6fd4c0e394fcf4793e14ca683880501003032e)\n[10:48:30.374]     #17 0x5573dbf4f971 in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (/ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/bin/fuzz+0x1d81971) (BuildId: 8f6fd4c0e394fcf4793e14ca683880501003032e)\n[10:48:30.374]     #18 0x5573dbf50000 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (/ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/bin/fuzz+0x1d82000) (BuildId: 8f6fd4c0e394fcf4793e14ca683880501003032e)\n[10:48:30.374]     #19 0x5573dbf3c655 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/bin/fuzz+0x1d6e655) (BuildId: 8f6fd4c0e394fcf4793e14ca683880501003032e)\n[10:48:30.374]     #20 0x5573dbf68a66 in main (/ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/bin/fuzz+0x1d9aa66) (BuildId: 8f6fd4c0e394fcf4793e14ca683880501003032e)\n[10:48:30.374]     #21 0x7fe3a629b1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 282c2c16e7b6600b0b22ea0c99010d2795752b5f)\n[10:48:30.374]     #22 0x7fe3a629b28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 282c2c16e7b6600b0b22ea0c99010d2795752b5f)\n[10:48:30.374]     #23 0x5573dbf30a94 in _start (/ci_container_base/ci/scratch/build-x86_64-pc-linux-gnu/bin/fuzz+0x1d62a94) (BuildId: 8f6fd4c0e394fcf4793e14ca683880501003032e)\n[10:48:30.374]\n[10:48:30.374] SUMMARY: UndefinedBehaviorSanitizer: signed-integer-overflow /usr/lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/chrono.h:225:38\n[10:48:30.374] MS: 0 ; base unit: 0000000000000000000000000000000000000000\n[10:48:30.375]\n[10:48:30.375]\n[10:48:30.375] artifact_prefix='./'; Test unit written to ./crash-da39a3ee5e6b4b0d3255bfef95601890afd80709\n[10:48:30.375] Base64:\n```"
  },
  {
   "t": "2025-07-16T16:38:07Z",
   "kind": "force_push",
   "who": "brunoerg",
   "commit": "747d0942413b26f0260126dfecf4f960a5e53a38"
  },
  {
   "t": "2025-07-16T18:13:58Z",
   "kind": "comment",
   "who": "brunoerg",
   "assoc": "CONTRIBUTOR",
   "text": "[quoted text omitted]\n\nFixed, thanks."
  },
  {
   "t": "2025-12-06T09:20:17Z",
   "kind": "comment",
   "who": "Chand-ra",
   "assoc": "NONE",
   "text": "tACK [747d094](https://github.com/bitcoin/bitcoin/pull/32993/commits/747d0942413b26f0260126dfecf4f960a5e53a38)\n\nThe target runs without crashing."
  },
  {
   "t": "2026-06-12T14:21:33Z",
   "kind": "review_comment",
   "who": "ekzyis",
   "assoc": "NONE",
   "path": "src/wallet/test/fuzz/scan.cpp",
   "commit": "747d0942413b26f0260126dfecf4f960a5e53a38",
   "in_reply_to": null,
   "text": "nit: Is this branch needed? I don't think it leads to increased coverage somewhere. `AbortRescan()` runs `fAbortRescan = true`, but `ScanForWalletTransactions()` will run `fAbortRescan = false` before scanning."
  },
  {
   "t": "2026-06-12T16:23:02Z",
   "kind": "review_comment",
   "who": "ekzyis",
   "assoc": "NONE",
   "path": "src/wallet/test/fuzz/scan.cpp",
   "commit": "fbeba67512b32a6a516905b01db661da39ab7340",
   "in_reply_to": null,
   "text": "I found an input with an ASan crash *after* fuzzing is done:\n\nFUZZ=wallet_scan build_fuzz/bin/fuzz -runs=1 fuzz_corpora/wallet_scan/386f79ce03c75ae120f5680cb3d0a9bcf263eec2\n\n```\n$ xxd -p fuzz_corpora/wallet_scan/386f79ce03c75ae120f5680cb3d0a9bcf263eec2\n657eaf25005fffff5f1ef7f5000a25\n$ FUZZ=wallet_scan build_fuzz/bin/fuzz -runs=1 fuzz_corpora/wallet_scan/386f79ce03c75ae120f5680cb3d0a9bcf263eec2\nINFO: Running with entropic power schedule (0xFF, 100).\nINFO: Seed: 143834296\nINFO: Loaded 1 modules   (555819 inline 8-bit counters): 555819 [0x555559e0f490, 0x555559e96fbb),\nINFO: Loaded 1 PC tables (555819 PCs): 555819 [0x555559e96fc0,0x55555a712270),\nbuild_fuzz/bin/fuzz: Running 1 inputs 1 time(s) each.\nRunning: fuzz_corpora/wallet_scan/386f79ce03c75ae120f5680cb3d0a9bcf263eec2\nExecuted fuzz_corpora/wallet_scan/386f79ce03c75ae120f5680cb3d0a9bcf263eec2 in 53 ms\n***\n*** NOTE: fuzzing was not performed, you have only\n***       executed the target code on a fixed set of inputs.\n***\n=================================================================\n==69449==ERROR: AddressSanitizer: heap-use-after-free on address 0x7d9ff67e1f90 at pc 0x555558ce008c bp 0x7fffffff5320 sp 0x7fffffff5318\nREAD of size 8 at 0x7d9ff67e1f90 thread T0 (b-test)\n    #0 0x555558ce008b in std::__uniq_ptr_impl<ValidationSignals, std::default_delete<ValidationSignals>>::_M_ptr() const /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/unique_ptr.h:193:51\n    #1 0x555558ce008b in std::unique_ptr<ValidationSignals, std::default_delete<ValidationSignals>>::get() const /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/unique_ptr.h:473:21\n    #2 0x555558ce008b in std::unique_ptr<ValidationSignals, std::default_delete<ValidationSignals>>::operator bool() const /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/unique_ptr.h:490:16\n    #3 0x555558ce008b in BaseIndex::Stop() /home/ekzyis/prog/bitcoin/build_fuzz/./index/base.cpp:457:9\n    #4 0x555558cdf99b in BaseIndex::~BaseIndex() /home/ekzyis/prog/bitcoin/build_fuzz/./index/base.cpp:82:5\n    #5 0x555558cf8b38 in std::_Rb_tree<BlockFilterType, std::pair<BlockFilterType const, BlockFilterIndex>, std::_Select1st<std::pair<BlockFilterType const, BlockFilterIndex>>, std::less<BlockFilterType>, std::allocator<std::pair<BlockFilterType const, BlockFilterIndex>>>::_M_drop_node(std::_Rb_tree_node<std::pair<BlockFilterType const, BlockFilterIndex>>*) /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/stl_tree.h:1273:2\n    #6 0x555558cf8b38 in std::_Rb_tree<BlockFilterType, std::pair<BlockFilterType const, BlockFilterIndex>, std::_Select1st<std::pair<BlockFilterType const, BlockFilterIndex>>, std::less<BlockFilterType>, std::allocator<std::pair<BlockFilterType const, BlockFilterIndex>>>::_M_erase(std::_Rb_tree_node<std::pair<BlockFilterType const, BlockFilterIndex>>*) /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/stl_tree.h:2590:4\n    #7 0x555558cea1bd in std::_Rb_tree<BlockFilterType, std::pair<BlockFilterType const, BlockFilterIndex>, std::_Select1st<std::pair<BlockFilterType const, BlockFilterIndex>>, std::less<BlockFilterType>, std::allocator<std::pair<BlockFilterType const, BlockFilterIndex>>>::~_Rb_tree() /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/stl_tree.h:1609:9\n    #8 0x555558cea1bd in std::map<BlockFilterType, BlockFilterIndex, std::less<BlockFilterType>, std::allocator<std::pair<BlockFilterType const, BlockFilterIndex>>>::~map() /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/stl_map.h:337:22\n    #9 0x7ffff76450d0 in __run_exit_handlers (/nix/store/l0l2ll1lmylczj1ihqn351af2kyp5x19-glibc-2.42-51/lib/libc.so.6+0x450d0) (BuildId: 76913033e82a3d45b50fdb9773ae48a91d69ad8e)\n    #10 0x7ffff76451ad in exit (/nix/store/l0l2ll1lmylczj1ihqn351af2kyp5x19-glibc-2.42-51/lib/libc.so.6+0x451ad) (BuildId: 76913033e82a3d45b50fdb9773ae48a91d69ad8e)\n    #11 0x55555749b685 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x1f47685)\n    #12 0x5555574dcf82 in main (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x1f88f82)\n    #13 0x7ffff762b284 in __libc_start_call_main (/nix/store/l0l2ll1lmylczj1ihqn351af2kyp5x19-glibc-2.42-51/lib/libc.so.6+0x2b284) (BuildId: 76913033e82a3d45b50fdb9773ae48a91d69ad8e)\n    #14 0x7ffff762b337 in __libc_start_main@GLIBC_2.2.5 (/nix/store/l0l2ll1lmylczj1ihqn351af2kyp5x19-glibc-2.42-51/lib/libc.so.6+0x2b337) (BuildId: 76913033e82a3d45b50fdb9773ae48a91d69ad8e)\n    #15 0x5555574829e4 in _start (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x1f2e9e4)\n\n0x7d9ff67e1f90 is located 272 bytes inside of 1176-byte region [0x7d9ff67e1e80,0x7d9ff67e2318)\nfreed by thread T0 (b-test) here:\n    #0 0x555557634a03 in operator delete(void*, unsigned long) (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x20e0a03)\n    #1 0x555557d76b37 in std::default_delete<TestingSetup>::operator()(TestingSetup*) const /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/unique_ptr.h:93:2\n    #2 0x555557d76b37 in std::unique_ptr<TestingSetup, std::default_delete<TestingSetup>>::~unique_ptr() /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/unique_ptr.h:399:4\n    #3 0x7ffff76450d0 in __run_exit_handlers (/nix/store/l0l2ll1lmylczj1ihqn351af2kyp5x19-glibc-2.42-51/lib/libc.so.6+0x450d0) (BuildId: 76913033e82a3d45b50fdb9773ae48a91d69ad8e)\n    #4 0x7ffff76451ad in exit (/nix/store/l0l2ll1lmylczj1ihqn351af2kyp5x19-glibc-2.42-51/lib/libc.so.6+0x451ad) (BuildId: 76913033e82a3d45b50fdb9773ae48a91d69ad8e)\n    #5 0x55555749b685 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x1f47685)\n    #6 0x5555574dcf82 in main (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x1f88f82)\n    #7 0x7ffff762b284 in __libc_start_call_main (/nix/store/l0l2ll1lmylczj1ihqn351af2kyp5x19-glibc-2.42-51/lib/libc.so.6+0x2b284) (BuildId: 76913033e82a3d45b50fdb9773ae48a91d69ad8e)\n    #8 0x7ffff762b337 in __libc_start_main@GLIBC_2.2.5 (/nix/store/l0l2ll1lmylczj1ihqn351af2kyp5x19-glibc-2.42-51/lib/libc.so.6+0x2b337) (BuildId: 76913033e82a3d45b50fdb9773ae48a91d69ad8e)\n    #9 0x5555574829e4 in _start (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x1f2e9e4)\n\npreviously allocated by thread T0 (b-test) here:\n    #0 0x5555576339c3 in operator new(unsigned long) (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x20df9c3)\n    #1 0x555557d76db8 in std::__detail::_MakeUniq<TestingSetup>::__single_object std::make_unique<TestingSetup, ChainType const&, TestOpts&>(ChainType const&, TestOpts&) /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/unique_ptr.h:1085:30\n    #2 0x555557d768d4 in std::unique_ptr<TestingSetup, std::default_delete<TestingSetup>> MakeNoLogFileContext<TestingSetup>(ChainType, TestOpts) /home/ekzyis/prog/bitcoin/build_fuzz/./test/util/setup_common.h:270:12\n    #3 0x555557f06cc4 in wallet::(anonymous namespace)::initialize() /home/ekzyis/prog/bitcoin/build_fuzz/./wallet/test/fuzz/scan.cpp:25:39\n    #4 0x555557f4c959 in std::function<void ()>::operator()() const /nix/store/sca0pf46jmxva40qahkcwys5c1lvk6n2-gcc-15.2.0/include/c++/15.2.0/bits/std_function.h:593:9\n    #5 0x555557f4c959 in initialize() /home/ekzyis/prog/bitcoin/build_fuzz/./test/fuzz/fuzz.cpp:167:5\n    #6 0x555557f4c959 in LLVMFuzzerInitialize /home/ekzyis/prog/bitcoin/build_fuzz/./test/fuzz/fuzz.cpp:224:5\n    #7 0x5555574987b9 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x1f447b9)\n    #8 0x5555574dcf82 in main (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x1f88f82)\n    #9 0x7ffff762b284 in __libc_start_call_main (/nix/store/l0l2ll1lmylczj1ihqn351af2kyp5x19-glibc-2.42-51/lib/libc.so.6+0x2b284) (BuildId: 76913033e82a3d45b50fdb9773ae48a91d69ad8e)\n    #10 0x7ffff762b337 in __libc_start_main@GLIBC_2.2.5 (/nix/store/l0l2ll1lmylczj1ihqn351af2kyp5x19-glibc-2.42-51/lib/libc.so.6+0x2b337) (BuildId: 76913033e82a3d45b50fdb9773ae48a91d69ad8e)\n    #11 0x5555574829e4 in _start (/home/ekzyis/prog/bitcoin/build_fuzz/bin/fuzz+0x1f2e9e4)\n\nSUMMARY: AddressSanitizer: heap-use-after-free /home/ekzyis/prog/bitcoin/build_fuzz/./index/base.cpp:457:9 in BaseIndex::Stop()\nShadow bytes around the buggy address:\n  0x7d9ff67e1d00: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa\n  0x7d9ff67e1d80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n  0x7d9ff67e1e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa\n  0x7d9ff67e1e80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd\n  0x7d9ff67e1f00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd\n=>0x7d9ff67e1f80: fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd\n  0x7d9ff67e2000: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd\n  0x7d9ff67e2080: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd\n  0x7d9ff67e2100: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd\n  0x7d9ff67e2180: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd\n  0x7d9ff67e2200: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd\nShadow byte legend (one shadow byte represents 8 application bytes):\n  Addressable:           00\n  Partially addressable: 01 02 03 04 05 06 07\n  Heap left redzone:       fa\n  Freed heap region:       fd\n  Stack left redzone:      f1\n  Stack mid redzone:       f2\n  Stack right redzone:     f3\n  Stack after return:      f5\n  Stack use after scope:   f8\n  Global redzone:          f9\n  Global init order:       f6\n  Poisoned by user:        f7\n  Container overflow:      fc\n  Array cookie:            ac\n  Intra object redzone:    bb\n  ASan internal:           fe\n  Left alloca redzone:     ca\n  Right alloca redzone:    cb\n==69449==ABORTING\n```\n\nI think it happens when `InitBlockFilterIndex()` at line 52 runs, but `DestroyAllBlockFilterIndexes()` here doesn't. This input doesn't crash anymore when I unconditionally call `DestroyAllBlockFilterIndexes()` at the end:\n\npatch\n\n```diff\ndiff --git a/src/wallet/test/fuzz/scan.cpp b/src/wallet/test/fuzz/scan.cpp\nindex 92d149d216f..cf1bf5cc4dc 100644\n--- a/src/wallet/test/fuzz/scan.cpp\n+++ b/src/wallet/test/fuzz/scan.cpp\n@@ -106,6 +106,8 @@ FUZZ_TARGET(wallet_scan, .init = initialize)\n     if (fuzzed_data_provider.ConsumeBool()) fuzzed_wallet.wallet->AbortRescan();\n\n     (void)fuzzed_wallet.wallet->ScanForWalletTransactions(start_block, start_height, max_height, reserver, /*fUpdate=*/fuzzed_data_provider.ConsumeBool(), /*save_progress=*/false);\n+\n+    DestroyAllBlockFilterIndexes();\n }\n } // namespace\n } // namespace wallet\n```\n\nNot sure if that's an appropriate patch, though."
  },
  {
   "t": "2026-06-12T17:04:42Z",
   "kind": "review",
   "who": "ekzyis",
   "assoc": "NONE",
   "state": "COMMENTED",
   "commit": "747d0942413b26f0260126dfecf4f960a5e53a38",
   "text": "tested 747d0942413, left two comments.\n\nThe ASan crash is not a target crash since it happens after fuzzing is done, but should be addressed before merge, I think. Could be that I'm misreading the importance of it, though."
  },
  {
   "t": "2026-06-12T18:03:10Z",
   "kind": "review_comment",
   "who": "brunoerg",
   "assoc": "CONTRIBUTOR",
   "path": "src/wallet/test/fuzz/scan.cpp",
   "commit": "747d0942413b26f0260126dfecf4f960a5e53a38",
   "in_reply_to": 3404019071,
   "text": "No, it's a no-op, leftover from other thing I was trying. Will remove, thank you."
  },
  {
   "t": "2026-06-12T18:15:18Z",
   "kind": "review_comment",
   "who": "brunoerg",
   "assoc": "CONTRIBUTOR",
   "path": "src/wallet/test/fuzz/scan.cpp",
   "commit": "fbeba67512b32a6a516905b01db661da39ab7340",
   "in_reply_to": 3404753306,
   "text": "Nice catch, it's correct. We should call `DestroyAllBlockFilterIndexes()` at the end of the iteration. It clears the g_filter_indexes registry that lives outside the per-iteration TestingSetup, so the filter index doesn't survive into the next fuzz iteration."
  },
  {
   "t": "2026-06-12T18:16:03Z",
   "kind": "force_push",
   "who": "brunoerg",
   "commit": "904edfc10a72d5cd9cb44ed06129f59ea8d7ee4f"
  },
  {
   "t": "2026-06-12T18:43:37Z",
   "kind": "force_push",
   "who": "brunoerg",
   "commit": "fbeba67512b32a6a516905b01db661da39ab7340"
  },
  {
   "t": "2026-06-12T18:44:55Z",
   "kind": "comment",
   "who": "brunoerg",
   "assoc": "CONTRIBUTOR",
   "text": "Force-pushed:\n\n- Refactored it to not sure `fs::remove_all`\n- Rebased and changed it to use `BlockCreateOptions`\n- Addressed:  https://github.com/bitcoin/bitcoin/pull/32993#discussion_r3404019071 and https://github.com/bitcoin/bitcoin/pull/32993#discussion_r3404753306"
  },
  {
   "t": "2026-06-12T18:53:43Z",
   "kind": "comment",
   "who": "brunoerg",
   "assoc": "CONTRIBUTOR",
   "text": "I just moved it to draft because I want to refactor some stuff here to make it more efficient (current avg exec/s is far from being good)."
  }
 ],
 "labels_log": [
  {
   "t": "2025-07-16T13:15:11Z",
   "action": "labeled",
   "label": "Tests",
   "who": "DrahtBot"
  },
  {
   "t": "2025-07-16T15:28:41Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-07-16T18:11:48Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2025-10-30T13:55:54Z",
   "action": "labeled",
   "label": "Fuzzing",
   "who": "fanquake"
  },
  {
   "t": "2026-06-12T18:44:04Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-06-12T19:46:55Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  }
 ],
 "state_log": [
  {
   "t": "2025-07-16T13:27:34Z",
   "kind": "ready_for_review",
   "who": "brunoerg"
  },
  {
   "t": "2025-07-16T15:43:40Z",
   "kind": "convert_to_draft",
   "who": "brunoerg"
  },
  {
   "t": "2025-07-16T18:13:50Z",
   "kind": "ready_for_review",
   "who": "brunoerg"
  },
  {
   "t": "2026-06-12T18:52:55Z",
   "kind": "convert_to_draft",
   "who": "brunoerg"
  }
 ],
 "text_chars": 21365,
 "text_tokens_estimate": 5341,
 "changed_paths": [
  "src/wallet/test/fuzz/CMakeLists.txt",
  "src/wallet/test/fuzz/scan.cpp"
 ],
 "files": [
  {
   "path": "src/wallet/test/fuzz/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/wallet/test/fuzz/scan.cpp",
   "add": 110,
   "del": 0
  }
 ],
 "test_lines": 111,
 "git": {
  "head": "fbeba67512b32a6a516905b01db661da39ab7340",
  "head_matches_backup": true,
  "base": "4c99ed10766c7fac1353d1402d1b99de4c656c08",
  "commits": [
   {
    "sha": "fbeba67512",
    "subject": "fuzz: add target for wallet tx scanning",
    "files": 2,
    "add": 111,
    "del": 0
   }
  ],
  "patch_truncated": false
 },
 "input_hash": "917016e12f54db28",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}