util: Add [[nodiscard]] to all {Decode,Parse}[...](...) functions returning bool #13815

pull practicalswift wants to merge 4 commits into bitcoin:master from practicalswift:check-return-values-from-parse changing 15 files +84 −53
  1. practicalswift commented at 5:50 AM on July 31, 2018: contributor

    Changes in this PR:

    • Add linter to make sure the return value of Parse[...](...) is checked
    • Add __attribute__((warn_unused_result)) to all {Decode,Parse}[...](...) functions returning bool
    • Fix violations

    Context:

    • #13712: wallet: Fix non-determinism in ParseHDKeypath(...). Avoid using an uninitialized variable in path calculation. would have been prevented by this
  2. fanquake added the label Scripts and tools on Jul 31, 2018
  3. fanquake commented at 5:52 AM on July 31, 2018: member
    $ test/lint/lint-all.sh
    Missing "export LC_ALL=C" (to avoid locale dependence) as first non-comment non-empty line in test/lint/lint-cpp.sh
    ^---- failure generated from test/lint/lint-shell-locale.sh
    The command "test/lint/lint-all.sh" exited with 1.
    
  4. in src/miner.cpp:79 in ee225c8913 outdated
      76 | -        options.blockMinFeeRate = CFeeRate(n);
      77 | +        if (ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) {
      78 | +            options.blockMinFeeRate = CFeeRate(n);
      79 | +        } else {
      80 | +            options.blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
      81 | +        }
    


    Empact commented at 7:03 AM on July 31, 2018:

    You could avoid the duplicate else clause by boosting amount out like so:

    if (gArgs.IsArgSet("-blockmintxfee") && ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) {
    
  5. practicalswift force-pushed on Jul 31, 2018
  6. practicalswift commented at 7:52 AM on July 31, 2018: contributor

    @fanquake Thanks! lint-shell-locale.sh to the rescue once again! Now fixed! Please re-review :-) @Empact Good point! Updated. Please re-review :-)

  7. skeees commented at 3:38 AM on August 2, 2018: contributor

    utACK (weakly regarding the linter) If you want to have lots of lint checks and similar static analysis to the kind you are adding here (it seems you do, and these things are useful!) - it might make sense to consider investing in building out tooling that uses libclang and inspects the AST directly as opposed to just regexp matching.

  8. practicalswift renamed this:
    build: Add linter to make sure the return value of Parse[...](...) is checked
    Add __attribute__((warn_unused_result)) to all Parse[...](...) functions
    on Aug 2, 2018
  9. practicalswift force-pushed on Aug 2, 2018
  10. practicalswift commented at 1:48 PM on August 2, 2018: contributor

    @skeees I removed the linter. Now using __attribute__((warn_unused_result)) instead. Please re-review :-)

  11. practicalswift force-pushed on Aug 2, 2018
  12. skeees commented at 2:20 PM on August 2, 2018: contributor

    :) Nice Is is best practice to #define this attribute similar to how this is done in threadsafety.h or # define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) ?

  13. practicalswift force-pushed on Aug 2, 2018
  14. practicalswift force-pushed on Aug 2, 2018
  15. practicalswift commented at 2:38 PM on August 2, 2018: contributor

    @skeees The secp256k1 define is used to handle ancient gcc versions AFAICS, so I see no reason to use that here. Let me know if you see any other reason :-)

  16. practicalswift force-pushed on Aug 2, 2018
  17. practicalswift force-pushed on Aug 2, 2018
  18. practicalswift force-pushed on Aug 2, 2018
  19. practicalswift renamed this:
    Add __attribute__((warn_unused_result)) to all Parse[...](...) functions
    Add __attribute__((warn_unused_result)) to all {Decode,Parse}[...](...) functions returning bool
    on Aug 2, 2018
  20. practicalswift commented at 2:56 PM on August 2, 2018: contributor

    Also added __attribute__((warn_unused_result)) to all Decode... functions returning bool. Please re-review :-)

  21. DrahtBot commented at 3:09 PM on August 2, 2018: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #14605 (Return of the Banman by dongcarl)
    • #14045 (WIP: refactor: Fix the chainparamsbase -> util circular dependency by Empact)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  22. DrahtBot cross-referenced this on Aug 2, 2018 from issue Test for Windows encoding issue by ken2812221
  23. skeees commented at 3:33 PM on August 2, 2018: contributor

    can reorder the Tests* commits first before adding the attribute commits so that you don't break a bisect

  24. DrahtBot cross-referenced this on Aug 2, 2018 from issue PSBT key path cleanups by sipa
  25. practicalswift commented at 3:44 PM on August 2, 2018: contributor

    @skeees When rethinking it I think you have a good point regarding using a #define. Perhaps we should go with:

    #ifdef __has_cpp_attribute
    #  if __has_cpp_attribute(nodiscard)
    #    define NODISCARD [[nodiscard]]
    #  endif
    #else
    #  define NODISCARD __attribute__((warn_unused_result))
    #endif
    

    That will have the benefit of being less verbose. That would use the newer [[nodiscard]] (required from C++17) where available and fall back on the older __attribute__((warn_unused_result)).

    Makes sense?

    What would be the most appropriate file to put that #define in? @MarcoFalke, any input?

  26. practicalswift force-pushed on Aug 2, 2018
  27. practicalswift force-pushed on Aug 2, 2018
  28. practicalswift commented at 3:49 PM on August 2, 2018: contributor

    @skeees Commits reordered as requested!

  29. skeees commented at 3:51 PM on August 2, 2018: contributor

    I like that #define solution @practicalswift I don't see an obviously appropriate place for these right now maybe add staticanalysis.h ?

  30. practicalswift renamed this:
    Add __attribute__((warn_unused_result)) to all {Decode,Parse}[...](...) functions returning bool
    Add [[nodiscard] (or warn_unused_result) to all {Decode,Parse}[...](...) functions returning bool
    on Aug 2, 2018
  31. practicalswift renamed this:
    Add [[nodiscard] (or warn_unused_result) to all {Decode,Parse}[...](...) functions returning bool
    Add [[nodiscard]] (or warn_unused_result) to all {Decode,Parse}[...](...) functions returning bool
    on Aug 2, 2018
  32. practicalswift commented at 3:57 PM on August 2, 2018: contributor

    What about the following?

    $ cat src/attributes.h
    // Copyright (c) 2009-2010 Satoshi Nakamoto
    // Copyright (c) 2009-2018 The Bitcoin Core developers
    // Distributed under the MIT software license, see the accompanying
    // file COPYING or http://www.opensource.org/licenses/mit-license.php.
    
    #ifndef BITCOIN_ATTRIBUTES_H
    #define BITCOIN_ATTRIBUTES_H
    
    #ifdef __has_cpp_attribute
    #  if __has_cpp_attribute(nodiscard)
    #    define NODISCARD [[nodiscard]]
    #  endif
    #else
    #  define NODISCARD __attribute__((warn_unused_result))
    #endif
    
    #endif // BITCOIN_ATTRIBUTES_H
    
  33. DrahtBot cross-referenced this on Aug 2, 2018 from issue [refactor] Fix the chainparamsbase -> util circular dependency by Empact
  34. practicalswift force-pushed on Aug 2, 2018
  35. practicalswift commented at 4:21 PM on August 2, 2018: contributor

    Now using NODISCARD ([[nodiscard]] or __attribute__((warn_unused_result))) throughout. Please re-review :-)

  36. practicalswift force-pushed on Aug 2, 2018
  37. practicalswift cross-referenced this on Aug 2, 2018 from issue wallet: Fix non-determinism in ParseHDKeypath(...). Avoid using an uninitialized variable in path calculation. by practicalswift
  38. DrahtBot cross-referenced this on Aug 2, 2018 from issue [bugfix] Fix encoding issue for Windows by ken2812221
  39. Empact commented at 6:40 PM on August 2, 2018: member

    Concept ACK, and loving NODISCARD. But you need to add attributes.h to src/Makefile.am. Also please sort your new include alphabetically.

  40. in src/attributes.h:10 in 1856b807d1 outdated
       5 | +
       6 | +#ifndef BITCOIN_ATTRIBUTES_H
       7 | +#define BITCOIN_ATTRIBUTES_H
       8 | +
       9 | +#ifdef __has_cpp_attribute
      10 | +#  if __has_cpp_attribute(nodiscard)
    


    Empact commented at 6:44 PM on August 2, 2018:

    You should collapse this to one level: #if defined(__has_cpp_attribute) && __has_cpp_attribute(nodiscard)

    Otherwise NODISCARD will be undefined if __has_cpp_attribute(nodiscard) is false.

  41. DrahtBot cross-referenced this on Aug 2, 2018 from issue rpc: Add submitheader by MarcoFalke
  42. practicalswift force-pushed on Aug 3, 2018
  43. practicalswift commented at 7:30 AM on August 3, 2018: contributor

    @Empact Thanks for reviewing! Feedback addressed. The broken ifdef logic was sloppy from my side – sorry about that. Would you mind re-reviewing? :-)

  44. DrahtBot cross-referenced this on Aug 3, 2018 from issue Move src/tinyformat.h to src/tinyformat/tinyformat.h by Empact
  45. DrahtBot cross-referenced this on Aug 3, 2018 from issue Include tinyformat as a subtree by Empact
  46. practicalswift renamed this:
    Add [[nodiscard]] (or warn_unused_result) to all {Decode,Parse}[...](...) functions returning bool
    util: Add [[nodiscard]] (or warn_unused_result) to all {Decode,Parse}[...](...) functions returning bool
    on Aug 3, 2018
  47. practicalswift renamed this:
    util: Add [[nodiscard]] (or warn_unused_result) to all {Decode,Parse}[...](...) functions returning bool
    util: Add [[nodiscard]] to all {Decode,Parse}[...](...) functions returning bool
    on Aug 3, 2018
  48. Empact commented at 3:00 PM on August 3, 2018: member

    On second thought, how about throw rather than default on unparsable option? Seems like a failure to be noisy about.

  49. skeees commented at 3:00 PM on August 3, 2018: contributor

    In terms of commit ordering, you need the #define NODISCARD commit to precede the commits where you use NODISCARD Other than that lgtm!

  50. DrahtBot added the label Needs rebase on Aug 15, 2018
  51. practicalswift force-pushed on Aug 15, 2018
  52. practicalswift commented at 8:36 PM on August 15, 2018: contributor

    Rebased! :-) @MarcoFalke I don't know if I've thanked you before but thanks for your work on @DrahtBot! It really helps keeping the PR:s up to date! Really nice!

  53. DrahtBot removed the label Needs rebase on Aug 15, 2018
  54. DrahtBot cross-referenced this on Aug 20, 2018 from issue refactor: Removal of circular dependency between index/txindex, validation and index/base by mgrychow
  55. DrahtBot cross-referenced this on Aug 22, 2018 from issue Import key origin data through descriptors in importmulti by achow101
  56. DrahtBot cross-referenced this on Aug 24, 2018 from issue refactor: Fix the chainparamsbase -> util circular dependency by Empact
  57. DrahtBot cross-referenced this on Aug 26, 2018 from issue Add tests and error handling to DecodeExtPubKey/DecodeExtKey. Add [[nodiscard]]. by practicalswift
  58. practicalswift force-pushed on Aug 27, 2018
  59. practicalswift commented at 5:15 PM on August 27, 2018: contributor

    Updated NODISCARD to work also with Visual C++ :-)

  60. DrahtBot added the label Needs rebase on Aug 28, 2018
  61. practicalswift force-pushed on Aug 28, 2018
  62. practicalswift commented at 8:58 PM on August 28, 2018: contributor

    Rebased!

  63. practicalswift force-pushed on Aug 28, 2018
  64. practicalswift force-pushed on Aug 28, 2018
  65. practicalswift force-pushed on Aug 28, 2018
  66. DrahtBot removed the label Needs rebase on Aug 28, 2018
  67. practicalswift force-pushed on Aug 28, 2018
  68. practicalswift cross-referenced this on Aug 31, 2018 from issue wallet: Remove unused local variable old_label by practicalswift
  69. DrahtBot cross-referenced this on Sep 10, 2018 from issue Annotate unused parameters with [[maybe_unused]] by practicalswift
  70. DrahtBot cross-referenced this on Sep 15, 2018 from issue Document intentional and unintentional unsigned integer overflows (wraparounds) using annotations by practicalswift
  71. in src/miner.cpp:74 in da78f95f5a outdated
      69 | @@ -70,9 +70,8 @@ static BlockAssembler::Options DefaultOptions()
      70 |      // If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT
      71 |      BlockAssembler::Options options;
      72 |      options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
      73 | -    if (gArgs.IsArgSet("-blockmintxfee")) {
      74 | -        CAmount n = 0;
      75 | -        ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n);
      76 | +    CAmount n = 0;
      77 | +    if (gArgs.IsArgSet("-blockmintxfee") && ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) {
    


    arvidn commented at 2:23 PM on September 17, 2018:

    with this change the scope of variable n expands and "leaks" outside of where it's used. perhaps not a big deal, but if we allow C++17 this could be written as:

    if (CAmount n = 0; gArgs.IsArgSet("-blockmintxfee") && ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) {


    practicalswift commented at 2:31 PM on September 17, 2018:

    @arvidn We allow only C++11 :-)

  72. in src/rest.cpp:109 in da78f95f5a outdated
     105 | @@ -105,7 +106,7 @@ static std::string AvailableDataFormatsString()
     106 |      return formats;
     107 |  }
     108 |  
     109 | -static bool ParseHashStr(const std::string& strReq, uint256& v)
     110 | +NODISCARD static bool ParseHashStr(const std::string& strReq, uint256& v)
    


    arvidn commented at 2:24 PM on September 17, 2018:

    I would expect you don't need this attribute on the function definition, but just the declaration. Do you really need it here too?


    arvidn commented at 2:27 PM on September 17, 2018:

    ditto for all other definitions


    Empact commented at 4:40 AM on September 25, 2018:

    This is misleading because it is actually a static function, there is no declaration, though there is another identically-named function. See #14307

  73. in src/script/descriptor.cpp:434 in da78f95f5a outdated
     430 | @@ -431,7 +431,7 @@ std::vector<Span<const char>> Split(const Span<const char>& sp, char sep)
     431 |  }
     432 |  
     433 |  /** Parse a key path, being passed a split list of elements (the first element is ignored). */
     434 | -bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out)
     435 | +NODISCARD static bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out)
    


    arvidn commented at 2:26 PM on September 17, 2018:

    in C++ it's generally preferred to putt functions with internal linkage in the anonymous namespace instead of using static, but I see a lot of static, so perhaps that's the style here


    practicalswift commented at 12:16 PM on October 7, 2018:

    Yes, going with static here to keep the number of lines touched lines to a minimum.


    practicalswift commented at 10:27 AM on October 9, 2018:

    Oh, turns out ParseKeyPath(…) is already in the anonymous namespace. Thus making static redundant. Now removed. Thanks for the nit @arvidn!

  74. DrahtBot cross-referenced this on Sep 19, 2018 from issue Move urlDecode to wallet/rpcwallet.cpp, where it's used by Empact
  75. DrahtBot cross-referenced this on Sep 20, 2018 from issue Skip tx-rehashing on historic blocks by MarcoFalke
  76. DrahtBot cross-referenced this on Sep 21, 2018 from issue Refactor: separate wallet from node by ryanofsky
  77. DrahtBot cross-referenced this on Sep 21, 2018 from issue rest: Do not re-use the function name ParseHashStr (core_io.h) for a function with different behaviour in rest.cpp by practicalswift
  78. DrahtBot cross-referenced this on Sep 24, 2018 from issue Consolidate redundant implementations of ParseHashStr by Empact
  79. in src/utilstrencodings.h:41 in da78f95f5a outdated
      36 | @@ -35,8 +37,8 @@ enum SafeChars
      37 |  * @return           A new string without unsafe chars
      38 |  */
      39 |  std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT);
      40 | -std::vector<unsigned char> ParseHex(const char* psz);
      41 | -std::vector<unsigned char> ParseHex(const std::string& str);
      42 | +NODISCARD std::vector<unsigned char> ParseHex(const char* psz);
      43 | +NODISCARD std::vector<unsigned char> ParseHex(const std::string& str);
    


    Empact commented at 4:49 AM on September 25, 2018:

    These don't return bool

  80. Empact commented at 4:51 AM on September 25, 2018: member

    I see apparently unnecessary changes to: src/wallet/rpcwallet.cpp src/wallet/test/psbt_wallet_tests.cpp

  81. practicalswift force-pushed on Sep 25, 2018
  82. practicalswift commented at 5:02 AM on September 25, 2018: contributor

    @Empact Unrelated sorting of includes in those two files removed :-)

  83. in src/Makefile.am:98 in 58cee45c23 outdated
      91 | @@ -92,6 +92,7 @@ endif
      92 |  BITCOIN_CORE_H = \
      93 |    addrdb.h \
      94 |    addrman.h \
      95 | +  attributes.h \
    


    ken2812221 commented at 5:35 AM on September 25, 2018:

    Wrong file, should be nodiscard.h?


    practicalswift commented at 7:28 AM on September 25, 2018:

    attributes.h is correct but that file got lost in the last rebase. Now re-added :-)

  84. in src/base58.h:17 in e6d8872366 outdated
      13 | @@ -14,6 +14,8 @@
      14 |  #ifndef BITCOIN_BASE58_H
      15 |  #define BITCOIN_BASE58_H
      16 |  
      17 | +#include <attributes.h>
    


    ken2812221 commented at 5:40 AM on September 25, 2018:

    Same here


    practicalswift commented at 7:28 AM on September 25, 2018:

    attributes.h is correct but that file got lost in the last rebase. Now re-added :-)


    ken2812221 commented at 7:35 AM on September 25, 2018:

    Seems attributes.h is as same as nodiscard.h now


    practicalswift commented at 7:45 AM on September 25, 2018:

    nodiscard.h now removed :-)

  85. practicalswift force-pushed on Sep 25, 2018
  86. practicalswift force-pushed on Sep 25, 2018
  87. DrahtBot cross-referenced this on Sep 26, 2018 from issue Use non-throwing type-safe ChainType where possible by MarcoFalke
  88. DrahtBot added the label Needs rebase on Sep 27, 2018
  89. practicalswift force-pushed on Oct 7, 2018
  90. practicalswift commented at 12:18 PM on October 7, 2018: contributor

    Rebased! Please re-review @ken2812221, @arvidn, @Empact, @skeees and @fanquake :-)

  91. DrahtBot removed the label Needs rebase on Oct 7, 2018
  92. practicalswift commented at 10:27 AM on October 9, 2018: contributor

    Updated to address @arvidn:s static nit. Please re-review :-)

  93. in src/attributes.h:21 in ee4b5b8e6d outdated
      11 | +#elif defined(_MSC_VER) && _MSC_VER >= 1700
      12 | +#  define NODISCARD _Check_return_
      13 | +#else
      14 | +#  define NODISCARD __attribute__((warn_unused_result))
      15 | +#endif
      16 | +
    


    ken2812221 commented at 10:53 AM on October 9, 2018:

    This solution might be too complex, but it can get rid of annoying MSVC warnings.

    #if defined(__has_cpp_attribute)
    #  if __has_cpp_attribute(nodiscard)
    #    define NODISCARD [[nodiscard]]
    #  endif
    #endif
    #ifndef NODISCARD
    #  if defined(_MSC_VER) && _MSC_VER >= 1700
    #    define NODISCARD _Check_return_
    #  else
    #    define NODISCARD __attribute__((warn_unused_result))
    #  endif
    #endif
    

    practicalswift commented at 10:19 AM on October 11, 2018:

    Fixed!

  94. practicalswift force-pushed on Oct 11, 2018
  95. practicalswift force-pushed on Oct 11, 2018
  96. practicalswift force-pushed on Oct 11, 2018
  97. practicalswift commented at 10:20 AM on October 11, 2018: contributor

    Updated to address MSVC warnings. Please re-review :-)

  98. practicalswift force-pushed on Oct 11, 2018
  99. practicalswift commented at 8:22 PM on October 11, 2018: contributor

    @ken2812221 Seems like I'm unable to get rid of the ugly MSVC warnings ("unexpected tokens following preprocessor directive […]"). Do you have any theory on how to fix it? I don't have MSVC available – only AppVeyor :-)

  100. ken2812221 commented at 8:25 PM on October 11, 2018: contributor

    Just put __has_cpp_attribute(...) inside the condition #ifdef __has_cpp_attribute. Like what I posted.

  101. practicalswift force-pushed on Oct 11, 2018
  102. DrahtBot cross-referenced this on Oct 20, 2018 from issue validation: Document where we are intentionally ignoring bool return values from validation related functions by practicalswift
  103. DrahtBot cross-referenced this on Oct 23, 2018 from issue Move util files to directory by jimpo
  104. DrahtBot cross-referenced this on Oct 30, 2018 from issue Return of the Banman by dongcarl
  105. DrahtBot added the label Needs rebase on Nov 5, 2018
  106. practicalswift force-pushed on Nov 5, 2018
  107. practicalswift commented at 12:54 PM on November 5, 2018: contributor

    Rebased!

  108. DrahtBot removed the label Needs rebase on Nov 5, 2018
  109. miner: Default to DEFAULT_BLOCK_MIN_TX_FEE if unable to parse -blockmintxfee 7c5bc2a523
  110. tests: Check return value of ParseParameters(...) 145fe95ec7
  111. tests: Explicitly ignore the return value of DecodeBase58(...) 579497e77a
  112. Add NODISCARD to all {Decode,Parse}[...](...) functions returning bool. Sort includes. 9cc0230cfc
  113. practicalswift force-pushed on Nov 5, 2018
  114. MarcoFalke commented at 8:43 PM on November 8, 2018: member

    utACK 9cc0230cfc1ae9b9c1c905cd9ac613bc98bfa43a

  115. Empact commented at 9:05 PM on November 8, 2018: member

    utACK 9cc0230

  116. sipa commented at 11:05 PM on November 14, 2018: member

    utACK 9cc0230cfc1ae9b9c1c905cd9ac613bc98bfa43a

  117. MarcoFalke merged this on Nov 15, 2018
  118. MarcoFalke closed this on Nov 15, 2018

  119. MarcoFalke referenced this in commit 384967f311 on Nov 15, 2018
  120. kwvg referenced this in commit c6f397067b on Mar 10, 2021
  121. kwvg referenced this in commit bf3997c7d4 on Mar 10, 2021
  122. kwvg referenced this in commit 38ef8ef742 on Mar 10, 2021
  123. kwvg referenced this in commit 6daf802aae on Mar 10, 2021
  124. kwvg referenced this in commit edbf85f003 on Mar 10, 2021
  125. kwvg referenced this in commit 3600feee2e on Mar 10, 2021
  126. kwvg referenced this in commit 0e6fdcf0e5 on Mar 10, 2021
  127. kwvg referenced this in commit 2380070b2e on Mar 12, 2021
  128. kwvg referenced this in commit c0845e585f on Mar 12, 2021
  129. kwvg referenced this in commit bd195f00f5 on Mar 12, 2021
  130. kwvg referenced this in commit eb3511395a on Mar 19, 2021
  131. PastaPastaPasta referenced this in commit e20dc9f374 on Mar 22, 2021
  132. practicalswift deleted the branch on Apr 10, 2021
  133. furszy cross-referenced this on Jun 7, 2021 from issue Road to Tor v3 support (BIP155) by furszy
  134. random-zebra referenced this in commit b4751e10ce on Aug 11, 2021
  135. gades referenced this in commit 0647f7b2bf on Mar 16, 2022
  136. bitcoin locked this on Aug 16, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-05-20 07:54 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me