diff --git a/doc/release-notes.md b/doc/release-notes.md
index ea5c492f6..102579a4b 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,10 +1,11 @@
# Bitcoin ABC 0.27.7 Release Notes
Bitcoin ABC version 0.27.7 is now available from:
This release includes the following features and fixes:
- - The `fees.ancestor` and `fees.descendant` fields from the `getrawmempool`,
+ - The `fees.ancestor`, `fees.descendant`, `descendantcount`, `descendantsize`,
+ `ancestorcount` and `ancestorsize` fields from the `getrawmempool`,
`getmempoolentry`, `getmempoolancestors` and `getmempooldescendants` were
deprecated since v0.27.0 and have been completely removed.
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index 4494ae7cd..5809c8531 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -1,339 +1,336 @@
// 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.
#ifndef BITCOIN_INTERFACES_CHAIN_H
#define BITCOIN_INTERFACES_CHAIN_H
#include
#include
#include // For util::SettingsValue
#include
#include
#include
#include
#include
#include
#include
class ArgsManager;
class CBlock;
class CChainParams;
class Coin;
class Config;
class CRPCCommand;
class CScheduler;
class TxValidationState;
enum class MemPoolRemovalReason;
struct BlockHash;
struct bilingual_str;
struct CBlockLocator;
namespace node {
struct NodeContext;
} // namespace node
namespace Consensus {
struct Params;
}
namespace interfaces {
class Handler;
class Wallet;
//! Helper for findBlock to selectively return pieces of block data.
class FoundBlock {
public:
FoundBlock &hash(BlockHash &hash) {
m_hash = &hash;
return *this;
}
FoundBlock &height(int &height) {
m_height = &height;
return *this;
}
FoundBlock &time(int64_t &time) {
m_time = &time;
return *this;
}
FoundBlock &maxTime(int64_t &max_time) {
m_max_time = &max_time;
return *this;
}
FoundBlock &mtpTime(int64_t &mtp_time) {
m_mtp_time = &mtp_time;
return *this;
}
//! Return whether block is in the active (most-work) chain.
FoundBlock &inActiveChain(bool &in_active_chain) {
m_in_active_chain = &in_active_chain;
return *this;
}
//! Return next block in the active chain if current block is in the active
//! chain.
FoundBlock &nextBlock(const FoundBlock &next_block) {
m_next_block = &next_block;
return *this;
}
//! Read block data from disk. If the block exists but doesn't have data
//! (for example due to pruning), the CBlock variable will be set to null.
FoundBlock &data(CBlock &data) {
m_data = &data;
return *this;
}
BlockHash *m_hash = nullptr;
int *m_height = nullptr;
int64_t *m_time = nullptr;
int64_t *m_max_time = nullptr;
int64_t *m_mtp_time = nullptr;
bool *m_in_active_chain = nullptr;
const FoundBlock *m_next_block = nullptr;
CBlock *m_data = nullptr;
};
//! Interface giving clients (wallet processes, maybe other analysis tools in
//! the future) ability to access to the chain state, receive notifications,
//! estimate fees, and submit transactions.
//!
//! TODO: Current chain methods are too low level, exposing too much of the
//! internal workings of the bitcoin node, and not being very convenient to use.
//! Chain methods should be cleaned up and simplified over time. Examples:
//!
//! * The initMessages() and showProgress() methods which the wallet uses to
//! send
//! notifications to the GUI should go away when GUI and wallet can directly
//! communicate with each other without going through the node
//! (https://github.com/bitcoin/bitcoin/pull/15288#discussion_r253321096).
//!
//! * The handleRpc, registerRpcs, rpcEnableDeprecated methods and other RPC
//! methods can go away if wallets listen for HTTP requests on their own
//! ports instead of registering to handle requests on the node HTTP port.
//!
//! * Move fee estimation queries to an asynchronous interface and let the
//! wallet cache it, fee estimation being driven by node mempool, wallet
//! should be the consumer.
//!
//! * `guessVerificationProgress` and similar methods can go away if rescan
//! logic moves out of the wallet, and the wallet just requests scans from the
//! node (https://github.com/bitcoin/bitcoin/issues/11756)
class Chain {
public:
virtual ~Chain() {}
//! Get current chain height, not including genesis block (returns 0 if
//! chain only contains genesis block, std::nullopt if chain does not
//! contain any blocks)
virtual std::optional getHeight() = 0;
//! Get block hash. Height must be valid or this function will abort.
virtual BlockHash getBlockHash(int height) = 0;
//! Check that the block is available on disk (i.e. has not been
//! pruned), and contains transactions.
virtual bool haveBlockOnDisk(int height) = 0;
//! Get locator for the current chain tip.
virtual CBlockLocator getTipLocator() = 0;
//! Return height of the highest block on chain in common with the locator,
//! which will either be the original block used to create the locator,
//! or one of its ancestors.
virtual std::optional
findLocatorFork(const CBlockLocator &locator) = 0;
//! Return whether node has the block and optionally return block metadata
//! or contents.
virtual bool findBlock(const BlockHash &hash,
const FoundBlock &block = {}) = 0;
//! Find first block in the chain with timestamp >= the given time
//! and height >= than the given height, return false if there is no block
//! with a high enough timestamp and height. Optionally return block
//! information.
virtual bool
findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height,
const FoundBlock &block = {}) = 0;
//! Find ancestor of block at specified height and optionally return
//! ancestor information.
virtual bool findAncestorByHeight(const BlockHash &block_hash,
int ancestor_height,
const FoundBlock &ancestor_out = {}) = 0;
//! Return whether block descends from a specified ancestor, and
//! optionally return ancestor information.
virtual bool findAncestorByHash(const BlockHash &block_hash,
const BlockHash &ancestor_hash,
const FoundBlock &ancestor_out = {}) = 0;
//! Find most recent common ancestor between two blocks and optionally
//! return block information.
virtual bool findCommonAncestor(const BlockHash &block_hash1,
const BlockHash &block_hash2,
const FoundBlock &ancestor_out = {},
const FoundBlock &block1_out = {},
const FoundBlock &block2_out = {}) = 0;
//! Look up unspent output information. Returns coins in the mempool and in
//! the current chain UTXO set. Iterates through all the keys in the map and
//! populates the values.
virtual void findCoins(std::map &coins) = 0;
//! Estimate fraction of total transactions verified if blocks up to
//! the specified block hash are verified.
virtual double guessVerificationProgress(const BlockHash &block_hash) = 0;
//! Return true if data is available for all blocks in the specified range
//! of blocks. This checks all blocks that are ancestors of block_hash in
//! the height range from min_height to max_height, inclusive.
virtual bool hasBlocks(const BlockHash &block_hash, int min_height = 0,
std::optional max_height = {}) = 0;
- //! Check if transaction has descendants in mempool.
- virtual bool hasDescendantsInMempool(const TxId &txid) = 0;
-
//! Transaction is added to memory pool, if the transaction fee is below the
//! amount specified by max_tx_fee, and broadcast to all peers if relay is
//! set to true. Return false if the transaction could not be added due to
//! the fee or for another reason.
virtual bool broadcastTransaction(const Config &config,
const CTransactionRef &tx,
const Amount &max_tx_fee, bool relay,
std::string &err_string) = 0;
//! Estimate fee
virtual CFeeRate estimateFee() const = 0;
//! Relay current minimum fee (from -minrelaytxfee settings).
virtual CFeeRate relayMinFee() = 0;
//! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's
//! economical to spend.
virtual CFeeRate relayDustFee() = 0;
//! Check if any block has been pruned.
virtual bool havePruned() = 0;
//! Check if the node is ready to broadcast transactions.
virtual bool isReadyToBroadcast() = 0;
//! Check if in IBD.
virtual bool isInitialBlockDownload() = 0;
//! Check if shutdown requested.
virtual bool shutdownRequested() = 0;
//! Get adjusted time.
virtual int64_t getAdjustedTime() = 0;
//! Send init message.
virtual void initMessage(const std::string &message) = 0;
//! Send init warning.
virtual void initWarning(const bilingual_str &message) = 0;
//! Send init error.
virtual void initError(const bilingual_str &message) = 0;
//! Send progress indicator.
virtual void showProgress(const std::string &title, int progress,
bool resume_possible) = 0;
//! Chain notifications.
class Notifications {
public:
virtual ~Notifications() {}
virtual void transactionAddedToMempool(const CTransactionRef &tx,
uint64_t mempool_sequence) {}
virtual void transactionRemovedFromMempool(const CTransactionRef &ptx,
MemPoolRemovalReason reason,
uint64_t mempool_sequence) {}
virtual void blockConnected(const CBlock &block, int height) {}
virtual void blockDisconnected(const CBlock &block, int height) {}
virtual void updatedBlockTip() {}
virtual void chainStateFlushed(const CBlockLocator &locator) {}
};
//! Register handler for notifications.
virtual std::unique_ptr
handleNotifications(std::shared_ptr notifications) = 0;
//! Wait for pending notifications to be processed unless block hash points
//! to the current chain tip.
virtual void waitForNotificationsIfTipChanged(const BlockHash &old_tip) = 0;
//! Register handler for RPC. Command is not copied, so reference
//! needs to remain valid until Handler is disconnected.
virtual std::unique_ptr handleRpc(const CRPCCommand &command) = 0;
//! Check if deprecated RPC is enabled.
virtual bool rpcEnableDeprecated(const std::string &method) = 0;
//! Run function after given number of seconds. Cancel any previous calls
//! with same name.
virtual void rpcRunLater(const std::string &name, std::function fn,
int64_t seconds) = 0;
//! Current RPC serialization flags.
virtual int rpcSerializationFlags() = 0;
//! Return /settings.json setting value.
virtual util::SettingsValue getRwSetting(const std::string &name) = 0;
//! Write a setting to /settings.json.
virtual bool updateRwSetting(const std::string &name,
const util::SettingsValue &value) = 0;
//! Synchronously send transactionAddedToMempool notifications about all
//! current mempool transactions to the specified handler and return after
//! the last one is sent. These notifications aren't coordinated with async
//! notifications sent by handleNotifications, so out of date async
//! notifications from handleNotifications can arrive during and after
//! synchronous notifications from requestMempoolTransactions. Clients need
//! to be prepared to handle this by ignoring notifications about unknown
//! removed transactions and already added new transactions.
virtual void requestMempoolTransactions(Notifications ¬ifications) = 0;
//! This Chain's parameters
virtual const CChainParams ¶ms() const = 0;
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
//! monitoring and analysis in the future).
class ChainClient {
public:
virtual ~ChainClient() {}
//! Register rpcs.
virtual void registerRpcs() = 0;
//! Check for errors before loading.
virtual bool verify() = 0;
//! Load saved state.
virtual bool load() = 0;
//! Start client execution and provide a scheduler.
virtual void start(CScheduler &scheduler) = 0;
//! Save state to disk.
virtual void flush() = 0;
//! Shut down client.
virtual void stop() = 0;
//! Set mock time.
virtual void setMockTime(int64_t time) = 0;
};
//! Return implementation of Chain interface.
std::unique_ptr MakeChain(node::NodeContext &node,
const CChainParams ¶ms);
} // namespace interfaces
#endif // BITCOIN_INTERFACES_CHAIN_H
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index d5d8668de..32cbccd3e 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -1,734 +1,726 @@
// Copyright (c) 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.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(HAVE_CONFIG_H)
#include
#endif
#include
#include
#include
#include
class HTTPRPCRequestProcessor;
using interfaces::BlockTip;
using interfaces::Chain;
using interfaces::FoundBlock;
using interfaces::Handler;
using interfaces::MakeHandler;
using interfaces::Node;
using interfaces::WalletClient;
namespace node {
namespace {
class NodeImpl : public Node {
private:
ChainstateManager &chainman() { return *Assert(m_context->chainman); }
public:
explicit NodeImpl(NodeContext *context) { setContext(context); }
void initLogging() override { InitLogging(*Assert(m_context->args)); }
void initParameterInteraction() override {
InitParameterInteraction(*Assert(m_context->args));
}
bilingual_str getWarnings() override { return GetWarnings(true); }
bool baseInitialize(Config &config) override {
return AppInitBasicSetup(gArgs) &&
AppInitParameterInteraction(config, gArgs) &&
AppInitSanityChecks() && AppInitLockDataDirectory() &&
AppInitInterfaces(*m_context);
}
bool appInitMain(Config &config, RPCServer &rpcServer,
HTTPRPCRequestProcessor &httpRPCRequestProcessor,
interfaces::BlockAndHeaderTipInfo *tip_info) override {
return AppInitMain(config, rpcServer, httpRPCRequestProcessor,
*m_context, tip_info);
}
void appShutdown() override {
Interrupt(*m_context);
Shutdown(*m_context);
}
void startShutdown() override {
StartShutdown();
// Stop RPC for clean shutdown if any of waitfor* commands is
// executed.
if (gArgs.GetBoolArg("-server", false)) {
InterruptRPC();
StopRPC();
}
}
bool shutdownRequested() override { return ShutdownRequested(); }
void mapPort(bool use_upnp, bool use_natpmp) override {
StartMapPort(use_upnp, use_natpmp);
}
bool getProxy(Network net, proxyType &proxy_info) override {
return GetProxy(net, proxy_info);
}
size_t getNodeCount(CConnman::NumConnections flags) override {
return m_context->connman ? m_context->connman->GetNodeCount(flags)
: 0;
}
bool getNodesStats(NodesStats &stats) override {
stats.clear();
if (m_context->connman) {
std::vector stats_temp;
m_context->connman->GetNodeStats(stats_temp);
stats.reserve(stats_temp.size());
for (auto &node_stats_temp : stats_temp) {
stats.emplace_back(std::move(node_stats_temp), false,
CNodeStateStats());
}
// Try to retrieve the CNodeStateStats for each node.
if (m_context->peerman) {
TRY_LOCK(::cs_main, lockMain);
if (lockMain) {
for (auto &node_stats : stats) {
std::get<1>(node_stats) =
m_context->peerman->GetNodeStateStats(
std::get<0>(node_stats).nodeid,
std::get<2>(node_stats));
}
}
}
return true;
}
return false;
}
bool getBanned(banmap_t &banmap) override {
if (m_context->banman) {
m_context->banman->GetBanned(banmap);
return true;
}
return false;
}
bool ban(const CNetAddr &net_addr, int64_t ban_time_offset) override {
if (m_context->banman) {
m_context->banman->Ban(net_addr, ban_time_offset);
return true;
}
return false;
}
bool unban(const CSubNet &ip) override {
if (m_context->banman) {
m_context->banman->Unban(ip);
return true;
}
return false;
}
bool disconnectByAddress(const CNetAddr &net_addr) override {
if (m_context->connman) {
return m_context->connman->DisconnectNode(net_addr);
}
return false;
}
bool disconnectById(NodeId id) override {
if (m_context->connman) {
return m_context->connman->DisconnectNode(id);
}
return false;
}
int64_t getTotalBytesRecv() override {
return m_context->connman ? m_context->connman->GetTotalBytesRecv()
: 0;
}
int64_t getTotalBytesSent() override {
return m_context->connman ? m_context->connman->GetTotalBytesSent()
: 0;
}
size_t getMempoolSize() override {
return m_context->mempool ? m_context->mempool->size() : 0;
}
size_t getMempoolDynamicUsage() override {
return m_context->mempool ? m_context->mempool->DynamicMemoryUsage()
: 0;
}
bool getHeaderTip(int &height, int64_t &block_time) override {
LOCK(::cs_main);
auto best_header = chainman().m_best_header;
if (best_header) {
height = best_header->nHeight;
block_time = best_header->GetBlockTime();
return true;
}
return false;
}
int getNumBlocks() override {
LOCK(::cs_main);
return chainman().ActiveChain().Height();
}
BlockHash getBestBlockHash() override {
const CBlockIndex *tip =
WITH_LOCK(::cs_main, return chainman().ActiveTip());
return tip ? tip->GetBlockHash()
: Params().GenesisBlock().GetHash();
}
int64_t getLastBlockTime() override {
LOCK(::cs_main);
if (chainman().ActiveChain().Tip()) {
return chainman().ActiveChain().Tip()->GetBlockTime();
}
// Genesis block's time of current network
return Params().GenesisBlock().GetBlockTime();
}
double getVerificationProgress() override {
const CBlockIndex *tip;
{
LOCK(::cs_main);
tip = chainman().ActiveChain().Tip();
}
return GuessVerificationProgress(Params().TxData(), tip);
}
bool isInitialBlockDownload() override {
return chainman().ActiveChainstate().IsInitialBlockDownload();
}
bool getReindex() override { return node::fReindex; }
bool getImporting() override { return node::fImporting; }
void setNetworkActive(bool active) override {
if (m_context->connman) {
m_context->connman->SetNetworkActive(active);
}
}
bool getNetworkActive() override {
return m_context->connman && m_context->connman->GetNetworkActive();
}
CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
UniValue executeRpc(const Config &config, const std::string &command,
const UniValue ¶ms,
const std::string &uri) override {
JSONRPCRequest req;
req.context = m_context;
req.params = params;
req.strMethod = command;
req.URI = uri;
return ::tableRPC.execute(config, req);
}
std::vector listRpcCommands() override {
return ::tableRPC.listCommands();
}
void rpcSetTimerInterfaceIfUnset(RPCTimerInterface *iface) override {
RPCSetTimerInterfaceIfUnset(iface);
}
void rpcUnsetTimerInterface(RPCTimerInterface *iface) override {
RPCUnsetTimerInterface(iface);
}
bool getUnspentOutput(const COutPoint &output, Coin &coin) override {
LOCK(::cs_main);
return chainman().ActiveChainstate().CoinsTip().GetCoin(output,
coin);
}
WalletClient &walletClient() override {
return *Assert(m_context->wallet_client);
}
std::unique_ptr handleInitMessage(InitMessageFn fn) override {
return MakeHandler(::uiInterface.InitMessage_connect(fn));
}
std::unique_ptr handleMessageBox(MessageBoxFn fn) override {
return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn));
}
std::unique_ptr handleQuestion(QuestionFn fn) override {
return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn));
}
std::unique_ptr
handleShowProgress(ShowProgressFn fn) override {
return MakeHandler(::uiInterface.ShowProgress_connect(fn));
}
std::unique_ptr handleNotifyNumConnectionsChanged(
NotifyNumConnectionsChangedFn fn) override {
return MakeHandler(
::uiInterface.NotifyNumConnectionsChanged_connect(fn));
}
std::unique_ptr handleNotifyNetworkActiveChanged(
NotifyNetworkActiveChangedFn fn) override {
return MakeHandler(
::uiInterface.NotifyNetworkActiveChanged_connect(fn));
}
std::unique_ptr
handleNotifyAlertChanged(NotifyAlertChangedFn fn) override {
return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn));
}
std::unique_ptr
handleBannedListChanged(BannedListChangedFn fn) override {
return MakeHandler(::uiInterface.BannedListChanged_connect(fn));
}
std::unique_ptr
handleNotifyBlockTip(NotifyBlockTipFn fn) override {
return MakeHandler(::uiInterface.NotifyBlockTip_connect(
[fn](SynchronizationState sync_state,
const CBlockIndex *block) {
fn(sync_state,
BlockTip{block->nHeight, block->GetBlockTime(),
block->GetBlockHash()},
GuessVerificationProgress(Params().TxData(), block));
}));
}
std::unique_ptr
handleNotifyHeaderTip(NotifyHeaderTipFn fn) override {
/* verification progress is unused when a header was received */
return MakeHandler(::uiInterface.NotifyHeaderTip_connect(
[fn](SynchronizationState sync_state,
const CBlockIndex *block) {
fn(sync_state,
BlockTip{block->nHeight, block->GetBlockTime(),
block->GetBlockHash()},
0);
}));
}
NodeContext *context() override { return m_context; }
void setContext(NodeContext *context) override { m_context = context; }
NodeContext *m_context{nullptr};
};
bool FillBlock(const CBlockIndex *index, const FoundBlock &block,
UniqueLock &lock, const CChain &active) {
if (!index) {
return false;
}
if (block.m_hash) {
*block.m_hash = index->GetBlockHash();
}
if (block.m_height) {
*block.m_height = index->nHeight;
}
if (block.m_time) {
*block.m_time = index->GetBlockTime();
}
if (block.m_max_time) {
*block.m_max_time = index->GetBlockTimeMax();
}
if (block.m_mtp_time) {
*block.m_mtp_time = index->GetMedianTimePast();
}
if (block.m_in_active_chain) {
*block.m_in_active_chain = active[index->nHeight] == index;
}
if (block.m_next_block) {
FillBlock(active[index->nHeight] == index
? active[index->nHeight + 1]
: nullptr,
*block.m_next_block, lock, active);
}
if (block.m_data) {
REVERSE_LOCK(lock);
if (!ReadBlockFromDisk(*block.m_data, index,
Params().GetConsensus())) {
block.m_data->SetNull();
}
}
return true;
}
class NotificationsProxy : public CValidationInterface {
public:
explicit NotificationsProxy(
std::shared_ptr notifications)
: m_notifications(std::move(notifications)) {}
virtual ~NotificationsProxy() = default;
void TransactionAddedToMempool(const CTransactionRef &tx,
uint64_t mempool_sequence) override {
m_notifications->transactionAddedToMempool(tx, mempool_sequence);
}
void TransactionRemovedFromMempool(const CTransactionRef &tx,
MemPoolRemovalReason reason,
uint64_t mempool_sequence) override {
m_notifications->transactionRemovedFromMempool(tx, reason,
mempool_sequence);
}
void BlockConnected(const std::shared_ptr &block,
const CBlockIndex *index) override {
m_notifications->blockConnected(*block, index->nHeight);
}
void BlockDisconnected(const std::shared_ptr &block,
const CBlockIndex *index) override {
m_notifications->blockDisconnected(*block, index->nHeight);
}
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);
}
std::shared_ptr m_notifications;
};
class NotificationsHandlerImpl : public Handler {
public:
explicit NotificationsHandlerImpl(
std::shared_ptr notifications)
: m_proxy(std::make_shared(
std::move(notifications))) {
RegisterSharedValidationInterface(m_proxy);
}
~NotificationsHandlerImpl() override { disconnect(); }
void disconnect() override {
if (m_proxy) {
UnregisterSharedValidationInterface(m_proxy);
m_proxy.reset();
}
}
std::shared_ptr m_proxy;
};
class RpcHandlerImpl : public Handler {
public:
explicit RpcHandlerImpl(const CRPCCommand &command)
: m_command(command), m_wrapped_command(&command) {
m_command.actor = [this](const Config &config,
const JSONRPCRequest &request,
UniValue &result, bool last_handler) {
if (!m_wrapped_command) {
return false;
}
try {
return m_wrapped_command->actor(config, 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() 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 {
private:
ChainstateManager &chainman() { return *Assert(m_node.chainman); }
public:
explicit ChainImpl(NodeContext &node, const CChainParams ¶ms)
: m_node(node), m_params(params) {}
std::optional getHeight() override {
LOCK(::cs_main);
const CChain &active = Assert(m_node.chainman)->ActiveChain();
int height = active.Height();
if (height >= 0) {
return height;
}
return std::nullopt;
}
BlockHash getBlockHash(int height) override {
LOCK(::cs_main);
const CChain &active = Assert(m_node.chainman)->ActiveChain();
CBlockIndex *block = active[height];
assert(block);
return block->GetBlockHash();
}
bool haveBlockOnDisk(int height) override {
LOCK(cs_main);
const CChain &active = Assert(m_node.chainman)->ActiveChain();
CBlockIndex *block = active[height];
return block && (block->nStatus.hasData() != 0) && block->nTx > 0;
}
CBlockLocator getTipLocator() override {
LOCK(cs_main);
const CChain &active = Assert(m_node.chainman)->ActiveChain();
return active.GetLocator();
}
std::optional
findLocatorFork(const CBlockLocator &locator) override {
LOCK(cs_main);
const Chainstate &active =
Assert(m_node.chainman)->ActiveChainstate();
if (const CBlockIndex *fork =
active.FindForkInGlobalIndex(locator)) {
return fork->nHeight;
}
return std::nullopt;
}
bool findBlock(const BlockHash &hash,
const FoundBlock &block) override {
WAIT_LOCK(cs_main, lock);
const CChain &active = Assert(m_node.chainman)->ActiveChain();
return FillBlock(m_node.chainman->m_blockman.LookupBlockIndex(hash),
block, lock, active);
}
bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height,
const FoundBlock &block) override {
WAIT_LOCK(cs_main, lock);
const CChain &active = Assert(m_node.chainman)->ActiveChain();
return FillBlock(active.FindEarliestAtLeast(min_time, min_height),
block, lock, active);
}
bool findAncestorByHeight(const BlockHash &block_hash,
int ancestor_height,
const FoundBlock &ancestor_out) override {
WAIT_LOCK(cs_main, lock);
const CChain &active = Assert(m_node.chainman)->ActiveChain();
if (const CBlockIndex *block =
m_node.chainman->m_blockman.LookupBlockIndex(block_hash)) {
if (const CBlockIndex *ancestor =
block->GetAncestor(ancestor_height)) {
return FillBlock(ancestor, ancestor_out, lock, active);
}
}
return FillBlock(nullptr, ancestor_out, lock, active);
}
bool findAncestorByHash(const BlockHash &block_hash,
const BlockHash &ancestor_hash,
const FoundBlock &ancestor_out) override {
WAIT_LOCK(cs_main, lock);
const CChain &active = Assert(m_node.chainman)->ActiveChain();
const CBlockIndex *block =
m_node.chainman->m_blockman.LookupBlockIndex(block_hash);
const CBlockIndex *ancestor =
m_node.chainman->m_blockman.LookupBlockIndex(ancestor_hash);
if (block && ancestor &&
block->GetAncestor(ancestor->nHeight) != ancestor) {
ancestor = nullptr;
}
return FillBlock(ancestor, ancestor_out, lock, active);
}
bool findCommonAncestor(const BlockHash &block_hash1,
const BlockHash &block_hash2,
const FoundBlock &ancestor_out,
const FoundBlock &block1_out,
const FoundBlock &block2_out) override {
WAIT_LOCK(cs_main, lock);
const CChain &active = Assert(m_node.chainman)->ActiveChain();
const CBlockIndex *block1 =
m_node.chainman->m_blockman.LookupBlockIndex(block_hash1);
const CBlockIndex *block2 =
m_node.chainman->m_blockman.LookupBlockIndex(block_hash2);
const CBlockIndex *ancestor =
block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;
// Using & instead of && below to avoid short circuiting and leaving
// output uninitialized. Cast bool to int to avoid
// -Wbitwise-instead-of-logical compiler warnings.
return int{FillBlock(ancestor, ancestor_out, lock, active)} &
int{FillBlock(block1, block1_out, lock, active)} &
int{FillBlock(block2, block2_out, lock, active)};
}
void findCoins(std::map &coins) override {
return FindCoins(m_node, coins);
}
double guessVerificationProgress(const BlockHash &block_hash) override {
LOCK(cs_main);
return GuessVerificationProgress(
Params().TxData(),
chainman().m_blockman.LookupBlockIndex(block_hash));
}
bool hasBlocks(const BlockHash &block_hash, int min_height,
std::optional max_height) override {
// hasBlocks returns true if all ancestors of block_hash in
// specified range have block data (are not pruned), false if any
// ancestors in specified range are missing data.
//
// For simplicity and robustness, min_height and max_height are only
// used to limit the range, and passing min_height that's too low or
// max_height that's too high will not crash or change the result.
LOCK(::cs_main);
if (const CBlockIndex *block =
chainman().m_blockman.LookupBlockIndex(block_hash)) {
if (max_height && block->nHeight >= *max_height) {
block = block->GetAncestor(*max_height);
}
for (; block->nStatus.hasData(); block = block->pprev) {
// Check pprev to not segfault if min_height is too low
if (block->nHeight <= min_height || !block->pprev) {
return true;
}
}
}
return false;
}
- bool hasDescendantsInMempool(const TxId &txid) override {
- if (!m_node.mempool) {
- return false;
- }
- LOCK(m_node.mempool->cs);
- auto it = m_node.mempool->GetIter(txid);
- return it && (*it)->GetCountWithDescendants() > 1;
- }
bool broadcastTransaction(const Config &config,
const CTransactionRef &tx,
const Amount &max_tx_fee, bool relay,
std::string &err_string) override {
const TransactionError err = BroadcastTransaction(
m_node, config, tx, err_string, max_tx_fee, relay,
/*wait_callback=*/false);
// Chain clients only care about failures to accept the tx to the
// mempool. Disregard non-mempool related failures. Note: this will
// need to be updated if BroadcastTransactions() is updated to
// return other non-mempool failures that Chain clients do not need
// to know about.
return err == TransactionError::OK;
}
CFeeRate estimateFee() const override {
if (!m_node.mempool) {
return {};
}
return m_node.mempool->estimateFee();
}
CFeeRate relayMinFee() override { return ::minRelayTxFee; }
CFeeRate relayDustFee() override { return ::dustRelayFee; }
bool havePruned() override {
LOCK(cs_main);
return m_node.chainman->m_blockman.m_have_pruned;
}
bool isReadyToBroadcast() override {
return !node::fImporting && !node::fReindex &&
!isInitialBlockDownload();
}
bool isInitialBlockDownload() override {
return chainman().ActiveChainstate().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 bilingual_str &message) override {
InitWarning(message);
}
void initError(const bilingual_str &message) override {
InitError(message);
}
void showProgress(const std::string &title, int progress,
bool resume_possible) override {
::uiInterface.ShowProgress(title, progress, resume_possible);
}
std::unique_ptr handleNotifications(
std::shared_ptr notifications) override {
return std::make_unique(
std::move(notifications));
}
void
waitForNotificationsIfTipChanged(const BlockHash &old_tip) override {
if (!old_tip.IsNull()) {
LOCK(::cs_main);
const CChain &active = Assert(m_node.chainman)->ActiveChain();
if (old_tip == active.Tip()->GetBlockHash()) {
return;
}
}
SyncWithValidationInterfaceQueue();
}
std::unique_ptr
handleRpc(const CRPCCommand &command) override {
return std::make_unique(command);
}
bool rpcEnableDeprecated(const std::string &method) override {
return IsDeprecatedRPCEnabled(gArgs, method);
}
void rpcRunLater(const std::string &name, std::function fn,
int64_t seconds) override {
RPCRunLater(name, std::move(fn), seconds);
}
int rpcSerializationFlags() override { return RPCSerializationFlags(); }
util::SettingsValue getRwSetting(const std::string &name) override {
util::SettingsValue result;
gArgs.LockSettings([&](const util::Settings &settings) {
if (const util::SettingsValue *value =
util::FindKey(settings.rw_settings, name)) {
result = *value;
}
});
return result;
}
bool updateRwSetting(const std::string &name,
const util::SettingsValue &value) override {
gArgs.LockSettings([&](util::Settings &settings) {
if (value.isNull()) {
settings.rw_settings.erase(name);
} else {
settings.rw_settings[name] = value;
}
});
return gArgs.WriteSettingsFile();
}
void requestMempoolTransactions(Notifications ¬ifications) override {
if (!m_node.mempool) {
return;
}
LOCK2(::cs_main, m_node.mempool->cs);
for (const CTxMemPoolEntry &entry : m_node.mempool->mapTx) {
notifications.transactionAddedToMempool(entry.GetSharedTx(),
/*mempool_sequence=*/0);
}
}
const CChainParams ¶ms() const override { return m_params; }
NodeContext &m_node;
const CChainParams &m_params;
};
} // namespace
} // namespace node
namespace interfaces {
std::unique_ptr MakeNode(node::NodeContext *context) {
return std::make_unique(context);
}
std::unique_ptr MakeChain(node::NodeContext &node,
const CChainParams ¶ms) {
return std::make_unique(node, params);
}
} // namespace interfaces
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 3b8bd90aa..e6515503b 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1,3337 +1,3267 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include