diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index fbacbd2e2..4fd329606 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -3,7 +3,10 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "ui_interface.h" #include "init.h" +#include "util.h" +#include "main.h" #include "bitcoinrpc.h" #include diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index f2a52e92e..f3ea0adb4 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -4,6 +4,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "chainparams.h" +#include "main.h" +#include "wallet.h" #include "init.h" #include "util.h" #include "sync.h" diff --git a/src/init.h b/src/init.h index 785a6cdba..8cb1bf52f 100644 --- a/src/init.h +++ b/src/init.h @@ -5,7 +5,10 @@ #ifndef BITCOIN_INIT_H #define BITCOIN_INIT_H -#include "wallet.h" +#include +#include + +class CWallet; extern std::string strWalletFile; extern CWallet* pwalletMain; diff --git a/src/main.cpp b/src/main.cpp index 49fc7abba..3d339b4fd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,93 +74,52 @@ int64 nTransactionFee = 0; // These functions dispatch to one or all registered wallets - -void RegisterWallet(CWallet* pwalletIn) -{ - { - LOCK(cs_setpwalletRegistered); - setpwalletRegistered.insert(pwalletIn); - } +namespace { +struct CMainSignals { + // Notifies listeners of updated transaction data (passing hash, transaction, and optionally the block it is found in. + boost::signals2::signal SyncTransaction; + // Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). + boost::signals2::signal EraseTransaction; + // Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). + boost::signals2::signal UpdatedTransaction; + // Notifies listeners of a new active block chain. + boost::signals2::signal SetBestChain; + // Notifies listeners about an inventory item being seen on the network. + boost::signals2::signal Inventory; + // Tells listeners to broadcast their data. + boost::signals2::signal Broadcast; +} g_signals; } -void UnregisterWallet(CWallet* pwalletIn) -{ - { - LOCK(cs_setpwalletRegistered); - setpwalletRegistered.erase(pwalletIn); - } +void RegisterWallet(CWalletInterface* pwalletIn) { + g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3)); + g_signals.EraseTransaction.connect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1)); + g_signals.UpdatedTransaction.connect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1)); + g_signals.SetBestChain.connect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1)); + g_signals.Inventory.connect(boost::bind(&CWalletInterface::Inventory, pwalletIn, _1)); + g_signals.Broadcast.connect(boost::bind(&CWalletInterface::ResendWalletTransactions, pwalletIn)); } -void UnregisterAllWallets() -{ - LOCK(cs_setpwalletRegistered); - setpwalletRegistered.clear(); +void UnregisterWallet(CWalletInterface* pwalletIn) { + g_signals.Broadcast.disconnect(boost::bind(&CWalletInterface::ResendWalletTransactions, pwalletIn)); + g_signals.Inventory.disconnect(boost::bind(&CWalletInterface::Inventory, pwalletIn, _1)); + g_signals.SetBestChain.disconnect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1)); + g_signals.UpdatedTransaction.disconnect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1)); + g_signals.EraseTransaction.disconnect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1)); + g_signals.SyncTransaction.disconnect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3)); } -// get the wallet transaction with the given hash (if it exists) -bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - if (pwallet->GetTransaction(hashTx,wtx)) - return true; - return false; +void UnregisterAllWallets() { + g_signals.Broadcast.disconnect_all_slots(); + g_signals.Inventory.disconnect_all_slots(); + g_signals.SetBestChain.disconnect_all_slots(); + g_signals.UpdatedTransaction.disconnect_all_slots(); + g_signals.EraseTransaction.disconnect_all_slots(); + g_signals.SyncTransaction.disconnect_all_slots(); } -// erases transaction with the given hash from all wallets -void static EraseFromWallets(uint256 hash) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->EraseFromWallet(hash); -} - -// make sure all wallets know about the given transaction, in the given block -void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->AddToWalletIfInvolvingMe(hash, tx, pblock, fUpdate); -} - -// notify wallets about a new best chain -void static SetBestChain(const CBlockLocator& loc) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->SetBestChain(loc); -} - -// notify wallets about an updated transaction -void static UpdatedTransaction(const uint256& hashTx) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->UpdatedTransaction(hashTx); -} - -// dump all wallets -void static PrintWallets(const CBlock& block) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->PrintWallet(block); -} - -// notify wallets about an incoming inventory (for request counts) -void static Inventory(const uint256& hash) -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->Inventory(hash); -} - -// ask wallets to resend their transactions -void static ResendWalletTransactions() -{ - LOCK(cs_setpwalletRegistered); - BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - pwallet->ResendWalletTransactions(); +void SyncWithWallets(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) { + g_signals.SyncTransaction(hash, tx, pblock); } ////////////////////////////////////////////////////////////////////////////// @@ -931,8 +890,8 @@ bool CTxMemPool::accept(CValidationState &state, const CTransaction &tx, bool fL ///// are we sure this is ok when loading transactions or restoring block txes // If updated, erase old tx from wallet if (ptxOld) - EraseFromWallets(ptxOld->GetHash()); - SyncWithWallets(hash, tx, NULL, true); + g_signals.EraseTransaction(ptxOld->GetHash()); + g_signals.SyncTransaction(hash, tx, NULL); LogPrint("mempool", "CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n", hash.ToString().c_str(), @@ -1095,27 +1054,6 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree) } - -bool CWalletTx::AcceptWalletTransaction() -{ - { - LOCK(mempool.cs); - // Add previous supporting transactions first - BOOST_FOREACH(CMerkleTx& tx, vtxPrev) - { - if (!tx.IsCoinBase()) - { - uint256 hash = tx.GetHash(); - if (!mempool.exists(hash) && pcoinsTip->HaveCoins(hash)) - tx.AcceptToMemoryPool(false); - } - } - return AcceptToMemoryPool(false); - } - return false; -} - - // Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) { @@ -1992,7 +1930,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C // Watch for transactions paying to me for (unsigned int i = 0; i < block.vtx.size(); i++) - SyncWithWallets(block.GetTxHash(i), block.vtx[i], &block, true); + g_signals.SyncTransaction(block.GetTxHash(i), block.vtx[i], &block); return true; } @@ -2126,7 +2064,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) // Update best block in wallet (so we can detect restored wallets) if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0)) - ::SetBestChain(chainActive.GetLocator(pindexNew)); + g_signals.SetBestChain(chainActive.GetLocator(pindexNew)); // New best block nTimeBestReceived = GetTime(); @@ -2206,7 +2144,7 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos CheckForkWarningConditions(); // Notify UI to display prev block's coinbase if it was ours static uint256 hashPrevBestCoinBase; - UpdatedTransaction(hashPrevBestCoinBase); + g_signals.UpdatedTransaction(hashPrevBestCoinBase); hashPrevBestCoinBase = block.GetTxHash(0); } else CheckForkWarningConditionsOnNewFork(pindexNew); @@ -3041,8 +2979,6 @@ void PrintBlockTree() DateTimeStrFormat("%Y-%m-%d %H:%M:%S", block.GetBlockTime()).c_str(), block.vtx.size()); - PrintWallets(block); - // put the main time-chain first vector& vNext = mapNext[pindex]; for (unsigned int i = 0; i < vNext.size(); i++) @@ -3331,7 +3267,7 @@ void static ProcessGetData(CNode* pfrom) } // Track requests for our stuff. - Inventory(inv.hash); + g_signals.Inventory(inv.hash); } } @@ -3593,7 +3529,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } // Track requests for our stuff - Inventory(inv.hash); + g_signals.Inventory(inv.hash); } } @@ -4215,7 +4151,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // transactions become unconfirmed and spams other nodes. if (!fReindex && !fImporting && !IsInitialBlockDownload()) { - ResendWalletTransactions(); + g_signals.Broadcast(); } // @@ -4243,15 +4179,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle) hashRand = Hash(BEGIN(hashRand), END(hashRand)); bool fTrickleWait = ((hashRand & 3) != 0); - // always trickle our own transactions - if (!fTrickleWait) - { - CWalletTx wtx; - if (GetTransaction(inv.hash, wtx)) - if (wtx.fFromMe) - fTrickleWait = true; - } - if (fTrickleWait) { vInvWait.push_back(inv); diff --git a/src/main.h b/src/main.h index 2a67747b4..b56a4a5e1 100644 --- a/src/main.h +++ b/src/main.h @@ -17,7 +17,6 @@ #include -class CWallet; class CBlock; class CBlockIndex; class CKeyItem; @@ -81,8 +80,6 @@ extern uint64 nLastBlockTx; extern uint64 nLastBlockSize; extern const std::string strMessageMagic; extern int64 nTimeBestReceived; -extern CCriticalSection cs_setpwalletRegistered; -extern std::set setpwalletRegistered; extern bool fImporting; extern bool fReindex; extern bool fBenchmark; @@ -108,17 +105,18 @@ class CCoinsView; class CCoinsViewCache; class CScriptCheck; class CValidationState; +class CWalletInterface; struct CBlockTemplate; /** Register a wallet to receive updates from core */ -void RegisterWallet(CWallet* pwalletIn); +void RegisterWallet(CWalletInterface* pwalletIn); /** Unregister a wallet from core */ -void UnregisterWallet(CWallet* pwalletIn); +void UnregisterWallet(CWalletInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllWallets(); /** Push an updated transaction to all registered wallets */ -void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); +void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL); /** Register with a network node to receive its signals */ void RegisterNodeSignals(CNodeSignals& nodeSignals); @@ -190,9 +188,6 @@ bool AbortNode(const std::string &msg); - -bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); - struct CDiskBlockPos { int nFile; @@ -1261,4 +1256,18 @@ public: ) }; + +class CWalletInterface { +protected: + virtual void SyncTransaction(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) =0; + virtual void EraseFromWallet(const uint256 &hash) =0; + virtual void SetBestChain(const CBlockLocator &locator) =0; + virtual void UpdatedTransaction(const uint256 &hash) =0; + virtual void Inventory(const uint256 &hash) =0; + virtual void ResendWalletTransactions() =0; + friend void ::RegisterWallet(CWalletInterface*); + friend void ::UnregisterWallet(CWalletInterface*); + friend void ::UnregisterAllWallets(); +}; + #endif diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 95efc5832..4db048dcc 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -6,6 +6,9 @@ #include "bitcoinunits.h" #include "init.h" +#include "core.h" +#include "wallet.h" +#include "netbase.h" #include "walletdb.h" #include "guiutil.h" diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 3589b4590..a5f7a542d 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -6,6 +6,7 @@ #include #include "init.h" // for pwalletMain +#include "wallet.h" #include "bitcoinrpc.h" #include "ui_interface.h" #include "base58.h" diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index d5bd39cb4..4d1381bc2 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -560,7 +560,7 @@ Value sendrawtransaction(const Array& params, bool fHelp) // Not in block, but already in the memory pool; will drop // through to re-relay it. } else { - SyncWithWallets(hashTx, tx, NULL, true); + SyncWithWallets(hashTx, tx, NULL); } RelayTransaction(tx, hashTx); diff --git a/src/wallet.cpp b/src/wallet.cpp index a7a2992bb..ea1e01e6e 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -505,7 +505,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) // Add a transaction to the wallet, or update it. // pblock is optional, but should be provided if the transaction is known to be in a block. // If fUpdate is true, existing transactions will be updated. -bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock) +bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate) { { LOCK(cs_wallet); @@ -525,16 +525,20 @@ bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& return false; } -bool CWallet::EraseFromWallet(uint256 hash) +void CWallet::SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock) { + AddToWalletIfInvolvingMe(hash, tx, pblock, true); +} + +void CWallet::EraseFromWallet(const uint256 &hash) { if (!fFileBacked) - return false; + return; { LOCK(cs_wallet); if (mapWallet.erase(hash)) CWalletDB(strWalletFile).EraseTx(hash); } - return true; + return; } @@ -773,6 +777,25 @@ void CWalletTx::AddSupportingTransactions() reverse(vtxPrev.begin(), vtxPrev.end()); } +bool CWalletTx::AcceptWalletTransaction() +{ + { + LOCK(mempool.cs); + // Add previous supporting transactions first + BOOST_FOREACH(CMerkleTx& tx, vtxPrev) + { + if (!tx.IsCoinBase()) + { + uint256 hash = tx.GetHash(); + if (!mempool.exists(hash) && pcoinsTip->HaveCoins(hash)) + tx.AcceptToMemoryPool(false); + } + } + return AcceptToMemoryPool(false); + } + return false; +} + bool CWalletTx::WriteToDisk() { return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this); @@ -1485,33 +1508,6 @@ bool CWallet::DelAddressBook(const CTxDestination& address) return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString()); } -void CWallet::PrintWallet(const CBlock& block) -{ - { - LOCK(cs_wallet); - if (mapWallet.count(block.vtx[0].GetHash())) - { - CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; - LogPrintf(" mine: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); - } - } - LogPrintf("\n"); -} - -bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx) -{ - { - LOCK(cs_wallet); - map::iterator mi = mapWallet.find(hashTx); - if (mi != mapWallet.end()) - { - wtx = (*mi).second; - return true; - } - } - return false; -} - bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) { if (fFileBacked) @@ -1523,14 +1519,6 @@ bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) return true; } -bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) -{ - if (!pwallet->fFileBacked) - return false; - strWalletFileOut = pwallet->strWalletFile; - return true; -} - // // Mark old keypool keys as used, // and generate all new keys diff --git a/src/wallet.h b/src/wallet.h index f87e9b08c..21510f8c3 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -80,7 +80,7 @@ public: /** 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. */ -class CWallet : public CCryptoKeyStore +class CWallet : public CCryptoKeyStore, public CWalletInterface { private: bool SelectCoins(int64 nTargetValue, std::set >& setCoinsRet, int64& nValueRet) const; @@ -197,8 +197,9 @@ public: void MarkDirty(); bool AddToWallet(const CWalletTx& wtxIn); - bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false); - bool EraseFromWallet(uint256 hash); + void SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock); + bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate); + void EraseFromWallet(const uint256 &hash); void WalletUpdateSpent(const CTransaction& prevout); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); void ReacceptWalletTransactions(); @@ -302,8 +303,6 @@ public: void UpdatedTransaction(const uint256 &hashTx); - void PrintWallet(const CBlock& block); - void Inventory(const uint256 &hash) { { @@ -319,8 +318,6 @@ public: return setKeyPool.size(); } - bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx); - bool SetDefaultKey(const CPubKey &vchPubKey); // signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower @@ -891,6 +888,4 @@ private: std::vector _ssExtra; }; -bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); - #endif