diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index a9e77c282..d5fc47067 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -1,491 +1,485 @@ // 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. #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 namespace interfaces { namespace { bool FillBlock(const CBlockIndex *index, const FoundBlock &block, UniqueLock &lock) { 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_data) { REVERSE_LOCK(lock); if (!ReadBlockFromDisk(*block.m_data, index, Params().GetConsensus())) { block.m_data->SetNull(); } } return true; } class LockImpl : public Chain::Lock, public UniqueLock { Optional getHeight() override { LockAssertion lock(::cs_main); int height = ::ChainActive().Height(); if (height >= 0) { return height; } return nullopt; } Optional getBlockHeight(const BlockHash &hash) override { LockAssertion lock(::cs_main); CBlockIndex *block = LookupBlockIndex(hash); if (block && ::ChainActive().Contains(block)) { return block->nHeight; } return nullopt; } BlockHash getBlockHash(int height) override { LockAssertion lock(::cs_main); CBlockIndex *block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockHash(); } - int64_t getBlockTime(int height) override { - LockAssertion lock(::cs_main); - CBlockIndex *block = ::ChainActive()[height]; - assert(block != nullptr); - return block->GetBlockTime(); - } bool haveBlockOnDisk(int height) override { LockAssertion lock(::cs_main); CBlockIndex *block = ::ChainActive()[height]; return block && (block->nStatus.hasData() != 0) && block->nTx > 0; } Optional findFirstBlockWithTimeAndHeight(int64_t time, int height, BlockHash *hash) override { LockAssertion lock(::cs_main); CBlockIndex *block = ::ChainActive().FindEarliestAtLeast(time, height); if (block) { if (hash) { *hash = block->GetBlockHash(); } return block->nHeight; } return nullopt; } Optional findFork(const BlockHash &hash, Optional *height) override { LockAssertion lock(::cs_main); const CBlockIndex *block = LookupBlockIndex(hash); const CBlockIndex *fork = block ? ::ChainActive().FindFork(block) : nullptr; if (height) { if (block) { *height = block->nHeight; } else { height->reset(); } } if (fork) { return fork->nHeight; } return nullopt; } CBlockLocator getTipLocator() override { LockAssertion lock(::cs_main); return ::ChainActive().GetLocator(); } Optional findLocatorFork(const CBlockLocator &locator) override { LockAssertion lock(::cs_main); if (CBlockIndex *fork = FindForkInGlobalIndex(::ChainActive(), locator)) { return fork->nHeight; } return nullopt; } bool contextualCheckTransactionForCurrentBlock( const Consensus::Params ¶ms, const CTransaction &tx, TxValidationState &state) override { LockAssertion lock(::cs_main); return ContextualCheckTransactionForCurrentBlock(params, tx, state); } using UniqueLock::UniqueLock; }; // namespace interfaces class NotificationsProxy : public CValidationInterface { public: explicit NotificationsProxy( std::shared_ptr notifications) : m_notifications(std::move(notifications)) {} virtual ~NotificationsProxy() = default; 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 &block, const CBlockIndex *index, const std::vector &tx_conflicted) override { m_notifications->BlockConnected(*block, tx_conflicted, 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](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() 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 { public: explicit ChainImpl(NodeContext &node, const CChainParams ¶ms) : m_node(node), m_params(params) {} std::unique_ptr lock(bool try_lock) override { auto lock = std::make_unique( ::cs_main, "cs_main", __FILE__, __LINE__, try_lock); if (try_lock && lock && !*lock) { return {}; } // Temporary to avoid CWG 1579 std::unique_ptr result = std::move(lock); return result; } bool findBlock(const BlockHash &hash, const FoundBlock &block) override { WAIT_LOCK(cs_main, lock); return FillBlock(LookupBlockIndex(hash), block, lock); } bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock &block) override { WAIT_LOCK(cs_main, lock); return FillBlock( ChainActive().FindEarliestAtLeast(min_time, min_height), block, lock); } bool findNextBlock(const BlockHash &block_hash, int block_height, const FoundBlock &next, bool *reorg) override { WAIT_LOCK(cs_main, lock); CBlockIndex *block = ChainActive()[block_height]; if (block && block->GetBlockHash() != block_hash) { block = nullptr; } if (reorg) { *reorg = !block; } return FillBlock(block ? ChainActive()[block_height + 1] : nullptr, next, lock); } bool findAncestorByHeight(const BlockHash &block_hash, int ancestor_height, const FoundBlock &ancestor_out) override { WAIT_LOCK(cs_main, lock); if (const CBlockIndex *block = LookupBlockIndex(block_hash)) { if (const CBlockIndex *ancestor = block->GetAncestor(ancestor_height)) { return FillBlock(ancestor, ancestor_out, lock); } } return FillBlock(nullptr, ancestor_out, lock); } bool findAncestorByHash(const BlockHash &block_hash, const BlockHash &ancestor_hash, const FoundBlock &ancestor_out) override { WAIT_LOCK(cs_main, lock); const CBlockIndex *block = LookupBlockIndex(block_hash); const CBlockIndex *ancestor = LookupBlockIndex(ancestor_hash); if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) { ancestor = nullptr; } return FillBlock(ancestor, ancestor_out, lock); } 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 CBlockIndex *block1 = LookupBlockIndex(block_hash1); const CBlockIndex *block2 = LookupBlockIndex(block_hash2); const CBlockIndex *ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr; return FillBlock(ancestor, ancestor_out, lock) & FillBlock(block1, block1_out, lock) & FillBlock(block2, block2_out, lock); } void findCoins(std::map &coins) override { return FindCoins(coins); } double guessVerificationProgress(const BlockHash &block_hash) override { LOCK(cs_main); return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash)); } bool hasBlocks(const BlockHash &block_hash, int min_height, 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 (CBlockIndex *block = 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 { LOCK(::g_mempool.cs); auto it = ::g_mempool.GetIter(txid); return it && (*it)->GetCountWithDescendants() > 1; } bool broadcastTransaction(const Config &config, const CTransactionRef &tx, std::string &err_string, const Amount &max_tx_fee, bool relay) 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; } void getTransactionAncestry(const TxId &txid, size_t &ancestors, size_t &descendants) override { ::g_mempool.GetTransactionAncestry(txid, ancestors, descendants); } void getPackageLimits(size_t &limit_ancestor_count, size_t &limit_descendant_count) override { limit_ancestor_count = size_t( std::max(1, gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT))); limit_descendant_count = size_t( std::max(1, gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT))); } bool checkChainLimits(const CTransactionRef &tx) override { LockPoints lp; CTxMemPoolEntry entry(tx, Amount(), 0, 0, false, 0, lp); CTxMemPool::setEntries ancestors; auto limit_ancestor_count = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); auto limit_ancestor_size = gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000; auto limit_descendant_count = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); auto limit_descendant_size = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000; std::string unused_error_string; LOCK(::g_mempool.cs); return ::g_mempool.CalculateMemPoolAncestors( entry, ancestors, limit_ancestor_count, limit_ancestor_size, limit_descendant_count, limit_descendant_size, unused_error_string); } CFeeRate estimateFee() const override { return ::g_mempool.estimateFee(); } CFeeRate relayMinFee() override { return ::minRelayTxFee; } CFeeRate relayDustFee() override { return ::dustRelayFee; } bool havePruned() override { LOCK(cs_main); return ::fHavePruned; } 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 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); if (old_tip == ::ChainActive().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(); } void requestMempoolTransactions(Notifications ¬ifications) override { LOCK2(::cs_main, ::g_mempool.cs); for (const CTxMemPoolEntry &entry : ::g_mempool.mapTx) { notifications.TransactionAddedToMempool(entry.GetSharedTx()); } } NodeContext &m_node; const CChainParams &m_params; }; } // namespace std::unique_ptr MakeChain(NodeContext &node, const CChainParams ¶ms) { return std::make_unique(node, params); } } // namespace interfaces diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 8d41d2ff5..592489ae2 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -1,377 +1,374 @@ // 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 #include #include #include #include #include class CBlock; class CChainParams; class Coin; class Config; class CRPCCommand; class CScheduler; class TxValidationState; struct BlockHash; struct CBlockLocator; struct NodeContext; 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; } //! 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; 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 Chain::lock() method, which lets clients delay chain tip updates //! should be removed when clients are able to respond to updates //! asynchronously //! (https://github.com/bitcoin/bitcoin/pull/10973#issuecomment-380101269). //! //! * The initMessage() 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. class Chain { public: virtual ~Chain() {} //! Interface for querying locked chain state, used by legacy code that //! assumes state won't change between calls. New code should avoid using //! the Lock interface and instead call higher-level Chain methods //! that return more information so the chain doesn't need to stay locked //! between calls. class Lock { public: virtual ~Lock() {} //! Get current chain height, not including genesis block (returns 0 if //! chain only contains genesis block, nullopt if chain does not contain //! any blocks). virtual Optional getHeight() = 0; //! Get block height above genesis block. Returns 0 for genesis block, //! 1 for following block, and so on. Returns nullopt for a block not //! included in the current chain. virtual Optional getBlockHeight(const BlockHash &hash) = 0; //! Get block hash. Height must be valid or this function will abort. virtual BlockHash getBlockHash(int height) = 0; - //! Get block time. Height must be valid or this function will abort. - virtual int64_t getBlockTime(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; //! Return height of the first block in the chain with timestamp equal //! or greater than the given time and height equal or greater than the //! given height, or nullopt if there is no block with a high enough //! timestamp and height. Also return the block hash as an optional //! output parameter (to avoid the cost of a second lookup in case this //! information is needed.) virtual Optional findFirstBlockWithTimeAndHeight(int64_t time, int height, BlockHash *hash) = 0; //! Return height of the highest block on the chain that is an ancestor //! of the specified block, or nullopt if no common ancestor is found. //! Also return the height of the specified block as an optional output //! parameter (to avoid the cost of a second hash lookup in case this //! information is desired). virtual Optional findFork(const BlockHash &hash, Optional *height) = 0; //! Get locator for the current chain tip. virtual CBlockLocator getTipLocator() = 0; //! Return height of the latest block common to locator and chain, which //! is guaranteed to be an ancestor of the block used to create the //! locator. virtual Optional findLocatorFork(const CBlockLocator &locator) = 0; //! Check if transaction will be final given chain height current time. virtual bool contextualCheckTransactionForCurrentBlock( const Consensus::Params ¶ms, const CTransaction &tx, TxValidationState &state) = 0; }; //! Return Lock interface. Chain is locked when this is called, and //! unlocked when the returned interface is freed. virtual std::unique_ptr lock(bool try_lock = false) = 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 next block if block is part of current chain. Also flag if //! there was a reorg and the specified block hash is no longer in the //! current chain, and optionally return block information. virtual bool findNextBlock(const BlockHash &block_hash, int block_height, const FoundBlock &next = {}, bool *reorg = nullptr) = 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, 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, std::string &err_string, const Amount &max_tx_fee, bool relay) = 0; //! Calculate mempool ancestor and descendant counts for the given //! transaction. virtual void getTransactionAncestry(const TxId &txid, size_t &ancestors, size_t &descendants) = 0; //! Get the node's package limits. //! Currently only returns the ancestor and descendant count limits, but //! could be enhanced to return more policy settings. virtual void getPackageLimits(size_t &limit_ancestor_count, size_t &limit_descendant_count) = 0; //! Check if transaction will pass the mempool's chain limits. virtual bool checkChainLimits(const CTransactionRef &tx) = 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 std::string &message) = 0; //! Send init error. virtual void initError(const std::string &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) {} virtual void TransactionRemovedFromMempool(const CTransactionRef &ptx) { } virtual void BlockConnected(const CBlock &block, const std::vector &tx_conflicted, 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; //! 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; }; //! 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(const CChainParams &chainParams) = 0; //! Load saved state. virtual bool load(const CChainParams &chainParams) = 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; }; //! Return implementation of Chain interface. std::unique_ptr MakeChain(NodeContext &node, const CChainParams ¶ms); //! Return implementation of ChainClient interface for a wallet client. This //! function will be undefined in builds where ENABLE_WALLET is false. //! //! Currently, wallets are the only chain clients. But in the future, other //! types of chain clients could be added, such as tools for monitoring, //! analysis, or fee estimation. These clients need to expose their own //! MakeXXXClient functions returning their implementations of the ChainClient //! interface. std::unique_ptr MakeWalletClient(Chain &chain, std::vector wallet_filenames); } // namespace interfaces #endif // BITCOIN_INTERFACES_CHAIN_H diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 78e4a2577..a33a9163a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1,4770 +1,4774 @@ // Copyright (c) 2009-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