move txindex back to its own thread

This commit is contained in:
Brannon King 2020-03-10 15:08:59 -06:00 committed by Anthony Fieroni
parent 10a898607f
commit 3fd448e552
16 changed files with 292 additions and 95 deletions

View file

@ -139,6 +139,7 @@ BITCOIN_CORE_H = \
httpserver.h \
index/base.h \
index/blockfilterindex.h \
index/txindex.h \
indirectmap.h \
init.h \
interfaces/chain.h \
@ -279,6 +280,7 @@ libbitcoin_server_a_SOURCES = \
httpserver.cpp \
index/base.cpp \
index/blockfilterindex.cpp \
index/txindex.cpp \
interfaces/chain.cpp \
interfaces/node.cpp \
init.cpp \

View file

@ -149,6 +149,7 @@ BITCOIN_TESTS =\
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
test/txindex_tests.cpp \
test/txvalidation_tests.cpp \
test/txvalidationcache_tests.cpp \
test/uint256_tests.cpp \

View file

@ -12,6 +12,8 @@
#include <validation.h>
#include <warnings.h>
#include <chrono>
constexpr int64_t SYNC_LOG_INTERVAL = 30; // seconds
constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL = 30; // seconds
@ -105,6 +107,7 @@ static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev) EXCLUSIV
void BaseIndex::ThreadSync()
{
auto start = std::chrono::high_resolution_clock::now();
const CBlockIndex* pindex = m_best_block_index.load();
if (!m_synced) {
auto& consensus_params = Params().GetConsensus();
@ -172,10 +175,11 @@ void BaseIndex::ThreadSync()
}
}
auto done = 1e-9 * std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - start).count();
if (pindex) {
LogPrintf("%s is enabled at height %d\n", GetName(), pindex->nHeight);
LogPrintf("%s is enabled at height %d. Indexing time: %f sec.\n", GetName(), pindex->nHeight, done);
} else {
LogPrintf("%s is enabled\n", GetName());
LogPrintf("%s is enabled. Indexing time: %f sec.\n", GetName(), done);
}
}
@ -209,7 +213,7 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
// In the case of a reorg, ensure persisted block locator is not stale.
m_best_block_index = new_tip;
if (!Commit()) {
if (!CommitInternal()) {
// If commit fails, revert the best block index to avoid corruption.
m_best_block_index = current_tip;
return false;

View file

@ -60,7 +60,7 @@ BlockFilterIndex::BlockFilterIndex(BlockFilterType filter_type,
(*m_db) << "CREATE TABLE IF NOT EXISTS block (height INTEGER, hash BLOB NOT NULL COLLATE BINARY, "
"filter_hash BLOB NOT NULL COLLATE BINARY, header BLOB NOT NULL COLLATE BINARY, "
"file INTEGER NOT NULL, pos INTEGER NOT NULL, "
"PRIMARY KEY(height, hash), UNIQUE(filter_hash, header, file, pos));";
"PRIMARY KEY(height, hash));";
(*m_db) << "CREATE TABLE IF NOT EXISTS file_pos (file INTEGER NOT NULL, pos INTEGER NOT NULL);";
@ -214,7 +214,7 @@ bool BlockFilterIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex
const auto filterHash = filter.GetHash(); // trying to avoid temps
const auto filterHeader = filter.ComputeHeader(prev_header);
(*m_db) << "INSERT INTO block VALUES(?, ?, ?, ?, ?, ?)"
(*m_db) << "INSERT OR REPLACE INTO block VALUES(?, ?, ?, ?, ?, ?)"
<< pindex->nHeight
<< pindex->hash
<< filterHash

85
src/index/txindex.cpp Normal file
View file

@ -0,0 +1,85 @@
// Copyright (c) 2017-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <clientversion.h>
#include <index/txindex.h>
#include <streams.h>
#include <ui_interface.h>
#include <util/system.h>
#include <validation.h>
std::unique_ptr<TxIndex> g_txindex;
/**
* Access to the txindex database (indexes/txindex/)
*
* The database stores a block locator of the chain the database is synced to
* so that the TxIndex can efficiently determine the point it last stopped at.
* A locator is used instead of a simple hash of the chain tip because blocks
* and block index entries may not be flushed to disk until after this database
* is updated.
*/
TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
: m_db(MakeUnique<BaseIndex::DB>(GetDataDir() / "txindex", n_cache_size, f_memory, f_wipe))
{
(*m_db) << "CREATE TABLE IF NOT EXISTS tx_to_block ("
"txID BLOB NOT NULL PRIMARY KEY, "
"file INTEGER NOT NULL, "
"blockPos INTEGER NOT NULL, "
"txPos INTEGER NOT NULL)";
if (f_wipe)
(*m_db) << "DELETE FROM tx_to_block";
}
bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
{
// Exclude genesis block transaction because outputs are not spendable.
if (pindex->nHeight == 0) return true;
// transaction is begin and commited in the caller of this method
auto query = (*m_db) << "INSERT OR REPLACE INTO tx_to_block VALUES(?,?,?,?)";
auto pos = pindex->GetBlockPos();
std::size_t offset = ::GetSizeOfCompactSize(block.vtx.size());
for (const auto& tx : block.vtx) {
query << tx->GetHash() << pos.nFile << pos.nPos << offset;
query++;
offset += ::GetSerializeSize(*tx, CLIENT_VERSION);
}
query.used(true);
return true;
}
bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRef& tx) const
{
FlatFilePos postx;
long txPos = 0;
{
auto query = (*m_db) << "SELECT file, blockPos, txPos FROM tx_to_block WHERE txID = ?" << tx_hash;
auto it = query.begin();
if (it == query.end())
return false;
*it >> postx.nFile >> postx.nPos >> txPos;
}
CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
if (file.IsNull()) {
return error("%s: OpenBlockFile failed", __func__);
}
CBlockHeader header;
try {
file >> header;
if (txPos > 0 && fseek(file.Get(), txPos, SEEK_CUR)) {
return error("%s: fseek(...) failed", __func__);
}
file >> tx;
} catch (const std::exception& e) {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
if (tx->GetHash() != tx_hash) {
return error("%s: txid mismatch", __func__);
}
block_hash = header.GetHash();
return true;
}

47
src/index/txindex.h Normal file
View file

@ -0,0 +1,47 @@
// Copyright (c) 2017-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_INDEX_TXINDEX_H
#define BITCOIN_INDEX_TXINDEX_H
#include <chain.h>
#include <index/base.h>
#include <txdb.h>
/**
* TxIndex is used to look up transactions included in the blockchain by hash.
* The index is written to a LevelDB database and records the filesystem
* location of each transaction by transaction hash.
*/
class TxIndex final : public BaseIndex
{
const std::unique_ptr<BaseIndex::DB> m_db;
protected:
bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
BaseIndex::DB& GetDB() const override { return *m_db; }
const char* GetName() const override { return "txindex"; }
public:
/// Constructs the index, which becomes available to be queried.
explicit TxIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
// Destructor is declared because this class contains a unique_ptr to an incomplete type.
virtual ~TxIndex() override = default;
/// Look up a transaction by hash.
///
/// @param[in] tx_hash The hash of the transaction to be returned.
/// @param[out] block_hash The hash of the block the transaction is found in.
/// @param[out] tx The transaction itself.
/// @return true if transaction is found, false otherwise
bool FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRef& tx) const;
};
/// The global transaction index, used in GetTransaction. May be null.
extern std::unique_ptr<TxIndex> g_txindex;
#endif // BITCOIN_INDEX_TXINDEX_H

View file

@ -24,6 +24,7 @@
#include <httprpc.h>
#include <httpserver.h>
#include <index/blockfilterindex.h>
#include <index/txindex.h>
#include <interfaces/chain.h>
#include <key.h>
#include <lbry.h>
@ -168,6 +169,8 @@ void Interrupt()
InterruptMapPort();
if (g_connman)
g_connman->Interrupt();
if (g_txindex)
g_txindex->Interrupt();
ForEachBlockFilterIndex([](BlockFilterIndex& index) { index.Interrupt(); });
}
@ -245,7 +248,10 @@ void Shutdown(InitInterfaces& interfaces)
GetMainSignals().FlushBackgroundCallbacks();
// Stop and delete all indexes only after flushing background callbacks.
ForEachBlockFilterIndex([](BlockFilterIndex& index) { index.Stop(); });
if (g_txindex) {
g_txindex->Stop();
g_txindex.reset();
}ForEachBlockFilterIndex([](BlockFilterIndex& index) { index.Stop(); });
DestroyAllBlockFilterIndexes();
// Any future callbacks will be dropped. This should absolutely be safe - if
@ -385,7 +391,7 @@ void SetupServerArgs()
-GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-pid=<file>", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -rescan. "
gArgs.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -rescan and -txindex. "
"Warning: Reverting this setting requires re-downloading the entire blockchain. "
"(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-reindex", "Rebuild chain state and block index from the blk*.dat files on disk", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@ -395,6 +401,7 @@ void SetupServerArgs()
#else
hidden_args.emplace_back("-sysperms");
#endif
gArgs.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
gArgs.AddArg("-blockfilterindex=<type>",
strprintf("Maintain an index of compact filters by block (default: %s, values: %s).", DEFAULT_BLOCKFILTERINDEX, ListBlockFilterTypes()) +
" If <type> is not supplied or if <type> = 1, indexes for all known types are enabled.",
@ -856,6 +863,9 @@ void InitLogging()
version_string += " (release build)";
#endif
LogPrintf(PACKAGE_NAME " version %s\n", version_string);
if (LogInstance().Enabled() && LogAcceptCategory(BCLog::CLAIMS))
CLogPrint::global().setLogger(&LogInstance());
}
namespace { // Variables internal to initialization process only
@ -963,6 +973,8 @@ bool AppInitParameterInteraction()
}
if (gArgs.GetArg("-prune", 0)) {
if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX))
return InitError(_("Prune mode is incompatible with -txindex.").translated);
if (!g_enabled_filter_types.empty()) {
return InitError(_("Prune mode is incompatible with -blockfilterindex.").translated);
}
@ -1254,9 +1266,6 @@ bool AppInitMain(InitInterfaces& interfaces)
}
);
if (LogInstance().Enabled() && LogAcceptCategory(BCLog::CLAIMS))
CLogPrint::global().setLogger(&LogInstance());
InitSignatureCache();
InitScriptExecutionCache();
@ -1438,17 +1447,19 @@ bool AppInitMain(InitInterfaces& interfaces)
// the coin cache, the block cache, the claimtrie cache
// however, we want the claimtrie cache to be larger than the others
int64_t nBlockTreeDBCache = std::min(nTotalCache / 4, nMaxBlockDBCache << 20);
int64_t nBlockTreeDBCache = std::min(nTotalCache / 5, nMaxBlockDBCache << 20);
int64_t nCoinDBCache = std::min(nTotalCache / 4, nMaxCoinsDBCache << 20);
int64_t nClaimtrieCache = ::Claimtrie().cache();
nTotalCache -= nBlockTreeDBCache;
int64_t nTxIndexCache = std::min(nTotalCache / 4, gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? int64_t(1 << 24) : 0);
int64_t filter_index_cache = 0;
if (!g_enabled_filter_types.empty()) {
size_t n_indexes = g_enabled_filter_types.size();
int64_t max_cache = std::min(nTotalCache / 8, max_filter_index_cache << 20);
int64_t max_cache = std::min(nTotalCache / 4, max_filter_index_cache << 20);
filter_index_cache = max_cache / n_indexes;
nTotalCache -= filter_index_cache * n_indexes;
}
nTotalCache -= nCoinDBCache;
nTotalCache -= nClaimtrieCache;
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
@ -1458,6 +1469,8 @@ bool AppInitMain(InitInterfaces& interfaces)
LogPrintf("* Using %.1fMiB for block index database cache\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1fMiB for chain state database cache\n", nCoinDBCache * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1fMiB for claimtrie database cache\n", nClaimtrieCache * (1.0 / 1024 / 1024));
if (nTxIndexCache)
LogPrintf("* Using %.1fMiB for txindex database cache\n", nTxIndexCache * (1.0 / 1024 / 1024));
for (BlockFilterType filter_type : g_enabled_filter_types) {
LogPrintf("* Using %.1f MiB for %s block filter index database\n",
filter_index_cache * (1.0 / 1024 / 1024), BlockFilterTypeName(filter_type));
@ -1671,7 +1684,8 @@ bool AppInitMain(InitInterfaces& interfaces)
// ********************************************************* Step 8: start indexers
if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
LogPrintf("The txindex parameter is no longer necessary. It is always on.\n");
g_txindex = MakeUnique<TxIndex>(nTxIndexCache, false, fReindex);
g_txindex->Start();
}
for (const auto& filter_type : g_enabled_filter_types) {

View file

@ -7,6 +7,7 @@
#include <chain.h>
#include <chainparams.h>
#include <core_io.h>
#include <index/txindex.h>
#include <httpserver.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
@ -358,6 +359,10 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
if (!ParseHashStr(hashStr, hash))
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
if (g_txindex) {
g_txindex->BlockUntilSyncedToCurrentChain();
}
CTransactionRef tx;
uint256 hashBlock = uint256();
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock))

