Skip to content
Merged
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
9 changes: 4 additions & 5 deletions src/bench/rpc_blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <chainlock/chainlock.h>
#include <consensus/validation.h>
#include <instantsend/instantsend.h>
#include <llmq/context.h>
#include <rpc/blockchain.h>
#include <streams.h>
#include <test/util/setup_common.h>
Expand Down Expand Up @@ -43,9 +42,9 @@ struct TestBlockAndIndex {
static void BlockToJsonVerbose(benchmark::Bench& bench)
{
TestBlockAndIndex data;
const LLMQContext& llmq_ctx = *data.testing_setup->m_node.llmq_ctx;
const llmq::CInstantSendManager& isman = *data.testing_setup->m_node.isman;
bench.run([&] {
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *data.testing_setup->m_node.chainlocks, *llmq_ctx.isman, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *data.testing_setup->m_node.chainlocks, isman, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
ankerl::nanobench::doNotOptimizeAway(univalue);
});
}
Expand All @@ -55,8 +54,8 @@ BENCHMARK(BlockToJsonVerbose, benchmark::PriorityLevel::HIGH);
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
{
TestBlockAndIndex data;
const LLMQContext& llmq_ctx = *data.testing_setup->m_node.llmq_ctx;
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *data.testing_setup->m_node.chainlocks, *llmq_ctx.isman, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
const llmq::CInstantSendManager& isman = *data.testing_setup->m_node.isman;
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *data.testing_setup->m_node.chainlocks, isman, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
bench.run([&] {
auto str = univalue.write();
ankerl::nanobench::doNotOptimizeAway(str);
Expand Down
14 changes: 7 additions & 7 deletions src/bitcoin-chainstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <evo/deterministicmns.h>
#include <evo/evodb.h>
#include <init/common.h>
#include <instantsend/instantsend.h>
#include <llmq/context.h>
#include <masternode/meta.h>
#include <masternode/sync.h>
Expand Down Expand Up @@ -93,11 +94,13 @@ int main(int argc, char* argv[])
ChainstateManager chainman{chainman_opts};

CMasternodeMetaMan metaman;
std::unique_ptr<CEvoDB> evodb;
std::unique_ptr<CDeterministicMNManager> dmnman;
CEvoDB evodb{util::DbWrapperParams{.path = gArgs.GetDataDirNet(), .memory = false, .wipe = false}};
CDeterministicMNManager dmnman{evodb, metaman};
CMasternodeSync mn_sync{std::make_unique<NullNodeSyncNotifier>()};
CSporkManager sporkman;
chainlock::Chainlocks chainlocks(sporkman);
// TODO: remove isman from bitcoin-chainstate and make it nullable for node::ChainstateLoadOptions same as mempool
llmq::CInstantSendManager isman{sporkman, util::DbWrapperParams{.path = gArgs.GetDataDirNet(), .memory = false, .wipe = false}};

std::unique_ptr<LLMQContext> llmq_ctx;
std::unique_ptr<CChainstateHelper> chain_helper;
Expand All @@ -107,8 +110,7 @@ int main(int argc, char* argv[])
cache_sizes.coins_db = 2 << 22;
cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22);
node::ChainstateLoadOptions options;
options.mn_metaman = &metaman;
options.sporkman = &sporkman;
options.isman = &isman;
options.chainlocks = &chainlocks;
options.mn_sync = &mn_sync;
options.data_dir = gArgs.GetDataDirNet();
Expand All @@ -119,7 +121,7 @@ int main(int argc, char* argv[])
std::cerr << "Failed to load Chain state from your datadir." << std::endl;
goto epilogue;
} else {
std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options, *evodb);
std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options, evodb);
if (status != node::ChainstateLoadStatus::SUCCESS) {
std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl;
goto epilogue;
Expand Down Expand Up @@ -278,6 +280,4 @@ int main(int argc, char* argv[])
// Tear down Dash kernel objects before kernel::~Context().
chain_helper.reset();
llmq_ctx.reset();
dmnman.reset();
evodb.reset();
}
4 changes: 4 additions & 0 deletions src/evo/chainhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ std::optional<std::pair</*islock_hash=*/uint256, /*txid=*/uint256>> CChainstateH
return std::make_pair(::SerializeHash(*islock), islock->txid);
}

bool CChainstateHelper::IsInstantSendEnabled() const { return isman.IsInstantSendEnabled(); }

bool CChainstateHelper::IsInstantSendLocked(const uint256& hash) const { return isman.IsLocked(hash); }

bool CChainstateHelper::IsInstantSendWaitingForTx(const uint256& hash) const { return isman.IsWaitingForTx(hash); }

