Skip to content

backport: Merge bitcoin/bitcoin#25849, 25683, 25077, 25852 #6595

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2187,7 +2187,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// Either install a handler to notify us when genesis activates, or set fHaveGenesis directly.
// No locking, as this happens before any background thread is started.
boost::signals2::connection block_notify_genesis_wait_connection;
if (chainman.ActiveChain().Tip() == nullptr) {
if (WITH_LOCK(chainman.GetMutex(), return chainman.ActiveChain().Tip() == nullptr)) {
block_notify_genesis_wait_connection = uiInterface.NotifyBlockTip_connect(std::bind(BlockNotifyGenesisWait, std::placeholders::_2));
} else {
fHaveGenesis = true;
Expand Down Expand Up @@ -2426,12 +2426,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// At this point, the RPC is "started", but still in warmup, which means it
// cannot yet be called. Before we make it callable, we need to make sure
// that the RPC's view of the best block is valid and consistent with
// ChainstateManager's ActiveTip.
// ChainstateManager's active tip.
//
// If we do not do this, RPC's view of the best block will be height=0 and
// hash=0x0. This will lead to erroroneous responses for things like
// waitforblockheight.
RPCNotifyBlockChange(chainman.ActiveTip());
RPCNotifyBlockChange(WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip()));
SetRPCWarmupFinished();

uiInterface.InitMessage(_("Done loading").translated);
Expand Down
7 changes: 2 additions & 5 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3177,7 +3177,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
const std::string msg_type = uses_compressed ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS;
if (nCount == GetHeadersLimit(pfrom, uses_compressed)) {
// Headers message had its maximum size; the peer may have more headers.
if (MaybeSendGetHeaders(pfrom, msg_type, m_chainman.ActiveChain().GetLocator(pindexLast), peer)) {
if (MaybeSendGetHeaders(pfrom, msg_type, WITH_LOCK(m_chainman.GetMutex(), return m_chainman.ActiveChain().GetLocator(pindexLast)), peer)) {
LogPrint(BCLog::NET, "more %s (%d) to end to peer=%d (startheight:%d)\n",
msg_type, pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height);
}
Expand Down Expand Up @@ -4543,10 +4543,7 @@ void PeerManagerImpl::ProcessMessage(

// DoS prevention: do not allow m_orphans to grow unbounded (see CVE-2012-3789)
unsigned int nMaxOrphanTxSize = (unsigned int)std::max((int64_t)0, gArgs.GetIntArg("-maxorphantxsize", DEFAULT_MAX_ORPHAN_TRANSACTIONS_SIZE)) * 1000000;
unsigned int nEvicted = m_orphanage.LimitOrphans(nMaxOrphanTxSize);
if (nEvicted > 0) {
LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted);
}
m_orphanage.LimitOrphans(nMaxOrphanTxSize);
} else {
LogPrint(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
// We will continue to reject this tx since it has rejected
Expand Down
4 changes: 2 additions & 2 deletions src/qt/test/wallettests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,14 @@ void TestGUI(interfaces::Node& node)
if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
CTxDestination dest = PKHash(test.coinbaseKey.GetPubKey());
wallet->SetAddressBook(dest, "", "receive");
wallet->SetLastBlockProcessed(105, node.context()->chainman->ActiveChain().Tip()->GetBlockHash());
wallet->SetLastBlockProcessed(105, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
}
{
WalletRescanReserver reserver(*wallet);
reserver.reserve();
CWallet::ScanResult result = wallet->ScanForWalletTransactions(Params().GetConsensus().hashGenesisBlock, 0 /* start_height */, {} /* max_height */, reserver, true /* fUpdate */);
QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
QCOMPARE(result.last_scanned_block, node.context()->chainman->ActiveChain().Tip()->GetBlockHash());
QCOMPARE(result.last_scanned_block, WITH_LOCK(node.context()->chainman->GetMutex(), return node.context()->chainman->ActiveChain().Tip()->GetBlockHash()));
QVERIFY(result.last_failed_block.IsNull());
}
wallet->SetBroadcastTransactions(true);
Expand Down
14 changes: 9 additions & 5 deletions src/rest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,14 +809,18 @@ static bool rest_getutxos(const CoreContext& context, HTTPRequest* req, const st
ChainstateManager* maybe_chainman = GetChainman(context, req);
if (!maybe_chainman) return false;
ChainstateManager& chainman = *maybe_chainman;
decltype(chainman.ActiveHeight()) active_height;
uint256 active_hash;
{
auto process_utxos = [&vOutPoints, &outs, &hits](const CCoinsView& view, const CTxMemPool& mempool) {
auto process_utxos = [&vOutPoints, &outs, &hits, &active_height, &active_hash, &chainman](const CCoinsView& view, const CTxMemPool& mempool) EXCLUSIVE_LOCKS_REQUIRED(chainman.GetMutex()) {
for (const COutPoint& vOutPoint : vOutPoints) {
Coin coin;
bool hit = !mempool.isSpent(vOutPoint) && view.GetCoin(vOutPoint, coin);
hits.push_back(hit);
if (hit) outs.emplace_back(std::move(coin));
}
active_height = chainman.ActiveHeight();
active_hash = chainman.ActiveTip()->GetBlockHash();
};

if (fCheckMemPool) {
Expand Down Expand Up @@ -844,7 +848,7 @@ static bool rest_getutxos(const CoreContext& context, HTTPRequest* req, const st
// serialize data
// use exact same output as mentioned in Bip64
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
ssGetUTXOResponse << chainman.ActiveChain().Height() << chainman.ActiveChain().Tip()->GetBlockHash() << bitmap << outs;
ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();

req->WriteHeader("Content-Type", "application/octet-stream");
Expand All @@ -854,7 +858,7 @@ static bool rest_getutxos(const CoreContext& context, HTTPRequest* req, const st

case RetFormat::HEX: {
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
ssGetUTXOResponse << chainman.ActiveChain().Height() << chainman.ActiveChain().Tip()->GetBlockHash() << bitmap << outs;
ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
std::string strHex = HexStr(ssGetUTXOResponse) + "\n";

req->WriteHeader("Content-Type", "text/plain");
Expand All @@ -867,8 +871,8 @@ static bool rest_getutxos(const CoreContext& context, HTTPRequest* req, const st

// pack in some essentials
// use more or less the same output as mentioned in Bip64
objGetUTXOResponse.pushKV("chainHeight", chainman.ActiveChain().Height());
objGetUTXOResponse.pushKV("chaintipHash", chainman.ActiveChain().Tip()->GetBlockHash().GetHex());
objGetUTXOResponse.pushKV("chainHeight", active_height);
objGetUTXOResponse.pushKV("chaintipHash", active_hash.GetHex());
objGetUTXOResponse.pushKV("bitmap", bitmapStringRepresentation);

UniValue utxos(UniValue::VARR);
Expand Down
6 changes: 5 additions & 1 deletion src/test/interfaces_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ BOOST_FIXTURE_TEST_SUITE(interfaces_tests, TestChain100Setup)

BOOST_AUTO_TEST_CASE(findBlock)
{
LOCK(Assert(m_node.chainman)->GetMutex());
auto& chain = m_node.chain;
const CChain& active = Assert(m_node.chainman)->ActiveChain();

Expand Down Expand Up @@ -61,6 +62,7 @@ BOOST_AUTO_TEST_CASE(findBlock)

BOOST_AUTO_TEST_CASE(findFirstBlockWithTimeAndHeight)
{
LOCK(Assert(m_node.chainman)->GetMutex());
auto& chain = m_node.chain;
const CChain& active = Assert(m_node.chainman)->ActiveChain();
uint256 hash;
Expand All @@ -73,6 +75,7 @@ BOOST_AUTO_TEST_CASE(findFirstBlockWithTimeAndHeight)

BOOST_AUTO_TEST_CASE(findAncestorByHeight)
{
LOCK(Assert(m_node.chainman)->GetMutex());
auto& chain = m_node.chain;
const CChain& active = Assert(m_node.chainman)->ActiveChain();
uint256 hash;
Expand All @@ -83,6 +86,7 @@ BOOST_AUTO_TEST_CASE(findAncestorByHeight)

BOOST_AUTO_TEST_CASE(findAncestorByHash)
{
LOCK(Assert(m_node.chainman)->GetMutex());
auto& chain = m_node.chain;
const CChain& active = Assert(m_node.chainman)->ActiveChain();
int height = -1;
Expand All @@ -94,7 +98,7 @@ BOOST_AUTO_TEST_CASE(findAncestorByHash)
BOOST_AUTO_TEST_CASE(findCommonAncestor)
{
auto& chain = m_node.chain;
const CChain& active = Assert(m_node.chainman)->ActiveChain();
const CChain& active = WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return Assert(m_node.chainman)->ActiveChain());
auto* orig_tip = active.Tip();
for (int i = 0; i < 10; ++i) {
BlockValidationState state;
Expand Down
4 changes: 2 additions & 2 deletions src/test/validation_block_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)

// Run the test multiple times
for (int test_runs = 3; test_runs > 0; --test_runs) {
BOOST_CHECK_EQUAL(last_mined->GetHash(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
BOOST_CHECK_EQUAL(last_mined->GetHash(), WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain().Tip()->GetBlockHash()));

// Later on split from here
const uint256 split_hash{last_mined->hashPrevBlock};
Expand Down Expand Up @@ -320,7 +320,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
ProcessBlock(b);
}
// Check that the reorg was eventually successful
BOOST_CHECK_EQUAL(last_mined->GetHash(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
BOOST_CHECK_EQUAL(last_mined->GetHash(), WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain().Tip()->GetBlockHash()));

// We can join the other thread, which returns when the reorg was successful
rpc_thread.join();
Expand Down
16 changes: 8 additions & 8 deletions src/test/validation_chainstatemanager_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
auto all = manager.GetAll();
BOOST_CHECK_EQUAL_COLLECTIONS(all.begin(), all.end(), chainstates.begin(), chainstates.end());

auto& active_chain = manager.ActiveChain();
auto& active_chain = WITH_LOCK(manager.GetMutex(), return manager.ActiveChain());
BOOST_CHECK_EQUAL(&active_chain, &c1.m_chain);

BOOST_CHECK_EQUAL(manager.ActiveHeight(), -1);
BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return manager.ActiveHeight()), -1);

auto active_tip = manager.ActiveTip();
auto active_tip = WITH_LOCK(manager.GetMutex(), return manager.ActiveTip());
auto exp_tip = c1.m_chain.Tip();
BOOST_CHECK_EQUAL(active_tip, exp_tip);

Expand Down Expand Up @@ -101,12 +101,12 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
auto all2 = manager.GetAll();
BOOST_CHECK_EQUAL_COLLECTIONS(all2.begin(), all2.end(), chainstates.begin(), chainstates.end());

auto& active_chain2 = manager.ActiveChain();
auto& active_chain2 = WITH_LOCK(manager.GetMutex(), return manager.ActiveChain());
BOOST_CHECK_EQUAL(&active_chain2, &c2.m_chain);

BOOST_CHECK_EQUAL(manager.ActiveHeight(), 0);
BOOST_CHECK_EQUAL(WITH_LOCK(manager.GetMutex(), return manager.ActiveHeight()), 0);

auto active_tip2 = manager.ActiveTip();
auto active_tip2 = WITH_LOCK(manager.GetMutex(), return manager.ActiveTip());
auto exp_tip2 = c2.m_chain.Tip();
BOOST_CHECK_EQUAL(active_tip2, exp_tip2);

Expand Down Expand Up @@ -259,7 +259,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
BOOST_CHECK(WITH_LOCK(::cs_main, return !chainman.ActiveChain().Genesis()->IsAssumedValid()));

const AssumeutxoData& au_data = *ExpectedAssumeutxo(snapshot_height, ::Params());
const CBlockIndex* tip = chainman.ActiveTip();
const CBlockIndex* tip = WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip());

BOOST_CHECK_EQUAL(tip->nChainTx, au_data.nChainTx);

Expand Down Expand Up @@ -358,7 +358,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
const int assumed_valid_start_idx = last_assumed_valid_idx - expected_assumed_valid;

CBlockIndex* validated_tip{nullptr};
CBlockIndex* assumed_tip{chainman.ActiveChain().Tip()};
CBlockIndex* assumed_tip{WITH_LOCK(chainman.GetMutex(), return chainman.ActiveChain().Tip())};

auto reload_all_block_indexes = [&]() {
for (CChainState* cs : chainman.GetAll()) {
Expand Down
4 changes: 2 additions & 2 deletions src/txorphanage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ void TxOrphanage::EraseForPeer(NodeId peer)
if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer);
}

unsigned int TxOrphanage::LimitOrphans(unsigned int max_orphans_size)
void TxOrphanage::LimitOrphans(unsigned int max_orphans_size)
{
AssertLockHeld(g_cs_orphans);

Expand Down Expand Up @@ -142,7 +142,7 @@ unsigned int TxOrphanage::LimitOrphans(unsigned int max_orphans_size)
EraseTx(m_orphan_list[randompos]->first);
++nEvicted;
}
return nEvicted;
if (nEvicted > 0) LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted);
}

void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256>& orphan_work_set) const
Expand Down
2 changes: 1 addition & 1 deletion src/txorphanage.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class TxOrphanage {
void EraseForBlock(const CBlock& block) LOCKS_EXCLUDED(::g_cs_orphans);

/** Limit the orphanage to the given maximum */
unsigned int LimitOrphans(unsigned int max_orphans_size) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
void LimitOrphans(unsigned int max_orphans_size) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);

/** Add any orphans that list a particular tx as a parent into a peer's work set
* (ie orphans that may have found their final missing parent, and so should be reconsidered for the mempool) */
Expand Down
6 changes: 3 additions & 3 deletions src/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -959,9 +959,9 @@ class ChainstateManager

//! The most-work chain.
CChainState& ActiveChainstate() const;
CChain& ActiveChain() const { return ActiveChainstate().m_chain; }
int ActiveHeight() const { return ActiveChain().Height(); }
CBlockIndex* ActiveTip() const { return ActiveChain().Tip(); }
CChain& ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChainstate().m_chain; }
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Height(); }
CBlockIndex* ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Tip(); }

BlockMap& BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
Expand Down
12 changes: 6 additions & 6 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,8 @@ static RPCHelpMan sendtoaddress()
{"use_is", RPCArg::Type::BOOL, RPCArg::Default{false}, "Deprecated and ignored"},
{"use_cj", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use CoinJoin funds only"},
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
" \"" + FeeModes("\"\n\"") + "\""},
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
"\"" + FeeModes("\"\n\"") + "\""},
{"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
" dirty if they have previously been used in a transaction."},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/B."},
Expand Down Expand Up @@ -795,8 +795,8 @@ static RPCHelpMan sendmany()
{"use_is", RPCArg::Type::BOOL, RPCArg::Default{false}, "Deprecated and ignored"},
{"use_cj", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use CoinJoin funds only"},
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
" \"" + FeeModes("\"\n\"") + "\""},
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
"\"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/B."},
{"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra infomration about the transaction."},
},
Expand Down Expand Up @@ -4112,8 +4112,8 @@ static RPCHelpMan send()
{"change_address", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The Dash address to receive the change"},
{"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
" \"" + FeeModes("\"\n\"") + "\""},
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
"\"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/B."},
{"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
"Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/test/spend_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ BOOST_FIXTURE_TEST_SUITE(spend_tests, WalletTestingSetup)
BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
auto wallet = CreateSyncedWallet(*m_node.chain, *m_node.coinjoin_loader, m_node.chainman->ActiveChain(), coinbaseKey);
auto wallet = CreateSyncedWallet(*m_node.chain, *m_node.coinjoin_loader, WITH_LOCK(Assert(m_node.chainman)->GetMutex(), return m_node.chainman->ActiveChain()), coinbaseKey);

// Check that a subtract-from-recipient transaction slightly less than the
// coinbase input amount does not create a change output (because it would
Expand Down
Loading
Loading