View file

@ -8,6 +8,7 @@
#include <compat/byteswap.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <index/txindex.h>
#include <key_io.h>
#include <merkleblock.h>
#include <node/coin.h>
@ -178,6 +179,11 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
in_active_chain = ::ChainActive().Contains(blockindex);
}
bool f_txindex_ready = false;
if (g_txindex && !blockindex) {
f_txindex_ready = g_txindex->BlockUntilSyncedToCurrentChain();
}
CTransactionRef tx;
uint256 hash_block;
if (!GetTransaction(hash, tx, Params().GetConsensus(), hash_block, blockindex)) {
@ -187,6 +193,10 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
throw JSONRPCError(RPC_MISC_ERROR, "Block not available");
}
errmsg = "No such transaction found in the provided block";
} else if (!g_txindex) {
errmsg = "No such mempool transaction. Use -txindex or provide a block hash to enable blockchain transaction queries";
} else if (!f_txindex_ready) {
errmsg = "No such mempool transaction. Blockchain transactions are still in the process of being indexed";
} else {
errmsg = "No such mempool or blockchain transaction";
}
@ -259,6 +269,10 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
}
}
if (g_txindex && !pblockindex) {
g_txindex->BlockUntilSyncedToCurrentChain();
}
LOCK(cs_main);
if (pblockindex == nullptr)