bool CChainstateHelper::RemoveConflictingISLockByTx(const CTransaction& tx)
Expand Down
2 changes: 2 additions & 0 deletions src/evo/chainhelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ class CChainstateHelper

/** Passthrough functions to CInstantSendManager */
std::optional<std::pair</*islock_hash=*/uint256, /*txid=*/uint256>> ConflictingISLockIfAny(const CTransaction& tx) const;
bool IsInstantSendEnabled() const;
bool IsInstantSendLocked(const uint256& hash) const;
bool IsInstantSendWaitingForTx(const uint256& hash) const;
bool RemoveConflictingISLockByTx(const CTransaction& tx);

Expand Down
79 changes: 48 additions & 31 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,13 +429,12 @@ void PrepareShutdown(NodeContext& node)
chainstate->ResetCoinsViews();
}
}
// The mempool holds raw pointers to dmnman and llmq_ctx->isman, so it has to
// let go of them before either manager is destroyed.
if (node.mempool) {
node.mempool->DisconnectManagers();
}
// The mempool holds raw pointers to dmnman and isman, so it must be
// destroyed before either manager.
node.mempool.reset();
node.chain_helper.reset();
node.llmq_ctx.reset();
node.isman.reset();
node.dmnman.reset();
node.evodb.reset();
}
Expand Down Expand Up @@ -900,7 +899,7 @@ static void PeriodicStats(NodeContext& node)
assert(::g_stats_client->active());
ChainstateManager& chainman = *Assert(node.chainman);
const CTxMemPool& mempool = *Assert(node.mempool);
const llmq::CInstantSendManager& isman = *Assert(node.llmq_ctx->isman);
const llmq::CInstantSendManager& isman = *Assert(node.isman);
chainman.ActiveChainstate().ForceFlushStateToDisk();
const auto maybe_stats = WITH_LOCK(::cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, /*hash_type=*/CoinStatsHashType::NONE, node.rpc_interruption_point, chainman.ActiveChain().Tip(), /*index_requested=*/true));
if (maybe_stats.has_value()) {
Expand Down Expand Up @@ -1949,7 +1948,30 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024));

for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) {
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
// On a retry iteration the previous instances still hold the on-disk
// database locks, so release them before opening the databases again.
node.mempool.reset();
node.isman.reset();
node.dmnman.reset();
node.evodb.reset();
auto catch_exceptions = [](auto&& f) {
try {
return f();
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());
return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error opening block database"));
}
};
auto [status, error] = catch_exceptions([&]() -> node::ChainstateLoadResult {
node.evodb = std::make_unique<CEvoDB>(util::DbWrapperParams{.path = args.GetDataDirNet(), .memory = false, .wipe = node::fReindex || fReindexChainState});
node.dmnman = std::make_unique<CDeterministicMNManager>(*node.evodb, *node.mn_metaman);
node.isman = std::make_unique<llmq::CInstantSendManager>(*node.sporkman, util::DbWrapperParams{.path = args.GetDataDirNet(), .memory = false, .wipe = node::fReindex || fReindexChainState});

mempool_opts.dmnman = node.dmnman.get();
mempool_opts.isman = node.isman.get();
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
return {node::ChainstateLoadStatus::SUCCESS, {}};
});

const ChainstateManager::Options chainman_opts{
.chainparams = chainparams,
Expand All @@ -1968,9 +1990,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
node.mn_sync = std::make_unique<CMasternodeSync>(std::make_unique<NodeSyncNotifierImpl>(*node.connman, *node.netfulfilledman));

node::ChainstateLoadOptions options;
options.mempool = Assert(node.mempool.get());
options.mn_metaman = Assert(node.mn_metaman.get());
options.sporkman = Assert(node.sporkman.get());
options.chainlocks = Assert(node.chainlocks.get());
options.mn_sync = Assert(node.mn_sync.get());
options.data_dir = args.GetDataDirNet();
Expand Down Expand Up @@ -2000,15 +2019,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)

