Coverage Report

Created: 2025-06-10 13:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/bitcoin/src/rpc/mining.cpp
Line
Count
Source
1
// Copyright (c) 2010 Satoshi Nakamoto
2
// Copyright (c) 2009-present The Bitcoin Core developers
3
// Distributed under the MIT software license, see the accompanying
4
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6
#include <bitcoin-build-config.h> // IWYU pragma: keep
7
8
#include <chain.h>
9
#include <chainparams.h>
10
#include <chainparamsbase.h>
11
#include <common/system.h>
12
#include <consensus/amount.h>
13
#include <consensus/consensus.h>
14
#include <consensus/merkle.h>
15
#include <consensus/params.h>
16
#include <consensus/validation.h>
17
#include <core_io.h>
18
#include <deploymentinfo.h>
19
#include <deploymentstatus.h>
20
#include <interfaces/mining.h>
21
#include <key_io.h>
22
#include <net.h>
23
#include <node/context.h>
24
#include <node/miner.h>
25
#include <node/warnings.h>
26
#include <policy/ephemeral_policy.h>
27
#include <pow.h>
28
#include <rpc/blockchain.h>
29
#include <rpc/mining.h>
30
#include <rpc/server.h>
31
#include <rpc/server_util.h>
32
#include <rpc/util.h>
33
#include <script/descriptor.h>
34
#include <script/script.h>
35
#include <script/signingprovider.h>
36
#include <txmempool.h>
37
#include <univalue.h>
38
#include <util/signalinterrupt.h>
39
#include <util/strencodings.h>
40
#include <util/string.h>
41
#include <util/time.h>
42
#include <util/translation.h>
43
#include <validation.h>
44
#include <validationinterface.h>
45
46
#include <memory>
47
#include <stdint.h>
48
49
using interfaces::BlockRef;
50
using interfaces::BlockTemplate;
51
using interfaces::Mining;
52
using node::BlockAssembler;
53
using node::GetMinimumTime;
54
using node::NodeContext;
55
using node::RegenerateCommitments;
56
using node::UpdateTime;
57
using util::ToString;
58
59
/**
60
 * Return average network hashes per second based on the last 'lookup' blocks,
61
 * or from the last difficulty change if 'lookup' is -1.
62
 * If 'height' is -1, compute the estimate from current chain tip.
63
 * If 'height' is a valid block height, compute the estimate at the time when a given block was found.
64
 */