View file

@ -33,6 +33,11 @@
#include <functional>
#ifdef BOOST_TEST_DYN_LINK // do not include in qt
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_parameters.hpp>
#endif
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
FastRandomContext g_insecure_rand_ctx;
@ -70,10 +75,20 @@ std::ostream& operator<<(std::ostream& os, const CSupportValue& support)
BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
: m_path_root(fs::temp_directory_path() / "test_common_" PACKAGE_TARNAME / strprintf("%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(1 << 30))))
{
gArgs.ForceSetArg("-printtoconsole", "0");
#ifdef BOOST_TEST_DYN_LINK // do not include in qt
// for debugging:
if (boost::unit_test::runtime_config::get<boost::unit_test::log_level>(boost::unit_test::runtime_config::btrt_log_level)
<= boost::unit_test::log_level::log_messages) {
gArgs.ForceSetArg("-printtoconsole", "1");
gArgs.ForceSetArg("-logtimemicros", "1");
LogInstance().EnableCategory(BCLog::ALL);
}
#endif
gArgs.ForceSetArg("-datadir", m_path_root.string());
ClearDatadirCache();
SelectParams(chainName);
gArgs.ForceSetArg("-printtoconsole", "0");
InitLogging();
LogInstance().StartLogging();
SHA256AutoDetect();

View file

@ -0,0 +1,76 @@
// Copyright (c) 2017-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
#include <index/txindex.h>
#include <script/standard.h>
#include <test/setup_common.h>
#include <util/time.h>
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(txindex_tests)
BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
{
TxIndex txindex(1 << 20, true);
CTransactionRef tx_disk;
uint256 block_hash;
// Transaction should not be found in the index before it is started.
for (const auto& txn : m_coinbase_txns) {
BOOST_CHECK(!txindex.FindTx(txn.GetHash(), block_hash, tx_disk));
}
// BlockUntilSyncedToCurrentChain should return false before txindex is started.
BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain());
txindex.Start();
// Allow tx index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000;
int64_t time_start = GetTimeMillis();
while (!txindex.BlockUntilSyncedToCurrentChain()) {
BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis());
MilliSleep(50);
}
// Check that txindex excludes genesis block transactions.
const CBlock& genesis_block = Params().GenesisBlock();
for (const auto& txn : genesis_block.vtx) {
BOOST_CHECK(!txindex.FindTx(txn->GetHash(), block_hash, tx_disk));
}
// Check that txindex has all txs that were in the chain before it started.
for (const auto& txn : m_coinbase_txns) {
if (!txindex.FindTx(txn.GetHash(), block_hash, tx_disk)) {
BOOST_ERROR("FindTx failed");
} else if (tx_disk->GetHash() != txn.GetHash()) {
BOOST_ERROR("Read incorrect tx");
}
}
// Check that new transactions in new blocks make it into the index.
for (int i = 0; i < 10; i++) {
CScript coinbase_script_pub_key = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
std::vector<CMutableTransaction> no_txns;
const CBlock& block = CreateAndProcessBlock(no_txns, coinbase_script_pub_key);
const CTransaction& txn = *block.vtx[0];
BOOST_CHECK(txindex.BlockUntilSyncedToCurrentChain());
if (!txindex.FindTx(txn.GetHash(), block_hash, tx_disk)) {
BOOST_ERROR("FindTx failed");
} else if (tx_disk->GetHash() != txn.GetHash()) {
BOOST_ERROR("Read incorrect tx");
}
}
// shutdown sequence (c.f. Shutdown() in init.cpp)
txindex.Stop();
// Rest of shutdown sequence and destructors happen in ~TestingSetup()
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -18,8 +18,6 @@
#include <stdint.h>
#include <boost/thread.hpp>
static const sqlite::sqlite_config sharedConfig {
sqlite::OpenFlags::READWRITE | sqlite::OpenFlags::CREATE,
nullptr, sqlite::Encoding::UTF8
@ -188,11 +186,7 @@ CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe)
"nonce INTEGER NOT NULL "
")";
db << "CREATE TABLE IF NOT EXISTS tx_to_block ("
"txID BLOB NOT NULL PRIMARY KEY, "
"file INTEGER NOT NULL, "
"blockPos INTEGER NOT NULL, "
"txPos INTEGER NOT NULL)";
db << "DROP TABLE IF EXISTS tx_to_block";
db << "CREATE TABLE IF NOT EXISTS flag ("
"name TEXT NOT NULL PRIMARY KEY, "
@ -392,32 +386,4 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
}
return true;
}
bool CBlockTreeDB::WriteTxIndex(const FlatFilePos& file, const std::vector<std::pair<uint256, uint32_t>>& txOffsets)
{
if (txOffsets.empty()) return true;
db << "begin";
auto query = db << "INSERT OR REPLACE INTO tx_to_block VALUES(?,?,?,?)";
for (auto& kvp: txOffsets) {
query << kvp.first << file.nFile << file.nPos << kvp.second;
query++;
}
query.used(true);
auto code = sqlite::commit(db);
if (code != SQLITE_OK) {
LogPrintf("%s: Error committing tx to database. SQLite error: %d\n", __func__, code);
return false;
}
return true;
}
bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, FlatFilePos &file, uint32_t& offset)
{
auto query = db << "SELECT file, blockPos, txPos FROM tx_to_block WHERE txID = ?" << txid;
for (auto&& row: query) {
row >> file.nFile >> file.nPos >> offset;
return true;
}
return false;
}
}

