Skip to content

Commit cf3ce8e

Browse files
committed
merge bitcoin#22626: Remove txindex migration code
1 parent b992e39 commit cf3ce8e

File tree

8 files changed

+49
-181
lines changed

8 files changed

+49
-181
lines changed

src/index/base.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66
#define BITCOIN_INDEX_BASE_H
77

88
#include <dbwrapper.h>
9-
#include <primitives/block.h>
10-
#include <primitives/transaction.h>
119
#include <threadinterrupt.h>
1210
#include <validationinterface.h>
1311

1412
#include <atomic>
1513

14+
class CBlock;
1615
class CBlockIndex;
1716
class CChainState;
1817

src/index/txindex.cpp

Lines changed: 2 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,14 @@
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

5-
#include <index/disktxpos.h>
65
#include <index/txindex.h>
6+
7+
#include <index/disktxpos.h>
78
#include <node/blockstorage.h>
8-
#include <node/ui_interface.h>
9-
#include <shutdown.h>
109
#include <util/system.h>
11-
#include <util/translation.h>
1210
#include <validation.h>
1311

14-
constexpr uint8_t DB_BEST_BLOCK{'B'};
1512
constexpr uint8_t DB_TXINDEX{'t'};
16-
constexpr uint8_t DB_TXINDEX_BLOCK{'T'};
1713

1814
std::unique_ptr<TxIndex> g_txindex;
1915

@@ -30,10 +26,6 @@ class TxIndex::DB : public BaseIndex::DB
3026

3127
/// Write a batch of transaction positions to the DB.
3228
bool WriteTxs(const std::vector<std::pair<uint256, CDiskTxPos>>& v_pos);
33-
34-
/// Migrate txindex data from the block tree DB, where it may be for older nodes that have not
35-
/// been upgraded yet to the new database.
36-
bool MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator& best_locator);
3729
};
3830

3931
TxIndex::DB::DB(size_t n_cache_size, bool f_memory, bool f_wipe) :
@@ -54,163 +46,12 @@ bool TxIndex::DB::WriteTxs(const std::vector<std::pair<uint256, CDiskTxPos>>& v_
5446
return WriteBatch(batch);
5547
}
5648