65
0
static UniValue GetNetworkHashPS(int lookup, int height, const CChain& active_chain) {
66
0
    if (lookup < -1 || lookup == 0) {
  Branch (66:9): [True: 0, False: 0]
  Branch (66:24): [True: 0, False: 0]
67
0
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid nblocks. Must be a positive number or -1.");
68
0
    }
69
70
0
    if (height < -1 || height > active_chain.Height()) {
  Branch (70:9): [True: 0, False: 0]
  Branch (70:24): [True: 0, False: 0]
71
0
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Block does not exist at specified height");
72
0
    }
73
74
0
    const CBlockIndex* pb = active_chain.Tip();
75
76
0
    if (height >= 0) {
  Branch (76:9): [True: 0, False: 0]
77
0
        pb = active_chain[height];
78
0
    }
79
80
0
    if (pb == nullptr || !pb->nHeight)
  Branch (80:9): [True: 0, False: 0]
  Branch (80:26): [True: 0, False: 0]
81
0
        return 0;
82
83
    // If lookup is -1, then use blocks since last difficulty change.
84
0
    if (lookup == -1)
  Branch (84:9): [True: 0, False: 0]
85
0
        lookup = pb->nHeight % Params().GetConsensus().DifficultyAdjustmentInterval() + 1;
86
87
    // If lookup is larger than chain, then set it to chain length.
88
0
    if (lookup > pb->nHeight)
  Branch (88:9): [True: 0, False: 0]
89
0
        lookup = pb->nHeight;
90
91
0
    const CBlockIndex* pb0 = pb;
92
0
    int64_t minTime = pb0->GetBlockTime();
93
0
    int64_t maxTime = minTime;
94
0
    for (int i = 0; i < lookup; i++) {
  Branch (94:21): [True: 0, False: 0]
95
0
        pb0 = pb0->pprev;
96
0
        int64_t time = pb0->GetBlockTime();
97
0
        minTime = std::min(time, minTime);
98
0
        maxTime = std::max(time, maxTime);
99
0
    }
100
101
    // In case there's a situation where minTime == maxTime, we don't want a divide by zero exception.
102
0
    if (minTime == maxTime)
  Branch (102:9): [True: 0, False: 0]
103
0
        return 0;
104
105
0
    arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork;
106
0
    int64_t timeDiff = maxTime - minTime;
107
108
0
    return workDiff.getdouble() / timeDiff;
109
0
}
110
111
static RPCHelpMan getnetworkhashps()
112
22.1k
{
113
22.1k
    return RPCHelpMan{
114
22.1k
        "getnetworkhashps",
115
22.1k
        "Returns the estimated network hashes per second based on the last n blocks.\n"
116
22.1k
                "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"
117
22.1k
                "Pass in [height] to estimate the network speed at the time when a certain block was found.\n",
118
22.1k
                {
119
22.1k
                    {"nblocks", RPCArg::Type::NUM, RPCArg::Default{120}, "The number of previous blocks to calculate estimate from, or -1 for blocks since last difficulty change."},
120
22.1k
                    {"height", RPCArg::Type::NUM, RPCArg::Default{-1}, "To estimate at the time of the given height."},
121
22.1k
                },
122
22.1k
                RPCResult{
123
22.1k
                    RPCResult::Type::NUM, "", "Hashes per second estimated"},
124
22.1k
                RPCExamples{
125
22.1k
                    HelpExampleCli("getnetworkhashps", "")
126
22.1k
            + HelpExampleRpc("getnetworkhashps", "")
127
22.1k
                },
128
22.1k
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
129
22.1k
{
130
0
    ChainstateManager& chainman = EnsureAnyChainman(request.context);
131
0
    LOCK(cs_main);
132
0
    return GetNetworkHashPS(self.Arg<int>("nblocks"), self.Arg<int>("height"), chainman.ActiveChain());
133
0
},
134
22.1k
    };
135
22.1k
}
136
137
static bool GenerateBlock(ChainstateManager& chainman, CBlock&& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
138
0
{
139
0
    block_out.reset();
140
0
    block.hashMerkleRoot = BlockMerkleRoot(block);
141
142
0
    while (max_tries > 0 && block.nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(block.GetHash(), block.nBits, chainman.GetConsensus()) && !chainman.m_interrupt) {
  Branch (142:12): [True: 0, False: 0]
  Branch (142:29): [True: 0, False: 0]
  Branch (142:84): [True: 0, False: 0]
  Branch (142:160): [True: 0, False: 0]
143
0
        ++block.nNonce;
144
0
        --max_tries;
145
0
    }
146
0
    if (max_tries == 0 || chainman.m_interrupt) {
  Branch (146:9): [True: 0, False: 0]
  Branch (146:27): [True: 0, False: 0]
147
0
        return false;
148
0
    }
149
0
    if (block.nNonce == std::numeric_limits<uint32_t>::max()) {
  Branch (149:9): [True: 0, False: 0]
150
0
        return true;
151
0
    }
152
153
0
    block_out = std::make_shared<const CBlock>(std::move(block));
154
155
0
    if (!process_new_block) return true;
  Branch (155:9): [True: 0, False: 0]
156
157
0
    if (!chainman.ProcessNewBlock(block_out, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) {
  Branch (157:9): [True: 0, False: 0]
158
0
        throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
159
0
    }
160
161
0
    return true;
162
0
}
163
164
static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const CScript& coinbase_output_script, int nGenerate, uint64_t nMaxTries)
165
0
{
166
0
    UniValue blockHashes(UniValue::VARR);
167
0
    while (nGenerate > 0 && !chainman.m_interrupt) {
  Branch (167:12): [True: 0, False: 0]
  Branch (167:29): [True: 0, False: 0]
168
0
        std::unique_ptr<BlockTemplate> block_template(miner.createNewBlock({ .coinbase_output_script = coinbase_output_script }));
169
0
        CHECK_NONFATAL(block_template);
170
171
0
        std::shared_ptr<const CBlock> block_out;
172
0
        if (!GenerateBlock(chainman, block_template->getBlock(), nMaxTries, block_out, /*process_new_block=*/true)) {
  Branch (172:13): [True: 0, False: 0]
173
0
            break;
174
0
        }
175
176
0
        if (block_out) {
  Branch (176:13): [True: 0, False: 0]
177
0
            --nGenerate;
178
0
            blockHashes.push_back(block_out->GetHash().GetHex());
179
0
        }
180
0
    }
181
0
    return blockHashes;
182
0
}
183
184
static bool getScriptFromDescriptor(const std::string& descriptor, CScript& script, std::string& error)
185
0
{
186
0
    FlatSigningProvider key_provider;
187
0
    const auto descs = Parse(descriptor, key_provider, error, /* require_checksum = */ false);
188
0
    if (descs.empty()) return false;
  Branch (188:9): [True: 0, False: 0]
189
0
    if (descs.size() > 1) {
  Branch (189:9): [True: 0, False: 0]
190
0
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Multipath descriptor not accepted");
191
0
    }
192
0
    const auto& desc = descs.at(0);
193
0
    if (desc->IsRange()) {
  Branch (193:9): [True: 0, False: 0]
194
0
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptor not accepted. Maybe pass through deriveaddresses first?");
195
0
    }
196
197
0
    FlatSigningProvider provider;
198
0
    std::vector<CScript> scripts;
199
0
    if (!desc->Expand(0, key_provider, scripts, provider)) {
  Branch (199:9): [True: 0, False: 0]
200
0
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot derive script without private keys");
201
0
    }
202
203
    // Combo descriptors can have 2 or 4 scripts, so we can't just check scripts.size() == 1
204
0
    CHECK_NONFATAL(scripts.size() > 0 && scripts.size() <= 4);
205
206
0
    if (scripts.size() == 1) {
  Branch (206:9): [True: 0, False: 0]
207
0
        script = scripts.at(0);
208
0
    } else if (scripts.size() == 4) {
  Branch (208:16): [True: 0, False: 0]
209
        // For uncompressed keys, take the 3rd script, since it is p2wpkh
210
0
        script = scripts.at(2);
211
0
    } else {
212
        // Else take the 2nd script, since it is p2pkh
213
0
        script = scripts.at(1);
214
0
    }
215
216
0
    return true;
217
0
}
218
219
static RPCHelpMan generatetodescriptor()
220
22.1k
{
221
22.1k
    return RPCHelpMan{
222
22.1k
        "generatetodescriptor",
223
22.1k
        "Mine to a specified descriptor and return the block hashes.",
224
22.1k
        {
225
22.1k
            {"num_blocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated."},
226
22.1k
            {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor to send the newly generated bitcoin to."},
227
22.1k
            {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."},
228
22.1k
        },
229
22.1k
        RPCResult{
230
22.1k
            RPCResult::Type::ARR, "", "hashes of blocks generated",
231
22.1k
            {
232
22.1k
                {RPCResult::Type::STR_HEX, "", "blockhash"},
233
22.1k
            }
234
22.1k
        },
235
22.1k
        RPCExamples{
236
22.1k
            "\nGenerate 11 blocks to mydesc\n" + HelpExampleCli("generatetodescriptor", "11 \"mydesc\"")},
237
22.1k
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
238
22.1k
{
239
0
    const auto num_blocks{self.Arg<int>("num_blocks")};
240
0
    const auto max_tries{self.Arg<uint64_t>("maxtries")};
241
242
0
    CScript coinbase_output_script;
243
0
    std::string error;
244
0
    if (!getScriptFromDescriptor(self.Arg<std::string>("descriptor"), coinbase_output_script, error)) {
  Branch (244:9): [True: 0, False: 0]
245
0
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
246
0
    }
247
248
0
    NodeContext& node = EnsureAnyNodeContext(request.context);
249
0
    Mining& miner = EnsureMining(node);
250
0
    ChainstateManager& chainman = EnsureChainman(node);
251
252
0
    return generateBlocks(chainman, miner, coinbase_output_script, num_blocks, max_tries);
253
0
},
254
22.1k
    };
255
22.1k
}
256
257
static RPCHelpMan generate()
258
22.1k
{
259
22.1k
    return RPCHelpMan{"generate", "has been replaced by the -generate cli option. Refer to -help for more information.", {}, {}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
260
0
        throw JSONRPCError(RPC_METHOD_NOT_FOUND, self.ToString());
261
0
    }};
262
22.1k
}
263
264
static RPCHelpMan generatetoaddress()
265
22.1k
{
266
22.1k
    return RPCHelpMan{"generatetoaddress",
267
22.1k
        "Mine to a specified address and return the block hashes.",
268
22.1k
         {
269
22.1k
             {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated."},
270
22.1k
             {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address to send the newly generated bitcoin to."},
271
22.1k
             {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."},
272
22.1k
         },
273
22.1k
         RPCResult{
274
22.1k
             RPCResult::Type::ARR, "", "hashes of blocks generated",
275
22.1k
             {
276
22.1k
                 {RPCResult::Type::STR_HEX, "", "blockhash"},
277
22.1k
             }},
278
22.1k
         RPCExamples{
279
22.1k
            "\nGenerate 11 blocks to myaddress\n"
280
22.1k
            + HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
281
22.1k
            + "If you are using the " CLIENT_NAME " wallet, you can get a new address to send the newly generated bitcoin to with:\n"
282
22.1k
            + HelpExampleCli("getnewaddress", "")
283
22.1k
                },
284
22.1k
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
285
22.1k
{
286
0
    const int num_blocks{request.params[0].getInt<int>()};
287
0
    const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].getInt<int>()};
  Branch (287:30): [True: 0, False: 0]
288
289
0
    CTxDestination destination = DecodeDestination(request.params[1].get_str());
290
0
    if (!IsValidDestination(destination)) {
  Branch (290:9): [True: 0, False: 0]
291
0
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
292
0
    }
293
294
0
    NodeContext& node = EnsureAnyNodeContext(request.context);
295
0
    Mining& miner = EnsureMining(node);
296
0
    ChainstateManager& chainman = EnsureChainman(node);
297
298
0
    CScript coinbase_output_script = GetScriptForDestination(destination);
299
300
0
    return generateBlocks(chainman, miner, coinbase_output_script, num_blocks, max_tries);
301
0
},
302
22.1k
    };
303
22.1k
}
304
305
static RPCHelpMan generateblock()
306
22.1k
{
307
22.1k
    return RPCHelpMan{"generateblock",
308
22.1k
        "Mine a set of ordered transactions to a specified address or descriptor and return the block hash.",
309
22.1k
        {
310
22.1k
            {"output", RPCArg::Type::STR, RPCArg::Optional::NO, "The address or descriptor to send the newly generated bitcoin to."},
311
22.1k
            {"transactions", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings which are either txids or raw transactions.\n"
312
22.1k
                "Txids must reference transactions currently in the mempool.\n"
313
22.1k
                "All transactions must be valid and in valid order, otherwise the block will be rejected.",
314
22.1k
                {
315
22.1k
                    {"rawtx/txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
316
22.1k
                },
317
22.1k
            },
318
22.1k
            {"submit", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to submit the block before the RPC call returns or to return it as hex."},
319
22.1k
        },
320
22.1k
        RPCResult{
321
22.1k
            RPCResult::Type::OBJ, "", "",
322
22.1k
            {
323
22.1k
                {RPCResult::Type::STR_HEX, "hash", "hash of generated block"},
324
22.1k
                {RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "hex of generated block, only present when submit=false"},
325
22.1k
            }
326
22.1k
        },
327
22.1k
        RPCExamples{
328
22.1k
            "\nGenerate a block to myaddress, with txs rawtx and mempool_txid\n"
329
22.1k
            + HelpExampleCli("generateblock", R"("myaddress" '["rawtx", "mempool_txid"]')")
330
22.1k
        },
331
22.1k
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
332
22.1k
{
333
0
    const auto address_or_descriptor = request.params[0].get_str();
334
0
    CScript coinbase_output_script;
335
0
    std::string error;
336
337
0
    if (!getScriptFromDescriptor(address_or_descriptor, coinbase_output_script, error)) {
  Branch (337:9): [True: 0, False: 0]
338
0
        const auto destination = DecodeDestination(address_or_descriptor);
339
0
        if (!IsValidDestination(destination)) {
  Branch (339:13): [True: 0, False: 0]
340
0
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address or descriptor");
341
0
        }
342
343
0
        coinbase_output_script = GetScriptForDestination(destination);
344
0
    }
345
346
0
    NodeContext& node = EnsureAnyNodeContext(request.context);
347
0
    Mining& miner = EnsureMining(node);
348
0
    const CTxMemPool& mempool = EnsureMemPool(node);
349
350
0
    std::vector<CTransactionRef> txs;
351
0
    const auto raw_txs_or_txids = request.params[1].get_array();
352
0
    for (size_t i = 0; i < raw_txs_or_txids.size(); i++) {
  Branch (352:24): [True: 0, False: 0]
353
0
        const auto& str{raw_txs_or_txids[i].get_str()};
354
355
0
        CMutableTransaction mtx;
356
0
        if (auto hash{uint256::FromHex(str)}) {
  Branch (356:18): [True: 0, False: 0]
357
0
            const auto tx{mempool.get(*hash)};
358
0
            if (!tx) {
  Branch (358:17): [True: 0, False: 0]
359
0
                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Transaction %s not in mempool.", str));
360
0
            }
361
362
0
            txs.emplace_back(tx);
363
364
0
        } else if (DecodeHexTx(mtx, str)) {
  Branch (364:20): [True: 0, False: 0]
365
0
            txs.push_back(MakeTransactionRef(std::move(mtx)));
366
367
0
        } else {
368
0
            throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Transaction decode failed for %s. Make sure the tx has at least one input.", str));
369
0
        }
370
0
    }
371
372
0
    const bool process_new_block{request.params[2].isNull() ? true : request.params[2].get_bool()};
  Branch (372:34): [True: 0, False: 0]
373
0
    CBlock block;
374
375
0
    ChainstateManager& chainman = EnsureChainman(node);
376
0
    {
377
0
        LOCK(chainman.GetMutex());
378
0
        {
379
0
            std::unique_ptr<BlockTemplate> block_template{miner.createNewBlock({.use_mempool = false, .coinbase_output_script = coinbase_output_script})};
380
0
            CHECK_NONFATAL(block_template);
381
382
0
            block = block_template->getBlock();
383
0
        }
384
385
0
        CHECK_NONFATAL(block.vtx.size() == 1);
386
387
        // Add transactions
388
0
        block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
389
0
        RegenerateCommitments(block, chainman);
390
391
0
        BlockValidationState state;
392
0
        if (!TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/false)) {
  Branch (392:13): [True: 0, False: 0]
393
0
            throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString()));
394
0
        }
395
0
    }
396
397
0
    std::shared_ptr<const CBlock> block_out;
398
0
    uint64_t max_tries{DEFAULT_MAX_TRIES};
399
400
0
    if (!GenerateBlock(chainman, std::move(block), max_tries, block_out, process_new_block) || !block_out) {
  Branch (400:9): [True: 0, False: 0]
  Branch (400:96): [True: 0, False: 0]
401
0
        throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
402
0
    }
403
404
0
    UniValue obj(UniValue::VOBJ);
405
0
    obj.pushKV("hash", block_out->GetHash().GetHex());
406
0
    if (!process_new_block) {
  Branch (406:9): [True: 0, False: 0]
407
0
        DataStream block_ser;
408
0
        block_ser << TX_WITH_WITNESS(*block_out);
409
0
        obj.pushKV("hex", HexStr(block_ser));
410
0
    }
411
0
    return obj;
412
0
},
413
22.1k
    };
414
22.1k
}
415
416
static RPCHelpMan getmininginfo()
417
22.1k
{
418
22.1k
    return RPCHelpMan{
419
22.1k
        "getmininginfo",
420
22.1k
        "Returns a json object containing mining-related information.",
421
22.1k
                {},
422
22.1k
                RPCResult{
423
22.1k
                    RPCResult::Type::OBJ, "", "",
424
22.1k
                    {
425
22.1k
                        {RPCResult::Type::NUM, "blocks", "The current block"},
426
22.1k
                        {RPCResult::Type::NUM, "currentblockweight", /*optional=*/true, "The block weight (including reserved weight for block header, txs count and coinbase tx) of the last assembled block (only present if a block was ever assembled)"},
427
22.1k
                        {RPCResult::Type::NUM, "currentblocktx", /*optional=*/true, "The number of block transactions (excluding coinbase) of the last assembled block (only present if a block was ever assembled)"},
428
22.1k
                        {RPCResult::Type::STR_HEX, "bits", "The current nBits, compact representation of the block difficulty target"},
429
22.1k
                        {RPCResult::Type::NUM, "difficulty", "The current difficulty"},
430
22.1k
                        {RPCResult::Type::STR_HEX, "target", "The current target"},
431
22.1k
                        {RPCResult::Type::NUM, "networkhashps", "The network hashes per second"},
432
22.1k
                        {RPCResult::Type::NUM, "pooledtx", "The size of the mempool"},
433
22.1k
                        {RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"},
434
22.1k
                        {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "The block challenge (aka. block script), in hexadecimal (only present if the current network is a signet)"},
435
22.1k
                        {RPCResult::Type::OBJ, "next", "The next block",
436
22.1k
                        {
437
22.1k
                            {RPCResult::Type::NUM, "height", "The next height"},
438
22.1k
                            {RPCResult::Type::STR_HEX, "bits", "The next target nBits"},
439
22.1k
                            {RPCResult::Type::NUM, "difficulty", "The next difficulty"},
440
22.1k
                            {RPCResult::Type::STR_HEX, "target", "The next target"}
441
22.1k
                        }},
442
22.1k
                        (IsDeprecatedRPCEnabled("warnings") ?
  Branch (442:26): [True: 0, False: 22.1k]
443
0
                            RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} :
444
22.1k
                            RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)",
445
22.1k
                            {
446
22.1k
                                {RPCResult::Type::STR, "", "warning"},
447
22.1k
                            }
448
22.1k
                            }
449
22.1k
                        ),
450
22.1k
                    }},
451
22.1k
                RPCExamples{
452
22.1k
                    HelpExampleCli("getmininginfo", "")
453
22.1k
            + HelpExampleRpc("getmininginfo", "")
454
22.1k
                },
455
22.1k
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
456
22.1k
{
457
0
    NodeContext& node = EnsureAnyNodeContext(request.context);
458
0
    const CTxMemPool& mempool = EnsureMemPool(node);
459
0
    ChainstateManager& chainman = EnsureChainman(node);
460
0
    LOCK(cs_main);
461
0
    const CChain& active_chain = chainman.ActiveChain();
462
0
    CBlockIndex& tip{*CHECK_NONFATAL(active_chain.Tip())};
463
464
0
    UniValue obj(UniValue::VOBJ);
465
0
    obj.pushKV("blocks",           active_chain.Height());
466
0
    if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
  Branch (466:9): [True: 0, False: 0]
467
0
    if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
  Branch (467:9): [True: 0, False: 0]
468
0
    obj.pushKV("bits", strprintf("%08x", tip.nBits));
469
0
    obj.pushKV("difficulty", GetDifficulty(tip));
470
0
    obj.pushKV("target", GetTarget(tip, chainman.GetConsensus().powLimit).GetHex());
471
0
    obj.pushKV("networkhashps",    getnetworkhashps().HandleRequest(request));
472
0
    obj.pushKV("pooledtx",         (uint64_t)mempool.size());
473
0
    obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
474
475
0
    UniValue next(UniValue::VOBJ);
476
0
    CBlockIndex next_index;
477
0
    NextEmptyBlockIndex(tip, chainman.GetConsensus(), next_index);
478
479
0
    next.pushKV("height", next_index.nHeight);
480
0
    next.pushKV("bits", strprintf("%08x", next_index.nBits));
481
0
    next.pushKV("difficulty", GetDifficulty(next_index));
482
0
    next.pushKV("target", GetTarget(next_index, chainman.GetConsensus().powLimit).GetHex());
483
0
    obj.pushKV("next", next);
484
485
0
    if (chainman.GetParams().GetChainType() == ChainType::SIGNET) {
  Branch (485:9): [True: 0, False: 0]
486
0
        const std::vector<uint8_t>& signet_challenge =
487
0
            chainman.GetConsensus().signet_challenge;
488
0
        obj.pushKV("signet_challenge", HexStr(signet_challenge));
489
0
    }
490
0
    obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings")));
491
0
    return obj;
492
0
},
493
22.1k
    };
494
22.1k
}
495
496
497
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
498
static RPCHelpMan prioritisetransaction()
499
22.1k
{
500
22.1k
    return RPCHelpMan{"prioritisetransaction",
501
22.1k
                "Accepts the transaction into mined blocks at a higher (or lower) priority\n",
502
22.1k
                {
503
22.1k
                    {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id."},
504
22.1k
                    {"dummy", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "API-Compatibility for previous API. Must be zero or null.\n"
505
22.1k
            "                  DEPRECATED. For forward compatibility use named arguments and omit this parameter."},
506
22.1k
                    {"fee_delta", RPCArg::Type::NUM, RPCArg::Optional::NO, "The fee value (in satoshis) to add (or subtract, if negative).\n"
507
22.1k
            "                  Note, that this value is not a fee rate. It is a value to modify absolute fee of the TX.\n"
508
22.1k
            "                  The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
509
22.1k
            "                  considers the transaction as it would have paid a higher (or lower) fee."},
510
22.1k
                },
511
22.1k
                RPCResult{
512
22.1k
                    RPCResult::Type::BOOL, "", "Returns true"},
513
22.1k
                RPCExamples{
514
22.1k
                    HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
515
22.1k
            + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
516
22.1k
                },
517
22.1k
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
518
22.1k
{
519
0
    LOCK(cs_main);
520
521
0
    uint256 hash(ParseHashV(request.params[0], "txid"));
522
0
    const auto dummy{self.MaybeArg<double>("dummy")};
523
0
    CAmount nAmount = request.params[2].getInt<int64_t>();
524
525
0
    if (dummy && *dummy != 0) {
  Branch (525:9): [True: 0, False: 0]
  Branch (525:18): [True: 0, False: 0]
526
0
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is no longer supported, dummy argument to prioritisetransaction must be 0.");
527
0
    }
528
529
0
    CTxMemPool& mempool = EnsureAnyMemPool(request.context);
530
531
    // Non-0 fee dust transactions are not allowed for entry, and modification not allowed afterwards
532
0
    const auto& tx = mempool.get(hash);
533
0
    if (mempool.m_opts.require_standard && tx && !GetDust(*tx, mempool.m_opts.dust_relay_feerate).empty()) {
  Branch (533:9): [True: 0, False: 0]
  Branch (533:9): [True: 0, False: 0]
  Branch (533:44): [True: 0, False: 0]
  Branch (533:50): [True: 0, False: 0]
534
0
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is not supported for transactions with dust outputs.");
535
0
    }
536
537
0
    mempool.PrioritiseTransaction(hash, nAmount);
538
0
    return true;
539
0
},
540
22.1k
    };
541
22.1k
}
542
543
static RPCHelpMan getprioritisedtransactions()
544
22.1k
{
545
22.1k
    return RPCHelpMan{"getprioritisedtransactions",
546
22.1k
        "Returns a map of all user-created (see prioritisetransaction) fee deltas by txid, and whether the tx is present in mempool.",
547
22.1k
        {},
548
22.1k
        RPCResult{
549
22.1k
            RPCResult::Type::OBJ_DYN, "", "prioritisation keyed by txid",
550
22.1k
            {
551
22.1k
                {RPCResult::Type::OBJ, "<transactionid>", "", {
552
22.1k
                    {RPCResult::Type::NUM, "fee_delta", "transaction fee delta in satoshis"},
553
22.1k
                    {RPCResult::Type::BOOL, "in_mempool", "whether this transaction is currently in mempool"},
554
22.1k
                    {RPCResult::Type::NUM, "modified_fee", /*optional=*/true, "modified fee in satoshis. Only returned if in_mempool=true"},
555
22.1k
                }}
556
22.1k
            },
557
22.1k
        },
558
22.1k
        RPCExamples{
559
22.1k
            HelpExampleCli("getprioritisedtransactions", "")
560
22.1k
            + HelpExampleRpc("getprioritisedtransactions", "")
561
22.1k
        },
562
22.1k
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
563
22.1k
        {
564
0
            NodeContext& node = EnsureAnyNodeContext(request.context);
565
0
            CTxMemPool& mempool = EnsureMemPool(node);
566
0
            UniValue rpc_result{UniValue::VOBJ};
567
0
            for (const auto& delta_info : mempool.GetPrioritisedTransactions()) {
  Branch (567:41): [True: 0, False: 0]
568
0
                UniValue result_inner{UniValue::VOBJ};
569
0
                result_inner.pushKV("fee_delta", delta_info.delta);
570
0
                result_inner.pushKV("in_mempool", delta_info.in_mempool);
571
0
                if (delta_info.in_mempool) {
  Branch (571:21): [True: 0, False: 0]
572
0
                    result_inner.pushKV("modified_fee", *delta_info.modified_fee);
573
0
                }
574
0
                rpc_result.pushKV(delta_info.txid.GetHex(), std::move(result_inner));
575
0
            }
576
0
            return rpc_result;
577
0
        },
578
22.1k
    };
579
22.1k
}
580
581
582
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
583
static UniValue BIP22ValidationResult(const BlockValidationState& state)
584
0
{
585
0
    if (state.IsValid())
  Branch (585:9): [True: 0, False: 0]
586
0
        return UniValue::VNULL;
587
588
0
    if (state.IsError())
  Branch (588:9): [True: 0, False: 0]
589
0
        throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
590
0
    if (state.IsInvalid())
  Branch (590:9): [True: 0, False: 0]
591
0
    {
592
0
        std::string strRejectReason = state.GetRejectReason();
593
0
        if (strRejectReason.empty())
  Branch (593:13): [True: 0, False: 0]
594
0
            return "rejected";
595
0
        return strRejectReason;
596
0
    }
597
    // Should be impossible
598
0
    return "valid?";
599
0
}
600
601
// Prefix rule name with ! if not optional, see BIP9
602
static std::string gbt_rule_value(const std::string& name, bool gbt_optional_rule)
603
0
{
604
0
    std::string s{name};
605
0
    if (!gbt_optional_rule) {
  Branch (605:9): [True: 0, False: 0]
606
0
        s.insert(s.begin(), '!');
607
0
    }
608
0
    return s;
609
0
}
610
611
static RPCHelpMan getblocktemplate()
612
22.1k
{
613
22.1k
    return RPCHelpMan{
614
22.1k
        "getblocktemplate",
615
22.1k
        "If the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
616
22.1k
        "It returns data needed to construct a block to work on.\n"
617
22.1k
        "For full specification, see BIPs 22, 23, 9, and 145:\n"
618
22.1k
        "    https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n"
619
22.1k
        "    https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n"
620
22.1k
        "    https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
621
22.1k
        "    https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n",
622
22.1k
        {
623
22.1k
            {"template_request", RPCArg::Type::OBJ, RPCArg::Optional::NO, "Format of the template",
624
22.1k
            {
625
22.1k
                {"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
626
22.1k
                {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED, "A list of strings",
627
22.1k
                {
628
22.1k
                    {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"},
629
22.1k
                }},
630
22.1k
                {"rules", RPCArg::Type::ARR, RPCArg::Optional::NO, "A list of strings",
631
22.1k
                {
632
22.1k
                    {"segwit", RPCArg::Type::STR, RPCArg::Optional::NO, "(literal) indicates client side segwit support"},
633
22.1k
                    {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "other client side supported softfork deployment"},
634
22.1k
                }},
635
22.1k
                {"longpollid", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "delay processing request until the result would vary significantly from the \"longpollid\" of a prior template"},
636
22.1k
                {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "proposed block data to check, encoded in hexadecimal; valid only for mode=\"proposal\""},
637
22.1k
            },
638
22.1k
            },
639
22.1k
        },
640
22.1k
        {
641
22.1k
            RPCResult{"If the proposal was accepted with mode=='proposal'", RPCResult::Type::NONE, "", ""},
642
22.1k
            RPCResult{"If the proposal was not accepted with mode=='proposal'", RPCResult::Type::STR, "", "According to BIP22"},
643
22.1k
            RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "",
644
22.1k
            {
645
22.1k
                {RPCResult::Type::NUM, "version", "The preferred block version"},
646
22.1k
                {RPCResult::Type::ARR, "rules", "specific block rules that are to be enforced",
647
22.1k
                {
648
22.1k
                    {RPCResult::Type::STR, "", "name of a rule the client must understand to some extent; see BIP 9 for format"},
649
22.1k
                }},
650
22.1k
                {RPCResult::Type::OBJ_DYN, "vbavailable", "set of pending, supported versionbit (BIP 9) softfork deployments",
651
22.1k
                {
652
22.1k
                    {RPCResult::Type::NUM, "rulename", "identifies the bit number as indicating acceptance and readiness for the named softfork rule"},
653
22.1k
                }},
654
22.1k
                {RPCResult::Type::ARR, "capabilities", "",
655
22.1k
                {
656
22.1k
                    {RPCResult::Type::STR, "value", "A supported feature, for example 'proposal'"},
657
22.1k
                }},
658
22.1k
                {RPCResult::Type::NUM, "vbrequired", "bit mask of versionbits the server requires set in submissions"},
659
22.1k
                {RPCResult::Type::STR, "previousblockhash", "The hash of current highest block"},
660
22.1k
                {RPCResult::Type::ARR, "transactions", "contents of non-coinbase transactions that should be included in the next block",
661
22.1k
                {
662
22.1k
                    {RPCResult::Type::OBJ, "", "",
663
22.1k
                    {
664
22.1k
                        {RPCResult::Type::STR_HEX, "data", "transaction data encoded in hexadecimal (byte-for-byte)"},
665
22.1k
                        {RPCResult::Type::STR_HEX, "txid", "transaction hash excluding witness data, shown in byte-reversed hex"},
666
22.1k
                        {RPCResult::Type::STR_HEX, "hash", "transaction hash including witness data, shown in byte-reversed hex"},
667
22.1k
                        {RPCResult::Type::ARR, "depends", "array of numbers",
668
22.1k
                        {
669
22.1k
                            {RPCResult::Type::NUM, "", "transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is"},
670
22.1k
                        }},
671
22.1k
                        {RPCResult::Type::NUM, "fee", "difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one"},
672
22.1k
                        {RPCResult::Type::NUM, "sigops", "total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero"},
673
22.1k
                        {RPCResult::Type::NUM, "weight", "total transaction weight, as counted for purposes of block limits"},
674
22.1k
                    }},
675
22.1k
                }},
676
22.1k
                {RPCResult::Type::OBJ_DYN, "coinbaseaux", "data that should be included in the coinbase's scriptSig content",
677
22.1k
                {
678
22.1k
                    {RPCResult::Type::STR_HEX, "key", "values must be in the coinbase (keys may be ignored)"},
679
22.1k
                }},
680
22.1k
                {RPCResult::Type::NUM, "coinbasevalue", "maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)"},
681
22.1k
                {RPCResult::Type::STR, "longpollid", "an id to include with a request to longpoll on an update to this template"},
682
22.1k
                {RPCResult::Type::STR, "target", "The hash target"},
683
22.1k
                {RPCResult::Type::NUM_TIME, "mintime", "The minimum timestamp appropriate for the next block time, expressed in " + UNIX_EPOCH_TIME + ". Adjusted for the proposed BIP94 timewarp rule."},
684
22.1k
                {RPCResult::Type::ARR, "mutable", "list of ways the block template may be changed",
685
22.1k
                {
686
22.1k
                    {RPCResult::Type::STR, "value", "A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'"},
687
22.1k
                }},
688
22.1k
                {RPCResult::Type::STR_HEX, "noncerange", "A range of valid nonces"},
689
22.1k
                {RPCResult::Type::NUM, "sigoplimit", "limit of sigops in blocks"},
690
22.1k
                {RPCResult::Type::NUM, "sizelimit", "limit of block size"},
691
22.1k
                {RPCResult::Type::NUM, "weightlimit", /*optional=*/true, "limit of block weight"},
692
22.1k
                {RPCResult::Type::NUM_TIME, "curtime", "current timestamp in " + UNIX_EPOCH_TIME + ". Adjusted for the proposed BIP94 timewarp rule."},
693
22.1k
                {RPCResult::Type::STR, "bits", "compressed target of next block"},
694
22.1k
                {RPCResult::Type::NUM, "height", "The height of the next block"},
695
22.1k
                {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "Only on signet"},
696
22.1k
                {RPCResult::Type::STR_HEX, "default_witness_commitment", /*optional=*/true, "a valid witness commitment for the unmodified block template"},
697
22.1k
            }},
698
22.1k
        },
699
22.1k
        RPCExamples{
700
22.1k
                    HelpExampleCli("getblocktemplate", "'{\"rules\": [\"segwit\"]}'")
701
22.1k
            + HelpExampleRpc("getblocktemplate", "{\"rules\": [\"segwit\"]}")
702
22.1k
                },
703
22.1k
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
704
22.1k
{
705
0
    NodeContext& node = EnsureAnyNodeContext(request.context);
706
0
    ChainstateManager& chainman = EnsureChainman(node);
707
0
    Mining& miner = EnsureMining(node);
708
0
    LOCK(cs_main);
709
0
    uint256 tip{CHECK_NONFATAL(miner.getTip()).value().hash};
710
711
0
    std::string strMode = "template";
712
0
    UniValue lpval = NullUniValue;
713
0
    std::set<std::string> setClientRules;
714
0
    if (!request.params[0].isNull())
  Branch (714:9): [True: 0, False: 0]
715
0
    {
716
0
        const UniValue& oparam = request.params[0].get_obj();
717
0
        const UniValue& modeval = oparam.find_value("mode");
718
0
        if (modeval.isStr())
  Branch (718:13): [True: 0, False: 0]
719
0
            strMode = modeval.get_str();
720
0
        else if (modeval.isNull())
  Branch (720:18): [True: 0, False: 0]
721
0
        {
722
            /* Do nothing */
723
0
        }
724
0
        else
725
0
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
726
0
        lpval = oparam.find_value("longpollid");
727
728
0
        if (strMode == "proposal")
  Branch (728:13): [True: 0, False: 0]
729
0
        {
730
0
            const UniValue& dataval = oparam.find_value("data");
731
0
            if (!dataval.isStr())
  Branch (731:17): [True: 0, False: 0]
732
0
                throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal");
733
734
0
            CBlock block;
735
0
            if (!DecodeHexBlk(block, dataval.get_str()))
  Branch (735:17): [True: 0, False: 0]
736
0
                throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
737
738
0
            uint256 hash = block.GetHash();
739
0
            const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
740
0
            if (pindex) {
  Branch (740:17): [True: 0, False: 0]
741
0
                if (pindex->IsValid(BLOCK_VALID_SCRIPTS))
  Branch (741:21): [True: 0, False: 0]
742
0
                    return "duplicate";
743
0
                if (pindex->nStatus & BLOCK_FAILED_MASK)
  Branch (743:21): [True: 0, False: 0]
744
0
                    return "duplicate-invalid";
745
0
                return "duplicate-inconclusive";
746
0
            }
747
748
            // TestBlockValidity only supports blocks built on the current Tip
749
0
            if (block.hashPrevBlock != tip) {
  Branch (749:17): [True: 0, False: 0]
750
0
                return "inconclusive-not-best-prevblk";
751
0
            }
752
0
            BlockValidationState state;
753
0
            TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/true);
754
0
            return BIP22ValidationResult(state);
755
0
        }
756
757
0
        const UniValue& aClientRules = oparam.find_value("rules");
758
0
        if (aClientRules.isArray()) {
  Branch (758:13): [True: 0, False: 0]
759
0
            for (unsigned int i = 0; i < aClientRules.size(); ++i) {
  Branch (759:38): [True: 0, False: 0]
760
0
                const UniValue& v = aClientRules[i];
761
0
                setClientRules.insert(v.get_str());
762
0
            }
763
0
        }
764
0
    }
765
766
0
    if (strMode != "template")
  Branch (766:9): [True: 0, False: 0]
767
0
        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
768
769
0
    if (!miner.isTestChain()) {
  Branch (769:9): [True: 0, False: 0]
770
0
        const CConnman& connman = EnsureConnman(node);
771
0
        if (connman.GetNodeCount(ConnectionDirection::Both) == 0) {
  Branch (771:13): [True: 0, False: 0]
772
0
            throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, CLIENT_NAME " is not connected!");
773
0
        }
774
775
0
        if (miner.isInitialBlockDownload()) {
  Branch (775:13): [True: 0, False: 0]
776
0
            throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, CLIENT_NAME " is in initial sync and waiting for blocks...");
777
0
        }
778
0
    }
779
780
0
    static unsigned int nTransactionsUpdatedLast;
781
0
    const CTxMemPool& mempool = EnsureMemPool(node);
782
783
    // Long Polling (BIP22)
784
0
    if (!lpval.isNull()) {
  Branch (784:9): [True: 0, False: 0]
785
        /**
786
         * Wait to respond until either the best block changes, OR there are more
787
         * transactions.
788
         *
789
         * The check for new transactions first happens after 1 minute and
790
         * subsequently every 10 seconds. BIP22 does not require this particular interval.
791
         * On mainnet the mempool changes frequently enough that in practice this RPC
792
         * returns after 60 seconds, or sooner if the best block changes.
793
         *
794
         * getblocktemplate is unlikely to be called by bitcoin-cli, so
795
         * -rpcclienttimeout is not a concern. BIP22 recommends a long request timeout.
796
         *
797
         * The longpollid is assumed to be a tip hash if it has the right format.
798
         */
799
0
        uint256 hashWatchedChain;
800
0
        unsigned int nTransactionsUpdatedLastLP;
801
802
0
        if (lpval.isStr())
  Branch (802:13): [True: 0, False: 0]
803
0
        {
804
            // Format: <hashBestChain><nTransactionsUpdatedLast>
805
0
            const std::string& lpstr = lpval.get_str();
806
807
            // Assume the longpollid is a block hash. If it's not then we return
808
            // early below.
809
0
            hashWatchedChain = ParseHashV(lpstr.substr(0, 64), "longpollid");
810
0
            nTransactionsUpdatedLastLP = LocaleIndependentAtoi<int64_t>(lpstr.substr(64));
811
0
        }
812
0
        else
813
0
        {
814
            // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier
815
0
            hashWatchedChain = tip;
816
0
            nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
817
0
        }
818
819
        // Release lock while waiting
820
0
        LEAVE_CRITICAL_SECTION(cs_main);
821
0
        {
822
0
            MillisecondsDouble checktxtime{std::chrono::minutes(1)};
823
0
            while (IsRPCRunning()) {
  Branch (823:20): [True: 0, False: 0]
824
                // If hashWatchedChain is not a real block hash, this will
825
                // return immediately.
826
0
                std::optional<BlockRef> maybe_tip{miner.waitTipChanged(hashWatchedChain, checktxtime)};
827
                // Node is shutting down
828
0
                if (!maybe_tip) break;
  Branch (828:21): [True: 0, False: 0]
829
0
                tip = maybe_tip->hash;
830
0
                if (tip != hashWatchedChain) break;
  Branch (830:21): [True: 0, False: 0]
831
832
                // Check transactions for update without holding the mempool
833
                // lock to avoid deadlocks.
834
0
                if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) {
  Branch (834:21): [True: 0, False: 0]
835
0
                    break;
836
0
                }
837
0
                checktxtime = std::chrono::seconds(10);
838
0
            }
839
0
        }
840
0
        ENTER_CRITICAL_SECTION(cs_main);
841
842
0
        tip = CHECK_NONFATAL(miner.getTip()).value().hash;
843
844
0
        if (!IsRPCRunning())
  Branch (844:13): [True: 0, False: 0]
845
0
            throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
846
        // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
847
0
    }
848
849
0
    const Consensus::Params& consensusParams = chainman.GetParams().GetConsensus();
850
851
    // GBT must be called with 'signet' set in the rules for signet chains
852
0
    if (consensusParams.signet_blocks && setClientRules.count("signet") != 1) {
  Branch (852:9): [True: 0, False: 0]
  Branch (852:9): [True: 0, False: 0]
  Branch (852:42): [True: 0, False: 0]
853
0
        throw JSONRPCError(RPC_INVALID_PARAMETER, "getblocktemplate must be called with the signet rule set (call with {\"rules\": [\"segwit\", \"signet\"]})");
854
0
    }
855
856
    // GBT must be called with 'segwit' set in the rules
857
0
    if (setClientRules.count("segwit") != 1) {
  Branch (857:9): [True: 0, False: 0]
858
0
        throw JSONRPCError(RPC_INVALID_PARAMETER, "getblocktemplate must be called with the segwit rule set (call with {\"rules\": [\"segwit\"]})");
859
0
    }
860
861
    // Update block
862
0
    static CBlockIndex* pindexPrev;
863
0
    static int64_t time_start;
864
0
    static std::unique_ptr<BlockTemplate> block_template;
865
0
    if (!pindexPrev || pindexPrev->GetBlockHash() != tip ||
  Branch (865:9): [True: 0, False: 0]
  Branch (865:9): [True: 0, False: 0]
  Branch (865:24): [True: 0, False: 0]
866
0
        (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
  Branch (866:10): [True: 0, False: 0]
  Branch (866:74): [True: 0, False: 0]
867
0
    {
868
        // Clear pindexPrev so future calls make a new block, despite any failures from here on
869
0
        pindexPrev = nullptr;
870
871
        // Store the pindexBest used before createNewBlock, to avoid races
872
0
        nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
873
0
        CBlockIndex* pindexPrevNew = chainman.m_blockman.LookupBlockIndex(tip);
874
0
        time_start = GetTime();
875
876
        // Create new block
877
0
        block_template = miner.createNewBlock();
878
0
        CHECK_NONFATAL(block_template);
879
880
881
        // Need to update only after we know createNewBlock succeeded
882
0
        pindexPrev = pindexPrevNew;
883
0
    }
884
0
    CHECK_NONFATAL(pindexPrev);
885
0
    CBlock block{block_template->getBlock()};
886
887
    // Update nTime
888
0
    UpdateTime(&block, consensusParams, pindexPrev);
889
0
    block.nNonce = 0;
890
891
    // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration
892
0
    const bool fPreSegWit = !DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_SEGWIT);
893
894
0
    UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
895
896
0
    UniValue transactions(UniValue::VARR);
897
0
    std::map<uint256, int64_t> setTxIndex;
898
0
    std::vector<CAmount> tx_fees{block_template->getTxFees()};
899
0
    std::vector<CAmount> tx_sigops{block_template->getTxSigops()};
900
901
0
    int i = 0;
902
0
    for (const auto& it : block.vtx) {
  Branch (902:25): [True: 0, False: 0]
903
0
        const CTransaction& tx = *it;
904
0
        uint256 txHash = tx.GetHash();
905
0
        setTxIndex[txHash] = i++;
906
907
0
        if (tx.IsCoinBase())
  Branch (907:13): [True: 0, False: 0]
908
0
            continue;
909
910
0
        UniValue entry(UniValue::VOBJ);
911
912
0
        entry.pushKV("data", EncodeHexTx(tx));
913
0
        entry.pushKV("txid", txHash.GetHex());
914
0
        entry.pushKV("hash", tx.GetWitnessHash().GetHex());
915
916
0
        UniValue deps(UniValue::VARR);
917
0
        for (const CTxIn &in : tx.vin)
  Branch (917:30): [True: 0, False: 0]
918
0
        {
919
0
            if (setTxIndex.count(in.prevout.hash))
  Branch (919:17): [True: 0, False: 0]
920
0
                deps.push_back(setTxIndex[in.prevout.hash]);
921
0
        }
922
0
        entry.pushKV("depends", std::move(deps));
923
924
0
        int index_in_template = i - 2;
925
0
        entry.pushKV("fee", tx_fees.at(index_in_template));
926
0
        int64_t nTxSigOps{tx_sigops.at(index_in_template)};
927
0
        if (fPreSegWit) {
  Branch (927:13): [True: 0, False: 0]
928
0
            CHECK_NONFATAL(nTxSigOps % WITNESS_SCALE_FACTOR == 0);
929
0
            nTxSigOps /= WITNESS_SCALE_FACTOR;
930
0
        }
931
0
        entry.pushKV("sigops", nTxSigOps);
932
0
        entry.pushKV("weight", GetTransactionWeight(tx));
933
934
0
        transactions.push_back(std::move(entry));
935
0
    }
936
937
0
    UniValue aux(UniValue::VOBJ);
938
939
0
    arith_uint256 hashTarget = arith_uint256().SetCompact(block.nBits);
940
941
0
    UniValue aMutable(UniValue::VARR);
942
0
    aMutable.push_back("time");
943
0
    aMutable.push_back("transactions");
944
0
    aMutable.push_back("prevblock");
945
946
0
    UniValue result(UniValue::VOBJ);
947
0
    result.pushKV("capabilities", std::move(aCaps));
948
949
0
    UniValue aRules(UniValue::VARR);
950
0
    aRules.push_back("csv");
951
0
    if (!fPreSegWit) aRules.push_back("!segwit");
  Branch (951:9): [True: 0, False: 0]
952
0
    if (consensusParams.signet_blocks) {
  Branch (952:9): [True: 0, False: 0]
953
        // indicate to miner that they must understand signet rules
954
        // when attempting to mine with this template
955
0
        aRules.push_back("!signet");
956
0
    }
957
958
0
    UniValue vbavailable(UniValue::VOBJ);
959
0
    const auto gbtstatus = chainman.m_versionbitscache.GBTStatus(*pindexPrev, consensusParams);
960
961
0
    for (const auto& [name, info] : gbtstatus.signalling) {
  Branch (961:35): [True: 0, False: 0]
962
0
        vbavailable.pushKV(gbt_rule_value(name, info.gbt_optional_rule), info.bit);
963
0
        if (!info.gbt_optional_rule && !setClientRules.count(name)) {
  Branch (963:13): [True: 0, False: 0]
  Branch (963:40): [True: 0, False: 0]
964
            // If the client doesn't support this, don't indicate it in the [default] version
965
0
            block.nVersion &= ~info.mask;
966
0
        }
967
0
    }
968
969
0
    for (const auto& [name, info] : gbtstatus.locked_in) {
  Branch (969:35): [True: 0, False: 0]
970
0
        block.nVersion |= info.mask;
971
0
        vbavailable.pushKV(gbt_rule_value(name, info.gbt_optional_rule), info.bit);
972
0
        if (!info.gbt_optional_rule && !setClientRules.count(name)) {
  Branch (972:13): [True: 0, False: 0]
  Branch (972:40): [True: 0, False: 0]
973
            // If the client doesn't support this, don't indicate it in the [default] version
974
0
            block.nVersion &= ~info.mask;
975
0
        }
976
0
    }
977
978
0
    for (const auto& [name, info] : gbtstatus.active) {
  Branch (978:35): [True: 0, False: 0]
979
0
        aRules.push_back(gbt_rule_value(name, info.gbt_optional_rule));
980
0
        if (!info.gbt_optional_rule && !setClientRules.count(name)) {
  Branch (980:13): [True: 0, False: 0]
  Branch (980:40): [True: 0, False: 0]
981
            // Not supported by the client; make sure it's safe to proceed
982
0
            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Support for '%s' rule requires explicit client support", name));
983
0
        }
984
0
    }
985
986
0
    result.pushKV("version", block.nVersion);
987
0
    result.pushKV("rules", std::move(aRules));
988
0
    result.pushKV("vbavailable", std::move(vbavailable));
989
0
    result.pushKV("vbrequired", int(0));
990
991
0
    result.pushKV("previousblockhash", block.hashPrevBlock.GetHex());
992
0
    result.pushKV("transactions", std::move(transactions));
993
0
    result.pushKV("coinbaseaux", std::move(aux));
994
0
    result.pushKV("coinbasevalue", (int64_t)block.vtx[0]->vout[0].nValue);
995
0
    result.pushKV("longpollid", tip.GetHex() + ToString(nTransactionsUpdatedLast));
996
0
    result.pushKV("target", hashTarget.GetHex());
997
0
    result.pushKV("mintime", GetMinimumTime(pindexPrev, consensusParams.DifficultyAdjustmentInterval()));
998
0
    result.pushKV("mutable", std::move(aMutable));
999
0
    result.pushKV("noncerange", "00000000ffffffff");
1000
0
    int64_t nSigOpLimit = MAX_BLOCK_SIGOPS_COST;
1001
0
    int64_t nSizeLimit = MAX_BLOCK_SERIALIZED_SIZE;
1002
0
    if (fPreSegWit) {
  Branch (1002:9): [True: 0, False: 0]
1003
0
        CHECK_NONFATAL(nSigOpLimit % WITNESS_SCALE_FACTOR == 0);
1004
0
        nSigOpLimit /= WITNESS_SCALE_FACTOR;
1005
0
        CHECK_NONFATAL(nSizeLimit % WITNESS_SCALE_FACTOR == 0);
1006
0
        nSizeLimit /= WITNESS_SCALE_FACTOR;
1007
0
    }
1008
0
    result.pushKV("sigoplimit", nSigOpLimit);
1009
0
    result.pushKV("sizelimit", nSizeLimit);
1010
0
    if (!fPreSegWit) {
  Branch (1010:9): [True: 0, False: 0]
1011
0
        result.pushKV("weightlimit", (int64_t)MAX_BLOCK_WEIGHT);
1012
0
    }
1013
0
    result.pushKV("curtime", block.GetBlockTime());
1014
0
    result.pushKV("bits", strprintf("%08x", block.nBits));
1015
0
    result.pushKV("height", (int64_t)(pindexPrev->nHeight+1));
1016
1017
0
    if (consensusParams.signet_blocks) {
  Branch (1017:9): [True: 0, False: 0]
1018
0
        result.pushKV("signet_challenge", HexStr(consensusParams.signet_challenge));
1019
0
    }
1020
1021
0
    if (!block_template->getCoinbaseCommitment().empty()) {
  Branch (1021:9): [True: 0, False: 0]
1022
0
        result.pushKV("default_witness_commitment", HexStr(block_template->getCoinbaseCommitment()));
1023
0
    }
1024
1025
0
    return result;
1026
0
},
1027
22.1k
    };