uiInterface.InitMessage(_("Loading block index…").translated);
const auto load_block_index_start_time{SteadyClock::now()};
auto catch_exceptions = [](auto&& f) {
try {
return f();
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());
return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error opening block database"));
}
};
auto [status, error] = catch_exceptions([&]{ return LoadChainstate(chainman, cache_sizes, options, node.evodb, node.dmnman, node.llmq_ctx, node.chain_helper); });
if (status == node::ChainstateLoadStatus::SUCCESS) {
options.mempool = Assert(node.mempool.get());
options.isman = Assert(node.isman.get());
std::tie(status, error) = catch_exceptions([&]{ return LoadChainstate(chainman, cache_sizes, options, *node.evodb, *node.dmnman, node.llmq_ctx, node.chain_helper); });
}
if (status == node::ChainstateLoadStatus::SUCCESS) {
uiInterface.InitMessage(_("Verifying blocks…").translated);
if (chainman.m_blockman.m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) {
Expand Down Expand Up @@ -2083,7 +2098,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// Will init later in ThreadImport
node.active_ctx = std::make_unique<ActiveContext>(*node.llmq_ctx->bls_worker, chainman, *node.connman, *node.dmnman,
*node.govman, *node.chain_helper->superblocks,
*node.sporkman, *node.chainlocks, *node.mempool, *node.clhandler, *node.llmq_ctx->isman,
*node.sporkman, *node.chainlocks, *node.mempool, *node.clhandler, *node.isman,
*node.llmq_ctx->qman, *node.llmq_ctx->qsnapman, *node.llmq_ctx->sigman,
*node.mn_sync, operator_sk, dash_db_params, quorums_watch);
RegisterValidationInterface(node.active_ctx.get());
Expand All @@ -2093,12 +2108,21 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
RegisterValidationInterface(node.observer_ctx.get());
}

assert(!node.cj_walletman);
#ifdef ENABLE_WALLET
if (!node.active_ctx) {
// Only constructed in wallet-enabled builds; stays null otherwise, must check before use
node.cj_walletman = CJWalletManager::make(chainman, *node.dmnman, *node.mn_metaman, *node.mempool, *node.mn_sync,
*node.isman, !ignores_incoming_txs);
}
#endif

assert(!node.peerman);
node.peerman = PeerManager::make(*node.connman, *node.addrman, node.banman.get(), *node.dstxman,
chainman, *node.mempool, *node.mn_metaman, *node.mn_sync,
*node.sporkman, *node.chainlocks, *node.clhandler,
node.active_ctx ? node.active_ctx->nodeman.get() : nullptr,
node.dmnman, node.cj_walletman, node.llmq_ctx, ignores_incoming_txs);
*node.dmnman, node.cj_walletman.get(), *node.isman, *node.llmq_ctx, ignores_incoming_txs);
RegisterValidationInterface(node.peerman.get());

node.ds_notification_interface = std::make_unique<CDSNotificationInterface>(
Expand All @@ -2108,7 +2132,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)

// ********************************************************* Step 7d: Setup other Dash services

node.peerman->AddExtraHandler(std::make_unique<NetInstantSend>(node.peerman.get(), *node.llmq_ctx->isman, node.active_ctx ? node.active_ctx->is_signer.get() : nullptr, *node.llmq_ctx->sigman, *node.llmq_ctx->qman, *node.chainlocks, chainman, *node.mempool, *node.mn_sync));
node.peerman->AddExtraHandler(std::make_unique<NetInstantSend>(node.peerman.get(), *node.isman, node.active_ctx ? node.active_ctx->is_signer.get() : nullptr, *node.llmq_ctx->sigman, *node.llmq_ctx->qman, *node.chainlocks, chainman, *node.mempool, *node.mn_sync));
node.peerman->AddExtraHandler(std::make_unique<llmq::NetSigning>(node.peerman.get(), *node.llmq_ctx->sigman, node.active_ctx ? node.active_ctx->shareman.get() : nullptr, *node.sporkman));

{
Expand Down Expand Up @@ -2140,16 +2164,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)

if (node.active_ctx) {
auto cj_server = std::make_unique<CCoinJoinServer>(node.peerman.get(), chainman, *node.connman, *node.dmnman, *node.dstxman, *node.mn_metaman,
*node.mempool, *node.active_ctx->nodeman, *node.mn_sync, *node.llmq_ctx->isman);
*node.mempool, *node.active_ctx->nodeman, *node.mn_sync, *node.isman);
node.active_ctx->SetCJServer(cj_server.get());
node.peerman->AddExtraHandler(std::move(cj_server));
} else {
assert(!node.cj_walletman);
// Only constructed in wallet-enabled builds; stays null otherwise, must check before use
#ifdef ENABLE_WALLET
node.cj_walletman = CJWalletManager::make(chainman, *node.dmnman, *node.mn_metaman, *node.mempool, *node.mn_sync,
*node.llmq_ctx->isman, !ignores_incoming_txs);
#endif
}

