Line data Source code
1 : // Copyright (c) 2009-2020 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 : #if defined(HAVE_CONFIG_H)
6 : #include <config/bitcoin-config.h>
7 : #endif
8 :
9 : #include <arith_uint256.h>
10 : #include <chain.h>
11 : #include <chainparams.h>
12 : #include <chainparamsbase.h>
13 : #include <clientversion.h>
14 : #include <core_io.h>
15 : #include <streams.h>
16 : #include <util/system.h>
17 : #include <util/translation.h>
18 :
19 : #include <atomic>
20 : #include <cstdio>
21 : #include <functional>
22 : #include <memory>
23 : #include <thread>
24 :
25 : static const int CONTINUE_EXECUTION=-1;
26 :
27 5 : const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
28 :
29 5 : static void SetupBitcoinUtilArgs(ArgsManager &argsman)
30 : {
31 5 : SetupHelpOptions(argsman);
32 :
33 5 : argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
34 :
35 5 : argsman.AddCommand("grind", "Perform proof of work on hex header string");
36 :
37 5 : SetupChainParamsBaseOptions(argsman);
38 5 : }
39 :
40 : // This function returns either one of EXIT_ codes when it's expected to stop the process or
41 : // CONTINUE_EXECUTION when it's expected to continue further.
42 5 : static int AppInitUtil(ArgsManager& args, int argc, char* argv[])
43 : {
44 5 : SetupBitcoinUtilArgs(args);
45 5 : std::string error;
46 5 : if (!args.ParseParameters(argc, argv, error)) {
47 2 : tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
48 2 : return EXIT_FAILURE;
49 : }
50 :
51 3 : if (HelpRequested(args) || args.IsArgSet("-version")) {
52 : // First part of help message is specific to this utility
53 0 : std::string strUsage = PACKAGE_NAME " dash-util utility version " + FormatFullVersion() + "\n";
54 0 : if (args.IsArgSet("-version")) {
55 0 : strUsage += FormatParagraph(LicenseInfo());
56 0 : } else {
57 0 : strUsage += "\n"
58 : "Usage: dash-util [options] [commands] Do stuff\n";
59 0 : strUsage += "\n" + args.GetHelpMessage();
60 : }
61 :
62 0 : tfm::format(std::cout, "%s", strUsage);
63 :
64 0 : if (argc < 2) {
65 0 : tfm::format(std::cerr, "Error: too few parameters\n");
66 0 : return EXIT_FAILURE;
67 : }
68 0 : return EXIT_SUCCESS;
69 0 : }
70 :
71 : // Check for chain settings (Params() calls are only valid after this clause)
72 : try {
73 3 : SelectParams(args.GetChainName());
74 3 : } catch (const std::exception& e) {
75 0 : tfm::format(std::cerr, "Error: %s\n", e.what());
76 0 : return EXIT_FAILURE;
77 0 : }
78 :
79 3 : return CONTINUE_EXECUTION;
80 5 : }
81 :
82 0 : static void grind_task(uint32_t nBits, CBlockHeader header, uint32_t offset, uint32_t step, std::atomic<bool>& found, uint32_t& proposed_nonce)
83 : {
84 0 : arith_uint256 target;
85 : bool neg, over;
86 0 : target.SetCompact(nBits, &neg, &over);
87 0 : if (target == 0 || neg || over) return;
88 0 : header.nNonce = offset;
89 :
90 0 : uint32_t finish = std::numeric_limits<uint32_t>::max() - step;
91 0 : finish = finish - (finish % step) + offset;
92 :
93 0 : while (!found && header.nNonce < finish) {
94 0 : const uint32_t next = (finish - header.nNonce < 5000*step) ? finish : header.nNonce + 5000*step;
95 0 : do {
96 0 : if (UintToArith256(header.GetHash()) <= target) {
97 0 : if (!found.exchange(true)) {
98 0 : proposed_nonce = header.nNonce;
99 0 : }
100 0 : return;
101 : }
102 0 : header.nNonce += step;
103 0 : } while(header.nNonce != next);
104 : }
105 0 : }
106 :
107 3 : static int Grind(const std::vector<std::string>& args, std::string& strPrint)
108 : {
109 3 : if (args.size() != 1) {
110 2 : strPrint = "Must specify block header to grind";
111 2 : return EXIT_FAILURE;
112 : }
113 :
114 1 : CBlockHeader header;
115 1 : if (!DecodeHexBlockHeader(header, args[0])) {
116 1 : strPrint = "Could not decode block header";
117 1 : return EXIT_FAILURE;
118 : }
119 :
120 0 : uint32_t nBits = header.nBits;
121 0 : std::atomic<bool> found{false};
122 0 : uint32_t proposed_nonce{};
123 :
124 0 : std::vector<std::thread> threads;
125 0 : int n_tasks = std::max(1u, std::thread::hardware_concurrency());
126 0 : for (int i = 0; i < n_tasks; ++i) {
127 0 : threads.emplace_back(grind_task, nBits, header, i, n_tasks, std::ref(found), std::ref(proposed_nonce));
128 0 : }
129 0 : for (auto& t : threads) {
130 0 : t.join();
131 : }
132 0 : if (found) {
133 0 : header.nNonce = proposed_nonce;
134 0 : } else {
135 0 : strPrint = "Could not satisfy difficulty target";
136 0 : return EXIT_FAILURE;
137 : }
138 :
139 0 : DataStream ss{};
140 0 : ss << header;
141 0 : strPrint = HexStr(ss);
142 0 : return EXIT_SUCCESS;
143 3 : }
144 :
145 : #ifdef WIN32
146 : // Export main() and ensure working ASLR on Windows.
147 : // Exporting a symbol will prevent the linker from stripping
148 : // the .reloc section from the binary, which is a requirement
149 : // for ASLR. This is a temporary workaround until a fixed
150 : // version of binutils is used for releases.
151 : __declspec(dllexport) int main(int argc, char* argv[])
152 : #else
153 5 : int main(int argc, char* argv[])
154 : #endif
155 : {
156 5 : ArgsManager& args = gArgs;
157 5 : SetupEnvironment();
158 :
159 : try {
160 5 : int ret = AppInitUtil(args, argc, argv);
161 5 : if (ret != CONTINUE_EXECUTION) {
162 2 : return ret;
163 : }
164 3 : } catch (...) {
165 0 : PrintExceptionContinue(std::current_exception(), "AppInitUtil()");
166 0 : return EXIT_FAILURE;
167 0 : }
168 :
169 3 : const auto cmd = args.GetCommand();
170 3 : if (!cmd) {
171 0 : tfm::format(std::cerr, "Error: must specify a command\n");
172 0 : return EXIT_FAILURE;
173 : }
174 :
175 3 : int ret = EXIT_FAILURE;
176 3 : std::string strPrint;
177 : try {
178 3 : if (cmd->command == "grind") {
179 3 : ret = Grind(cmd->args, strPrint);
180 3 : } else {
181 0 : assert(false); // unknown command should be caught earlier
182 : }
183 3 : } catch (const std::exception& e) {
184 0 : strPrint = std::string("error: ") + e.what();
185 0 : } catch (...) {
186 0 : strPrint = "unknown error";
187 0 : }
188 :
189 3 : if (strPrint != "") {
190 3 : tfm::format(ret == 0 ? std::cout : std::cerr, "%s\n", strPrint);
191 3 : }
192 :
193 3 : return ret;
194 5 : }
|