Coverage Report

Created: 2024-09-19 18:47

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