LCOV - code coverage report
Current view: top level - src - bitcoin-util.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 80.9 % 152 123
Test Date: 2026-08-07 06:44:34 Functions: 100.0 % 6 6
Branches: 47.9 % 288 138

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2009-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <bitcoin-build-config.h> // IWYU pragma: keep
       6                 :             : 
       7                 :             : #include <arith_uint256.h>
       8                 :             : #include <chain.h>
       9                 :             : #include <chainparams.h>
      10                 :             : #include <chainparamsbase.h>
      11                 :             : #include <clientversion.h>
      12                 :             : #include <common/args.h>
      13                 :             : #include <common/license_info.h>
      14                 :             : #include <common/system.h>
      15                 :             : #include <compat/compat.h>
      16                 :             : #include <core_io.h>
      17                 :             : #include <streams.h>
      18                 :             : #include <univalue.h>
      19                 :             : #include <util/exception.h>
      20                 :             : #include <util/strencodings.h>
      21                 :             : #include <util/translation.h>
      22                 :             : 
      23                 :             : #include <atomic>
      24                 :             : #include <cstdio>
      25                 :             : #include <functional>
      26                 :             : #include <memory>
      27                 :             : #include <thread>
      28                 :             : 
      29                 :             : static const int CONTINUE_EXECUTION=-1;
      30                 :             : 
      31                 :             : const TranslateFn G_TRANSLATION_FUN{nullptr};
      32                 :             : 
      33                 :          18 : static void SetupBitcoinUtilArgs(ArgsManager &argsman)
      34                 :             : {
      35                 :          18 :     SetupHelpOptions(argsman);
      36                 :             : 
      37   [ +  -  +  - ]:          36 :     argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
      38                 :             : 
      39   [ +  -  +  -  :          36 :     argsman.AddCommand("grind", "Perform proof of work on hex header string");
                   +  - ]
      40   [ +  -  +  -  :          36 :     argsman.AddCommand("getchainparams", "Get hardcoded parameters for the selected chain");
                   +  - ]
      41                 :             : 
      42                 :          18 :     SetupChainParamsBaseOptions(argsman);
      43                 :          18 : }
      44                 :             : 
      45                 :             : // This function returns either one of EXIT_ codes when it's expected to stop the process or
      46                 :             : // CONTINUE_EXECUTION when it's expected to continue further.
      47                 :          18 : static int AppInitUtil(ArgsManager& args, int argc, char* argv[])
      48                 :             : {
      49                 :          18 :     SetupBitcoinUtilArgs(args);
      50         [ +  - ]:          18 :     std::string error;
      51   [ +  -  +  + ]:          18 :     if (!args.ParseParameters(argc, argv, error)) {
      52         [ +  - ]:           2 :         tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
      53                 :             :         return EXIT_FAILURE;
      54                 :             :     }
      55                 :             : 
      56   [ +  -  +  -  :          32 :     if (HelpRequested(args) || args.GetBoolArg("-version", false)) {
          +  -  +  -  +  
                -  -  + ]
      57                 :             :         // First part of help message is specific to this utility
      58   [ #  #  #  # ]:           0 :         std::string strUsage = CLIENT_NAME " bitcoin-util utility version " + FormatFullVersion() + "\n";
      59                 :             : 
      60   [ #  #  #  #  :           0 :         if (args.GetBoolArg("-version", false)) {
                   #  # ]
      61   [ #  #  #  # ]:           0 :             strUsage += FormatParagraph(LicenseInfo());
      62                 :             :         } else {
      63         [ #  # ]:           0 :             strUsage += "\n"
      64                 :             :                 "The bitcoin-util tool provides bitcoin related functionality that does not rely on the ability to access a running node. Available [commands] are listed below.\n"
      65                 :             :                 "\n"
      66                 :             :                 "Usage:  bitcoin-util [options] [command]\n"
      67                 :           0 :                 "or:     bitcoin-util [options] grind <hex-block-header>\n";
      68   [ #  #  #  # ]:           0 :             strUsage += "\n" + args.GetHelpMessage();
      69                 :             :         }
      70                 :             : 
      71         [ #  # ]:           0 :         tfm::format(std::cout, "%s", strUsage);
      72                 :             : 
      73         [ #  # ]:           0 :         if (argc < 2) {
      74         [ #  # ]:           0 :             tfm::format(std::cerr, "Error: too few parameters\n");
      75                 :             :             return EXIT_FAILURE;
      76                 :             :         }
      77                 :             :         return EXIT_SUCCESS;
      78                 :           0 :     }
      79                 :             : 
      80                 :             :     // Check for chain settings (Params() calls are only valid after this clause)
      81                 :          16 :     try {
      82   [ +  -  +  - ]:          16 :         SelectParams(args.GetChainType());
      83         [ -  - ]:           0 :     } catch (const std::exception& e) {
      84         [ -  - ]:           0 :         tfm::format(std::cerr, "Error: %s\n", e.what());
      85                 :           0 :         return EXIT_FAILURE;
      86                 :           0 :     }
      87                 :             : 
      88                 :             :     return CONTINUE_EXECUTION;
      89                 :          18 : }
      90                 :             : 
      91                 :          24 : static void grind_task(uint32_t nBits, CBlockHeader header, uint32_t offset, uint32_t step, std::atomic<bool>& found, uint32_t& proposed_nonce)
      92                 :             : {
      93                 :          24 :     arith_uint256 target;
      94                 :          24 :     bool neg, over;
      95                 :          24 :     target.SetCompact(nBits, &neg, &over);
      96   [ +  -  +  -  :          24 :     if (target == 0 || neg || over) return;
                   +  - ]
      97                 :          24 :     header.nNonce = offset;
      98                 :             : 
      99                 :          24 :     uint32_t finish = std::numeric_limits<uint32_t>::max() - step;
     100                 :          24 :     finish = finish - (finish % step) + offset;
     101                 :             : 
     102   [ +  +  +  - ]:        6522 :     while (!found && header.nNonce < finish) {
     103         [ +  - ]:        6504 :         const uint32_t next = (finish - header.nNonce < 5000*step) ? finish : header.nNonce + 5000*step;
     104                 :    32510547 :         do {
     105         [ +  + ]:    32510547 :             if (UintToArith256(header.GetHash()) <= target) {
     106         [ +  - ]:           6 :                 if (!found.exchange(true)) {
     107                 :           6 :                     proposed_nonce = header.nNonce;
     108                 :             :                 }
     109                 :           6 :                 return;
     110                 :             :             }
     111                 :    32510541 :             header.nNonce += step;
     112         [ +  + ]:    32510541 :         } while(header.nNonce != next);
     113                 :             :     }
     114                 :             : }
     115                 :             : 
     116                 :           9 : static int Grind(const std::vector<std::string>& args, std::string& strPrint)
     117                 :             : {
     118   [ -  +  +  + ]:           9 :     if (args.size() != 1) {
     119                 :           2 :         strPrint = "Must specify block header to grind";
     120                 :           2 :         return EXIT_FAILURE;
     121                 :             :     }
     122                 :             : 
     123                 :           7 :     CBlockHeader header;
     124         [ +  + ]:           7 :     if (!DecodeHexBlockHeader(header, args[0])) {
     125                 :           1 :         strPrint = "Could not decode block header";
     126                 :           1 :         return EXIT_FAILURE;
     127                 :             :     }
     128                 :             : 
     129                 :           6 :     uint32_t nBits = header.nBits;
     130                 :           6 :     std::atomic<bool> found{false};
     131                 :           6 :     uint32_t proposed_nonce{};
     132                 :             : 
     133                 :           6 :     std::vector<std::thread> threads;
     134         [ -  + ]:           6 :     int n_tasks = std::max(1u, std::thread::hardware_concurrency());
     135         [ +  - ]:           6 :     threads.reserve(n_tasks);
     136         [ +  + ]:          30 :     for (int i = 0; i < n_tasks; ++i) {
     137         [ +  - ]:          24 :         threads.emplace_back(grind_task, nBits, header, i, n_tasks, std::ref(found), std::ref(proposed_nonce));
     138                 :             :     }
     139         [ +  + ]:          30 :     for (auto& t : threads) {
     140         [ +  - ]:          24 :         t.join();
     141                 :             :     }
     142         [ +  - ]:           6 :     if (found) {
     143                 :           6 :         header.nNonce = proposed_nonce;
     144                 :             :     } else {
     145         [ #  # ]:           0 :         strPrint = "Could not satisfy difficulty target";
     146                 :             :         return EXIT_FAILURE;
     147                 :             :     }
     148                 :             : 
     149                 :           6 :     DataStream ss{};
     150         [ +  - ]:           6 :     ss << header;
     151   [ -  +  +  - ]:           6 :     strPrint = HexStr(ss);
     152                 :           6 :     return EXIT_SUCCESS;
     153                 :           6 : }
     154                 :             : 
     155                 :           7 : static int GetChainParams(const std::vector<std::string>& args, std::string& strPrint)
     156                 :             : {
     157         [ +  + ]:           7 :     if (!args.empty()) {
     158                 :           1 :         strPrint = "getchainparams does not take arguments";
     159                 :           1 :         return EXIT_FAILURE;
     160                 :             :     }
     161                 :             : 
     162                 :           6 :     const auto& params = Params();
     163                 :           6 :     const auto& consensus = params.GetConsensus();
     164                 :             : 
     165                 :           6 :     UniValue result{UniValue::VOBJ};
     166   [ +  -  +  -  :          12 :     result.pushKV("chain", params.GetChainTypeString());
             +  -  +  - ]
     167   [ +  -  +  -  :          12 :     result.pushKV("test_chain", params.IsTestChain());
                   +  - ]
     168   [ +  -  +  -  :          12 :     result.pushKV("genesis", HexStr(consensus.hashGenesisBlock));
             +  -  +  - ]
     169   [ +  -  +  -  :          12 :     result.pushKV("subsidy_halving_interval", consensus.nSubsidyHalvingInterval);
                   +  - ]
     170                 :             : 
     171         [ +  + ]:           6 :     if (consensus.signet_blocks) {
     172                 :           2 :         UniValue signet{UniValue::VOBJ};
     173   [ -  +  +  -  :           4 :         signet.pushKV("challenge", HexStr(consensus.signet_challenge));
          +  -  +  -  +  
                      - ]
     174   [ +  -  +  -  :           4 :         result.pushKV("signet", signet);
                   +  - ]
     175                 :           2 :     }
     176                 :             : 
     177                 :           6 :     {
     178                 :           6 :         UniValue pow{UniValue::VOBJ};
     179   [ +  -  +  -  :          12 :         pow.pushKV("limit", consensus.powLimit.ToString());
             +  -  +  - ]
     180         [ +  + ]:           6 :         if (!consensus.fPowNoRetargeting) {
     181   [ +  -  +  -  :          10 :             pow.pushKV("target_spacing", TicksSeconds(consensus.PowTargetSpacing()));
                   +  - ]
     182   [ +  -  +  -  :          10 :             pow.pushKV("difficulty_retarget_interval", consensus.DifficultyAdjustmentInterval());
                   +  - ]
     183                 :           5 :             std::string mindiff_blocks = (consensus.fPowAllowMinDifficultyBlocks ?
     184   [ +  +  +  +  :           6 :                   (consensus.enforce_BIP94 ? "bip94" : "yes") : "no");
                   +  - ]
     185   [ +  -  +  -  :          10 :             pow.pushKV("mindiff_blocks", mindiff_blocks);
                   +  - ]
     186                 :           5 :         }
     187   [ +  -  +  -  :          12 :         result.pushKV("pow", pow);
                   +  - ]
     188                 :           6 :     }
     189                 :             : 
     190                 :           6 :     {
     191                 :           6 :         UniValue net{UniValue::VOBJ};
     192   [ +  -  +  -  :          12 :         net.pushKV("default_port", params.GetDefaultPort());
                   +  - ]
     193   [ +  -  +  -  :          12 :         net.pushKV("magic", HexStr(params.MessageStart()));
             +  -  +  - ]
     194                 :           6 :         UniValue dns{UniValue::VARR};
     195         [ +  + ]:          22 :         for (const auto& seed : params.DNSSeeds()) {
     196   [ +  -  +  - ]:          16 :             dns.push_back(seed);
     197                 :             :         }
     198   [ +  -  +  -  :          12 :         net.pushKV("dns_seeds", dns);
                   +  - ]
     199   [ +  -  +  -  :          12 :         result.pushKV("net", net);
                   +  - ]
     200                 :           6 :     }
     201                 :             : 
     202                 :           6 :     {
     203                 :           6 :         UniValue addr{UniValue::VOBJ};
     204   [ +  -  +  -  :          12 :         addr.pushKV("bech32_hrp", params.Bech32HRP());
                   +  - ]
     205   [ +  -  +  -  :          12 :         result.pushKV("addresses", addr);
                   +  - ]
     206                 :           6 :     }
     207                 :             : 
     208         [ +  - ]:           6 :     strPrint = result.write(/*prettyIndent=*/2);
     209                 :           6 :     return EXIT_SUCCESS;
     210                 :           6 : }
     211                 :             : 
     212                 :          18 : MAIN_FUNCTION
     213                 :             : {
     214                 :          18 :     ArgsManager& args = gArgs;
     215                 :          18 :     SetupEnvironment();
     216                 :             : 
     217                 :          18 :     try {
     218         [ +  - ]:          18 :         int ret = AppInitUtil(args, argc, argv);
     219         [ +  + ]:          18 :         if (ret != CONTINUE_EXECUTION) {
     220                 :             :             return ret;
     221                 :             :         }
     222         [ -  - ]:           0 :     } catch (const std::exception& e) {
     223         [ -  - ]:           0 :         PrintExceptionContinue(&e, "AppInitUtil()");
     224                 :           0 :         return EXIT_FAILURE;
     225                 :           0 :     } catch (...) {
     226         [ -  - ]:           0 :         PrintExceptionContinue(nullptr, "AppInitUtil()");
     227                 :           0 :         return EXIT_FAILURE;
     228                 :           0 :     }
     229                 :             : 
     230                 :          16 :     const auto cmd = args.GetCommand();
     231         [ -  + ]:          16 :     if (!cmd) {
     232         [ #  # ]:           0 :         tfm::format(std::cerr, "Error: must specify a command\n");
     233                 :             :         return EXIT_FAILURE;
     234                 :             :     }
     235                 :             : 
     236                 :          16 :     int ret = EXIT_FAILURE;
     237         [ +  + ]:          16 :     std::string strPrint;
     238                 :          16 :     try {
     239         [ +  + ]:          16 :         if (cmd->command == "grind") {
     240         [ +  - ]:           9 :             ret = Grind(cmd->args, strPrint);
     241         [ +  - ]:           7 :         } else if (cmd->command == "getchainparams") {
     242         [ +  - ]:           7 :             ret = GetChainParams(cmd->args, strPrint);
     243                 :             :         } else {
     244                 :           0 :             assert(false); // unknown command should be caught earlier
     245                 :             :         }
     246         [ -  - ]:           0 :     } catch (const std::exception& e) {
     247         [ -  - ]:           0 :         strPrint = std::string("error: ") + e.what();
     248                 :           0 :     } catch (...) {
     249         [ -  - ]:           0 :         strPrint = "unknown error";
     250         [ -  - ]:           0 :     }
     251                 :             : 
     252         [ +  - ]:          16 :     if (strPrint != "") {
     253   [ +  +  +  - ]:          20 :         tfm::format(ret == 0 ? std::cout : std::cerr, "%s\n", strPrint);
     254                 :             :     }
     255                 :             : 
     256                 :          16 :     return ret;
     257                 :          32 : }
        

Generated by: LCOV version 2.0-1