Skip to content

Commit

Permalink
rpc: minize getTipHash() calls in gbt
Browse files Browse the repository at this point in the history
Set tip at the start of the function and only update it for a long poll.

Additionally have getTipHash return an optional, so the
caller can explicitly check that a tip exists.
  • Loading branch information
Sjors committed Jun 18, 2024
1 parent 7b4d324 commit dda0b08
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 9 deletions.
5 changes: 3 additions & 2 deletions src/interfaces/mining.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef BITCOIN_INTERFACES_MINING_H
#define BITCOIN_INTERFACES_MINING_H

#include <optional>
#include <uint256.h>

namespace node {
Expand All @@ -29,8 +30,8 @@ class Mining
//! If this chain is exclusively used for testing
virtual bool isTestChain() = 0;

//! Returns the hash for the tip of this chain, 0 if none
virtual uint256 getTipHash() = 0;
//! Returns the hash for the tip of this chain
virtual std::optional<uint256> getTipHash() = 0;

/**
* Construct a new block template
Expand Down
4 changes: 2 additions & 2 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,11 +847,11 @@ class MinerImpl : public Mining
return chainman().GetParams().IsTestChain();
}

uint256 getTipHash() override
std::optional<uint256> getTipHash() override
{
LOCK(::cs_main);
CBlockIndex* tip{chainman().ActiveChain().Tip()};
if (!tip) return uint256{0};
if (!tip) return {};
return tip->GetBlockHash();
}

Expand Down
17 changes: 12 additions & 5 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,9 @@ static RPCHelpMan getblocktemplate()
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;
Expand Down Expand Up @@ -706,7 +709,7 @@ static RPCHelpMan getblocktemplate()
}

// testBlockValidity only supports blocks built on the current Tip
if (block.hashPrevBlock != miner.getTipHash()) {
if (block.hashPrevBlock != tip) {
return "inconclusive-not-best-prevblk";
}
BlockValidationState state;
Expand Down Expand Up @@ -757,7 +760,7 @@ static RPCHelpMan getblocktemplate()
else
{
// NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier
hashWatchedChain = miner.getTipHash();
hashWatchedChain = tip;
nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
}

Expand All @@ -781,6 +784,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?
Expand All @@ -802,15 +809,15 @@ static RPCHelpMan getblocktemplate()
static CBlockIndex* pindexPrev;
static int64_t time_start;
static std::unique_ptr<CBlockTemplate> pblocktemplate;
if (!pindexPrev || pindexPrev->GetBlockHash() != miner.getTipHash() ||
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 = miner.getTransactionsUpdated();
CBlockIndex* pindexPrevNew = chainman.m_blockman.LookupBlockIndex(miner.getTipHash());
CBlockIndex* pindexPrevNew = chainman.m_blockman.LookupBlockIndex(tip);
time_start = GetTime();

// Create new block
Expand Down Expand Up @@ -943,7 +950,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);
result.pushKV("longpollid", miner.getTipHash().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));
Expand Down

0 comments on commit dda0b08

Please sign in to comment.