mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-17 13:07:54 +02:00
Merge 323b0acfcb into merged_master (Bitcoin PR bitcoin/bitcoin#30200)
This commit is contained in:
commit
7f7a7c4e0c
21 changed files with 231 additions and 53 deletions
|
|
@ -16,6 +16,7 @@
|
|||
#include <core_io.h>
|
||||
#include <deploymentinfo.h>
|
||||
#include <deploymentstatus.h>
|
||||
#include <interfaces/mining.h>
|
||||
#include <key_io.h>
|
||||
#include <net.h>
|
||||
#include <node/context.h>
|
||||
|
|
@ -53,6 +54,7 @@
|
|||
|
||||
using node::BlockAssembler;
|
||||
using node::CBlockTemplate;
|
||||
using interfaces::Mining;
|
||||
using node::NodeContext;
|
||||
using node::RegenerateCommitments;
|
||||
using node::UpdateTime;
|
||||
|
|
@ -135,7 +137,7 @@ static RPCHelpMan getnetworkhashps()
|
|||
};
|
||||
}
|
||||
|
||||
static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
|
||||
static bool GenerateBlock(ChainstateManager& chainman, Mining& miner, CBlock& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
|
||||
{
|
||||
block_out.reset();
|
||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||
|
|
@ -167,23 +169,23 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
|
|||
|
||||
if (!process_new_block) return true;
|
||||
|
||||
if (!chainman.ProcessNewBlock(block_out, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) {
|
||||
if (!miner.processNewBlock(block_out, nullptr)) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& mempool, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
|
||||
static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
|
||||
{
|
||||
UniValue blockHashes(UniValue::VARR);
|
||||
while (nGenerate > 0 && !chainman.m_interrupt) {
|
||||
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler{chainman.ActiveChainstate(), &mempool}.CreateNewBlock(coinbase_script));
|
||||
std::unique_ptr<CBlockTemplate> pblocktemplate(miner.createNewBlock(coinbase_script));
|
||||
if (!pblocktemplate.get())
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
|
||||
|
||||
std::shared_ptr<const CBlock> block_out;
|
||||
if (!GenerateBlock(chainman, pblocktemplate->block, nMaxTries, block_out, /*process_new_block=*/true)) {
|
||||
if (!GenerateBlock(chainman, miner, pblocktemplate->block, nMaxTries, block_out, /*process_new_block=*/true)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -259,10 +261,10 @@ static RPCHelpMan generatetodescriptor()
|
|||
}
|
||||
|
||||
NodeContext& node = EnsureAnyNodeContext(request.context);
|
||||
const CTxMemPool& mempool = EnsureMemPool(node);
|
||||
Mining& miner = EnsureMining(node);
|
||||
ChainstateManager& chainman = EnsureChainman(node);
|
||||
|
||||
return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries);
|
||||
return generateBlocks(chainman, miner, coinbase_script, num_blocks, max_tries);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -305,12 +307,12 @@ static RPCHelpMan generatetoaddress()
|
|||
}
|
||||
|
||||
NodeContext& node = EnsureAnyNodeContext(request.context);
|
||||
const CTxMemPool& mempool = EnsureMemPool(node);
|
||||
Mining& miner = EnsureMining(node);
|
||||
ChainstateManager& chainman = EnsureChainman(node);
|
||||
|
||||
CScript coinbase_script = GetScriptForDestination(destination);
|
||||
|
||||
return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries);
|
||||
return generateBlocks(chainman, miner, coinbase_script, num_blocks, max_tries);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -357,6 +359,7 @@ static RPCHelpMan generateblock()
|
|||
}
|
||||
|
||||
NodeContext& node = EnsureAnyNodeContext(request.context);
|
||||
Mining& miner = EnsureMining(node);
|
||||
const CTxMemPool& mempool = EnsureMemPool(node);
|
||||
|
||||
std::vector<CTransactionRef> txs;
|
||||
|
|
@ -390,7 +393,7 @@ static RPCHelpMan generateblock()
|
|||
{
|
||||
LOCK(cs_main);
|
||||
|
||||
std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler{chainman.ActiveChainstate(), nullptr}.CreateNewBlock(coinbase_script));
|
||||
std::unique_ptr<CBlockTemplate> blocktemplate{miner.createNewBlock(coinbase_script, /*use_mempool=*/false)};
|
||||
if (!blocktemplate) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
|
||||
}
|
||||
|
|
@ -407,15 +410,15 @@ static RPCHelpMan generateblock()
|
|||
LOCK(cs_main);
|
||||
|
||||
BlockValidationState state;
|
||||
if (!TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) {
|
||||
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString()));
|
||||
if (!miner.testBlockValidity(state, block, /*check_merkle_root=*/false)) {
|
||||
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("testBlockValidity failed: %s", state.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const CBlock> block_out;
|
||||
uint64_t max_tries{DEFAULT_MAX_TRIES};
|
||||
|
||||
if (!GenerateBlock(chainman, block, max_tries, block_out, process_new_block) || !block_out) {
|
||||
if (!GenerateBlock(chainman, miner, block, max_tries, block_out, process_new_block) || !block_out) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
|
||||
}
|
||||
|
||||
|
|
@ -684,13 +687,15 @@ static RPCHelpMan getblocktemplate()
|
|||
{
|
||||
NodeContext& node = EnsureAnyNodeContext(request.context);
|
||||
ChainstateManager& chainman = EnsureChainman(node);
|
||||
Mining& miner = EnsureMining(node);
|
||||
LOCK(cs_main);
|
||||
std::optional<uint256> maybe_tip{miner.getTipHash()};
|
||||
CHECK_NONFATAL(maybe_tip);
|
||||
uint256 tip{maybe_tip.value()};
|
||||
|
||||
std::string strMode = "template";
|
||||
UniValue lpval = NullUniValue;
|
||||
std::set<std::string> setClientRules;
|
||||
Chainstate& active_chainstate = chainman.ActiveChainstate();
|
||||
CChain& active_chain = active_chainstate.m_chain;
|
||||
if (!request.params[0].isNull())
|
||||
{
|
||||
const UniValue& oparam = request.params[0].get_obj();
|
||||
|
|
@ -725,12 +730,12 @@ static RPCHelpMan getblocktemplate()
|
|||
return "duplicate-inconclusive";
|
||||
}
|
||||
|
||||
CBlockIndex* const pindexPrev = active_chain.Tip();
|
||||
// TestBlockValidity only supports blocks built on the current Tip
|
||||
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
|
||||
// testBlockValidity only supports blocks built on the current Tip
|
||||
if (block.hashPrevBlock != tip) {
|
||||
return "inconclusive-not-best-prevblk";
|
||||
}
|
||||
BlockValidationState state;
|
||||
TestBlockValidity(state, chainman.GetParams(), active_chainstate, block, pindexPrev, false, true);
|
||||
miner.testBlockValidity(state, block);
|
||||
return BIP22ValidationResult(state);
|
||||
}
|
||||
|
||||
|
|
@ -746,19 +751,18 @@ static RPCHelpMan getblocktemplate()
|
|||
if (strMode != "template")
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
|
||||
|
||||
if (!chainman.GetParams().IsTestChain()) {
|
||||
if (!miner.isTestChain()) {
|
||||
const CConnman& connman = EnsureConnman(node);
|
||||
if (connman.GetNodeCount(ConnectionDirection::Both) == 0) {
|
||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
|
||||
}
|
||||
|
||||
if (chainman.IsInitialBlockDownload()) {
|
||||
if (miner.isInitialBlockDownload()) {
|
||||
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int nTransactionsUpdatedLast;
|
||||
const CTxMemPool& mempool = EnsureMemPool(node);
|
||||
|
||||
if (!lpval.isNull())
|
||||
{
|
||||
|
|
@ -778,7 +782,7 @@ static RPCHelpMan getblocktemplate()
|
|||
else
|
||||
{
|
||||
// NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier
|
||||
hashWatchedChain = active_chain.Tip()->GetBlockHash();
|
||||
hashWatchedChain = tip;
|
||||
nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
|
||||
}
|
||||
|
||||
|
|
@ -794,7 +798,7 @@ static RPCHelpMan getblocktemplate()
|
|||
{
|
||||
// Timeout: Check transactions for update
|
||||
// without holding the mempool lock to avoid deadlocks
|
||||
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP)
|
||||
if (miner.getTransactionsUpdated() != nTransactionsUpdatedLastLP)
|
||||
break;
|
||||
checktxtime += std::chrono::seconds(10);
|
||||
}
|
||||
|
|
@ -802,6 +806,10 @@ static RPCHelpMan getblocktemplate()
|
|||
}
|
||||
ENTER_CRITICAL_SECTION(cs_main);
|
||||
|
||||
std::optional<uint256> maybe_tip{miner.getTipHash()};
|
||||
CHECK_NONFATAL(maybe_tip);
|
||||
tip = maybe_tip.value();
|
||||
|
||||
if (!IsRPCRunning())
|
||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
|
||||
// TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
|
||||
|
|
@ -823,24 +831,25 @@ static RPCHelpMan getblocktemplate()
|
|||
static CBlockIndex* pindexPrev;
|
||||
static int64_t time_start;
|
||||
static std::unique_ptr<CBlockTemplate> pblocktemplate;
|
||||
if (pindexPrev != active_chain.Tip() ||
|
||||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
|
||||
if (!pindexPrev || pindexPrev->GetBlockHash() != tip ||
|
||||
(miner.getTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
|
||||
{
|
||||
// Clear pindexPrev so future calls make a new block, despite any failures from here on
|
||||
pindexPrev = nullptr;
|
||||
|
||||
// Store the pindexBest used before CreateNewBlock, to avoid races
|
||||
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
||||
CBlockIndex* pindexPrevNew = active_chain.Tip();
|
||||
// Store the pindexBest used before createNewBlock, to avoid races
|
||||
nTransactionsUpdatedLast = miner.getTransactionsUpdated();
|
||||
CBlockIndex* pindexPrevNew = chainman.m_blockman.LookupBlockIndex(tip);
|
||||
time_start = GetTime();
|
||||
|
||||
// Create new block
|
||||
CScript scriptDummy = CScript() << OP_TRUE;
|
||||
pblocktemplate = BlockAssembler{active_chainstate, &mempool}.CreateNewBlock(scriptDummy);
|
||||
if (!pblocktemplate)
|
||||
pblocktemplate = miner.createNewBlock(scriptDummy);
|
||||
if (!pblocktemplate) {
|
||||
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
|
||||
}
|
||||
|
||||
// Need to update only after we know CreateNewBlock succeeded
|
||||
// Need to update only after we know createNewBlock succeeded
|
||||
pindexPrev = pindexPrevNew;
|
||||
}
|
||||
CHECK_NONFATAL(pindexPrev);
|
||||
|
|
@ -963,7 +972,7 @@ static RPCHelpMan getblocktemplate()
|
|||
result.pushKV("transactions", std::move(transactions));
|
||||
result.pushKV("coinbaseaux", std::move(aux));
|
||||
result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue.GetAmount());
|
||||
result.pushKV("longpollid", active_chain.Tip()->GetBlockHash().GetHex() + ToString(nTransactionsUpdatedLast));
|
||||
result.pushKV("longpollid", tip.GetHex() + ToString(nTransactionsUpdatedLast));
|
||||
result.pushKV("target", hashTarget.GetHex());
|
||||
result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1);
|
||||
result.pushKV("mutable", std::move(aMutable));
|
||||
|
|
@ -1069,10 +1078,13 @@ static RPCHelpMan submitblock()
|
|||
}
|
||||
}
|
||||
|
||||
NodeContext& node = EnsureAnyNodeContext(request.context);
|
||||
Mining& miner = EnsureMining(node);
|
||||
|
||||
bool new_block;
|
||||
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
|
||||
CHECK_NONFATAL(chainman.m_options.signals)->RegisterSharedValidationInterface(sc);
|
||||
bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
|
||||
bool accepted = miner.processNewBlock(blockptr, /*new_block=*/&new_block);
|
||||
CHECK_NONFATAL(chainman.m_options.signals)->UnregisterSharedValidationInterface(sc);
|
||||
if (!new_block && accepted) {
|
||||
return "duplicate";
|
||||
|
|
@ -1231,7 +1243,11 @@ static RPCHelpMan getnewblockhex()
|
|||
CScript feeDestinationScript = Params().GetConsensus().mandatory_coinbase_destination;
|
||||
if (feeDestinationScript == CScript()) feeDestinationScript = CScript() << OP_TRUE;
|
||||
const NodeContext& node = EnsureAnyNodeContext(request.context);
|
||||
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(chainman.ActiveChainstate(), node.mempool.get()).CreateNewBlock(feeDestinationScript, std::chrono::seconds(required_wait), &proposed, data_commitments.empty() ? nullptr : &data_commitments));
|
||||
|
||||
BlockAssembler::Options options;
|
||||
ApplyArgsManOptions(gArgs, options);
|
||||
|
||||
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(chainman.ActiveChainstate(), node.mempool.get(), options).CreateNewBlock(feeDestinationScript, std::chrono::seconds(required_wait), &proposed, data_commitments.empty() ? nullptr : &data_commitments));
|
||||
if (!pblocktemplate.get()) {
|
||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue