diff options
Diffstat (limited to 'src/main.cpp')
| -rw-r--r-- | src/main.cpp | 198 |
1 files changed, 64 insertions, 134 deletions
diff --git a/src/main.cpp b/src/main.cpp index 01a1babc7..875cd6734 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,7 +49,7 @@ int64 CTransaction::nMinTxFee = 10000; // Override with -mintxfee /** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */ int64 CTransaction::nMinRelayTxFee = 10000; -CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have +static CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have map<uint256, CBlock*> mapOrphanBlocks; multimap<uint256, CBlock*> mapOrphanBlocksByPrev; @@ -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); - } -} - -void UnregisterWallet(CWallet* pwalletIn) -{ - { - LOCK(cs_setpwalletRegistered); - setpwalletRegistered.erase(pwalletIn); - } +namespace { +struct CMainSignals { + // Notifies listeners of updated transaction data (passing hash, transaction, and optionally the block it is found in. + boost::signals2::signal<void (const uint256 &, const CTransaction &, const CBlock *)> SyncTransaction; + // Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). + boost::signals2::signal<void (const uint256 &)> EraseTransaction; + // Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). + boost::signals2::signal<void (const uint256 &)> UpdatedTransaction; + // Notifies listeners of a new active block chain. + boost::signals2::signal<void (const CBlockLocator &)> SetBestChain; + // Notifies listeners about an inventory item being seen on the network. + boost::signals2::signal<void (const uint256 &)> Inventory; + // Tells listeners to broadcast their data. + boost::signals2::signal<void ()> Broadcast; +} g_signals; } -void UnregisterAllWallets() -{ - LOCK(cs_setpwalletRegistered); - setpwalletRegistered.clear(); +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)); } -// 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 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)); } -// 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); +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(); } -// 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) { @@ -1750,12 +1688,12 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex const CTransaction &tx = block.vtx[i]; uint256 hash = tx.GetHash(); - // check that all outputs are available - if (!view.HaveCoins(hash)) { - fClean = fClean && error("DisconnectBlock() : outputs still spent? database corrupted"); - view.SetCoins(hash, CCoins()); - } - CCoins &outs = view.GetCoins(hash); + // Check that all outputs are available and match the outputs in the block itself + // exactly. Note that transactions with only provably unspendable outputs won't + // have outputs available even in the block itself, so we handle that case + // specially with outsEmpty. + CCoins outsEmpty; + CCoins &outs = view.HaveCoins(hash) ? view.GetCoins(hash) : outsEmpty; outs.ClearUnspendable(); CCoins outsBlock = CCoins(tx, pindex->nHeight); @@ -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); @@ -2355,7 +2293,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo uniqueTx.insert(block.GetTxHash(i)); } if (uniqueTx.size() != block.vtx.size()) - return state.DoS(100, error("CheckBlock() : duplicate transaction")); + return state.DoS(100, error("CheckBlock() : duplicate transaction"), true); unsigned int nSigOps = 0; BOOST_FOREACH(const CTransaction& tx, block.vtx) @@ -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<CBlockIndex*>& 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); } } @@ -3460,8 +3396,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) LogPrintf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str()); - LOCK(cs_main); AddTimeData(pfrom->addr, nTime); + + LOCK(cs_main); cPeerBlockCounts.input(pfrom->nStartingHeight); } @@ -3593,7 +3530,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } // Track requests for our stuff - Inventory(inv.hash); + g_signals.Inventory(inv.hash); } } @@ -3608,10 +3545,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) return error("message getdata size() = %"PRIszu"", vInv.size()); } - if (fDebugNet || (vInv.size() != 1)) + if (fDebug || (vInv.size() != 1)) LogPrint("net", "received getdata (%"PRIszu" invsz)\n", vInv.size()); - if ((fDebugNet && vInv.size() > 0) || (vInv.size() == 1)) + if ((fDebug && vInv.size() > 0) || (vInv.size() == 1)) LogPrint("net", "received getdata for: %s\n", vInv[0].ToString().c_str()); pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); @@ -3783,7 +3720,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) LOCK(cs_main); CValidationState state; - if (ProcessBlock(state, pfrom, &block)) + if (ProcessBlock(state, pfrom, &block) || state.CorruptionPossible()) mapAlreadyAskedFor.erase(inv); int nDoS = 0; if (state.IsInvalid(nDoS)) @@ -3814,8 +3751,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(mempool.lookup(hash), hash)) || (!pfrom->pfilter)) vInv.push_back(inv); - if (vInv.size() == MAX_INV_SZ) - break; + if (vInv.size() == MAX_INV_SZ) { + pfrom->PushMessage("inv", vInv); + vInv.clear(); + } } if (vInv.size() > 0) pfrom->PushMessage("inv", vInv); @@ -4213,7 +4152,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // transactions become unconfirmed and spams other nodes. if (!fReindex && !fImporting && !IsInitialBlockDownload()) { - ResendWalletTransactions(); + g_signals.Broadcast(); } // @@ -4241,15 +4180,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); @@ -4284,7 +4214,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) const CInv& inv = (*pto->mapAskFor.begin()).second; if (!AlreadyHave(inv)) { - if (fDebugNet) + if (fDebug) LogPrint("net", "sending getdata: %s\n", inv.ToString().c_str()); vGetData.push_back(inv); if (vGetData.size() >= 1000) |