fuzz coverage

Coverage Report

Created: 2025-06-01 19:34

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