57-
/*
58-
* Safely persist a transfer of data from the old txindex database to the new one, and compact the
59-
* range of keys updated. This is used internally by MigrateData.
60-
*/
61-
static void WriteTxIndexMigrationBatches(CDBWrapper& newdb, CDBWrapper& olddb,
62-
CDBBatch& batch_newdb, CDBBatch& batch_olddb,
63-
const std::pair<uint8_t, uint256>& begin_key,
64-
const std::pair<uint8_t, uint256>& end_key)
65-
{
66-
// Sync new DB changes to disk before deleting from old DB.
67-
newdb.WriteBatch(batch_newdb, /*fSync=*/ true);
68-
olddb.WriteBatch(batch_olddb);
69-
olddb.CompactRange(begin_key, end_key);
70-
71-
batch_newdb.Clear();
72-
batch_olddb.Clear();
73-
}
74-
75-
bool TxIndex::DB::MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator& best_locator)
76-
{
77-
// The prior implementation of txindex was always in sync with block index
78-
// and presence was indicated with a boolean DB flag. If the flag is set,
79-
// this means the txindex from a previous version is valid and in sync with
80-
// the chain tip. The first step of the migration is to unset the flag and
81-
// write the chain hash to a separate key, DB_TXINDEX_BLOCK. After that, the
82-
// index entries are copied over in batches to the new database. Finally,
83-
// DB_TXINDEX_BLOCK is erased from the old database and the block hash is
84-
// written to the new database.
85-
//
86-
// Unsetting the boolean flag ensures that if the node is downgraded to a
87-
// previous version, it will not see a corrupted, partially migrated index
88-
// -- it will see that the txindex is disabled. When the node is upgraded
89-
// again, the migration will pick up where it left off and sync to the block
90-
// with hash DB_TXINDEX_BLOCK.
91-
bool f_legacy_flag = false;
92-
block_tree_db.ReadFlag("txindex", f_legacy_flag);
93-
if (f_legacy_flag) {
94-
if (!block_tree_db.Write(DB_TXINDEX_BLOCK, best_locator)) {
95-
return error("%s: cannot write block indicator", __func__);
96-
}
97-
if (!block_tree_db.WriteFlag("txindex", false)) {
98-
return error("%s: cannot write block index db flag", __func__);
99-
}
100-
}
101-
102-
CBlockLocator locator;
103-
if (!block_tree_db.Read(DB_TXINDEX_BLOCK, locator)) {
104-
return true;
105-
}
106-
107-
int64_t count = 0;
108-
LogPrintf("Upgrading txindex database... [0%%]\n");
109-
uiInterface.ShowProgress(_("Upgrading txindex database").translated, 0, true);
110-
int report_done = 0;
111-
const size_t batch_size = 1 << 24; // 16 MiB
112-
113-
CDBBatch batch_newdb(*this);
114-
CDBBatch batch_olddb(block_tree_db);
115-
116-
std::pair<uint8_t, uint256> key;
117-
std::pair<uint8_t, uint256> begin_key{DB_TXINDEX, uint256()};
118-
std::pair<uint8_t, uint256> prev_key = begin_key;
119-
120-
bool interrupted = false;
121-
std::unique_ptr<CDBIterator> cursor(block_tree_db.NewIterator());
122-
for (cursor->Seek(begin_key); cursor->Valid(); cursor->Next()) {
123-
if (ShutdownRequested()) {
124-
interrupted = true;
125-
break;
126-
}
127-
128-
if (!cursor->GetKey(key)) {
129-
return error("%s: cannot get key from valid cursor", __func__);
130-
}
131-
if (key.first != DB_TXINDEX) {
132-
break;
133-
}
134-
135-
// Log progress every 10%.
136-
if (++count % 256 == 0) {
137-
// Since txids are uniformly random and traversed in increasing order, the high 16 bits
138-
// of the hash can be used to estimate the current progress.
139-
const uint256& txid = key.second;
140-
uint32_t high_nibble =
141-
(static_cast<uint32_t>(*(txid.begin() + 0)) << 8) +
142-
(static_cast<uint32_t>(*(txid.begin() + 1)) << 0);
143-
int percentage_done = (int)(high_nibble * 100.0 / 65536.0 + 0.5);
144-
145-
uiInterface.ShowProgress(_("Upgrading txindex database").translated, percentage_done, true);
146-
if (report_done < percentage_done/10) {
147-
LogPrintf("Upgrading txindex database... [%d%%]\n", percentage_done);
148-
report_done = percentage_done/10;
149-
}
150-
}
151-
152-
CDiskTxPos value;
153-
if (!cursor->GetValue(value)) {
154-
return error("%s: cannot parse txindex record", __func__);
155-
}
156-
batch_newdb.Write(key, value);
157-
batch_olddb.Erase(key);
158-
159-
if (batch_newdb.SizeEstimate() > batch_size || batch_olddb.SizeEstimate() > batch_size) {
160-
// NOTE: it's OK to delete the key pointed at by the current DB cursor while iterating
161-
// because LevelDB iterators are guaranteed to provide a consistent view of the
162-
// underlying data, like a lightweight snapshot.
163-
WriteTxIndexMigrationBatches(*this, block_tree_db,
164-
batch_newdb, batch_olddb,
165-
prev_key, key);
166-
prev_key = key;
167-
}
168-
}
169-
170-
// If these final DB batches complete the migration, write the best block
171-
// hash marker to the new database and delete from the old one. This signals
172-
// that the former is fully caught up to that point in the blockchain and
173-
// that all txindex entries have been removed from the latter.
174-
if (!interrupted) {
175-
batch_olddb.Erase(DB_TXINDEX_BLOCK);
176-
batch_newdb.Write(DB_BEST_BLOCK, locator);
177-
}
178-
179-
WriteTxIndexMigrationBatches(*this, block_tree_db,
180-
batch_newdb, batch_olddb,
181-
begin_key, key);
182-
183-
if (interrupted) {
184-
LogPrintf("[CANCELLED].\n");
185-
return false;
186-
}
187-
188-
uiInterface.ShowProgress("", 100, false);
189-
190-
LogPrintf("[DONE].\n");
191-
return true;
192-
}
193-
19449
TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
19550
: m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
19651
{}
19752

19853
TxIndex::~TxIndex() {}
19954