if (node.cj_walletman) {
Expand Down Expand Up @@ -2386,7 +2403,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// Seed InstantSend tip-height cache; NetInstantSend receives future
// updates via CValidationInterface but misses InitializeCurrentBlockTip.
// TODO: move cache updates from NetInstantSend to g_ds_notification due to specific of Tip's processing
node.llmq_ctx->isman->CacheTipHeight(WITH_LOCK(::cs_main, return chainman.ActiveChain().Tip()));
node.isman->CacheTipHeight(WITH_LOCK(::cs_main, return chainman.ActiveChain().Tip()));

{
// Get all UTXOs for each MN collateral in one go so that we can fill coin cache early
Expand Down
9 changes: 9 additions & 0 deletions src/kernel/mempool_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
#include <optional>

class CBlockPolicyEstimator;
class CDeterministicMNManager;

namespace llmq {
class CInstantSendManager;
} // namespace llmq

/** Default for -maxmempool, maximum megabytes of mempool memory usage */
static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE_MB{300};
Expand All @@ -32,6 +37,10 @@ namespace kernel {
struct MemPoolOptions {
/* Used to estimate appropriate transaction fees. */
CBlockPolicyEstimator* estimator{nullptr};
/* Used to validate special transactions; required, must outlive the mempool. */
CDeterministicMNManager* dmnman{nullptr};
/* Used to protect InstantSend-locked transactions; required, must outlive the mempool. */
llmq::CInstantSendManager* isman{nullptr};
/* The ratio used to determine how often sanity checks will run. */
int check_ratio{0};
int64_t max_size_bytes{DEFAULT_MAX_MEMPOOL_SIZE_MB * 1'000'000};
Expand Down
10 changes: 4 additions & 6 deletions src/llmq/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,22 @@
#include <llmq/context.h>

#include <bls/bls_worker.h>
#include <instantsend/instantsend.h>
#include <llmq/blockprocessor.h>
#include <llmq/quorumsman.h>
#include <llmq/signing.h>
#include <llmq/snapshot.h>
#include <validation.h>

LLMQContext::LLMQContext(CDeterministicMNManager& dmnman, CEvoDB& evo_db, CSporkManager& sporkman,
ChainstateManager& chainman, const util::DbWrapperParams& db_params, int8_t bls_threads,
int16_t worker_count, int64_t max_recsigs_age) :
LLMQContext::LLMQContext(CDeterministicMNManager& dmnman, CEvoDB& evo_db, ChainstateManager& chainman,
const util::DbWrapperParams& db_params, int8_t bls_threads, int16_t worker_count,
int64_t max_recsigs_age) :
bls_worker{std::make_shared<CBLSWorker>()},
qsnapman{std::make_unique<llmq::CQuorumSnapshotManager>(evo_db)},
quorum_block_processor{
std::make_unique<llmq::CQuorumBlockProcessor>(chainman, dmnman, evo_db, *qsnapman, bls_threads)},
qman{std::make_unique<llmq::CQuorumManager>(*bls_worker, dmnman, evo_db, *quorum_block_processor, *qsnapman,
chainman, db_params)},
sigman{std::make_unique<llmq::CSigningManager>(*qman, db_params, max_recsigs_age)},
isman{std::make_unique<llmq::CInstantSendManager>(sporkman, db_params)}
sigman{std::make_unique<llmq::CSigningManager>(*qman, db_params, max_recsigs_age)}
{
// Have to start it early to let VerifyDB check ChainLock signatures in coinbase
bls_worker->Start(worker_count);
Expand Down
9 changes: 3 additions & 6 deletions src/llmq/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ class CBLSWorker;
class ChainstateManager;
class CDeterministicMNManager;
class CEvoDB;
class CSporkManager;
class PeerManager;

namespace llmq {
class CInstantSendManager;
class CQuorumBlockProcessor;
class CQuorumManager;
class CQuorumSnapshotManager;
Expand All @@ -32,9 +30,9 @@ struct LLMQContext {
LLMQContext() = delete;
LLMQContext(const LLMQContext&) = delete;
LLMQContext& operator=(const LLMQContext&) = delete;
explicit LLMQContext(CDeterministicMNManager& dmnman, CEvoDB& evo_db, CSporkManager& sporkman,
ChainstateManager& chainman, const util::DbWrapperParams& db_params, int8_t bls_threads,
int16_t worker_count, int64_t max_recsigs_age);
explicit LLMQContext(CDeterministicMNManager& dmnman, CEvoDB& evo_db, ChainstateManager& chainman,
const util::DbWrapperParams& db_params, int8_t bls_threads, int16_t worker_count,
int64_t max_recsigs_age);
~LLMQContext();

/** Guaranteed if LLMQContext is initialized then all members are valid too
Expand All @@ -48,7 +46,6 @@ struct LLMQContext {
const std::unique_ptr<llmq::CQuorumBlockProcessor> quorum_block_processor;
const std::unique_ptr<llmq::CQuorumManager> qman;
const std::unique_ptr<llmq::CSigningManager> sigman;
const std::unique_ptr<llmq::CInstantSendManager> isman;
};

#endif // BITCOIN_LLMQ_CONTEXT_H
Loading
Loading