Remove use CValidationInterface in wallet code

This commit does not change behavior.
This commit is contained in:
Russell Yanofsky 2017-07-30 16:00:56 -04:00
parent d8a62db8bf
commit 91868e6288
6 changed files with 107 additions and 25 deletions

View File

@ -6,6 +6,7 @@
#include <chain.h> #include <chain.h>
#include <chainparams.h> #include <chainparams.h>
#include <interfaces/handler.h>
#include <interfaces/wallet.h> #include <interfaces/wallet.h>
#include <net.h> #include <net.h>
#include <policy/fees.h> #include <policy/fees.h>
@ -22,6 +23,7 @@
#include <uint256.h> #include <uint256.h>
#include <util/system.h> #include <util/system.h>
#include <validation.h> #include <validation.h>
#include <validationinterface.h>
#include <memory> #include <memory>
#include <utility> #include <utility>
@ -161,6 +163,55 @@ class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
using UniqueLock::UniqueLock; using UniqueLock::UniqueLock;
}; };
class NotificationsHandlerImpl : public Handler, CValidationInterface
{
public:
explicit NotificationsHandlerImpl(Chain& chain, Chain::Notifications& notifications)
: m_chain(chain), m_notifications(&notifications)
{
RegisterValidationInterface(this);
}
~NotificationsHandlerImpl() override { disconnect(); }
void disconnect() override
{
if (m_notifications) {
m_notifications = nullptr;
UnregisterValidationInterface(this);
}
}
void TransactionAddedToMempool(const CTransactionRef& tx) override
{
m_notifications->TransactionAddedToMempool(tx);
}
void TransactionRemovedFromMempool(const CTransactionRef& tx) override
{
m_notifications->TransactionRemovedFromMempool(tx);
}
void BlockConnected(const std::shared_ptr<const CBlock>& block,
const CBlockIndex* index,
const std::vector<CTransactionRef>& tx_conflicted) override
{
m_notifications->BlockConnected(*block, tx_conflicted);
}
void BlockDisconnected(const std::shared_ptr<const CBlock>& block) override
{
m_notifications->BlockDisconnected(*block);
}
void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->ChainStateFlushed(locator); }
void ResendWalletTransactions(int64_t best_block_time, CConnman*) override
{
// `cs_main` is always held when this method is called, so it is safe to
// call `assumeLocked`. This is awkward, and the `assumeLocked` method
// should be able to be removed entirely if `ResendWalletTransactions`
// is replaced by a wallet timer as suggested in
// https://github.com/bitcoin/bitcoin/issues/15619
auto locked_chain = m_chain.assumeLocked();
m_notifications->ResendWalletTransactions(*locked_chain, best_block_time);
}
Chain& m_chain;
Chain::Notifications* m_notifications;
};
class ChainImpl : public Chain class ChainImpl : public Chain
{ {
public: public:
@ -254,6 +305,11 @@ public:
void initWarning(const std::string& message) override { InitWarning(message); } void initWarning(const std::string& message) override { InitWarning(message); }
void initError(const std::string& message) override { InitError(message); } void initError(const std::string& message) override { InitError(message); }
void loadWallet(std::unique_ptr<Wallet> wallet) override { ::uiInterface.LoadWallet(wallet); } void loadWallet(std::unique_ptr<Wallet> wallet) override { ::uiInterface.LoadWallet(wallet); }
std::unique_ptr<Handler> handleNotifications(Notifications& notifications) override
{
return MakeUnique<NotificationsHandlerImpl>(*this, notifications);
}
void waitForNotifications() override { SyncWithValidationInterfaceQueue(); }
}; };
} // namespace } // namespace

View File

