aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces')
-rw-r--r--src/interfaces/README.md4
-rw-r--r--src/interfaces/chain.cpp370
-rw-r--r--src/interfaces/chain.h277
-rw-r--r--src/interfaces/handler.cpp16
-rw-r--r--src/interfaces/handler.h6
-rw-r--r--src/interfaces/node.cpp136
-rw-r--r--src/interfaces/node.h64
-rw-r--r--src/interfaces/wallet.cpp410
-rw-r--r--src/interfaces/wallet.h87
9 files changed, 1032 insertions, 338 deletions
diff --git a/src/interfaces/README.md b/src/interfaces/README.md
index 57d41df746..f77d172153 100644
--- a/src/interfaces/README.md
+++ b/src/interfaces/README.md
@@ -2,9 +2,9 @@
The following interfaces are defined here:
-* [`Chain`](chain.h) — used by wallet to access blockchain and mempool state. Added in [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
+* [`Chain`](chain.h) — used by wallet to access blockchain and mempool state. Added in [#14437](https://github.com/bitcoin/bitcoin/pull/14437), [#14711](https://github.com/bitcoin/bitcoin/pull/14711), [#15288](https://github.com/bitcoin/bitcoin/pull/15288), and [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
-* [`ChainClient`](chain.h) — used by node to start & stop `Chain` clients. Added in [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
+* [`ChainClient`](chain.h) — used by node to start & stop `Chain` clients. Added in [#14437](https://github.com/bitcoin/bitcoin/pull/14437).
* [`Node`](node.h) — used by GUI to start & stop bitcoin node. Added in [#10244](https://github.com/bitcoin/bitcoin/pull/10244).
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index 2571a91031..d8e459a8e8 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -1,12 +1,36 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2020 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 <interfaces/chain.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <interfaces/handler.h>
+#include <interfaces/wallet.h>
+#include <net.h>
+#include <net_processing.h>
+#include <node/coin.h>
+#include <node/context.h>
+#include <node/transaction.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 <rpc/protocol.h>
+#include <rpc/server.h>
+#include <shutdown.h>
#include <sync.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>
@@ -14,31 +38,351 @@
namespace interfaces {
namespace {
-class LockImpl : public Chain::Lock
+bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& 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 NotificationsProxy : public CValidationInterface
+{
+public:
+ explicit NotificationsProxy(std::shared_ptr<Chain::Notifications> 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<const CBlock>& block, const CBlockIndex* index) override
+ {
+ m_notifications->blockConnected(*block, index->nHeight);
+ }
+ void BlockDisconnected(const std::shared_ptr<const CBlock>& 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<Chain::Notifications> m_notifications;
};
-class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
+class NotificationsHandlerImpl : public Handler
{
- using UniqueLock::UniqueLock;
+public:
+ explicit NotificationsHandlerImpl(std::shared_ptr<Chain::Notifications> notifications)
+ : m_proxy(std::make_shared<NotificationsProxy>(std::move(notifications)))
+ {
+ RegisterSharedValidationInterface(m_proxy);
+ }
+ ~NotificationsHandlerImpl() override { disconnect(); }
+ void disconnect() override
+ {
+ if (m_proxy) {
+ UnregisterSharedValidationInterface(m_proxy);
+ m_proxy.reset();
+ }
+ }
+ std::shared_ptr<NotificationsProxy> m_proxy;
};
-class ChainImpl : public Chain
+class RpcHandlerImpl : public Handler
{
public:
- std::unique_ptr<Chain::Lock> lock(bool try_lock) override
+ explicit 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() final
{
- auto result = MakeUnique<LockingStateImpl>(::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
- return std::move(result);
+ if (m_wrapped_command) {
+ m_wrapped_command = nullptr;
+ ::tableRPC.removeCommand(m_command.name, &m_command);
+ }
}
- std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); }
+
+ ~RpcHandlerImpl() override { disconnect(); }
+
+ CRPCCommand m_command;
+ const CRPCCommand* m_wrapped_command;
};
+class ChainImpl : public Chain
+{
+public:
+ explicit ChainImpl(NodeContext& node) : m_node(node) {}
+ Optional<int> getHeight() override
+ {
+ LOCK(::cs_main);
+ int height = ::ChainActive().Height();
+ if (height >= 0) {
+ return height;
+ }
+ return nullopt;
+ }
+ Optional<int> getBlockHeight(const uint256& hash) override
+ {
+ LOCK(::cs_main);
+ CBlockIndex* block = LookupBlockIndex(hash);
+ if (block && ::ChainActive().Contains(block)) {
+ return block->nHeight;
+ }
+ return nullopt;
+ }
+ uint256 getBlockHash(int height) override
+ {
+ LOCK(::cs_main);
+ CBlockIndex* block = ::ChainActive()[height];
+ assert(block);
+ return block->GetBlockHash();
+ }
+ bool haveBlockOnDisk(int height) override
+ {
+ LOCK(cs_main);
+ CBlockIndex* block = ::ChainActive()[height];
+ return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
+ }
+ Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override
+ {
+ LOCK(cs_main);
+ CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height);
+ if (block) {
+ if (hash) *hash = block->GetBlockHash();
+ return block->nHeight;
+ }
+ return nullopt;
+ }
+ CBlockLocator getTipLocator() override
+ {
+ LOCK(cs_main);
+ return ::ChainActive().GetLocator();
+ }
+ bool checkFinalTx(const CTransaction& tx) override
+ {
+ LOCK(cs_main);
+ return CheckFinalTx(tx);
+ }
+ Optional<int> findLocatorFork(const CBlockLocator& locator) override
+ {
+ LOCK(cs_main);
+ if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) {
+ return fork->nHeight;
+ }
+ return nullopt;
+ }
+ bool findBlock(const uint256& 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 uint256& 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 uint256& 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 uint256& block_hash, const uint256& 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 uint256& block_hash1, const uint256& 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;
+ // Using & instead of && below to avoid short circuiting and leaving
+ // output uninitialized.
+ return FillBlock(ancestor, ancestor_out, lock) & FillBlock(block1, block1_out, lock) & FillBlock(block2, block2_out, lock);
+ }
+ void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
+ double guessVerificationProgress(const uint256& block_hash) override
+ {
+ LOCK(cs_main);
+ return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash));
+ }
+ bool hasBlocks(const uint256& block_hash, int min_height, Optional<int> 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 & BLOCK_HAVE_DATA; 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;
+ }
+ RBFTransactionState isRBFOptIn(const CTransaction& tx) override
+ {
+ LOCK(::mempool.cs);
+ return IsRBFOptIn(tx, ::mempool);
+ }
+ bool hasDescendantsInMempool(const uint256& txid) override
+ {
+ LOCK(::mempool.cs);
+ auto it = ::mempool.GetIter(txid);
+ return it && (*it)->GetCountWithDescendants() > 1;
+ }
+ bool broadcastTransaction(const CTransactionRef& tx,
+ const CAmount& max_tx_fee,
+ bool relay,
+ std::string& err_string) override
+ {
+ const TransactionError err = BroadcastTransaction(m_node, 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 TransactionError::OK == err;
+ }
+ void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) override
+ {
+ ::mempool.GetTransactionAncestry(txid, ancestors, descendants);
+ }
+ void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override
+ {
+ limit_ancestor_count = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
+ limit_descendant_count = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
+ }
+ bool checkChainLimits(const CTransactionRef& tx) override
+ {
+ LockPoints lp;
+ CTxMemPoolEntry entry(tx, 0, 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(::mempool.cs);
+ return ::mempool.CalculateMemPoolAncestors(entry, ancestors, limit_ancestor_count, limit_ancestor_size,
+ limit_descendant_count, limit_descendant_size, unused_error_string);
+ }
+ CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
+ {
+ return ::feeEstimator.estimateSmartFee(num_blocks, calc, conservative);
+ }
+ unsigned int estimateMaxBlocks() override
+ {
+ return ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+ }
+ CFeeRate mempoolMinFee() override
+ {
+ return ::mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
+ }
+ CFeeRate relayMinFee() override { return ::minRelayTxFee; }
+ CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
+ 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 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<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) override
+ {
+ return MakeUnique<NotificationsHandlerImpl>(std::move(notifications));
+ }
+ void waitForNotificationsIfTipChanged(const uint256& old_tip) override
+ {
+ if (!old_tip.IsNull()) {
+ LOCK(::cs_main);
+ if (old_tip == ::ChainActive().Tip()->GetBlockHash()) 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());
+ }
+ }
+ NodeContext& m_node;
+};
} // namespace
-std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
+std::unique_ptr<Chain> MakeChain(NodeContext& node) { return MakeUnique<ChainImpl>(node); }
} // namespace interfaces
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index fe5658de4b..7dfc77db7b 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -1,43 +1,280 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2020 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 <optional.h> // For Optional and nullopt
+#include <primitives/transaction.h> // For CTransactionRef
+
#include <memory>
+#include <stddef.h>
+#include <stdint.h>
#include <string>
#include <vector>
+class CBlock;
+class CFeeRate;
+class CRPCCommand;
class CScheduler;
+class Coin;
+class uint256;
+enum class RBFTransactionState;
+struct bilingual_str;
+struct CBlockLocator;
+struct FeeCalculation;
+struct NodeContext;
namespace interfaces {
-//! Interface for giving wallet processes access to blockchain state.
+class Handler;
+class Wallet;
+
+//! Helper for findBlock to selectively return pieces of block data.
+class FoundBlock
+{
+public:
+ FoundBlock& hash(uint256& 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; }
+
+ uint256* 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 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.
+//!
+//! * The `guessVerificationProgress`, `getBlockHeight`, `getBlockHash`, etc
+//! methods can go away if rescan logic is moved on the node side, and wallet
+//! only register rescan request.
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
+ //! 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<int> 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<int> getBlockHeight(const uint256& hash) = 0;
+
+ //! Get block hash. Height must be valid or this function will abort.
+ virtual uint256 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;
+
+ //! 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<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) = 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 Optional<int> findLocatorFork(const CBlockLocator& locator) = 0;
+
+ //! Check if transaction will be final given chain height current time.
+ virtual bool checkFinalTx(const CTransaction& tx) = 0;
+
+ //! Return whether node has the block and optionally return block metadata
+ //! or contents.
+ virtual bool findBlock(const uint256& 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 uint256& 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 uint256& 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 uint256& block_hash,
+ const uint256& ancestor_hash,
+ const FoundBlock& ancestor_out={}) = 0;
+
+ //! Find most recent common ancestor between two blocks and optionally
+ //! return block information.
+ virtual bool findCommonAncestor(const uint256& block_hash1,
+ const uint256& 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<COutPoint, Coin>& coins) = 0;
+
+ //! Estimate fraction of total transactions verified if blocks up to
+ //! the specified block hash are verified.
+ virtual double guessVerificationProgress(const uint256& 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 uint256& block_hash, int min_height = 0, Optional<int> max_height = {}) = 0;
+
+ //! Check if transaction is RBF opt in.
+ virtual RBFTransactionState isRBFOptIn(const CTransaction& tx) = 0;
+
+ //! Check if transaction has descendants in mempool.
+ virtual bool hasDescendantsInMempool(const uint256& 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 CTransactionRef& tx,
+ const CAmount& max_tx_fee,
+ bool relay,
+ std::string& err_string) = 0;
+
+ //! Calculate mempool ancestor and descendant counts for the given transaction.
+ virtual void getTransactionAncestry(const uint256& 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(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) = 0;
+
+ //! Check if transaction will pass the mempool's chain limits.
+ virtual bool checkChainLimits(const CTransactionRef& tx) = 0;
+
+ //! Estimate smart fee.
+ virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc = nullptr) = 0;
+
+ //! Fee estimator max target.
+ virtual unsigned int estimateMaxBlocks() = 0;
+
+ //! Mempool minimum fee.
+ virtual CFeeRate mempoolMinFee() = 0;
+
+ //! Relay current minimum fee (from -minrelaytxfee and -incrementalrelayfee settings).
+ virtual CFeeRate relayMinFee() = 0;
+
+ //! Relay incremental fee setting (-incrementalrelayfee), reflecting cost of relay.
+ virtual CFeeRate relayIncrementalFee() = 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 ~Lock() {}
+ virtual ~Notifications() {}
+ virtual void transactionAddedToMempool(const CTransactionRef& tx) {}
+ virtual void transactionRemovedFromMempool(const CTransactionRef& ptx) {}
+ 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) {}
};
- //! Return Lock interface. Chain is locked when this is called, and
- //! unlocked when the returned interface is freed.
- virtual std::unique_ptr<Lock> lock(bool try_lock = false) = 0;
+ //! Register handler for notifications.
+ virtual std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) = 0;
- //! Return Lock interface assuming chain is already locked. This
- //! method is temporary and is only used in a few places to avoid changing
- //! behavior while code is transitioned to use the Chain::Lock interface.
- virtual std::unique_ptr<Lock> assumeLocked() = 0;
+ //! Wait for pending notifications to be processed unless block hash points to the current
+ //! chain tip.
+ virtual void waitForNotificationsIfTipChanged(const uint256& 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<Handler> 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<void()> 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& notifications) = 0;
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
@@ -64,10 +301,16 @@ public:
//! Shut down client.
virtual void stop() = 0;
+
+ //! Set mock time.
+ virtual void setMockTime(int64_t time) = 0;
+
+ //! Return interfaces for accessing wallets (if any).
+ virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;
};
//! Return implementation of Chain interface.
-std::unique_ptr<Chain> MakeChain();
+std::unique_ptr<Chain> MakeChain(NodeContext& node);
//! Return implementation of ChainClient interface for a wallet client. This
//! function will be undefined in builds where ENABLE_WALLET is false.
diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp
index 92601fc4e9..4134a4527f 100644
--- a/src/interfaces/handler.cpp
+++ b/src/interfaces/handler.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -22,6 +22,15 @@ public:
boost::signals2::scoped_connection m_connection;
};
+class CleanupHandler : public Handler
+{
+public:
+ explicit CleanupHandler(std::function<void()> cleanup) : m_cleanup(std::move(cleanup)) {}
+ ~CleanupHandler() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; }
+ void disconnect() override { if (!m_cleanup) return; m_cleanup(); m_cleanup = nullptr; }
+ std::function<void()> m_cleanup;
+};
+
} // namespace
std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection)
@@ -29,4 +38,9 @@ std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection)
return MakeUnique<HandlerImpl>(std::move(connection));
}
+std::unique_ptr<Handler> MakeHandler(std::function<void()> cleanup)
+{
+ return MakeUnique<CleanupHandler>(std::move(cleanup));
+}
+
} // namespace interfaces
diff --git a/src/interfaces/handler.h b/src/interfaces/handler.h
index c4c674cac5..11baf9dd65 100644
--- a/src/interfaces/handler.h
+++ b/src/interfaces/handler.h
@@ -1,10 +1,11 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2020 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_HANDLER_H
#define BITCOIN_INTERFACES_HANDLER_H
+#include <functional>
#include <memory>
namespace boost {
@@ -30,6 +31,9 @@ public:
//! Return handler wrapping a boost signal connection.
std::unique_ptr<Handler> MakeHandler(boost::signals2::connection connection);
+//! Return handler wrapping a cleanup function.
+std::unique_ptr<Handler> MakeHandler(std::function<void()> cleanup);
+
} // namespace interfaces
#endif // BITCOIN_INTERFACES_HANDLER_H
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index bd7e414ff3..ca1435fe60 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2020 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 <interfaces/node.h>
#include <addrdb.h>
-#include <amount.h>
+#include <banman.h>
#include <chain.h>
#include <chainparams.h>
#include <init.h>
@@ -16,17 +16,20 @@
#include <net_processing.h>
#include <netaddress.h>
#include <netbase.h>
+#include <node/context.h>
#include <policy/feerate.h>
#include <policy/fees.h>
-#include <policy/policy.h>
+#include <policy/settings.h>
#include <primitives/block.h>
#include <rpc/server.h>
-#include <scheduler.h>
#include <shutdown.h>
+#include <support/allocators/secure.h>
#include <sync.h>
#include <txmempool.h>
#include <ui_interface.h>
+#include <util/ref.h>
#include <util/system.h>
+#include <util/translation.h>
#include <validation.h>
#include <warnings.h>
@@ -34,47 +37,56 @@
#include <config/bitcoin-config.h>
#endif
-#include <atomic>
#include <univalue.h>
+#include <boost/signals2/signal.hpp>
+
class CWallet;
fs::path GetWalletDir();
std::vector<fs::path> ListWalletDir();
std::vector<std::shared_ptr<CWallet>> GetWallets();
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings);
+WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result);
+std::unique_ptr<interfaces::Handler> HandleLoadWallet(interfaces::Node::LoadWalletFn load_wallet);
namespace interfaces {
-class Wallet;
-
namespace {
class NodeImpl : public Node
{
public:
- NodeImpl() { m_interfaces.chain = MakeChain(); }
+ void initError(const std::string& message) override { InitError(Untranslated(message)); }
bool parseParameters(int argc, const char* const argv[], std::string& error) override
{
return gArgs.ParseParameters(argc, argv, error);
}
bool readConfigFiles(std::string& error) override { return gArgs.ReadConfigFiles(error, true); }
+ void forceSetArg(const std::string& arg, const std::string& value) override { gArgs.ForceSetArg(arg, value); }
bool softSetArg(const std::string& arg, const std::string& value) override { return gArgs.SoftSetArg(arg, value); }
bool softSetBoolArg(const std::string& arg, bool value) override { return gArgs.SoftSetBoolArg(arg, value); }
void selectParams(const std::string& network) override { SelectParams(network); }
+ uint64_t getAssumedBlockchainSize() override { return Params().AssumedBlockchainSize(); }
+ uint64_t getAssumedChainStateSize() override { return Params().AssumedChainStateSize(); }
std::string getNetwork() override { return Params().NetworkIDString(); }
void initLogging() override { InitLogging(); }
void initParameterInteraction() override { InitParameterInteraction(); }
- std::string getWarnings(const std::string& type) override { return GetWarnings(type); }
- uint32_t getLogCategories() override { return g_logger->GetCategoryMask(); }
+ std::string getWarnings() override { return GetWarnings(true); }
+ uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
bool baseInitialize() override
{
return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() &&
AppInitLockDataDirectory();
}
- bool appInitMain() override { return AppInitMain(m_interfaces); }
+ bool appInitMain() override
+ {
+ m_context.chain = MakeChain(m_context);
+ return AppInitMain(m_context_ref, m_context);
+ }
void appShutdown() override
{
- Interrupt();
- Shutdown(m_interfaces);
+ Interrupt(m_context);
+ Shutdown(m_context);
}
void startShutdown() override { StartShutdown(); }
bool shutdownRequested() override { return ShutdownRequested(); }
@@ -87,19 +99,19 @@ public:
StopMapPort();
}
}
- void setupServerArgs() override { return SetupServerArgs(); }
+ void setupServerArgs() override { return SetupServerArgs(m_context); }
bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
size_t getNodeCount(CConnman::NumConnections flags) override
{
- return g_connman ? g_connman->GetNodeCount(flags) : 0;
+ return m_context.connman ? m_context.connman->GetNodeCount(flags) : 0;
}
bool getNodesStats(NodesStats& stats) override
{
stats.clear();
- if (g_connman) {
+ if (m_context.connman) {
std::vector<CNodeStats> stats_temp;
- g_connman->GetNodeStats(stats_temp);
+ m_context.connman->GetNodeStats(stats_temp);
stats.reserve(stats_temp.size());
for (auto& node_stats_temp : stats_temp) {
@@ -120,39 +132,46 @@ public:
}
bool getBanned(banmap_t& banmap) override
{
- if (g_connman) {
- g_connman->GetBanned(banmap);
+ if (m_context.banman) {
+ m_context.banman->GetBanned(banmap);
return true;
}
return false;
}
bool ban(const CNetAddr& net_addr, BanReason reason, int64_t ban_time_offset) override
{
- if (g_connman) {
- g_connman->Ban(net_addr, reason, ban_time_offset);
+ if (m_context.banman) {
+ m_context.banman->Ban(net_addr, reason, ban_time_offset);
return true;
}
return false;
}
bool unban(const CSubNet& ip) override
{
- if (g_connman) {
- g_connman->Unban(ip);
+ if (m_context.banman) {
+ m_context.banman->Unban(ip);
return true;
}
return false;
}
- bool disconnect(NodeId id) override
+ 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 (g_connman) {
- return g_connman->DisconnectNode(id);
+ if (m_context.connman) {
+ return m_context.connman->DisconnectNode(id);
}
return false;
}
- int64_t getTotalBytesRecv() override { return g_connman ? g_connman->GetTotalBytesRecv() : 0; }
- int64_t getTotalBytesSent() override { return g_connman ? g_connman->GetTotalBytesSent() : 0; }
- size_t getMempoolSize() override { return ::mempool.size(); }
- size_t getMempoolDynamicUsage() override { return ::mempool.DynamicMemoryUsage(); }
+ 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);
@@ -166,13 +185,18 @@ public:
int getNumBlocks() override
{
LOCK(::cs_main);
- return ::chainActive.Height();
+ return ::ChainActive().Height();
+ }
+ uint256 getBestBlockHash() override
+ {
+ const CBlockIndex* tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip());
+ return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash();
}
int64_t getLastBlockTime() override
{
LOCK(::cs_main);
- if (::chainActive.Tip()) {
- return ::chainActive.Tip()->GetBlockTime();
+ if (::ChainActive().Tip()) {
+ return ::ChainActive().Tip()->GetBlockTime();
}
return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network
}
@@ -181,21 +205,20 @@ public:
const CBlockIndex* tip;
{
LOCK(::cs_main);
- tip = ::chainActive.Tip();
+ tip = ::ChainActive().Tip();
}
return GuessVerificationProgress(Params().TxData(), tip);
}
- bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
+ bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
bool getReindex() override { return ::fReindex; }
bool getImporting() override { return ::fImporting; }
void setNetworkActive(bool active) override
{
- if (g_connman) {
- g_connman->SetNetworkActive(active);
+ if (m_context.connman) {
+ m_context.connman->SetNetworkActive(active);
}
}
- bool getNetworkActive() override { return g_connman && g_connman->GetNetworkActive(); }
- CAmount getMaxTxFee() override { return ::maxTxFee; }
+ bool getNetworkActive() override { return m_context.connman && m_context.connman->GetNetworkActive(); }
CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override
{
FeeCalculation fee_calc;
@@ -208,7 +231,7 @@ public:
CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
{
- JSONRPCRequest req;
+ JSONRPCRequest req(m_context_ref);
req.params = params;
req.strMethod = command;
req.URI = uri;
@@ -220,7 +243,7 @@ public:
bool getUnspentOutput(const COutPoint& output, Coin& coin) override
{
LOCK(::cs_main);
- return ::pcoinsTip->GetCoin(output, coin);
+ return ::ChainstateActive().CoinsTip().GetCoin(output, coin);
}
std::string getWalletDir() override
{
@@ -237,11 +260,22 @@ public:
std::vector<std::unique_ptr<Wallet>> getWallets() override
{
std::vector<std::unique_ptr<Wallet>> wallets;
- for (const std::shared_ptr<CWallet>& wallet : GetWallets()) {
- wallets.emplace_back(MakeWallet(wallet));
+ for (auto& client : m_context.chain_clients) {
+ auto client_wallets = client->getWallets();
+ std::move(client_wallets.begin(), client_wallets.end(), std::back_inserter(wallets));
}
return wallets;
}
+ std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
+ {
+ return MakeWallet(LoadWallet(*m_context.chain, name, error, warnings));
+ }
+ std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, WalletCreationStatus& status) override
+ {
+ std::shared_ptr<CWallet> wallet;
+ status = CreateWallet(*m_context.chain, passphrase, wallet_creation_flags, name, error, warnings, wallet);
+ return MakeWallet(wallet);
+ }
std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
{
return MakeHandler(::uiInterface.InitMessage_connect(fn));
@@ -260,7 +294,7 @@ public:
}
std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) override
{
- return MakeHandler(::uiInterface.LoadWallet_connect([fn](std::shared_ptr<CWallet> wallet) { fn(MakeWallet(wallet)); }));
+ return HandleLoadWallet(std::move(fn));
}
std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override
{
@@ -280,20 +314,22 @@ public:
}
std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override
{
- return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](bool initial_download, const CBlockIndex* block) {
- fn(initial_download, block->nHeight, block->GetBlockTime(),
+ 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<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override
{
return MakeHandler(
- ::uiInterface.NotifyHeaderTip_connect([fn](bool initial_download, const CBlockIndex* block) {
- fn(initial_download, block->nHeight, block->GetBlockTime(),
- GuessVerificationProgress(Params().TxData(), block));
+ ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) {
+ fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()},
+ /* verification progress is unused when a header was received */ 0);
}));
}
- InitInterfaces m_interfaces;
+ NodeContext* context() override { return &m_context; }
+ NodeContext m_context;
+ util::Ref m_context_ref{m_context};
};
} // namespace
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 1f8bbbff7a..0b7fb6736a 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -1,14 +1,15 @@
-// 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.
#ifndef BITCOIN_INTERFACES_NODE_H
#define BITCOIN_INTERFACES_NODE_H
-#include <addrdb.h> // For banmap_t
#include <amount.h> // For CAmount
#include <net.h> // For CConnman::NumConnections
+#include <net_types.h> // For banmap_t
#include <netaddress.h> // For Network
+#include <support/allocators/secure.h> // For SecureString
#include <functional>
#include <memory>
@@ -18,6 +19,7 @@
#include <tuple>
#include <vector>
+class BanMan;
class CCoinControl;
class CFeeRate;
class CNodeStats;
@@ -25,11 +27,16 @@ class Coin;
class RPCTimerInterface;
class UniValue;
class proxyType;
+enum class SynchronizationState;
+enum class WalletCreationStatus;
struct CNodeStateStats;
+struct NodeContext;
+struct bilingual_str;
namespace interfaces {
class Handler;
class Wallet;
+struct BlockTip;
//! Top-level interface for a bitcoin node (bitcoind process).
class Node
@@ -37,9 +44,15 @@ class Node
public:
virtual ~Node() {}
+ //! Send init error.
+ virtual void initError(const std::string& message) = 0;
+
//! Set command line arguments.
virtual bool parseParameters(int argc, const char* const argv[], std::string& error) = 0;
+ //! Set a command line argument
+ virtual void forceSetArg(const std::string& arg, const std::string& value) = 0;
+
//! Set a command line argument if it doesn't already have a value
virtual bool softSetArg(const std::string& arg, const std::string& value) = 0;
@@ -52,6 +65,12 @@ public:
//! Choose network parameters.
virtual void selectParams(const std::string& network) = 0;
+ //! Get the (assumed) blockchain size.
+ virtual uint64_t getAssumedBlockchainSize() = 0;
+
+ //! Get the (assumed) chain state size.
+ virtual uint64_t getAssumedChainStateSize() = 0;
+
//! Get network name.
virtual std::string getNetwork() = 0;
@@ -62,7 +81,7 @@ public:
virtual void initParameterInteraction() = 0;
//! Get warnings.
- virtual std::string getWarnings(const std::string& type) = 0;
+ virtual std::string getWarnings() = 0;
// Get log flags.
virtual uint32_t getLogCategories() = 0;
@@ -107,8 +126,11 @@ public:
//! Unban node.
virtual bool unban(const CSubNet& ip) = 0;
- //! Disconnect node.
- virtual bool disconnect(NodeId id) = 0;
+ //! Disconnect node by address.
+ virtual bool disconnectByAddress(const CNetAddr& net_addr) = 0;
+
+ //! Disconnect node by id.
+ virtual bool disconnectById(NodeId id) = 0;
//! Get total bytes recv.
virtual int64_t getTotalBytesRecv() = 0;
@@ -128,6 +150,9 @@ public:
//! Get num blocks.
virtual int getNumBlocks() = 0;
+ //! Get best block hash.
+ virtual uint256 getBestBlockHash() = 0;
+
//! Get last block time.
virtual int64_t getLastBlockTime() = 0;
@@ -149,9 +174,6 @@ public:
//! Get network active.
virtual bool getNetworkActive() = 0;
- //! Get max tx fee.
- virtual CAmount getMaxTxFee() = 0;
-
//! Estimate smart fee.
virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) = 0;
@@ -182,17 +204,25 @@ public:
//! Return interfaces for accessing wallets (if any).
virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;
+ //! Attempts to load a wallet from file or directory.
+ //! The loaded wallet is also notified to handlers previously registered
+ //! with handleLoadWallet.
+ virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
+
+ //! Create a wallet from file
+ virtual std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, WalletCreationStatus& status) = 0;
+
//! Register handler for init messages.
using InitMessageFn = std::function<void(const std::string& message)>;
virtual std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) = 0;
//! Register handler for message box messages.
using MessageBoxFn =
- std::function<bool(const std::string& message, const std::string& caption, unsigned int style)>;
+ std::function<bool(const bilingual_str& message, const std::string& caption, unsigned int style)>;
virtual std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) = 0;
//! Register handler for question messages.
- using QuestionFn = std::function<bool(const std::string& message,
+ using QuestionFn = std::function<bool(const bilingual_str& message,
const std::string& non_interactive_message,
const std::string& caption,
unsigned int style)>;
@@ -224,18 +254,28 @@ public:
//! Register handler for block tip messages.
using NotifyBlockTipFn =
- std::function<void(bool initial_download, int height, int64_t block_time, double verification_progress)>;
+ std::function<void(SynchronizationState, interfaces::BlockTip tip, double verification_progress)>;
virtual std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) = 0;
//! Register handler for header tip messages.
using NotifyHeaderTipFn =
- std::function<void(bool initial_download, int height, int64_t block_time, double verification_progress)>;
+ std::function<void(SynchronizationState, interfaces::BlockTip tip, double verification_progress)>;
virtual std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) = 0;
+
+ //! Return pointer to internal chain interface, useful for testing.
+ virtual NodeContext* context() { return nullptr; }
};
//! Return implementation of Node interface.
std::unique_ptr<Node> MakeNode();
+//! Block tip (could be a header or not, depends on the subscribed signal).
+struct BlockTip {
+ int block_height;
+ int64_t block_time;
+ uint256 block_hash;
+};
+
} // namespace interfaces
#endif // BITCOIN_INTERFACES_NODE_H
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 672a557d41..cec75030ad 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -1,36 +1,27 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2020 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 <interfaces/wallet.h>
#include <amount.h>
-#include <chain.h>
-#include <consensus/validation.h>
-#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/handler.h>
-#include <net.h>
-#include <policy/feerate.h>
#include <policy/fees.h>
-#include <policy/policy.h>
#include <primitives/transaction.h>
-#include <rpc/server.h>
-#include <scheduler.h>
-#include <script/ismine.h>
#include <script/standard.h>
#include <support/allocators/secure.h>
#include <sync.h>
-#include <timedata.h>
#include <ui_interface.h>
#include <uint256.h>
+#include <util/check.h>
#include <util/system.h>
-#include <validation.h>
#include <wallet/feebumper.h>
#include <wallet/fees.h>
+#include <wallet/ismine.h>
+#include <wallet/load.h>
#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
-#include <wallet/walletutil.h>
#include <memory>
#include <string>
@@ -40,36 +31,8 @@
namespace interfaces {
namespace {
-class PendingWalletTxImpl : public PendingWalletTx
-{
-public:
- explicit PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {}
-
- const CTransaction& get() override { return *m_tx; }
-
- int64_t getVirtualSize() override { return GetVirtualTransactionSize(*m_tx); }
-
- bool commit(WalletValueMap value_map,
- WalletOrderForm order_form,
- std::string& reject_reason) override
- {
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- CValidationState state;
- if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), m_key, g_connman.get(), state)) {
- reject_reason = state.GetRejectReason();
- return false;
- }
- return true;
- }
-
- CTransactionRef m_tx;
- CWallet& m_wallet;
- CReserveKey m_key;
-};
-
//! Construct wallet tx struct.
-WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, const CWalletTx& wtx)
+WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
{
WalletTx result;
result.tx = wtx.tx;
@@ -84,10 +47,10 @@ WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, co
result.txout_is_mine.emplace_back(wallet.IsMine(txout));
result.txout_address.emplace_back();
result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ?
- IsMine(wallet, result.txout_address.back()) :
+ wallet.IsMine(result.txout_address.back()) :
ISMINE_NO);
}
- result.credit = wtx.GetCredit(locked_chain, ISMINE_ALL);
+ result.credit = wtx.GetCredit(ISMINE_ALL);
result.debit = wtx.GetDebit(ISMINE_ALL);
result.change = wtx.GetChange();
result.time = wtx.GetTxTime();
@@ -97,29 +60,24 @@ WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, co
}
//! Construct wallet tx status struct.
-WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx)
+WalletTxStatus MakeWalletTxStatus(CWallet& wallet, const CWalletTx& wtx)
{
- LockAnnotation lock(::cs_main); // Temporary, for CheckFinalTx below. Removed in upcoming commit.
-
WalletTxStatus result;
- auto mi = ::mapBlockIndex.find(wtx.hashBlock);
- CBlockIndex* block = mi != ::mapBlockIndex.end() ? mi->second : nullptr;
- result.block_height = (block ? block->nHeight : std::numeric_limits<int>::max());
- result.blocks_to_maturity = wtx.GetBlocksToMaturity(locked_chain);
- result.depth_in_main_chain = wtx.GetDepthInMainChain(locked_chain);
+ result.block_height = wtx.m_confirm.block_height > 0 ? wtx.m_confirm.block_height : std::numeric_limits<int>::max();
+ result.blocks_to_maturity = wtx.GetBlocksToMaturity();
+ result.depth_in_main_chain = wtx.GetDepthInMainChain();
result.time_received = wtx.nTimeReceived;
result.lock_time = wtx.tx->nLockTime;
- result.is_final = CheckFinalTx(*wtx.tx);
- result.is_trusted = wtx.IsTrusted(locked_chain);
+ result.is_final = wallet.chain().checkFinalTx(*wtx.tx);
+ result.is_trusted = wtx.IsTrusted();
result.is_abandoned = wtx.isAbandoned();
result.is_coinbase = wtx.IsCoinBase();
- result.is_in_main_chain = wtx.IsInMainChain(locked_chain);
+ result.is_in_main_chain = wtx.IsInMainChain();
return result;
}
//! Construct wallet TxOut struct.
-WalletTxOut MakeWalletTxOut(interfaces::Chain::Lock& locked_chain,
- CWallet& wallet,
+WalletTxOut MakeWalletTxOut(CWallet& wallet,
const CWalletTx& wtx,
int n,
int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
@@ -128,62 +86,81 @@ WalletTxOut MakeWalletTxOut(interfaces::Chain::Lock& locked_chain,
result.txout = wtx.tx->vout[n];
result.time = wtx.GetTxTime();
result.depth_in_main_chain = depth;
- result.is_spent = wallet.IsSpent(locked_chain, wtx.GetHash(), n);
+ result.is_spent = wallet.IsSpent(wtx.GetHash(), n);
return result;
}
class WalletImpl : public Wallet
{
public:
- explicit WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_shared_wallet(wallet), m_wallet(*wallet.get()) {}
+ explicit WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_wallet(wallet) {}
bool encryptWallet(const SecureString& wallet_passphrase) override
{
- return m_wallet.EncryptWallet(wallet_passphrase);
+ return m_wallet->EncryptWallet(wallet_passphrase);
}
- bool isCrypted() override { return m_wallet.IsCrypted(); }
- bool lock() override { return m_wallet.Lock(); }
- bool unlock(const SecureString& wallet_passphrase) override { return m_wallet.Unlock(wallet_passphrase); }
- bool isLocked() override { return m_wallet.IsLocked(); }
+ bool isCrypted() override { return m_wallet->IsCrypted(); }
+ bool lock() override { return m_wallet->Lock(); }
+ bool unlock(const SecureString& wallet_passphrase) override { return m_wallet->Unlock(wallet_passphrase); }
+ bool isLocked() override { return m_wallet->IsLocked(); }
bool changeWalletPassphrase(const SecureString& old_wallet_passphrase,
const SecureString& new_wallet_passphrase) override
{
- return m_wallet.ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase);
+ return m_wallet->ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase);
}
- void abortRescan() override { m_wallet.AbortRescan(); }
- bool backupWallet(const std::string& filename) override { return m_wallet.BackupWallet(filename); }
- std::string getWalletName() override { return m_wallet.GetName(); }
- bool getKeyFromPool(bool internal, CPubKey& pub_key) override
+ void abortRescan() override { m_wallet->AbortRescan(); }
+ bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }
+ std::string getWalletName() override { return m_wallet->GetName(); }
+ bool getNewDestination(const OutputType type, const std::string label, CTxDestination& dest) override
{
- return m_wallet.GetKeyFromPool(pub_key, internal);
+ LOCK(m_wallet->cs_wallet);
+ std::string error;
+ return m_wallet->GetNewDestination(type, label, dest, error);
}
- bool getPubKey(const CKeyID& address, CPubKey& pub_key) override { return m_wallet.GetPubKey(address, pub_key); }
- bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet.GetKey(address, key); }
- bool isSpendable(const CTxDestination& dest) override { return IsMine(m_wallet, dest) & ISMINE_SPENDABLE; }
- bool haveWatchOnly() override { return m_wallet.HaveWatchOnly(); };
+ bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) override
+ {
+ std::unique_ptr<SigningProvider> provider = m_wallet->GetSolvingProvider(script);
+ if (provider) {
+ return provider->GetPubKey(address, pub_key);
+ }
+ return false;
+ }
+ SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) override
+ {
+ return m_wallet->SignMessage(message, pkhash, str_sig);
+ }
+ bool isSpendable(const CTxDestination& dest) override { return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; }
+ bool haveWatchOnly() override
+ {
+ auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
+ if (spk_man) {
+ return spk_man->HaveWatchOnly();
+ }
+ return false;
+ };
bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::string& purpose) override
{
- return m_wallet.SetAddressBook(dest, name, purpose);
+ return m_wallet->SetAddressBook(dest, name, purpose);
}
bool delAddressBook(const CTxDestination& dest) override
{
- return m_wallet.DelAddressBook(dest);
+ return m_wallet->DelAddressBook(dest);
}
bool getAddress(const CTxDestination& dest,
std::string* name,
isminetype* is_mine,
std::string* purpose) override
{
- LOCK(m_wallet.cs_wallet);
- auto it = m_wallet.mapAddressBook.find(dest);
- if (it == m_wallet.mapAddressBook.end()) {
+ LOCK(m_wallet->cs_wallet);
+ auto it = m_wallet->m_address_book.find(dest);
+ if (it == m_wallet->m_address_book.end() || it->second.IsChange()) {
return false;
}
if (name) {
- *name = it->second.name;
+ *name = it->second.GetLabel();
}
if (is_mine) {
- *is_mine = IsMine(m_wallet, dest);
+ *is_mine = m_wallet->IsMine(dest);
}
if (purpose) {
*purpose = it->second.purpose;
@@ -192,148 +169,146 @@ public:
}
std::vector<WalletAddress> getAddresses() override
{
- LOCK(m_wallet.cs_wallet);
+ LOCK(m_wallet->cs_wallet);
std::vector<WalletAddress> result;
- for (const auto& item : m_wallet.mapAddressBook) {
- result.emplace_back(item.first, IsMine(m_wallet, item.first), item.second.name, item.second.purpose);
+ for (const auto& item : m_wallet->m_address_book) {
+ if (item.second.IsChange()) continue;
+ result.emplace_back(item.first, m_wallet->IsMine(item.first), item.second.GetLabel(), item.second.purpose);
}
return result;
}
- void learnRelatedScripts(const CPubKey& key, OutputType type) override { m_wallet.LearnRelatedScripts(key, type); }
bool addDestData(const CTxDestination& dest, const std::string& key, const std::string& value) override
{
- LOCK(m_wallet.cs_wallet);
- return m_wallet.AddDestData(dest, key, value);
+ LOCK(m_wallet->cs_wallet);
+ WalletBatch batch{m_wallet->GetDatabase()};
+ return m_wallet->AddDestData(batch, dest, key, value);
}
bool eraseDestData(const CTxDestination& dest, const std::string& key) override
{
- LOCK(m_wallet.cs_wallet);
- return m_wallet.EraseDestData(dest, key);
+ LOCK(m_wallet->cs_wallet);
+ WalletBatch batch{m_wallet->GetDatabase()};
+ return m_wallet->EraseDestData(batch, dest, key);
}
std::vector<std::string> getDestValues(const std::string& prefix) override
{
- return m_wallet.GetDestValues(prefix);
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->GetDestValues(prefix);
}
void lockCoin(const COutPoint& output) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- return m_wallet.LockCoin(output);
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->LockCoin(output);
}
void unlockCoin(const COutPoint& output) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- return m_wallet.UnlockCoin(output);
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->UnlockCoin(output);
}
bool isLockedCoin(const COutPoint& output) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- return m_wallet.IsLockedCoin(output.hash, output.n);
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->IsLockedCoin(output.hash, output.n);
}
void listLockedCoins(std::vector<COutPoint>& outputs) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- return m_wallet.ListLockedCoins(outputs);
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->ListLockedCoins(outputs);
}
- std::unique_ptr<PendingWalletTx> createTransaction(const std::vector<CRecipient>& recipients,
+ CTransactionRef createTransaction(const std::vector<CRecipient>& recipients,
const CCoinControl& coin_control,
bool sign,
int& change_pos,
CAmount& fee,
- std::string& fail_reason) override
+ bilingual_str& fail_reason) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- auto pending = MakeUnique<PendingWalletTxImpl>(m_wallet);
- if (!m_wallet.CreateTransaction(*locked_chain, recipients, pending->m_tx, pending->m_key, fee, change_pos,
+ LOCK(m_wallet->cs_wallet);
+ CTransactionRef tx;
+ if (!m_wallet->CreateTransaction(recipients, tx, fee, change_pos,
fail_reason, coin_control, sign)) {
return {};
}
- return std::move(pending);
+ return tx;
+ }
+ void commitTransaction(CTransactionRef tx,
+ WalletValueMap value_map,
+ WalletOrderForm order_form) override
+ {
+ LOCK(m_wallet->cs_wallet);
+ m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form));
}
- bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet.TransactionCanBeAbandoned(txid); }
+ bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); }
bool abandonTransaction(const uint256& txid) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- return m_wallet.AbandonTransaction(*locked_chain, txid);
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->AbandonTransaction(txid);
}
bool transactionCanBeBumped(const uint256& txid) override
{
- return feebumper::TransactionCanBeBumped(&m_wallet, txid);
+ return feebumper::TransactionCanBeBumped(*m_wallet.get(), txid);
}
bool createBumpTransaction(const uint256& txid,
const CCoinControl& coin_control,
- CAmount total_fee,
- std::vector<std::string>& errors,
+ std::vector<bilingual_str>& errors,
CAmount& old_fee,
CAmount& new_fee,
CMutableTransaction& mtx) override
{
- return feebumper::CreateTransaction(&m_wallet, txid, coin_control, total_fee, errors, old_fee, new_fee, mtx) ==
- feebumper::Result::OK;
+ return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx) == feebumper::Result::OK;
}
- bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(&m_wallet, mtx); }
+ bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); }
bool commitBumpTransaction(const uint256& txid,
CMutableTransaction&& mtx,
- std::vector<std::string>& errors,
+ std::vector<bilingual_str>& errors,
uint256& bumped_txid) override
{
- return feebumper::CommitTransaction(&m_wallet, txid, std::move(mtx), errors, bumped_txid) ==
+ return feebumper::CommitTransaction(*m_wallet.get(), txid, std::move(mtx), errors, bumped_txid) ==
feebumper::Result::OK;
}
CTransactionRef getTx(const uint256& txid) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- auto mi = m_wallet.mapWallet.find(txid);
- if (mi != m_wallet.mapWallet.end()) {
+ LOCK(m_wallet->cs_wallet);
+ auto mi = m_wallet->mapWallet.find(txid);
+ if (mi != m_wallet->mapWallet.end()) {
return mi->second.tx;
}
return {};
}
WalletTx getWalletTx(const uint256& txid) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- auto mi = m_wallet.mapWallet.find(txid);
- if (mi != m_wallet.mapWallet.end()) {
- return MakeWalletTx(*locked_chain, m_wallet, mi->second);
+ LOCK(m_wallet->cs_wallet);
+ auto mi = m_wallet->mapWallet.find(txid);
+ if (mi != m_wallet->mapWallet.end()) {
+ return MakeWalletTx(*m_wallet, mi->second);
}
return {};
}
std::vector<WalletTx> getWalletTxs() override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
+ LOCK(m_wallet->cs_wallet);
std::vector<WalletTx> result;
- result.reserve(m_wallet.mapWallet.size());
- for (const auto& entry : m_wallet.mapWallet) {
- result.emplace_back(MakeWalletTx(*locked_chain, m_wallet, entry.second));
+ result.reserve(m_wallet->mapWallet.size());
+ for (const auto& entry : m_wallet->mapWallet) {
+ result.emplace_back(MakeWalletTx(*m_wallet, entry.second));
}
return result;
}
bool tryGetTxStatus(const uint256& txid,
interfaces::WalletTxStatus& tx_status,
- int& num_blocks) override
+ int& num_blocks,
+ int64_t& block_time) override
{
- auto locked_chain = m_wallet.chain().lock(true /* try_lock */);
- if (!locked_chain) {
- return false;
- }
- TRY_LOCK(m_wallet.cs_wallet, locked_wallet);
+ TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
if (!locked_wallet) {
return false;
}
- auto mi = m_wallet.mapWallet.find(txid);
- if (mi == m_wallet.mapWallet.end()) {
+ auto mi = m_wallet->mapWallet.find(txid);
+ if (mi == m_wallet->mapWallet.end()) {
return false;
}
- num_blocks = ::chainActive.Height();
- tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
+ num_blocks = m_wallet->GetLastBlockHeight();
+ block_time = -1;
+ CHECK_NONFATAL(m_wallet->chain().findBlock(m_wallet->GetLastBlockHash(), FoundBlock().time(block_time)));
+ tx_status = MakeWalletTxStatus(*m_wallet, mi->second);
return true;
}
WalletTx getWalletTxDetails(const uint256& txid,
@@ -342,106 +317,106 @@ public:
bool& in_mempool,
int& num_blocks) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- auto mi = m_wallet.mapWallet.find(txid);
- if (mi != m_wallet.mapWallet.end()) {
- num_blocks = ::chainActive.Height();
+ LOCK(m_wallet->cs_wallet);
+ auto mi = m_wallet->mapWallet.find(txid);
+ if (mi != m_wallet->mapWallet.end()) {
+ num_blocks = m_wallet->GetLastBlockHeight();
in_mempool = mi->second.InMempool();
order_form = mi->second.vOrderForm;
- tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
- return MakeWalletTx(*locked_chain, m_wallet, mi->second);
+ tx_status = MakeWalletTxStatus(*m_wallet, mi->second);
+ return MakeWalletTx(*m_wallet, mi->second);
}
return {};
}
+ TransactionError fillPSBT(int sighash_type,
+ bool sign,
+ bool bip32derivs,
+ PartiallySignedTransaction& psbtx,
+ bool& complete) override
+ {
+ return m_wallet->FillPSBT(psbtx, complete, sighash_type, sign, bip32derivs);
+ }
WalletBalances getBalances() override
{
+ const auto bal = m_wallet->GetBalance();
WalletBalances result;
- result.balance = m_wallet.GetBalance();
- result.unconfirmed_balance = m_wallet.GetUnconfirmedBalance();
- result.immature_balance = m_wallet.GetImmatureBalance();
- result.have_watch_only = m_wallet.HaveWatchOnly();
+ result.balance = bal.m_mine_trusted;
+ result.unconfirmed_balance = bal.m_mine_untrusted_pending;
+ result.immature_balance = bal.m_mine_immature;
+ result.have_watch_only = haveWatchOnly();
if (result.have_watch_only) {
- result.watch_only_balance = m_wallet.GetBalance(ISMINE_WATCH_ONLY);
- result.unconfirmed_watch_only_balance = m_wallet.GetUnconfirmedWatchOnlyBalance();
- result.immature_watch_only_balance = m_wallet.GetImmatureWatchOnlyBalance();
+ result.watch_only_balance = bal.m_watchonly_trusted;
+ result.unconfirmed_watch_only_balance = bal.m_watchonly_untrusted_pending;
+ result.immature_watch_only_balance = bal.m_watchonly_immature;
}
return result;
}
- bool tryGetBalances(WalletBalances& balances, int& num_blocks) override
+ bool tryGetBalances(WalletBalances& balances, uint256& block_hash) override
{
- auto locked_chain = m_wallet.chain().lock(true /* try_lock */);
- if (!locked_chain) return false;
- TRY_LOCK(m_wallet.cs_wallet, locked_wallet);
+ TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
if (!locked_wallet) {
return false;
}
+ block_hash = m_wallet->GetLastBlockHash();
balances = getBalances();
- num_blocks = ::chainActive.Height();
return true;
}
- CAmount getBalance() override { return m_wallet.GetBalance(); }
+ CAmount getBalance() override { return m_wallet->GetBalance().m_mine_trusted; }
CAmount getAvailableBalance(const CCoinControl& coin_control) override
{
- return m_wallet.GetAvailableBalance(&coin_control);
+ return m_wallet->GetAvailableBalance(&coin_control);
}
isminetype txinIsMine(const CTxIn& txin) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- return m_wallet.IsMine(txin);
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->IsMine(txin);
}
isminetype txoutIsMine(const CTxOut& txout) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- return m_wallet.IsMine(txout);
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->IsMine(txout);
}
CAmount getDebit(const CTxIn& txin, isminefilter filter) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- return m_wallet.GetDebit(txin, filter);
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->GetDebit(txin, filter);
}
CAmount getCredit(const CTxOut& txout, isminefilter filter) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
- return m_wallet.GetCredit(txout, filter);
+ LOCK(m_wallet->cs_wallet);
+ return m_wallet->GetCredit(txout, filter);
}
CoinsList listCoins() override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
+ LOCK(m_wallet->cs_wallet);
CoinsList result;
- for (const auto& entry : m_wallet.ListCoins(*locked_chain)) {
+ for (const auto& entry : m_wallet->ListCoins()) {
auto& group = result[entry.first];
for (const auto& coin : entry.second) {
group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i),
- MakeWalletTxOut(*locked_chain, m_wallet, *coin.tx, coin.i, coin.nDepth));
+ MakeWalletTxOut(*m_wallet, *coin.tx, coin.i, coin.nDepth));
}
}
return result;
}
std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override
{
- auto locked_chain = m_wallet.chain().lock();
- LOCK(m_wallet.cs_wallet);
+ LOCK(m_wallet->cs_wallet);
std::vector<WalletTxOut> result;
result.reserve(outputs.size());
for (const auto& output : outputs) {
result.emplace_back();
- auto it = m_wallet.mapWallet.find(output.hash);
- if (it != m_wallet.mapWallet.end()) {
- int depth = it->second.GetDepthInMainChain(*locked_chain);
+ auto it = m_wallet->mapWallet.find(output.hash);
+ if (it != m_wallet->mapWallet.end()) {
+ int depth = it->second.GetDepthInMainChain();
if (depth >= 0) {
- result.back() = MakeWalletTxOut(*locked_chain, m_wallet, it->second, output.n, depth);
+ result.back() = MakeWalletTxOut(*m_wallet, it->second, output.n, depth);
}
}
}
return result;
}
- CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(m_wallet, tx_bytes); }
+ CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(*m_wallet, tx_bytes); }
CAmount getMinimumFee(unsigned int tx_bytes,
const CCoinControl& coin_control,
int* returned_target,
@@ -449,46 +424,57 @@ public:
{
FeeCalculation fee_calc;
CAmount result;
- result = GetMinimumFee(m_wallet, tx_bytes, coin_control, ::mempool, ::feeEstimator, &fee_calc);
+ result = GetMinimumFee(*m_wallet, tx_bytes, coin_control, &fee_calc);
if (returned_target) *returned_target = fee_calc.returnedTarget;
if (reason) *reason = fee_calc.reason;
return result;
}
- unsigned int getConfirmTarget() override { return m_wallet.m_confirm_target; }
- bool hdEnabled() override { return m_wallet.IsHDEnabled(); }
- bool IsWalletFlagSet(uint64_t flag) override { return m_wallet.IsWalletFlagSet(flag); }
- OutputType getDefaultAddressType() override { return m_wallet.m_default_address_type; }
- OutputType getDefaultChangeType() override { return m_wallet.m_default_change_type; }
+ unsigned int getConfirmTarget() override { return m_wallet->m_confirm_target; }
+ bool hdEnabled() override { return m_wallet->IsHDEnabled(); }
+ bool canGetAddresses() override { return m_wallet->CanGetAddresses(); }
+ bool privateKeysDisabled() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); }
+ OutputType getDefaultAddressType() override { return m_wallet->m_default_address_type; }
+ OutputType getDefaultChangeType() override { return m_wallet->m_default_change_type; }
+ CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; }
+ void remove() override
+ {
+ RemoveWallet(m_wallet);
+ }
+ bool isLegacy() override { return m_wallet->IsLegacy(); }
std::unique_ptr<Handler> handleUnload(UnloadFn fn) override
{
- return MakeHandler(m_wallet.NotifyUnload.connect(fn));
+ return MakeHandler(m_wallet->NotifyUnload.connect(fn));
}
std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
{
- return MakeHandler(m_wallet.ShowProgress.connect(fn));
+ return MakeHandler(m_wallet->ShowProgress.connect(fn));
}
std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override
{
- return MakeHandler(m_wallet.NotifyStatusChanged.connect([fn](CCryptoKeyStore*) { fn(); }));
+ return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); }));
}
std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override
{
- return MakeHandler(m_wallet.NotifyAddressBookChanged.connect(
+ return MakeHandler(m_wallet->NotifyAddressBookChanged.connect(
[fn](CWallet*, const CTxDestination& address, const std::string& label, bool is_mine,
const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); }));
}
std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override
{
- return MakeHandler(m_wallet.NotifyTransactionChanged.connect(
+ return MakeHandler(m_wallet->NotifyTransactionChanged.connect(
[fn](CWallet*, const uint256& txid, ChangeType status) { fn(txid, status); }));
}
std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override
{
- return MakeHandler(m_wallet.NotifyWatchonlyChanged.connect(fn));
+ return MakeHandler(m_wallet->NotifyWatchonlyChanged.connect(fn));
}
+ std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override
+ {
+ return MakeHandler(m_wallet->NotifyCanGetAddressesChanged.connect(fn));
+ }
+ CWallet* wallet() override { return m_wallet.get(); }
- std::shared_ptr<CWallet> m_shared_wallet;
- CWallet& m_wallet;
+ std::shared_ptr<CWallet> m_wallet;
};
class WalletClientImpl : public ChainClient
@@ -498,21 +484,35 @@ public:
: m_chain(chain), m_wallet_filenames(std::move(wallet_filenames))
{
}
- void registerRpcs() override { return RegisterWalletRPCCommands(::tableRPC); }
+ void registerRpcs() override
+ {
+ g_rpc_chain = &m_chain;
+ return RegisterWalletRPCCommands(m_chain, m_rpc_handlers);
+ }
bool verify() override { return VerifyWallets(m_chain, m_wallet_filenames); }
bool load() override { return LoadWallets(m_chain, m_wallet_filenames); }
void start(CScheduler& scheduler) override { return StartWallets(scheduler); }
void flush() override { return FlushWallets(); }
void stop() override { return StopWallets(); }
+ void setMockTime(int64_t time) override { return SetMockTime(time); }
+ std::vector<std::unique_ptr<Wallet>> getWallets() override
+ {
+ std::vector<std::unique_ptr<Wallet>> wallets;
+ for (const auto& wallet : GetWallets()) {
+ wallets.emplace_back(MakeWallet(wallet));
+ }
+ return wallets;
+ }
~WalletClientImpl() override { UnloadWallets(); }
Chain& m_chain;
std::vector<std::string> m_wallet_filenames;
+ std::vector<std::unique_ptr<Handler>> m_rpc_handlers;
};
} // namespace
-std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return MakeUnique<WalletImpl>(wallet); }
+std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<WalletImpl>(wallet) : nullptr; }
std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames)
{
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index c79b9afce3..67569a3e55 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,10 +7,10 @@
#include <amount.h> // For CAmount
#include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation)
-#include <script/ismine.h> // For isminefilter, isminetype
#include <script/standard.h> // For CTxDestination
#include <support/allocators/secure.h> // For SecureString
#include <ui_interface.h> // For ChangeType
+#include <util/message.h>
#include <functional>
#include <map>
@@ -27,12 +27,16 @@ class CKey;
class CWallet;
enum class FeeReason;
enum class OutputType;
+enum class TransactionError;
+enum isminetype : unsigned int;
struct CRecipient;
+struct PartiallySignedTransaction;
+struct bilingual_str;
+typedef uint8_t isminefilter;
namespace interfaces {
class Handler;
-class PendingWalletTx;
struct WalletAddress;
struct WalletBalances;
struct WalletTx;
@@ -76,14 +80,14 @@ public:
//! Get wallet name.
virtual std::string getWalletName() = 0;
- // Get key from pool.
- virtual bool getKeyFromPool(bool internal, CPubKey& pub_key) = 0;
+ // Get a new address.
+ virtual bool getNewDestination(const OutputType type, const std::string label, CTxDestination& dest) = 0;
//! Get public key.
- virtual bool getPubKey(const CKeyID& address, CPubKey& pub_key) = 0;
+ virtual bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) = 0;
- //! Get private key.
- virtual bool getPrivKey(const CKeyID& address, CKey& key) = 0;
+ //! Sign message
+ virtual SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) = 0;
//! Return whether wallet has private key.
virtual bool isSpendable(const CTxDestination& dest) = 0;
@@ -106,10 +110,6 @@ public:
//! Get wallet address list.
virtual std::vector<WalletAddress> getAddresses() = 0;
- //! Add scripts to key store so old so software versions opening the wallet
- //! database can detect payments to newer address types.
- virtual void learnRelatedScripts(const CPubKey& key, OutputType type) = 0;
-
//! Add dest data.
virtual bool addDestData(const CTxDestination& dest, const std::string& key, const std::string& value) = 0;
@@ -132,12 +132,17 @@ public:
virtual void listLockedCoins(std::vector<COutPoint>& outputs) = 0;
//! Create transaction.
- virtual std::unique_ptr<PendingWalletTx> createTransaction(const std::vector<CRecipient>& recipients,
+ virtual CTransactionRef createTransaction(const std::vector<CRecipient>& recipients,
const CCoinControl& coin_control,
bool sign,
int& change_pos,
CAmount& fee,
- std::string& fail_reason) = 0;
+ bilingual_str& fail_reason) = 0;
+
+ //! Commit transaction.
+ virtual void commitTransaction(CTransactionRef tx,
+ WalletValueMap value_map,
+ WalletOrderForm order_form) = 0;
//! Return whether transaction can be abandoned.
virtual bool transactionCanBeAbandoned(const uint256& txid) = 0;
@@ -151,8 +156,7 @@ public:
//! Create bump transaction.
virtual bool createBumpTransaction(const uint256& txid,
const CCoinControl& coin_control,
- CAmount total_fee,
- std::vector<std::string>& errors,
+ std::vector<bilingual_str>& errors,
CAmount& old_fee,
CAmount& new_fee,
CMutableTransaction& mtx) = 0;
@@ -163,7 +167,7 @@ public:
//! Commit bump transaction.
virtual bool commitBumpTransaction(const uint256& txid,
CMutableTransaction&& mtx,
- std::vector<std::string>& errors,
+ std::vector<bilingual_str>& errors,
uint256& bumped_txid) = 0;
//! Get a transaction.
@@ -178,7 +182,8 @@ public:
//! Try to get updated status for a particular transaction, if possible without blocking.
virtual bool tryGetTxStatus(const uint256& txid,
WalletTxStatus& tx_status,
- int& num_blocks) = 0;
+ int& num_blocks,
+ int64_t& block_time) = 0;
//! Get transaction details.
virtual WalletTx getWalletTxDetails(const uint256& txid,
@@ -187,11 +192,18 @@ public:
bool& in_mempool,
int& num_blocks) = 0;
+ //! Fill PSBT.
+ virtual TransactionError fillPSBT(int sighash_type,
+ bool sign,
+ bool bip32derivs,
+ PartiallySignedTransaction& psbtx,
+ bool& complete) = 0;
+
//! Get balances.
virtual WalletBalances getBalances() = 0;
//! Get balances if possible without blocking.
- virtual bool tryGetBalances(WalletBalances& balances, int& num_blocks) = 0;
+ virtual bool tryGetBalances(WalletBalances& balances, uint256& block_hash) = 0;
//! Get balance.
virtual CAmount getBalance() = 0;
@@ -234,8 +246,11 @@ public:
// Return whether HD enabled.
virtual bool hdEnabled() = 0;
- // check if a certain wallet flag is set.
- virtual bool IsWalletFlagSet(uint64_t flag) = 0;
+ // Return whether the wallet is blank.
+ virtual bool canGetAddresses() = 0;
+
+ // Return whether private keys enabled.
+ virtual bool privateKeysDisabled() = 0;
// Get default address type.
virtual OutputType getDefaultAddressType() = 0;
@@ -243,6 +258,15 @@ public:
// Get default change type.
virtual OutputType getDefaultChangeType() = 0;
+ //! Get max tx fee.
+ virtual CAmount getDefaultMaxTxFee() = 0;
+
+ // Remove wallet.
+ virtual void remove() = 0;
+
+ //! Return whether is a legacy wallet
+ virtual bool isLegacy() = 0;
+
//! Register handler for unload message.
using UnloadFn = std::function<void()>;
virtual std::unique_ptr<Handler> handleUnload(UnloadFn fn) = 0;
@@ -270,24 +294,13 @@ public:
//! Register handler for watchonly changed messages.
using WatchOnlyChangedFn = std::function<void(bool have_watch_only)>;
virtual std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) = 0;
-};
-
-//! Tracking object returned by CreateTransaction and passed to CommitTransaction.
-class PendingWalletTx
-{
-public:
- virtual ~PendingWalletTx() {}
-
- //! Get transaction data.
- virtual const CTransaction& get() = 0;
- //! Get virtual transaction size.
- virtual int64_t getVirtualSize() = 0;
+ //! Register handler for keypool changed messages.
+ using CanGetAddressesChangedFn = std::function<void()>;
+ virtual std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) = 0;
- //! Send pending transaction and commit to wallet.
- virtual bool commit(WalletValueMap value_map,
- WalletOrderForm order_form,
- std::string& reject_reason) = 0;
+ //! Return pointer to internal wallet class, useful for testing.
+ virtual CWallet* wallet() { return nullptr; }
};
//! Information about one wallet address.