Skip to content

Commit 7317e14

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#22263: refactor: wrap CCoinsViewCursor in unique_ptr
7ad414f doc: add comment about CCoinsViewDBCursor constructor (James O'Beirne) 0f8a5a4 move-only(ish): don't expose CCoinsViewDBCursor (James O'Beirne) 615c1ad refactor: wrap CCoinsViewCursor in unique_ptr (James O'Beirne) Pull request description: I tripped over this one for a few hours at the beginning of the week, so I've sort of got a personal vendetta against `CCoinsView::Cursor()` returning a raw pointer. Specifically in the case of CCoinsViewDB, if a raw cursor is allocated and not freed, a cryptic leveldb assertion failure occurs on CCoinsViewDB destruction (`Assertion 'dummy_versions_.next_ == &dummy_versions_' failed.`). This is a pretty simple change. Related to: bitcoin/bitcoin#21766 See also: google/leveldb#142 (comment) ACKs for top commit: MarcoFalke: review ACK 7ad414f 🔎 jonatack: re-ACK 7ad414f modulo suggestion ryanofsky: Code review ACK 7ad414f. Two new commits look good and thanks for clarifying constructor comment Tree-SHA512: 6471d03e2de674d84b1ea0d31e25f433d52aa1aa4996f7b4aab1bd02b6bc340b15e64cc8ea07bbefefa3b5da35384ca5400cc230434e787c30931b8574c672f9
2 parents c0e3093 + 7ad414f commit 7317e14

File tree

6 files changed

+37
-34
lines changed

6 files changed

+37
-34
lines changed

src/coins.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return f
1313
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
1414
std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
1515
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
16-
CCoinsViewCursor *CCoinsView::Cursor() const { return nullptr; }
16+
std::unique_ptr<CCoinsViewCursor> CCoinsView::Cursor() const { return nullptr; }
1717

1818
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const
1919
{
@@ -28,7 +28,7 @@ uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
2828
std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
2929
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
3030
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
31-
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
31+
std::unique_ptr<CCoinsViewCursor> CCoinsViewBacked::Cursor() const { return base->Cursor(); }
3232
size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
3333

3434
CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}

src/coins.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ class CCoinsView
180180
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
181181

182182
//! Get a cursor to iterate over the whole state
183-
virtual CCoinsViewCursor *Cursor() const;
183+
virtual std::unique_ptr<CCoinsViewCursor> Cursor() const;
184184

185185
//! As we use CCoinsViews polymorphically, have a virtual destructor
186186
virtual ~CCoinsView() {}
@@ -204,7 +204,7 @@ class CCoinsViewBacked : public CCoinsView
204204
std::vector<uint256> GetHeadBlocks() const override;
205205
void SetBackend(CCoinsView &viewIn);
206206
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
207-
CCoinsViewCursor *Cursor() const override;
207+
std::unique_ptr<CCoinsViewCursor> Cursor() const override;
208208
size_t EstimateSize() const override;
209209
};
210210

@@ -237,7 +237,7 @@ class CCoinsViewCache : public CCoinsViewBacked
237237
uint256 GetBestBlock() const override;
238238
void SetBestBlock(const uint256 &hashBlock);
239239
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
240-
CCoinsViewCursor* Cursor() const override {
240+
std::unique_ptr<CCoinsViewCursor> Cursor() const override {
241241
throw std::logic_error("CCoinsViewCache cursor iteration not supported.");
242242
}
243243

src/rpc/blockchain.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -2391,7 +2391,7 @@ static RPCHelpMan scantxoutset()
23912391
LOCK(cs_main);
23922392
CChainState& active_chainstate = chainman.ActiveChainstate();
23932393
active_chainstate.ForceFlushStateToDisk();
2394-
pcursor = std::unique_ptr<CCoinsViewCursor>(active_chainstate.CoinsDB().Cursor());
2394+
pcursor = active_chainstate.CoinsDB().Cursor();
23952395
CHECK_NONFATAL(pcursor);
23962396
tip = active_chainstate.m_chain.Tip();
23972397
CHECK_NONFATAL(tip);
@@ -2590,7 +2590,7 @@ UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFil
25902590
throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
25912591
}
25922592