@ -25,6 +25,7 @@ struct FeeCalculation;
namespace interfaces { namespace interfaces {
class Handler;
class Wallet; class Wallet;
//! Interface giving clients (wallet processes, maybe other analysis tools in //! Interface giving clients (wallet processes, maybe other analysis tools in
@ -40,6 +41,12 @@ class Wallet;
//! asynchronously //! asynchronously
//! (https://github.com/bitcoin/bitcoin/pull/10973#issuecomment-380101269). //! (https://github.com/bitcoin/bitcoin/pull/10973#issuecomment-380101269).
//! //!
//! * The isPotentialTip() and waitForNotifications() methods are too low-level
//! and should be replaced with a higher level
//! waitForNotificationsUpTo(block_hash) method that the wallet can call
//! instead
//! (https://github.com/bitcoin/bitcoin/pull/10973#discussion_r266995234).
//!
//! * The relayTransactions() and submitToMemoryPool() methods could be replaced //! * The relayTransactions() and submitToMemoryPool() methods could be replaced
//! with a higher-level broadcastTransaction method //! with a higher-level broadcastTransaction method
//! (https://github.com/bitcoin/bitcoin/pull/14978#issuecomment-459373984). //! (https://github.com/bitcoin/bitcoin/pull/14978#issuecomment-459373984).
@ -217,6 +224,25 @@ public:
//! Send wallet load notification to the GUI. //! Send wallet load notification to the GUI.
virtual void loadWallet(std::unique_ptr<Wallet> wallet) = 0; virtual void loadWallet(std::unique_ptr<Wallet> wallet) = 0;
//! Chain notifications.
class Notifications
{
public:
virtual ~Notifications() {}
virtual void TransactionAddedToMempool(const CTransactionRef& tx) {}
virtual void TransactionRemovedFromMempool(const CTransactionRef& ptx) {}
virtual void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& tx_conflicted) {}
virtual void BlockDisconnected(const CBlock& block) {}
virtual void ChainStateFlushed(const CBlockLocator& locator) {}
virtual void ResendWalletTransactions(Lock& locked_chain, int64_t best_block_time) {}
};
//! Register handler for notifications.
virtual std::unique_ptr<Handler> handleNotifications(Notifications& notifications) = 0;
//! Wait for pending notifications to be handled.
virtual void waitForNotifications() = 0;
}; };
//! Interface to let node manage chain clients (wallets, or maybe tools for //! Interface to let node manage chain clients (wallets, or maybe tools for

View File

@ -13,12 +13,7 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
{ {
bool fFirstRun; bool fFirstRun;
m_wallet.LoadWallet(fFirstRun); m_wallet.LoadWallet(fFirstRun);
RegisterValidationInterface(&m_wallet); m_wallet.m_chain_notifications_handler = m_chain->handleNotifications(m_wallet);
RegisterWalletRPCCommands(tableRPC); RegisterWalletRPCCommands(tableRPC);
} }
WalletTestingSetup::~WalletTestingSetup()
{
UnregisterValidationInterface(&m_wallet);
}

View File

@ -17,7 +17,6 @@
*/ */
struct WalletTestingSetup: public TestingSetup { struct WalletTestingSetup: public TestingSetup {
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~WalletTestingSetup();
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain(); std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
CWallet m_wallet; CWallet m_wallet;

View File

@ -96,7 +96,7 @@ static void ReleaseWallet(CWallet* wallet)
wallet->WalletLogPrintf("Releasing wallet\n"); wallet->WalletLogPrintf("Releasing wallet\n");
wallet->BlockUntilSyncedToCurrentChain(); wallet->BlockUntilSyncedToCurrentChain();
wallet->Flush(); wallet->Flush();
UnregisterValidationInterface(wallet); wallet->m_chain_notifications_handler.reset();
delete wallet; delete wallet;
// Wallet is now released, notify UnloadWallet, if any. // Wallet is now released, notify UnloadWallet, if any.
{ {
@ -1243,7 +1243,8 @@ void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
} }
} }
void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) { void CWallet::BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted) {
const uint256& block_hash = block.GetHash();
auto locked_chain = chain().lock(); auto locked_chain = chain().lock();
LOCK(cs_wallet); LOCK(cs_wallet);
// TODO: Temporarily ensure that mempool removals are notified before // TODO: Temporarily ensure that mempool removals are notified before
@ -1258,19 +1259,19 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */); SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
TransactionRemovedFromMempool(ptx); TransactionRemovedFromMempool(ptx);
} }
for (size_t i = 0; i < pblock->vtx.size(); i++) { for (size_t i = 0; i < block.vtx.size(); i++) {
SyncTransaction(pblock->vtx[i], pindex->GetBlockHash(), i); SyncTransaction(block.vtx[i], block_hash, i);
TransactionRemovedFromMempool(pblock->vtx[i]); TransactionRemovedFromMempool(block.vtx[i]);
} }
m_last_block_processed = pindex->GetBlockHash(); m_last_block_processed = block_hash;
} }
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) { void CWallet::BlockDisconnected(const CBlock& block) {
auto locked_chain = chain().lock(); auto locked_chain = chain().lock();
LOCK(cs_wallet); LOCK(cs_wallet);
for (const CTransactionRef& ptx : pblock->vtx) { for (const CTransactionRef& ptx : block.vtx) {
SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */); SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
} }
} }
@ -1297,7 +1298,7 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
// ...otherwise put a callback in the validation interface queue and wait // ...otherwise put a callback in the validation interface queue and wait
// for the queue to drain enough to execute it (indicating we are caught up // for the queue to drain enough to execute it (indicating we are caught up
// at least with the time we entered this function). // at least with the time we entered this function).
SyncWithValidationInterfaceQueue(); chain().waitForNotifications();
} }
@ -2137,7 +2138,7 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(interfaces::Chain::
return result; return result;
} }
void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) void CWallet::ResendWalletTransactions(interfaces::Chain::Lock& locked_chain, int64_t nBestBlockTime)
{ {
// Do this infrequently and randomly to avoid giving away // Do this infrequently and randomly to avoid giving away
// that these are our transactions. // that these are our transactions.
@ -2155,8 +2156,7 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman
// Rebroadcast unconfirmed txes older than 5 minutes before the last // Rebroadcast unconfirmed txes older than 5 minutes before the last
// block was found: // block was found:
auto locked_chain = chain().assumeLocked(); // Temporary. Removed in upcoming lock cleanup std::vector<uint256> relayed = ResendWalletTransactionsBefore(locked_chain, nBestBlockTime-5*60);
std::vector<uint256> relayed = ResendWalletTransactionsBefore(*locked_chain, nBestBlockTime-5*60);
if (!relayed.empty()) if (!relayed.empty())
WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size()); WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
} }
@ -4385,8 +4385,8 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
chain.loadWallet(interfaces::MakeWallet(walletInstance)); chain.loadWallet(interfaces::MakeWallet(walletInstance));
// Register with the validation interface. It's ok to do this after rescan since we're still holding cs_main. // Register with the validation interface. It's ok to do this after rescan since we're still holding locked_chain.
RegisterValidationInterface(walletInstance.get()); walletInstance->m_chain_notifications_handler = chain.handleNotifications(*walletInstance);
walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));

