mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-09 10:43:19 -05:00
Fix logical race in rest_getutxos
Calling ActiveHeight() and ActiveTip() subsequently without holding the ::cs_main lock over both calls may result in a height that does not correspond to the tip due to a race. Fix this by holding the lock.
This commit is contained in:
parent
fa97a528d6
commit
fac15ff673
1 changed files with 9 additions and 5 deletions
14
src/rest.cpp
14
src/rest.cpp
|
@ -784,14 +784,18 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
|
||||||
ChainstateManager* maybe_chainman = GetChainman(context, req);
|
ChainstateManager* maybe_chainman = GetChainman(context, req);
|
||||||
if (!maybe_chainman) return false;
|
if (!maybe_chainman) return false;
|
||||||
ChainstateManager& chainman = *maybe_chainman;
|
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) {
|
for (const COutPoint& vOutPoint : vOutPoints) {
|
||||||
Coin coin;
|
Coin coin;
|
||||||
bool hit = (!mempool || !mempool->isSpent(vOutPoint)) && view.GetCoin(vOutPoint, coin);
|
bool hit = (!mempool || !mempool->isSpent(vOutPoint)) && view.GetCoin(vOutPoint, coin);
|
||||||
hits.push_back(hit);
|
hits.push_back(hit);
|
||||||
if (hit) outs.emplace_back(std::move(coin));
|
if (hit) outs.emplace_back(std::move(coin));
|
||||||
}
|
}
|
||||||
|
active_height = chainman.ActiveHeight();
|
||||||
|
active_hash = chainman.ActiveTip()->GetBlockHash();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (fCheckMemPool) {
|
if (fCheckMemPool) {
|
||||||
|
@ -819,7 +823,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
|
||||||
// serialize data
|
// serialize data
|
||||||
// use exact same output as mentioned in Bip64
|
// use exact same output as mentioned in Bip64
|
||||||
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
|
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();
|
std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
|
||||||
|
|
||||||
req->WriteHeader("Content-Type", "application/octet-stream");
|
req->WriteHeader("Content-Type", "application/octet-stream");
|
||||||
|
@ -829,7 +833,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
|
||||||
|
|
||||||
case RESTResponseFormat::HEX: {
|
case RESTResponseFormat::HEX: {
|
||||||
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
|
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";
|
std::string strHex = HexStr(ssGetUTXOResponse) + "\n";
|
||||||
|
|
||||||
req->WriteHeader("Content-Type", "text/plain");
|
req->WriteHeader("Content-Type", "text/plain");
|
||||||
|
@ -842,8 +846,8 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
|
||||||
|
|
||||||
// pack in some essentials
|
// pack in some essentials
|
||||||
// use more or less the same output as mentioned in Bip64
|
// use more or less the same output as mentioned in Bip64
|
||||||
objGetUTXOResponse.pushKV("chainHeight", chainman.ActiveChain().Height());
|
objGetUTXOResponse.pushKV("chainHeight", active_height);
|
||||||
objGetUTXOResponse.pushKV("chaintipHash", chainman.ActiveChain().Tip()->GetBlockHash().GetHex());
|
objGetUTXOResponse.pushKV("chaintipHash", active_hash.GetHex());
|
||||||
objGetUTXOResponse.pushKV("bitmap", bitmapStringRepresentation);
|
objGetUTXOResponse.pushKV("bitmap", bitmapStringRepresentation);
|
||||||
|
|
||||||
UniValue utxos(UniValue::VARR);
|
UniValue utxos(UniValue::VARR);
|
||||||
|
|
Loading…
Add table
Reference in a new issue