200-
bool TxIndex::Init()
201-
{
202-
LOCK(cs_main);
203-
204-
// Attempt to migrate txindex from the old database to the new one. Even if
205-
// chain_tip is null, the node could be reindexing and we still want to
206-
// delete txindex records in the old database.
207-
if (!m_db->MigrateData(*m_chainstate->m_blockman.m_block_tree_db, m_chainstate->m_chain.GetLocator())) {
208-
return false;
209-
}
210-
211-
return BaseIndex::Init();
212-
}
213-
21455
bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
21556
{
21657
// Exclude genesis block transaction because outputs are not spendable.

src/index/txindex.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
#ifndef BITCOIN_INDEX_TXINDEX_H
66
#define BITCOIN_INDEX_TXINDEX_H
77

8-
#include <chain.h>
98
#include <index/base.h>
10-
#include <txdb.h>
119

1210
/**
1311
* TxIndex is used to look up transactions included in the blockchain by hash.
@@ -23,9 +21,6 @@ class TxIndex final : public BaseIndex
2321
const std::unique_ptr<DB> m_db;
2422

2523
protected:
26-
/// Override base class init to migrate from old database.
27-
bool Init() override;
28-
2924
bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
3025

3126
BaseIndex::DB& GetDB() const override;

src/init.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,6 +2199,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
21992199

22002200
// ********************************************************* Step 8: start indexers
22012201
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
2202+
LOCK(::cs_main);
2203+
if (const auto error{CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db))}) {
2204+
return InitError(*error);
2205+
}
2206+
22022207
g_txindex = std::make_unique<TxIndex>(nTxIndexCache, false, fReindex);
22032208
if (!g_txindex->Start(chainman.ActiveChainstate())) {
22042209
return false;

src/txdb.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <txdb.h>
77

8+
#include <chain.h>
89
#include <node/ui_interface.h>
910
#include <pow.h>
1011
#include <random.h>
@@ -31,6 +32,28 @@ static constexpr uint8_t DB_FLAG{'F'};
3132
static constexpr uint8_t DB_REINDEX_FLAG{'R'};
3233
static constexpr uint8_t DB_LAST_BLOCK{'l'};
3334

35+
// Keys used in previous version that might still be found in the DB:
36+
static constexpr uint8_t DB_TXINDEX_BLOCK{'T'};
37+
// uint8_t DB_TXINDEX{'t'}
38+
39+
std::optional<bilingual_str> CheckLegacyTxindex(CBlockTreeDB& block_tree_db)
40+
{
41+
CBlockLocator ignored{};
42+
if (block_tree_db.Read(DB_TXINDEX_BLOCK, ignored)) {
43+
return _("The -txindex upgrade started by a previous version can not be completed. Restart with the previous version or run a full -reindex.");
44+
}
45+
bool txindex_legacy_flag{false};
46+
block_tree_db.ReadFlag("txindex", txindex_legacy_flag);
47+
if (txindex_legacy_flag) {
48+
// Disable legacy txindex and warn once about occupied disk space
49+
if (!block_tree_db.WriteFlag("txindex", false)) {
50+
return Untranslated("Failed to write block index db flag 'txindex'='0'");
51+
}
52+
return _("The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.");
53+
}
54+
return std::nullopt;
55+
}
56+
3457
namespace {
3558

3659
struct CoinEntry {

src/txdb.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,22 @@
88

99
#include <coins.h>
1010
#include <dbwrapper.h>
11-
#include <chain.h>
12-
#include <primitives/block.h>
1311
#include <spentindex.h>
1412
#include <timestampindex.h>
1513

1614
#include <memory>
15+
#include <optional>
1716
#include <string>
1817
#include <utility>
1918
#include <vector>
2019

20+
class CBlockFileInfo;
2121
class CBlockIndex;
22-
class CCoinsViewDBCursor;
2322
class uint256;
23+
namespace Consensus {
24+
struct Params;
25+
};
26+
struct bilingual_str;
2427

2528
//! -dbcache default (MiB)
2629
static const int64_t nDefaultDbCache = 300;
@@ -108,4 +111,6 @@ class CBlockTreeDB : public CDBWrapper
108111
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
109112
};
110113

114+
std::optional<bilingual_str> CheckLegacyTxindex(CBlockTreeDB& block_tree_db);
115+
111116
#endif // BITCOIN_TXDB_H

src/validation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ bool CheckFinalTx(const CBlockIndex* active_chain_tip, const CTransaction &tx, i
155155

156156
// CheckFinalTx() uses active_chain_tip.Height()+1 to evaluate
157157
// nLockTime because when IsFinalTx() is called within
158-
// CBlock::AcceptBlock(), the height of the block *being*
158+
// AcceptBlock(), the height of the block *being*
159159
// evaluated is what is used. Thus if we want to know if a
160160
// transaction can be part of the *next* block, we need to call
161161
// IsFinalTx() with one more than active_chain_tip.Height().

src/validation.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,19 @@
1212
#endif
1313

1414
#include <amount.h>
15+
#include <arith_uint256.h>
1516
#include <attributes.h>
1617
#include <chain.h>
1718
#include <fs.h>
1819
#include <node/blockstorage.h>
1920
#include <policy/feerate.h>
2021
#include <policy/packages.h>
2122
#include <script/script_error.h>
23+
#include <serialize.h>
2224
#include <sync.h>
2325
#include <txdb.h>
2426
#include <txmempool.h> // For CTxMemPool::cs
25-
#include <serialize.h>
27+
#include <uint256.h>
2628
#include <util/check.h>
2729
#include <util/hasher.h>
2830
#include <util/translation.h>
@@ -38,17 +40,10 @@
3840
#include <utility>
3941
#include <vector>
4042

41-
namespace llmq {
42-
class CChainLocksHandler;
43-
class CInstantSendManager;
44-
} // namespace llmq
45-
46-
class CEvoDB;
47-
4843
class CChainState;
49-
class CBlockIndex;
5044
class CBlockTreeDB;
5145
class CChainParams;
46+
class CEvoDB;
5247
class CMNHFManager;
5348
class CTxMemPool;
5449
class TxValidationState;
@@ -61,6 +56,11 @@ struct DisconnectedBlockTransactions;
6156
struct LockPoints;
6257
struct AssumeutxoData;
6358

59+
namespace llmq {
60+
class CChainLocksHandler;
61+
class CInstantSendManager;
62+
} // namespace llmq
63+
6464
/** Default for -minrelaytxfee, minimum relay fee for transactions */
6565
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;
6666
/** Default for -limitancestorcount, max number of in-mempool ancestors */

0 commit comments

Comments
 (0)