View File

@ -8,6 +8,7 @@
#include <amount.h> #include <amount.h>
#include <interfaces/chain.h> #include <interfaces/chain.h>
#include <interfaces/handler.h>
#include <outputtype.h> #include <outputtype.h>
#include <policy/feerate.h> #include <policy/feerate.h>
#include <streams.h> #include <streams.h>
@ -637,7 +638,7 @@ class WalletRescanReserver; //forward declarations for ScanForWalletTransactions
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, * A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions. * and provides the ability to create new transactions.
*/ */
class CWallet final : public CCryptoKeyStore, public CValidationInterface class CWallet final : public CCryptoKeyStore, private interfaces::Chain::Notifications
{ {
private: private:
std::atomic<bool> fAbortRescan{false}; std::atomic<bool> fAbortRescan{false};
@ -808,6 +809,9 @@ public:
std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet); std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet);
/** Registered interfaces::Chain::Notifications handler. */
std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
/** Interface for accessing chain state. */ /** Interface for accessing chain state. */
interfaces::Chain& chain() const { return m_chain; } interfaces::Chain& chain() const { return m_chain; }
@ -920,8 +924,8 @@ public:
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true); bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
void LoadToWallet(const CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void LoadToWallet(const CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void TransactionAddedToMempool(const CTransactionRef& tx) override; void TransactionAddedToMempool(const CTransactionRef& tx) override;
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override; void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted) override;
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override; void BlockDisconnected(const CBlock& block) override;
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update); int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
struct ScanResult { struct ScanResult {
@ -942,7 +946,7 @@ public:
ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate); ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override; void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions(); void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main); void ResendWalletTransactions(interfaces::Chain::Lock& locked_chain, int64_t nBestBlockTime) override;
// ResendWalletTransactionsBefore may only be called if fBroadcastTransactions! // ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
std::vector<uint256> ResendWalletTransactionsBefore(interfaces::Chain::Lock& locked_chain, int64_t nTime); std::vector<uint256> ResendWalletTransactionsBefore(interfaces::Chain::Lock& locked_chain, int64_t nTime);
CAmount GetBalance(const isminefilter& filter=ISMINE_SPENDABLE, const int min_depth=0) const; CAmount GetBalance(const isminefilter& filter=ISMINE_SPENDABLE, const int min_depth=0) const;
@ -1220,6 +1224,8 @@ public:
/** Add a KeyOriginInfo to the wallet */ /** Add a KeyOriginInfo to the wallet */
bool AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info); bool AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info);
friend struct WalletTestingSetup;
}; };
/** A key allocated from the key pool. */ /** A key allocated from the key pool. */