2593-
pcursor = std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor());
2593+
pcursor = chainstate.CoinsDB().Cursor();
25942594
tip = chainstate.m_blockman.LookupBlockIndex(stats.hashBlock);
25952595
CHECK_NONFATAL(tip);
25962596
}

src/test/fuzz/coins_view.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
183183
}
184184

185185
{
186-
const CCoinsViewCursor* coins_view_cursor = backend_coins_view.Cursor();
187-
assert(coins_view_cursor == nullptr);
186+
std::unique_ptr<CCoinsViewCursor> coins_view_cursor = backend_coins_view.Cursor();
187+
assert(!coins_view_cursor);
188188
(void)backend_coins_view.EstimateSize();
189189
(void)backend_coins_view.GetBestBlock();
190190
(void)backend_coins_view.GetHeadBlocks();

src/txdb.cpp

+27-2
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,34 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
168168
return Read(DB_LAST_BLOCK, nFile);
169169
}
170170

171-
CCoinsViewCursor *CCoinsViewDB::Cursor() const
171+
/** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */
172+
class CCoinsViewDBCursor: public CCoinsViewCursor
172173
{
173-
CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper&>(*m_db).NewIterator(), GetBestBlock());
174+
public:
175+
// Prefer using CCoinsViewDB::Cursor() since we want to perform some
176+
// cache warmup on instantiation.
177+
CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256&hashBlockIn):
178+
CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
179+
~CCoinsViewDBCursor() {}
180+
181+
bool GetKey(COutPoint &key) const override;
182+
bool GetValue(Coin &coin) const override;
183+
unsigned int GetValueSize() const override;
184+
185+
bool Valid() const override;
186+
void Next() override;
187+
188+
private:
189+
std::unique_ptr<CDBIterator> pcursor;
190+
std::pair<char, COutPoint> keyTmp;
191+
192+
friend class CCoinsViewDB;
193+
};
194+
195+
std::unique_ptr<CCoinsViewCursor> CCoinsViewDB::Cursor() const
196+
{
197+
auto i = std::make_unique<CCoinsViewDBCursor>(
198+
const_cast<CDBWrapper&>(*m_db).NewIterator(), GetBestBlock());
174199
/* It seems that there are no "const iterators" for LevelDB. Since we
175200
only need read operations on it, use a const-cast to get around
176201
that restriction. */

src/txdb.h

+1-23
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class CCoinsViewDB final : public CCoinsView
6060
uint256 GetBestBlock() const override;
6161
std::vector<uint256> GetHeadBlocks() const override;
6262
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
63-
CCoinsViewCursor *Cursor() const override;
63+
std::unique_ptr<CCoinsViewCursor> Cursor() const override;
6464

6565
//! Attempt to update from an older database format. Returns whether an error occurred.
6666
bool Upgrade();
@@ -70,28 +70,6 @@ class CCoinsViewDB final : public CCoinsView
7070
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
7171
};
7272

73-
/** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */
74-
class CCoinsViewDBCursor: public CCoinsViewCursor
75-
{
76-
public:
77-
~CCoinsViewDBCursor() {}
78-
79-
bool GetKey(COutPoint &key) const override;
80-
bool GetValue(Coin &coin) const override;
81-
unsigned int GetValueSize() const override;
82-
83-
bool Valid() const override;
84-
void Next() override;
85-
86-
private:
87-
CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256 &hashBlockIn):
88-
CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
89-
std::unique_ptr<CDBIterator> pcursor;
90-
std::pair<char, COutPoint> keyTmp;
91-
92-
friend class CCoinsViewDB;
93-
};
94-
9573
/** Access to the block database (blocks/index/) */
9674
class CBlockTreeDB : public CDBWrapper
9775
{

0 commit comments

Comments
 (0)