aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/chain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/chain.cpp')
-rw-r--r--src/interfaces/chain.cpp218
1 files changed, 170 insertions, 48 deletions
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index fb634e73da..161dd01ffe 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-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.
@@ -6,22 +6,30 @@
#include <chain.h>
#include <chainparams.h>
+#include <interfaces/handler.h>
#include <interfaces/wallet.h>
#include <net.h>
+#include <node/coin.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/rbf.h>
+#include <policy/settings.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <protocol.h>
+#include <rpc/protocol.h>
+#include <rpc/server.h>
+#include <shutdown.h>
#include <sync.h>
#include <threadsafety.h>
#include <timedata.h>
#include <txmempool.h>
#include <ui_interface.h>
#include <uint256.h>
+#include <univalue.h>
#include <util/system.h>
#include <validation.h>
+#include <validationinterface.h>
#include <memory>
#include <utility>
@@ -29,11 +37,12 @@
namespace interfaces {
namespace {
-class LockImpl : public Chain::Lock
+class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection>
{
Optional<int> getHeight() override
{
- int height = ::chainActive.Height();
+ LockAssertion lock(::cs_main);
+ int height = ::ChainActive().Height();
if (height >= 0) {
return height;
}
@@ -41,8 +50,9 @@ class LockImpl : public Chain::Lock
}
Optional<int> getBlockHeight(const uint256& hash) override
{
+ LockAssertion lock(::cs_main);
CBlockIndex* block = LookupBlockIndex(hash);
- if (block && ::chainActive.Contains(block)) {
+ if (block && ::ChainActive().Contains(block)) {
return block->nHeight;
}
return nullopt;
@@ -55,54 +65,46 @@ class LockImpl : public Chain::Lock
}
uint256 getBlockHash(int height) override
{
- CBlockIndex* block = ::chainActive[height];
+ LockAssertion lock(::cs_main);
+ CBlockIndex* block = ::ChainActive()[height];
assert(block != nullptr);
return block->GetBlockHash();
}
int64_t getBlockTime(int height) override
{
- CBlockIndex* block = ::chainActive[height];
+ LockAssertion lock(::cs_main);
+ CBlockIndex* block = ::ChainActive()[height];
assert(block != nullptr);
return block->GetBlockTime();
}
int64_t getBlockMedianTimePast(int height) override
{
- CBlockIndex* block = ::chainActive[height];
+ LockAssertion lock(::cs_main);
+ CBlockIndex* block = ::ChainActive()[height];
assert(block != nullptr);
return block->GetMedianTimePast();
}
bool haveBlockOnDisk(int height) override
{
- CBlockIndex* block = ::chainActive[height];
+ LockAssertion lock(::cs_main);
+ CBlockIndex* block = ::ChainActive()[height];
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
}
- Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) override
+ Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override
{
- CBlockIndex* block = ::chainActive.FindEarliestAtLeast(time);
+ LockAssertion lock(::cs_main);
+ CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height);
if (block) {
if (hash) *hash = block->GetBlockHash();
return block->nHeight;
}
return nullopt;
}
- Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) override
- {
- // TODO: Could update CChain::FindEarliestAtLeast() to take a height
- // parameter and use it with std::lower_bound() to make this
- // implementation more efficient and allow combining
- // findFirstBlockWithTime and findFirstBlockWithTimeAndHeight into one
- // method.
- for (CBlockIndex* block = ::chainActive[height]; block; block = ::chainActive.Next(block)) {
- if (block->GetBlockTime() >= time) {
- return block->nHeight;
- }
- }
- return nullopt;
- }
Optional<int> findPruned(int start_height, Optional<int> stop_height) override
{
+ LockAssertion lock(::cs_main);
if (::fPruneMode) {
- CBlockIndex* block = stop_height ? ::chainActive[*stop_height] : ::chainActive.Tip();
+ CBlockIndex* block = stop_height ? ::ChainActive()[*stop_height] : ::ChainActive().Tip();
while (block && block->nHeight >= start_height) {
if ((block->nStatus & BLOCK_HAVE_DATA) == 0) {
return block->nHeight;
@@ -114,8 +116,9 @@ class LockImpl : public Chain::Lock
}
Optional<int> findFork(const uint256& hash, Optional<int>* height) override
{
+ LockAssertion lock(::cs_main);
const CBlockIndex* block = LookupBlockIndex(hash);
- const CBlockIndex* fork = block ? ::chainActive.FindFork(block) : nullptr;
+ const CBlockIndex* fork = block ? ::ChainActive().FindFork(block) : nullptr;
if (height) {
if (block) {
*height = block->nHeight;
@@ -128,37 +131,114 @@ class LockImpl : public Chain::Lock
}
return nullopt;
}
- bool isPotentialTip(const uint256& hash) override
+ CBlockLocator getTipLocator() override
{
- if (::chainActive.Tip()->GetBlockHash() == hash) return true;
- CBlockIndex* block = LookupBlockIndex(hash);
- return block && block->GetAncestor(::chainActive.Height()) == ::chainActive.Tip();
+ LockAssertion lock(::cs_main);
+ return ::ChainActive().GetLocator();
}
- CBlockLocator getTipLocator() override { return ::chainActive.GetLocator(); }
Optional<int> findLocatorFork(const CBlockLocator& locator) override
{
- LockAnnotation lock(::cs_main);
- if (CBlockIndex* fork = FindForkInGlobalIndex(::chainActive, locator)) {
+ LockAssertion lock(::cs_main);
+ if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) {
return fork->nHeight;
}
return nullopt;
}
bool checkFinalTx(const CTransaction& tx) override
{
- LockAnnotation lock(::cs_main);
+ LockAssertion lock(::cs_main);
return CheckFinalTx(tx);
}
- bool submitToMemoryPool(CTransactionRef tx, CAmount absurd_fee, CValidationState& state) override
+ bool submitToMemoryPool(const CTransactionRef& tx, CAmount absurd_fee, CValidationState& state) override
{
- LockAnnotation lock(::cs_main);
+ LockAssertion lock(::cs_main);
return AcceptToMemoryPool(::mempool, state, tx, nullptr /* missing inputs */, nullptr /* txn replaced */,
false /* bypass limits */, absurd_fee);
}
+
+ using UniqueLock::UniqueLock;
};
-class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
+class NotificationsHandlerImpl : public Handler, CValidationInterface
{
- using UniqueLock::UniqueLock;
+public:
+ explicit NotificationsHandlerImpl(Chain& chain, Chain::Notifications& notifications)
+ : m_chain(chain), m_notifications(&notifications)
+ {
+ RegisterValidationInterface(this);
+ }
+ ~NotificationsHandlerImpl() override { disconnect(); }
+ void disconnect() override
+ {
+ if (m_notifications) {
+ m_notifications = nullptr;
+ UnregisterValidationInterface(this);
+ }
+ }
+ void TransactionAddedToMempool(const CTransactionRef& tx) override
+ {
+ m_notifications->TransactionAddedToMempool(tx);
+ }
+ void TransactionRemovedFromMempool(const CTransactionRef& tx) override
+ {
+ m_notifications->TransactionRemovedFromMempool(tx);
+ }
+ void BlockConnected(const std::shared_ptr<const CBlock>& block,
+ const CBlockIndex* index,
+ const std::vector<CTransactionRef>& tx_conflicted) override
+ {
+ m_notifications->BlockConnected(*block, tx_conflicted);
+ }
+ void BlockDisconnected(const std::shared_ptr<const CBlock>& block) override
+ {
+ m_notifications->BlockDisconnected(*block);
+ }
+ void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
+ {
+ m_notifications->UpdatedBlockTip();
+ }
+ void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->ChainStateFlushed(locator); }
+ Chain& m_chain;
+ Chain::Notifications* m_notifications;
+};
+
+class RpcHandlerImpl : public Handler
+{
+public:
+ RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
+ {
+ m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
+ if (!m_wrapped_command) return false;
+ try {
+ return m_wrapped_command->actor(request, result, last_handler);
+ } catch (const UniValue& e) {
+ // If this is not the last handler and a wallet not found
+ // exception was thrown, return false so the next handler can
+ // try to handle the request. Otherwise, reraise the exception.
+ if (!last_handler) {
+ const UniValue& code = e["code"];
+ if (code.isNum() && code.get_int() == RPC_WALLET_NOT_FOUND) {
+ return false;
+ }
+ }
+ throw;
+ }
+ };
+ ::tableRPC.appendCommand(m_command.name, &m_command);
+ }
+
+ void disconnect() override final
+ {
+ if (m_wrapped_command) {
+ m_wrapped_command = nullptr;
+ ::tableRPC.removeCommand(m_command.name, &m_command);
+ }
+ }
+
+ ~RpcHandlerImpl() override { disconnect(); }
+
+ CRPCCommand m_command;
+ const CRPCCommand* m_wrapped_command;
};
class ChainImpl : public Chain
@@ -166,13 +246,12 @@ class ChainImpl : public Chain
public:
std::unique_ptr<Chain::Lock> lock(bool try_lock) override
{
- auto result = MakeUnique<LockingStateImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
+ auto result = MakeUnique<LockImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
if (try_lock && result && !*result) return {};
// std::move necessary on some compilers due to conversion from
- // LockingStateImpl to Lock pointer
+ // LockImpl to Lock pointer
return std::move(result);
}
- std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); }
bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override
{
CBlockIndex* index;
@@ -194,6 +273,7 @@ public:
}
return true;
}
+ void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(coins); }
double guessVerificationProgress(const uint256& block_hash) override
{
LOCK(cs_main);
@@ -207,8 +287,8 @@ public:
bool hasDescendantsInMempool(const uint256& txid) override
{
LOCK(::mempool.cs);
- auto it_mp = ::mempool.mapTx.find(txid);
- return it_mp != ::mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1;
+ auto it = ::mempool.GetIter(txid);
+ return it && (*it)->GetCountWithDescendants() > 1;
}
void relayTransaction(const uint256& txid) override
{
@@ -219,7 +299,7 @@ public:
{
::mempool.GetTransactionAncestry(txid, ancestors, descendants);
}
- bool checkChainLimits(CTransactionRef tx) override
+ bool checkChainLimits(const CTransactionRef& tx) override
{
LockPoints lp;
CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp);
@@ -245,17 +325,59 @@ public:
{
return ::mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
}
- CAmount maxTxFee() override { return ::maxTxFee; }
- bool getPruneMode() override { return ::fPruneMode; }
+ CFeeRate relayMinFee() override { return ::minRelayTxFee; }
+ CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
+ CFeeRate relayDustFee() override { return ::dustRelayFee; }
+ bool havePruned() override
+ {
+ LOCK(cs_main);
+ return ::fHavePruned;
+ }
bool p2pEnabled() override { return g_connman != nullptr; }
- bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
+ bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); }
+ bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
+ bool shutdownRequested() override { return ShutdownRequested(); }
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
void initWarning(const std::string& message) override { InitWarning(message); }
void initError(const std::string& message) override { InitError(message); }
void loadWallet(std::unique_ptr<Wallet> wallet) override { ::uiInterface.LoadWallet(wallet); }
+ void showProgress(const std::string& title, int progress, bool resume_possible) override
+ {
+ ::uiInterface.ShowProgress(title, progress, resume_possible);
+ }
+ std::unique_ptr<Handler> handleNotifications(Notifications& notifications) override
+ {
+ return MakeUnique<NotificationsHandlerImpl>(*this, notifications);
+ }
+ void waitForNotificationsIfNewBlocksConnected(const uint256& old_tip) override
+ {
+ if (!old_tip.IsNull()) {
+ LOCK(::cs_main);
+ if (old_tip == ::ChainActive().Tip()->GetBlockHash()) return;
+ CBlockIndex* block = LookupBlockIndex(old_tip);
+ if (block && block->GetAncestor(::ChainActive().Height()) == ::ChainActive().Tip()) return;
+ }
+ SyncWithValidationInterfaceQueue();
+ }
+ std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
+ {
+ return MakeUnique<RpcHandlerImpl>(command);
+ }
+ bool rpcEnableDeprecated(const std::string& method) override { return IsDeprecatedRPCEnabled(method); }
+ void rpcRunLater(const std::string& name, std::function<void()> fn, int64_t seconds) override
+ {
+ RPCRunLater(name, std::move(fn), seconds);
+ }
+ int rpcSerializationFlags() override { return RPCSerializationFlags(); }
+ void requestMempoolTransactions(Notifications& notifications) override
+ {
+ LOCK2(::cs_main, ::mempool.cs);
+ for (const CTxMemPoolEntry& entry : ::mempool.mapTx) {
+ notifications.TransactionAddedToMempool(entry.GetSharedTx());
+ }
+ }
};
-
} // namespace
std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }