diff options
Diffstat (limited to 'src/interfaces')
-rw-r--r-- | src/interfaces/README.md | 2 | ||||
-rw-r--r-- | src/interfaces/chain.cpp | 44 | ||||
-rw-r--r-- | src/interfaces/chain.h | 84 | ||||
-rw-r--r-- | src/interfaces/handler.cpp | 2 | ||||
-rw-r--r-- | src/interfaces/node.cpp | 11 | ||||
-rw-r--r-- | src/interfaces/wallet.cpp | 147 | ||||
-rw-r--r-- | src/interfaces/wallet.h | 6 |
7 files changed, 240 insertions, 56 deletions
diff --git a/src/interfaces/README.md b/src/interfaces/README.md index e93b91d23c..57d41df746 100644 --- a/src/interfaces/README.md +++ b/src/interfaces/README.md @@ -4,7 +4,7 @@ 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::Client`](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 [#10973](https://github.com/bitcoin/bitcoin/pull/10973). * [`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 new file mode 100644 index 0000000000..2571a91031 --- /dev/null +++ b/src/interfaces/chain.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <interfaces/chain.h> + +#include <sync.h> +#include <util/system.h> +#include <validation.h> + +#include <memory> +#include <utility> + +namespace interfaces { +namespace { + +class LockImpl : public Chain::Lock +{ +}; + +class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection> +{ + using UniqueLock::UniqueLock; +}; + +class ChainImpl : public Chain +{ +public: + std::unique_ptr<Chain::Lock> lock(bool try_lock) override + { + auto result = MakeUnique<LockingStateImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock); + if (try_lock && result && !*result) return {}; + // std::move necessary on some compilers due to conversion from + // LockingStateImpl to Lock pointer + return std::move(result); + } + std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); } +}; + +} // namespace + +std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); } + +} // namespace interfaces diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h new file mode 100644 index 0000000000..fe5658de4b --- /dev/null +++ b/src/interfaces/chain.h @@ -0,0 +1,84 @@ +// Copyright (c) 2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_INTERFACES_CHAIN_H +#define BITCOIN_INTERFACES_CHAIN_H + +#include <memory> +#include <string> +#include <vector> + +class CScheduler; + +namespace interfaces { + +//! Interface for giving wallet processes access to blockchain state. +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() {} + }; + + //! 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; + + //! 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; +}; + +//! Interface to let node manage chain clients (wallets, or maybe tools for +//! monitoring and analysis in the future). +class ChainClient +{ +public: + virtual ~ChainClient() {} + + //! Register rpcs. + virtual void registerRpcs() = 0; + + //! Check for errors before loading. + virtual bool verify() = 0; + + //! Load saved state. + virtual bool load() = 0; + + //! Start client execution and provide a scheduler. + virtual void start(CScheduler& scheduler) = 0; + + //! Save state to disk. + virtual void flush() = 0; + + //! Shut down client. + virtual void stop() = 0; +}; + +//! Return implementation of Chain interface. +std::unique_ptr<Chain> MakeChain(); + +//! 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<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames); + +} // namespace interfaces + +#endif // BITCOIN_INTERFACES_CHAIN_H diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp index ddf9b342d8..92601fc4e9 100644 --- a/src/interfaces/handler.cpp +++ b/src/interfaces/handler.cpp @@ -4,7 +4,7 @@ #include <interfaces/handler.h> -#include <utilmemory.h> +#include <util/memory.h> #include <boost/signals2/connection.hpp> #include <utility> diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 2b19e11f08..bd7e414ff3 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -9,6 +9,7 @@ #include <chain.h> #include <chainparams.h> #include <init.h> +#include <interfaces/chain.h> #include <interfaces/handler.h> #include <interfaces/wallet.h> #include <net.h> @@ -25,7 +26,7 @@ #include <sync.h> #include <txmempool.h> #include <ui_interface.h> -#include <util.h> +#include <util/system.h> #include <validation.h> #include <warnings.h> @@ -34,7 +35,6 @@ #endif #include <atomic> -#include <boost/thread/thread.hpp> #include <univalue.h> class CWallet; @@ -50,6 +50,8 @@ namespace { class NodeImpl : public Node { +public: + NodeImpl() { m_interfaces.chain = MakeChain(); } bool parseParameters(int argc, const char* const argv[], std::string& error) override { return gArgs.ParseParameters(argc, argv, error); @@ -68,11 +70,11 @@ class NodeImpl : public Node return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() && AppInitLockDataDirectory(); } - bool appInitMain() override { return AppInitMain(); } + bool appInitMain() override { return AppInitMain(m_interfaces); } void appShutdown() override { Interrupt(); - Shutdown(); + Shutdown(m_interfaces); } void startShutdown() override { StartShutdown(); } bool shutdownRequested() override { return ShutdownRequested(); } @@ -291,6 +293,7 @@ class NodeImpl : public Node GuessVerificationProgress(Params().TxData(), block)); })); } + InitInterfaces m_interfaces; }; } // namespace diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 84079fdc3c..672a557d41 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -7,12 +7,16 @@ #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> @@ -20,10 +24,18 @@ #include <timedata.h> #include <ui_interface.h> #include <uint256.h> +#include <util/system.h> #include <validation.h> #include <wallet/feebumper.h> #include <wallet/fees.h> +#include <wallet/rpcwallet.h> #include <wallet/wallet.h> +#include <wallet/walletutil.h> + +#include <memory> +#include <string> +#include <utility> +#include <vector> namespace interfaces { namespace { @@ -41,7 +53,8 @@ public: WalletOrderForm order_form, std::string& reject_reason) override { - LOCK2(cs_main, m_wallet.cs_wallet); + 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(); @@ -56,7 +69,7 @@ public: }; //! Construct wallet tx struct. -static WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, const CWalletTx& wtx) { WalletTx result; result.tx = wtx.tx; @@ -74,7 +87,7 @@ static WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) EXCLUSIVE_LO IsMine(wallet, result.txout_address.back()) : ISMINE_NO); } - result.credit = wtx.GetCredit(ISMINE_ALL); + result.credit = wtx.GetCredit(locked_chain, ISMINE_ALL); result.debit = wtx.GetDebit(ISMINE_ALL); result.change = wtx.GetChange(); result.time = wtx.GetTxTime(); @@ -84,32 +97,38 @@ static WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) EXCLUSIVE_LO } //! Construct wallet tx status struct. -static WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock& locked_chain, 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(); - result.depth_in_main_chain = wtx.GetDepthInMainChain(); + result.blocks_to_maturity = wtx.GetBlocksToMaturity(locked_chain); + result.depth_in_main_chain = wtx.GetDepthInMainChain(locked_chain); result.time_received = wtx.nTimeReceived; result.lock_time = wtx.tx->nLockTime; result.is_final = CheckFinalTx(*wtx.tx); - result.is_trusted = wtx.IsTrusted(); + result.is_trusted = wtx.IsTrusted(locked_chain); result.is_abandoned = wtx.isAbandoned(); result.is_coinbase = wtx.IsCoinBase(); - result.is_in_main_chain = wtx.IsInMainChain(); + result.is_in_main_chain = wtx.IsInMainChain(locked_chain); return result; } //! Construct wallet TxOut struct. -static WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth) EXCLUSIVE_LOCKS_REQUIRED(cs_main, wallet.cs_wallet) +WalletTxOut MakeWalletTxOut(interfaces::Chain::Lock& locked_chain, + CWallet& wallet, + const CWalletTx& wtx, + int n, + int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) { WalletTxOut result; result.txout = wtx.tx->vout[n]; result.time = wtx.GetTxTime(); result.depth_in_main_chain = depth; - result.is_spent = wallet.IsSpent(wtx.GetHash(), n); + result.is_spent = wallet.IsSpent(locked_chain, wtx.GetHash(), n); return result; } @@ -197,22 +216,26 @@ public: } void lockCoin(const COutPoint& output) override { - LOCK2(cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); return m_wallet.LockCoin(output); } void unlockCoin(const COutPoint& output) override { - LOCK2(cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); return m_wallet.UnlockCoin(output); } bool isLockedCoin(const COutPoint& output) override { - LOCK2(cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); return m_wallet.IsLockedCoin(output.hash, output.n); } void listLockedCoins(std::vector<COutPoint>& outputs) override { - LOCK2(cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); return m_wallet.ListLockedCoins(outputs); } std::unique_ptr<PendingWalletTx> createTransaction(const std::vector<CRecipient>& recipients, @@ -222,9 +245,10 @@ public: CAmount& fee, std::string& fail_reason) override { - LOCK2(cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); auto pending = MakeUnique<PendingWalletTxImpl>(m_wallet); - if (!m_wallet.CreateTransaction(recipients, pending->m_tx, pending->m_key, fee, change_pos, + if (!m_wallet.CreateTransaction(*locked_chain, recipients, pending->m_tx, pending->m_key, fee, change_pos, fail_reason, coin_control, sign)) { return {}; } @@ -233,8 +257,9 @@ public: bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet.TransactionCanBeAbandoned(txid); } bool abandonTransaction(const uint256& txid) override { - LOCK2(cs_main, m_wallet.cs_wallet); - return m_wallet.AbandonTransaction(txid); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); + return m_wallet.AbandonTransaction(*locked_chain, txid); } bool transactionCanBeBumped(const uint256& txid) override { @@ -262,7 +287,8 @@ public: } CTransactionRef getTx(const uint256& txid) override { - LOCK2(::cs_main, m_wallet.cs_wallet); + 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 mi->second.tx; @@ -271,29 +297,30 @@ public: } WalletTx getWalletTx(const uint256& txid) override { - LOCK2(::cs_main, m_wallet.cs_wallet); + 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(m_wallet, mi->second); + return MakeWalletTx(*locked_chain, m_wallet, mi->second); } return {}; } std::vector<WalletTx> getWalletTxs() override { - LOCK2(::cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + 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(m_wallet, entry.second)); + result.emplace_back(MakeWalletTx(*locked_chain, m_wallet, entry.second)); } return result; } bool tryGetTxStatus(const uint256& txid, interfaces::WalletTxStatus& tx_status, - int& num_blocks, - int64_t& adjusted_time) override + int& num_blocks) override { - TRY_LOCK(::cs_main, locked_chain); + auto locked_chain = m_wallet.chain().lock(true /* try_lock */); if (!locked_chain) { return false; } @@ -306,26 +333,24 @@ public: return false; } num_blocks = ::chainActive.Height(); - adjusted_time = GetAdjustedTime(); - tx_status = MakeWalletTxStatus(mi->second); + tx_status = MakeWalletTxStatus(*locked_chain, mi->second); return true; } WalletTx getWalletTxDetails(const uint256& txid, WalletTxStatus& tx_status, WalletOrderForm& order_form, bool& in_mempool, - int& num_blocks, - int64_t& adjusted_time) override + int& num_blocks) override { - LOCK2(::cs_main, m_wallet.cs_wallet); + 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(); - adjusted_time = GetAdjustedTime(); in_mempool = mi->second.InMempool(); order_form = mi->second.vOrderForm; - tx_status = MakeWalletTxStatus(mi->second); - return MakeWalletTx(m_wallet, mi->second); + tx_status = MakeWalletTxStatus(*locked_chain, mi->second); + return MakeWalletTx(*locked_chain, m_wallet, mi->second); } return {}; } @@ -345,7 +370,7 @@ public: } bool tryGetBalances(WalletBalances& balances, int& num_blocks) override { - TRY_LOCK(cs_main, locked_chain); + auto locked_chain = m_wallet.chain().lock(true /* try_lock */); if (!locked_chain) return false; TRY_LOCK(m_wallet.cs_wallet, locked_wallet); if (!locked_wallet) { @@ -362,49 +387,55 @@ public: } isminetype txinIsMine(const CTxIn& txin) override { - LOCK2(::cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); return m_wallet.IsMine(txin); } isminetype txoutIsMine(const CTxOut& txout) override { - LOCK2(::cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); return m_wallet.IsMine(txout); } CAmount getDebit(const CTxIn& txin, isminefilter filter) override { - LOCK2(::cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); return m_wallet.GetDebit(txin, filter); } CAmount getCredit(const CTxOut& txout, isminefilter filter) override { - LOCK2(::cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); return m_wallet.GetCredit(txout, filter); } CoinsList listCoins() override { - LOCK2(::cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + LOCK(m_wallet.cs_wallet); CoinsList result; - for (const auto& entry : m_wallet.ListCoins()) { + for (const auto& entry : m_wallet.ListCoins(*locked_chain)) { auto& group = result[entry.first]; for (const auto& coin : entry.second) { - group.emplace_back( - COutPoint(coin.tx->GetHash(), coin.i), MakeWalletTxOut(m_wallet, *coin.tx, coin.i, coin.nDepth)); + group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i), + MakeWalletTxOut(*locked_chain, m_wallet, *coin.tx, coin.i, coin.nDepth)); } } return result; } std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override { - LOCK2(::cs_main, m_wallet.cs_wallet); + auto locked_chain = m_wallet.chain().lock(); + 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(); + int depth = it->second.GetDepthInMainChain(*locked_chain); if (depth >= 0) { - result.back() = MakeWalletTxOut(m_wallet, it->second, output.n, depth); + result.back() = MakeWalletTxOut(*locked_chain, m_wallet, it->second, output.n, depth); } } } @@ -460,8 +491,32 @@ public: CWallet& m_wallet; }; +class WalletClientImpl : public ChainClient +{ +public: + WalletClientImpl(Chain& chain, std::vector<std::string> wallet_filenames) + : m_chain(chain), m_wallet_filenames(std::move(wallet_filenames)) + { + } + void registerRpcs() override { return RegisterWalletRPCCommands(::tableRPC); } + 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(); } + ~WalletClientImpl() override { UnloadWallets(); } + + Chain& m_chain; + std::vector<std::string> m_wallet_filenames; +}; + } // namespace std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return MakeUnique<WalletImpl>(wallet); } +std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames) +{ + return MakeUnique<WalletClientImpl>(chain, std::move(wallet_filenames)); +} + } // namespace interfaces diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 7aa91f37e1..c79b9afce3 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -178,16 +178,14 @@ 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, - int64_t& adjusted_time) = 0; + int& num_blocks) = 0; //! Get transaction details. virtual WalletTx getWalletTxDetails(const uint256& txid, WalletTxStatus& tx_status, WalletOrderForm& order_form, bool& in_mempool, - int& num_blocks, - int64_t& adjusted_time) = 0; + int& num_blocks) = 0; //! Get balances. virtual WalletBalances getBalances() = 0; |