View file

@ -130,8 +130,6 @@ public:
void ReadReindexing(bool &fReindexing);
bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue);
bool ReadTxIndex(const uint256 &txid, FlatFilePos &file, uint32_t& offset);
bool WriteTxIndex(const FlatFilePos& file, const std::vector<std::pair<uint256, uint32_t>>& txOffsets);
bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex);
};

View file

@ -18,6 +18,7 @@
#include <consensus/validation.h>
#include <cuckoocache.h>
#include <flatfile.h>
#include <index/txindex.h>
#include <hash.h>
#include <nameclaim.h>
#include <policy/fees.h>
@ -1137,29 +1138,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, pfMissingInputs, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee, test_accept);
}
bool FillTx(const uint256& tx_hash, const FlatFilePos& pos, uint32_t offset, uint256& block_hash, CTransactionRef& tx)
{
CAutoFile file(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
if (file.IsNull()) {
return error("%s: OpenBlockFile failed", __func__);
}
CBlockHeader header;
try {
file >> header;
if (fseek(file.Get(), offset, SEEK_CUR)) {
return error("%s: fseek(...) failed", __func__);
}
file >> tx;
} catch (const std::exception& e) {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
if (tx->GetHash() != tx_hash) {
return error("%s: txid mismatch", __func__);
}
block_hash = header.GetHash();
return true;
}
/**
* Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock.
* If blockIndex is provided, the transaction is fetched from the corresponding block.
@ -1174,13 +1152,9 @@ bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus
txOut = ptx;
return true;
}
if (pblocktree) {
uint32_t offset;
FlatFilePos pos;
if (pblocktree->ReadTxIndex(hash, pos, offset) && FillTx(hash, pos, offset, hashBlock, ptx)) {
txOut = ptx;
return true;
}
if (g_txindex) {
return g_txindex->FindTx(hash, hashBlock, txOut);
}
} else {
CBlock block;
@ -2261,9 +2235,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
CAmount nFees = 0;
int nInputs = 0;
int64_t nSigOpsCost = 0;
std::vector<std::pair<uint256, uint32_t>> txOffsets;
uint32_t offset = ::GetSizeOfCompactSize(block.vtx.size());
txOffsets.reserve(block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
std::vector<PrecomputedTransactionData> txdata;
txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
@ -2371,9 +2342,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// or cache when trying to spend it, we shouldn't try to put a claim or support back
// in. Some OP_UPDATE_CLAIM's, for example, may be invalid, and so may never have been
// inserted into the trie in the first place.
txOffsets.push_back(std::make_pair(tx.GetHash(), offset));
offset += ::GetSerializeSize(tx, CLIENT_VERSION);
}
// TODO: if the "just check" flag is set, we should reduce the work done here. Incrementing blocks twice per mine is not efficient.
@ -2406,8 +2374,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
if (pindex->pprev && !WriteUndoDataForBlock(blockundo, state, pindex, chainparams))
return false;
if (!pblocktree->WriteTxIndex(pindex->GetBlockPos(), txOffsets))
return false;
if (!pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS);

View file

@ -122,7 +122,7 @@ static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = false;
static const bool DEFAULT_TXINDEX = true;
static const char* const DEFAULT_BLOCKFILTERINDEX = "0";
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
/** Default for -persistmempool */

View file

@ -7,6 +7,7 @@
#include <consensus/validation.h>
#include <core_io.h>
#include <claimtrie/forks.h>
#include <index/txindex.h>
#include <init.h>
#include <interfaces/chain.h>
#include <key_io.h>
@ -788,6 +789,13 @@ UniValue supportclaim(const JSONRPCRequest& request)
if (sClaimId.length() > claimLength)
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("claimid must be maximum of length %d", claimLength));
auto isTip = false;
if (request.params.size() > 4)
isTip = request.params[4].get_bool();
if (isTip && g_txindex)
g_txindex->BlockUntilSyncedToCurrentChain();
pwallet->BlockUntilSyncedToCurrentChain();
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@ -822,10 +830,6 @@ UniValue supportclaim(const JSONRPCRequest& request)
supportScript = supportScript << OP_2DROP << lastOp;
auto isTip = false;
if (request.params.size() > 4)
isTip = request.params[4].get_bool();
CTxDestination dest;
if (isTip) {
CTransactionRef ref;