1028
22.1k
}
1029
1030
class submitblock_StateCatcher final : public CValidationInterface
1031
{
1032
public:
1033
    uint256 hash;
1034
    bool found{false};
1035
    BlockValidationState state;
1036
1037
0
    explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), state() {}
1038
1039
protected:
1040
0
    void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override {
1041
0
        if (block.GetHash() != hash)
  Branch (1041:13): [True: 0, False: 0]
1042
0
            return;
1043
0
        found = true;
1044
0
        state = stateIn;
1045
0
    }
1046
};
1047
1048
static RPCHelpMan submitblock()
1049
22.1k
{
1050
    // We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
1051
22.1k
    return RPCHelpMan{
1052
22.1k
        "submitblock",
1053
22.1k
        "Attempts to submit new block to network.\n"
1054
22.1k
        "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n",
1055
22.1k
        {
1056
22.1k
            {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block data to submit"},
1057
22.1k
            {"dummy", RPCArg::Type::STR, RPCArg::DefaultHint{"ignored"}, "dummy value, for compatibility with BIP22. This value is ignored."},
1058
22.1k
        },
1059
22.1k
        {
1060
22.1k
            RPCResult{"If the block was accepted", RPCResult::Type::NONE, "", ""},
1061
22.1k
            RPCResult{"Otherwise", RPCResult::Type::STR, "", "According to BIP22"},
1062
22.1k
        },
1063
22.1k
        RPCExamples{
1064
22.1k
                    HelpExampleCli("submitblock", "\"mydata\"")
1065
22.1k
            + HelpExampleRpc("submitblock", "\"mydata\"")
1066
22.1k
                },
1067
22.1k
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1068
22.1k
{
1069
0
    std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
1070
0
    CBlock& block = *blockptr;
1071
0
    if (!DecodeHexBlk(block, request.params[0].get_str())) {
  Branch (1071:9): [True: 0, False: 0]
1072
0
        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
1073
0
    }
1074
1075
0
    ChainstateManager& chainman = EnsureAnyChainman(request.context);
1076
0
    {
1077
0
        LOCK(cs_main);
1078
0
        const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
1079
0
        if (pindex) {
  Branch (1079:13): [True: 0, False: 0]
1080
0
            chainman.UpdateUncommittedBlockStructures(block, pindex);
1081
0
        }
1082
0
    }
1083
1084
0
    bool new_block;
1085
0
    auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
1086
0
    CHECK_NONFATAL(chainman.m_options.signals)->RegisterSharedValidationInterface(sc);
1087
0
    bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
1088
0
    CHECK_NONFATAL(chainman.m_options.signals)->UnregisterSharedValidationInterface(sc);
1089
0
    if (!new_block && accepted) {
  Branch (1089:9): [True: 0, False: 0]
  Branch (1089:23): [True: 0, False: 0]
1090
0
        return "duplicate";
1091
0
    }
1092
0
    if (!sc->found) {
  Branch (1092:9): [True: 0, False: 0]
1093
0
        return "inconclusive";
1094
0
    }
1095
0
    return BIP22ValidationResult(sc->state);
1096
0
},
1097
22.1k
    };
1098
22.1k
}
1099
1100
static RPCHelpMan submitheader()
1101
22.1k
{
1102
22.1k
    return RPCHelpMan{
1103
22.1k
        "submitheader",
1104
22.1k
        "Decode the given hexdata as a header and submit it as a candidate chain tip if valid."
1105
22.1k
                "\nThrows when the header is invalid.\n",
1106
22.1k
                {
1107
22.1k
                    {"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block header data"},
1108
22.1k
                },
1109
22.1k
                RPCResult{
1110
22.1k
                    RPCResult::Type::NONE, "", "None"},
1111
22.1k
                RPCExamples{
1112
22.1k
                    HelpExampleCli("submitheader", "\"aabbcc\"") +
1113
22.1k
                    HelpExampleRpc("submitheader", "\"aabbcc\"")
1114
22.1k
                },
1115
22.1k
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1116
22.1k
{
1117
0
    CBlockHeader h;
1118
0
    if (!DecodeHexBlockHeader(h, request.params[0].get_str())) {
  Branch (1118:9): [True: 0, False: 0]
1119
0
        throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block header decode failed");
1120
0
    }
1121
0
    ChainstateManager& chainman = EnsureAnyChainman(request.context);
1122
0
    {
1123
0
        LOCK(cs_main);
1124
0
        if (!chainman.m_blockman.LookupBlockIndex(h.hashPrevBlock)) {
  Branch (1124:13): [True: 0, False: 0]
1125
0
            throw JSONRPCError(RPC_VERIFY_ERROR, "Must submit previous header (" + h.hashPrevBlock.GetHex() + ") first");
1126
0
        }
1127
0
    }
1128
1129
0
    BlockValidationState state;
1130
0
    chainman.ProcessNewBlockHeaders({{h}}, /*min_pow_checked=*/true, state);
1131
0
    if (state.IsValid()) return UniValue::VNULL;
  Branch (1131:9): [True: 0, False: 0]
1132
0
    if (state.IsError()) {
  Branch (1132:9): [True: 0, False: 0]
1133
0
        throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
1134
0
    }
1135
0
    throw JSONRPCError(RPC_VERIFY_ERROR, state.GetRejectReason());
1136
0
},
1137
22.1k
    };
1138
22.1k
}
1139
1140
void RegisterMiningRPCCommands(CRPCTable& t)
1141
11.0k
{
1142
11.0k
    static const CRPCCommand commands[]{
1143
11.0k
        {"mining", &getnetworkhashps},
1144
11.0k
        {"mining", &getmininginfo},
1145
11.0k
        {"mining", &prioritisetransaction},
1146
11.0k
        {"mining", &getprioritisedtransactions},
1147
11.0k
        {"mining", &getblocktemplate},
1148
11.0k
        {"mining", &submitblock},
1149
11.0k
        {"mining", &submitheader},
1150
1151
11.0k
        {"hidden", &generatetoaddress},
1152
11.0k
        {"hidden", &generatetodescriptor},
1153
11.0k
        {"hidden", &generateblock},
1154
11.0k
        {"hidden", &generate},
1155
11.0k
    };
1156
122k
    for (const auto& c : commands) {
  Branch (1156:24): [True: 122k, False: 11.0k]
1157
122k
        t.appendCommand(c.name, &c);
1158
122k
    }
1159
11.0k
}