diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 681f9a77ed..376982c025 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1,1396 +1,1396 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 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 "txmempool.h" - -#include "chain.h" -#include "chainparams.h" // for GetConsensus. -#include "clientversion.h" -#include "config.h" -#include "consensus/consensus.h" -#include "consensus/tx_verify.h" -#include "consensus/validation.h" -#include "policy/fees.h" -#include "policy/policy.h" -#include "reverse_iterator.h" -#include "streams.h" -#include "timedata.h" -#include "util.h" -#include "utilmoneystr.h" -#include "utiltime.h" -#include "validation.h" -#include "version.h" +#include + +#include +#include // for GetConsensus. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef &_tx, const Amount _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, Amount _inChainInputValue, bool _spendsCoinbase, int64_t _sigOpsCount, LockPoints lp) : tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), inChainInputValue(_inChainInputValue), spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOpsCount), lockPoints(lp) { nTxSize = tx->GetTotalSize(); nTxBillableSize = tx->GetBillableSize(); nModSize = tx->CalculateModifiedSize(GetTxSize()); nUsageSize = RecursiveDynamicUsage(tx); nCountWithDescendants = 1; nSizeWithDescendants = GetTxSize(); nBillableSizeWithDescendants = GetTxBillableSize(); nModFeesWithDescendants = nFee; Amount nValueIn = tx->GetValueOut() + nFee; assert(inChainInputValue <= nValueIn); feeDelta = Amount::zero(); nCountWithAncestors = 1; nSizeWithAncestors = GetTxSize(); nBillableSizeWithAncestors = GetTxBillableSize(); nModFeesWithAncestors = nFee; nSigOpCountWithAncestors = sigOpCount; } double CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const { double deltaPriority = double((currentHeight - entryHeight) * (inChainInputValue / SATOSHI)) / nModSize; double dResult = entryPriority + deltaPriority; // This should only happen if it was called with a height below entry height if (dResult < 0) { dResult = 0; } return dResult; } void CTxMemPoolEntry::UpdateFeeDelta(Amount newFeeDelta) { nModFeesWithDescendants += newFeeDelta - feeDelta; nModFeesWithAncestors += newFeeDelta - feeDelta; feeDelta = newFeeDelta; } void CTxMemPoolEntry::UpdateLockPoints(const LockPoints &lp) { lockPoints = lp; } // Update the given tx for any in-mempool descendants. // Assumes that setMemPoolChildren is correct for the given tx and all // descendants. void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set &setExclude) { setEntries stageEntries, setAllDescendants; stageEntries = GetMemPoolChildren(updateIt); while (!stageEntries.empty()) { const txiter cit = *stageEntries.begin(); setAllDescendants.insert(cit); stageEntries.erase(cit); const setEntries &setChildren = GetMemPoolChildren(cit); for (const txiter childEntry : setChildren) { cacheMap::iterator cacheIt = cachedDescendants.find(childEntry); if (cacheIt != cachedDescendants.end()) { // We've already calculated this one, just add the entries for // this set but don't traverse again. for (const txiter cacheEntry : cacheIt->second) { setAllDescendants.insert(cacheEntry); } } else if (!setAllDescendants.count(childEntry)) { // Schedule for later processing stageEntries.insert(childEntry); } } } // setAllDescendants now contains all in-mempool descendants of updateIt. // Update and add to cached descendant map int64_t modifySize = 0; int64_t modifyBillableSize = 0; int64_t modifyCount = 0; Amount modifyFee = Amount::zero(); for (txiter cit : setAllDescendants) { if (!setExclude.count(cit->GetTx().GetId())) { modifySize += cit->GetTxSize(); modifyBillableSize += cit->GetTxBillableSize(); modifyFee += cit->GetModifiedFee(); modifyCount++; cachedDescendants[updateIt].insert(cit); // Update ancestor state for each descendant mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), updateIt->GetTxBillableSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCount())); } } mapTx.modify(updateIt, update_descendant_state(modifySize, modifyBillableSize, modifyFee, modifyCount)); } // txidsToUpdate is the set of transaction hashes from a disconnected block // which has been re-added to the mempool. For each entry, look for descendants // that are outside txidsToUpdate, and add fee/size information for such // descendants to the parent. For each such descendant, also update the ancestor // state to include the parent. void CTxMemPool::UpdateTransactionsFromBlock( const std::vector &txidsToUpdate) { LOCK(cs); // For each entry in txidsToUpdate, store the set of in-mempool, but not // in-txidsToUpdate transactions, so that we don't have to recalculate // descendants when we come across a previously seen entry. cacheMap mapMemPoolDescendantsToUpdate; // Use a set for lookups into txidsToUpdate (these entries are already // accounted for in the state of their ancestors) std::set setAlreadyIncluded(txidsToUpdate.begin(), txidsToUpdate.end()); // Iterate in reverse, so that whenever we are looking at at a transaction // we are sure that all in-mempool descendants have already been processed. // This maximizes the benefit of the descendant cache and guarantees that // setMemPoolChildren will be updated, an assumption made in // UpdateForDescendants. for (const TxId &txid : reverse_iterate(txidsToUpdate)) { // we cache the in-mempool children to avoid duplicate updates setEntries setChildren; // calculate children from mapNextTx txiter it = mapTx.find(txid); if (it == mapTx.end()) { continue; } auto iter = mapNextTx.lower_bound(COutPoint(txid, 0)); // First calculate the children, and update setMemPoolChildren to // include them, and update their setMemPoolParents to include this tx. for (; iter != mapNextTx.end() && iter->first->GetTxId() == txid; ++iter) { const TxId &childTxId = iter->second->GetId(); txiter childIter = mapTx.find(childTxId); assert(childIter != mapTx.end()); // We can skip updating entries we've encountered before or that are // in the block (which are already accounted for). if (setChildren.insert(childIter).second && !setAlreadyIncluded.count(childTxId)) { UpdateChild(it, childIter, true); UpdateParent(childIter, it, true); } } UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded); } } bool CTxMemPool::CalculateMemPoolAncestors( const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents /* = true */) const { LOCK(cs); setEntries parentHashes; const CTransaction &tx = entry.GetTx(); if (fSearchForParents) { // Get parents of this transaction that are in the mempool // GetMemPoolParents() is only valid for entries in the mempool, so we // iterate mapTx to find parents. for (const CTxIn &in : tx.vin) { txiter piter = mapTx.find(in.prevout.GetTxId()); if (piter == mapTx.end()) { continue; } parentHashes.insert(piter); if (parentHashes.size() + 1 > limitAncestorCount) { errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount); return false; } } } else { // If we're not searching for parents, we require this to be an entry in // the mempool already. txiter it = mapTx.iterator_to(entry); parentHashes = GetMemPoolParents(it); } size_t totalSizeWithAncestors = entry.GetTxSize(); while (!parentHashes.empty()) { txiter stageit = *parentHashes.begin(); setAncestors.insert(stageit); parentHashes.erase(stageit); totalSizeWithAncestors += stageit->GetTxSize(); if (stageit->GetSizeWithDescendants() + entry.GetTxSize() > limitDescendantSize) { errString = strprintf( "exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetId().ToString(), limitDescendantSize); return false; } if (stageit->GetCountWithDescendants() + 1 > limitDescendantCount) { errString = strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetId().ToString(), limitDescendantCount); return false; } if (totalSizeWithAncestors > limitAncestorSize) { errString = strprintf("exceeds ancestor size limit [limit: %u]", limitAncestorSize); return false; } const setEntries &setMemPoolParents = GetMemPoolParents(stageit); for (const txiter &phash : setMemPoolParents) { // If this is a new ancestor, add it. if (setAncestors.count(phash) == 0) { parentHashes.insert(phash); } if (parentHashes.size() + setAncestors.size() + 1 > limitAncestorCount) { errString = strprintf("too many unconfirmed ancestors [limit: %u]", limitAncestorCount); return false; } } } return true; } void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors) { setEntries parentIters = GetMemPoolParents(it); // add or remove this tx as a child of each parent for (txiter piter : parentIters) { UpdateChild(piter, it, add); } const int64_t updateCount = (add ? 1 : -1); const int64_t updateSize = updateCount * it->GetTxSize(); const int64_t updateBillableSize = updateCount * it->GetTxBillableSize(); const Amount updateFee = updateCount * it->GetModifiedFee(); for (txiter ancestorIt : setAncestors) { mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateBillableSize, updateFee, updateCount)); } } void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncestors) { int64_t updateCount = setAncestors.size(); int64_t updateSize = 0; int64_t updateBillableSize = 0; int64_t updateSigOpsCount = 0; Amount updateFee = Amount::zero(); for (txiter ancestorIt : setAncestors) { updateSize += ancestorIt->GetTxSize(); updateBillableSize += ancestorIt->GetTxBillableSize(); updateFee += ancestorIt->GetModifiedFee(); updateSigOpsCount += ancestorIt->GetSigOpCount(); } mapTx.modify(it, update_ancestor_state(updateSize, updateBillableSize, updateFee, updateCount, updateSigOpsCount)); } void CTxMemPool::UpdateChildrenForRemoval(txiter it) { const setEntries &setMemPoolChildren = GetMemPoolChildren(it); for (txiter updateIt : setMemPoolChildren) { UpdateParent(updateIt, it, false); } } void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants) { // For each entry, walk back all ancestors and decrement size associated // with this transaction. const uint64_t nNoLimit = std::numeric_limits::max(); if (updateDescendants) { // updateDescendants should be true whenever we're not recursively // removing a tx and all its descendants, eg when a transaction is // confirmed in a block. Here we only update statistics and not data in // mapLinks (which we need to preserve until we're finished with all // operations that need to traverse the mempool). for (txiter removeIt : entriesToRemove) { setEntries setDescendants; CalculateDescendants(removeIt, setDescendants); setDescendants.erase(removeIt); // don't update state for self int64_t modifySize = -int64_t(removeIt->GetTxSize()); int64_t modifyBillableSize = -int64_t(removeIt->GetTxBillableSize()); Amount modifyFee = -1 * removeIt->GetModifiedFee(); int modifySigOps = -removeIt->GetSigOpCount(); for (txiter dit : setDescendants) { mapTx.modify( dit, update_ancestor_state(modifySize, modifyBillableSize, modifyFee, -1, modifySigOps)); } } } for (txiter removeIt : entriesToRemove) { setEntries setAncestors; const CTxMemPoolEntry &entry = *removeIt; std::string dummy; // Since this is a tx that is already in the mempool, we can call CMPA // with fSearchForParents = false. If the mempool is in a consistent // state, then using true or false should both be correct, though false // should be a bit faster. // However, if we happen to be in the middle of processing a reorg, then // the mempool can be in an inconsistent state. In this case, the set of // ancestors reachable via mapLinks will be the same as the set of // ancestors whose packages include this transaction, because when we // add a new transaction to the mempool in addUnchecked(), we assume it // has no children, and in the case of a reorg where that assumption is // false, the in-mempool children aren't linked to the in-block tx's // until UpdateTransactionsFromBlock() is called. So if we're being // called during a reorg, ie before UpdateTransactionsFromBlock() has // been called, then mapLinks[] will differ from the set of mempool // parents we'd calculate by searching, and it's important that we use // the mapLinks[] notion of ancestor transactions as the set of things // to update for removal. CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); // Note that UpdateAncestorsOf severs the child links that point to // removeIt in the entries for the parents of removeIt. UpdateAncestorsOf(false, removeIt, setAncestors); } // After updating all the ancestor sizes, we can now sever the link between // each transaction being removed and any mempool children (ie, update // setMemPoolParents for each direct child of a transaction being removed). for (txiter removeIt : entriesToRemove) { UpdateChildrenForRemoval(removeIt); } } void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, int64_t modifyBillableSize, Amount modifyFee, int64_t modifyCount) { nSizeWithDescendants += modifySize; assert(int64_t(nSizeWithDescendants) > 0); nBillableSizeWithDescendants += modifyBillableSize; assert(int64_t(nBillableSizeWithDescendants) >= 0); nModFeesWithDescendants += modifyFee; nCountWithDescendants += modifyCount; assert(int64_t(nCountWithDescendants) > 0); } void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, int64_t modifyBillableSize, Amount modifyFee, int64_t modifyCount, int modifySigOps) { nSizeWithAncestors += modifySize; assert(int64_t(nSizeWithAncestors) > 0); nBillableSizeWithAncestors += modifyBillableSize; assert(int64_t(nBillableSizeWithAncestors) >= 0); nModFeesWithAncestors += modifyFee; nCountWithAncestors += modifyCount; assert(int64_t(nCountWithAncestors) > 0); nSigOpCountWithAncestors += modifySigOps; assert(int(nSigOpCountWithAncestors) >= 0); } CTxMemPool::CTxMemPool() : nTransactionsUpdated(0) { // lock free clear _clear(); // Sanity checks off by default for performance, because otherwise accepting // transactions becomes O(N^2) where N is the number of transactions in the // pool nCheckFrequency = 0; } CTxMemPool::~CTxMemPool() {} bool CTxMemPool::isSpent(const COutPoint &outpoint) { LOCK(cs); return mapNextTx.count(outpoint); } unsigned int CTxMemPool::GetTransactionsUpdated() const { LOCK(cs); return nTransactionsUpdated; } void CTxMemPool::AddTransactionsUpdated(unsigned int n) { LOCK(cs); nTransactionsUpdated += n; } bool CTxMemPool::addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry, setEntries &setAncestors) { NotifyEntryAdded(entry.GetSharedTx()); // Add to memory pool without checking anything. // Used by AcceptToMemoryPool(), which DOES do all the appropriate checks. LOCK(cs); indexed_transaction_set::iterator newit = mapTx.insert(entry).first; mapLinks.insert(make_pair(newit, TxLinks())); // Update transaction for any feeDelta created by PrioritiseTransaction // TODO: refactor so that the fee delta is calculated before inserting into // mapTx. std::map::const_iterator pos = mapDeltas.find(hash); if (pos != mapDeltas.end()) { const TXModifier &deltas = pos->second; if (deltas.second != Amount::zero()) { mapTx.modify(newit, update_fee_delta(deltas.second)); } } // Update cachedInnerUsage to include contained transaction's usage. // (When we update the entry for in-mempool parents, memory usage will be // further updated.) cachedInnerUsage += entry.DynamicMemoryUsage(); const CTransaction &tx = newit->GetTx(); std::set setParentTransactions; for (const CTxIn &in : tx.vin) { mapNextTx.insert(std::make_pair(&in.prevout, &tx)); setParentTransactions.insert(in.prevout.GetTxId()); } // Don't bother worrying about child transactions of this one. Normal case // of a new transaction arriving is that there can't be any children, // because such children would be orphans. An exception to that is if a // transaction enters that used to be in a block. In that case, our // disconnect block logic will call UpdateTransactionsFromBlock to clean up // the mess we're leaving here. // Update ancestors with information about this tx for (const uint256 &phash : setParentTransactions) { txiter pit = mapTx.find(phash); if (pit != mapTx.end()) { UpdateParent(newit, pit, true); } } UpdateAncestorsOf(true, newit, setAncestors); UpdateEntryForAncestors(newit, setAncestors); nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); vTxHashes.emplace_back(tx.GetHash(), newit); newit->vTxHashesIdx = vTxHashes.size() - 1; return true; } void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) { NotifyEntryRemoved(it->GetSharedTx(), reason); for (const CTxIn &txin : it->GetTx().vin) { mapNextTx.erase(txin.prevout); } if (vTxHashes.size() > 1) { vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back()); vTxHashes[it->vTxHashesIdx].second->vTxHashesIdx = it->vTxHashesIdx; vTxHashes.pop_back(); if (vTxHashes.size() * 2 < vTxHashes.capacity()) { vTxHashes.shrink_to_fit(); } } else { vTxHashes.clear(); } totalTxSize -= it->GetTxSize(); cachedInnerUsage -= it->DynamicMemoryUsage(); cachedInnerUsage -= memusage::DynamicUsage(mapLinks[it].parents) + memusage::DynamicUsage(mapLinks[it].children); mapLinks.erase(it); mapTx.erase(it); nTransactionsUpdated++; } // Calculates descendants of entry that are not already in setDescendants, and // adds to setDescendants. Assumes entryit is already a tx in the mempool and // setMemPoolChildren is correct for tx and all descendants. Also assumes that // if an entry is in setDescendants already, then all in-mempool descendants of // it are already in setDescendants as well, so that we can save time by not // iterating over those entries. void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants) const { setEntries stage; if (setDescendants.count(entryit) == 0) { stage.insert(entryit); } // Traverse down the children of entry, only adding children that are not // accounted for in setDescendants already (because those children have // either already been walked, or will be walked in this iteration). while (!stage.empty()) { txiter it = *stage.begin(); setDescendants.insert(it); stage.erase(it); const setEntries &setChildren = GetMemPoolChildren(it); for (const txiter &childiter : setChildren) { if (!setDescendants.count(childiter)) { stage.insert(childiter); } } } } void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReason reason) { // Remove transaction from memory pool. LOCK(cs); setEntries txToRemove; txiter origit = mapTx.find(origTx.GetId()); if (origit != mapTx.end()) { txToRemove.insert(origit); } else { // When recursively removing but origTx isn't in the mempool be sure to // remove any children that are in the pool. This can happen during // chain re-orgs if origTx isn't re-accepted into the mempool for any // reason. for (size_t i = 0; i < origTx.vout.size(); i++) { auto it = mapNextTx.find(COutPoint(origTx.GetId(), i)); if (it == mapNextTx.end()) { continue; } txiter nextit = mapTx.find(it->second->GetId()); assert(nextit != mapTx.end()); txToRemove.insert(nextit); } } setEntries setAllRemoves; for (txiter it : txToRemove) { CalculateDescendants(it, setAllRemoves); } RemoveStaged(setAllRemoves, false, reason); } void CTxMemPool::removeForReorg(const Config &config, const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) { // Remove transactions spending a coinbase which are now immature and // no-longer-final transactions. LOCK(cs); setEntries txToRemove; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction &tx = it->GetTx(); LockPoints lp = it->GetLockPoints(); bool validLP = TestLockPointValidity(&lp); CValidationState state; if (!ContextualCheckTransactionForCurrentBlock(config, tx, state, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) { // Note if CheckSequenceLocks fails the LockPoints may still be // invalid. So it's critical that we remove the tx and not depend on // the LockPoints. txToRemove.insert(it); } else if (it->GetSpendsCoinbase()) { for (const CTxIn &txin : tx.vin) { indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.GetTxId()); if (it2 != mapTx.end()) { continue; } const Coin &coin = pcoins->AccessCoin(txin.prevout); if (nCheckFrequency != 0) { assert(!coin.IsSpent()); } if (coin.IsSpent() || (coin.IsCoinBase() && int64_t(nMemPoolHeight) - coin.GetHeight() < COINBASE_MATURITY)) { txToRemove.insert(it); break; } } } if (!validLP) { mapTx.modify(it, update_lock_points(lp)); } } setEntries setAllRemoves; for (txiter it : txToRemove) { CalculateDescendants(it, setAllRemoves); } RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG); } void CTxMemPool::removeConflicts(const CTransaction &tx) { // Remove transactions which depend on inputs of tx, recursively LOCK(cs); for (const CTxIn &txin : tx.vin) { auto it = mapNextTx.find(txin.prevout); if (it != mapNextTx.end()) { const CTransaction &txConflict = *it->second; if (txConflict != tx) { ClearPrioritisation(txConflict.GetId()); removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT); } } } } /** * Called when a block is connected. Removes from mempool and updates the miner * fee estimator. */ void CTxMemPool::removeForBlock(const std::vector &vtx, unsigned int nBlockHeight) { LOCK(cs); DisconnectedBlockTransactions disconnectpool; disconnectpool.addForBlock(vtx); std::vector entries; for (const CTransactionRef &tx : reverse_iterate(disconnectpool.GetQueuedTx().get())) { uint256 txid = tx->GetId(); indexed_transaction_set::iterator i = mapTx.find(txid); if (i != mapTx.end()) { entries.push_back(&*i); } } for (const CTransactionRef &tx : reverse_iterate(disconnectpool.GetQueuedTx().get())) { txiter it = mapTx.find(tx->GetId()); if (it != mapTx.end()) { setEntries stage; stage.insert(it); RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK); } removeConflicts(*tx); ClearPrioritisation(tx->GetId()); } disconnectpool.clear(); lastRollingFeeUpdate = GetTime(); blockSinceLastRollingFeeBump = true; } void CTxMemPool::_clear() { mapLinks.clear(); mapTx.clear(); mapNextTx.clear(); vTxHashes.clear(); totalTxSize = 0; cachedInnerUsage = 0; lastRollingFeeUpdate = GetTime(); blockSinceLastRollingFeeBump = false; rollingMinimumFeeRate = 0; ++nTransactionsUpdated; } void CTxMemPool::clear() { LOCK(cs); _clear(); } void CTxMemPool::check(const CCoinsViewCache *pcoins) const { if (nCheckFrequency == 0) { return; } if (GetRand(std::numeric_limits::max()) >= nCheckFrequency) { return; } LogPrint(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); uint64_t checkTotal = 0; uint64_t innerUsage = 0; CCoinsViewCache mempoolDuplicate(const_cast(pcoins)); const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate); LOCK(cs); std::list waitingOnDependants; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { unsigned int i = 0; checkTotal += it->GetTxSize(); innerUsage += it->DynamicMemoryUsage(); const CTransaction &tx = it->GetTx(); txlinksMap::const_iterator linksiter = mapLinks.find(it); assert(linksiter != mapLinks.end()); const TxLinks &links = linksiter->second; innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children); bool fDependsWait = false; setEntries setParentCheck; int64_t parentSizes = 0; int64_t parentSigOpCount = 0; for (const CTxIn &txin : tx.vin) { // Check that every mempool transaction's inputs refer to available // coins, or other mempool tx's. indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.GetTxId()); if (it2 != mapTx.end()) { const CTransaction &tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.GetN() && !tx2.vout[txin.prevout.GetN()].IsNull()); fDependsWait = true; if (setParentCheck.insert(it2).second) { parentSizes += it2->GetTxSize(); parentSigOpCount += it2->GetSigOpCount(); } } else { assert(pcoins->HaveCoin(txin.prevout)); } // Check whether its inputs are marked in mapNextTx. auto it3 = mapNextTx.find(txin.prevout); assert(it3 != mapNextTx.end()); assert(it3->first == &txin.prevout); assert(it3->second == &tx); i++; } assert(setParentCheck == GetMemPoolParents(it)); // Verify ancestor state is correct. setEntries setAncestors; uint64_t nNoLimit = std::numeric_limits::max(); std::string dummy; CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); uint64_t nCountCheck = setAncestors.size() + 1; uint64_t nSizeCheck = it->GetTxSize(); Amount nFeesCheck = it->GetModifiedFee(); int64_t nSigOpCheck = it->GetSigOpCount(); for (txiter ancestorIt : setAncestors) { nSizeCheck += ancestorIt->GetTxSize(); nFeesCheck += ancestorIt->GetModifiedFee(); nSigOpCheck += ancestorIt->GetSigOpCount(); } assert(it->GetCountWithAncestors() == nCountCheck); assert(it->GetSizeWithAncestors() == nSizeCheck); assert(it->GetSigOpCountWithAncestors() == nSigOpCheck); assert(it->GetModFeesWithAncestors() == nFeesCheck); // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetId(), 0)); int64_t childSizes = 0; for (; iter != mapNextTx.end() && iter->first->GetTxId() == it->GetTx().GetId(); ++iter) { txiter childit = mapTx.find(iter->second->GetId()); // mapNextTx points to in-mempool transactions assert(childit != mapTx.end()); if (setChildrenCheck.insert(childit).second) { childSizes += childit->GetTxSize(); } } assert(setChildrenCheck == GetMemPoolChildren(it)); // Also check to make sure size is greater than sum with immediate // children. Just a sanity check, not definitive that this calc is // correct... assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize()); if (fDependsWait) { waitingOnDependants.push_back(&(*it)); } else { CValidationState state; bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs( tx, state, mempoolDuplicate, nSpendHeight); assert(fCheckResult); UpdateCoins(mempoolDuplicate, tx, 1000000); } } unsigned int stepsSinceLastRemove = 0; while (!waitingOnDependants.empty()) { const CTxMemPoolEntry *entry = waitingOnDependants.front(); waitingOnDependants.pop_front(); CValidationState state; if (!mempoolDuplicate.HaveInputs(entry->GetTx())) { waitingOnDependants.push_back(entry); stepsSinceLastRemove++; assert(stepsSinceLastRemove < waitingOnDependants.size()); } else { bool fCheckResult = entry->GetTx().IsCoinBase() || Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight); assert(fCheckResult); UpdateCoins(mempoolDuplicate, entry->GetTx(), 1000000); stepsSinceLastRemove = 0; } } for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) { uint256 txid = it->second->GetId(); indexed_transaction_set::const_iterator it2 = mapTx.find(txid); const CTransaction &tx = it2->GetTx(); assert(it2 != mapTx.end()); assert(&tx == it->second); } assert(totalTxSize == checkTotal); assert(innerUsage == cachedInnerUsage); } bool CTxMemPool::CompareDepthAndScore(const uint256 &hasha, const uint256 &hashb) { LOCK(cs); indexed_transaction_set::const_iterator i = mapTx.find(hasha); if (i == mapTx.end()) { return false; } indexed_transaction_set::const_iterator j = mapTx.find(hashb); if (j == mapTx.end()) { return true; } uint64_t counta = i->GetCountWithAncestors(); uint64_t countb = j->GetCountWithAncestors(); if (counta == countb) { return CompareTxMemPoolEntryByScore()(*i, *j); } return counta < countb; } namespace { class DepthAndScoreComparator { public: bool operator()(const CTxMemPool::indexed_transaction_set::const_iterator &a, const CTxMemPool::indexed_transaction_set::const_iterator &b) { uint64_t counta = a->GetCountWithAncestors(); uint64_t countb = b->GetCountWithAncestors(); if (counta == countb) { return CompareTxMemPoolEntryByScore()(*a, *b); } return counta < countb; } }; } // namespace std::vector CTxMemPool::GetSortedDepthAndScore() const { std::vector iters; AssertLockHeld(cs); iters.reserve(mapTx.size()); for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi) { iters.push_back(mi); } std::sort(iters.begin(), iters.end(), DepthAndScoreComparator()); return iters; } void CTxMemPool::queryHashes(std::vector &vtxid) { LOCK(cs); auto iters = GetSortedDepthAndScore(); vtxid.clear(); vtxid.reserve(mapTx.size()); for (auto it : iters) { vtxid.push_back(it->GetTx().GetId()); } } static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) { return TxMempoolInfo{it->GetSharedTx(), it->GetTime(), CFeeRate(it->GetFee(), it->GetTxBillableSize()), it->GetModifiedFee() - it->GetFee()}; } std::vector CTxMemPool::infoAll() const { LOCK(cs); auto iters = GetSortedDepthAndScore(); std::vector ret; ret.reserve(mapTx.size()); for (auto it : iters) { ret.push_back(GetInfo(it)); } return ret; } CTransactionRef CTxMemPool::get(const uint256 &txid) const { LOCK(cs); indexed_transaction_set::const_iterator i = mapTx.find(txid); if (i == mapTx.end()) { return nullptr; } return i->GetSharedTx(); } TxMempoolInfo CTxMemPool::info(const uint256 &txid) const { LOCK(cs); indexed_transaction_set::const_iterator i = mapTx.find(txid); if (i == mapTx.end()) { return TxMempoolInfo(); } return GetInfo(i); } CFeeRate CTxMemPool::estimateFee() const { LOCK(cs); uint64_t maxMempoolSize = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; // minerPolicy uses recent blocks to figure out a reasonable fee. This // may disagree with the rollingMinimumFeerate under certain scenarios // where the mempool increases rapidly, or blocks are being mined which // do not contain propagated transactions. return std::max(GetConfig().GetMinFeePerKB(), GetMinFee(maxMempoolSize)); } void CTxMemPool::PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const Amount nFeeDelta) { { LOCK(cs); TXModifier &deltas = mapDeltas[hash]; deltas.first += dPriorityDelta; deltas.second += nFeeDelta; txiter it = mapTx.find(hash); if (it != mapTx.end()) { mapTx.modify(it, update_fee_delta(deltas.second)); // Now update all ancestors' modified fees with descendants setEntries setAncestors; uint64_t nNoLimit = std::numeric_limits::max(); std::string dummy; CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); for (txiter ancestorIt : setAncestors) { mapTx.modify(ancestorIt, update_descendant_state(0, 0, nFeeDelta, 0)); } // Now update all descendants' modified fees with ancestors setEntries setDescendants; CalculateDescendants(it, setDescendants); setDescendants.erase(it); for (txiter descendantIt : setDescendants) { mapTx.modify(descendantIt, update_ancestor_state(0, 0, nFeeDelta, 0, 0)); } } } LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta)); } void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, Amount &nFeeDelta) const { LOCK(cs); std::map::const_iterator pos = mapDeltas.find(hash); if (pos == mapDeltas.end()) { return; } const TXModifier &deltas = pos->second; dPriorityDelta += deltas.first; nFeeDelta += deltas.second; } void CTxMemPool::ClearPrioritisation(const uint256 hash) { LOCK(cs); mapDeltas.erase(hash); } bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const { for (const CTxIn &in : tx.vin) { if (exists(in.prevout.GetTxId())) { return false; } } return true; } CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, const CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) {} bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const { // If an entry in the mempool exists, always return that one, as it's // guaranteed to never conflict with the underlying cache, and it cannot // have pruned entries (as it contains full) transactions. First checking // the underlying cache risks returning a pruned entry instead. CTransactionRef ptx = mempool.get(outpoint.GetTxId()); if (ptx) { if (outpoint.GetN() < ptx->vout.size()) { coin = Coin(ptx->vout[outpoint.GetN()], MEMPOOL_HEIGHT, false); return true; } return false; } return base->GetCoin(outpoint, coin) && !coin.IsSpent(); } bool CCoinsViewMemPool::HaveCoin(const COutPoint &outpoint) const { return mempool.exists(outpoint) || base->HaveCoin(outpoint); } size_t CTxMemPool::DynamicMemoryUsage() const { LOCK(cs); // Estimate the overhead of mapTx to be 15 pointers + an allocation, as no // exact formula for boost::multi_index_contained is implemented. return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void *)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage; } void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) { AssertLockHeld(cs); UpdateForRemoveFromMempool(stage, updateDescendants); for (const txiter &it : stage) { removeUnchecked(it, reason); } } int CTxMemPool::Expire(int64_t time) { LOCK(cs); indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); setEntries toremove; while (it != mapTx.get().end() && it->GetTime() < time) { toremove.insert(mapTx.project<0>(it)); it++; } setEntries stage; for (txiter removeit : toremove) { CalculateDescendants(removeit, stage); } RemoveStaged(stage, false, MemPoolRemovalReason::EXPIRY); return stage.size(); } void CTxMemPool::LimitSize(size_t limit, unsigned long age) { int expired = Expire(GetTime() - age); if (expired != 0) { LogPrint(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired); } std::vector vNoSpendsRemaining; TrimToSize(limit, &vNoSpendsRemaining); for (const COutPoint &removed : vNoSpendsRemaining) { pcoinsTip->Uncache(removed); } } bool CTxMemPool::addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry) { LOCK(cs); setEntries setAncestors; uint64_t nNoLimit = std::numeric_limits::max(); std::string dummy; CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); return addUnchecked(hash, entry, setAncestors); } void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add) { setEntries s; if (add && mapLinks[entry].children.insert(child).second) { cachedInnerUsage += memusage::IncrementalDynamicUsage(s); } else if (!add && mapLinks[entry].children.erase(child)) { cachedInnerUsage -= memusage::IncrementalDynamicUsage(s); } } void CTxMemPool::UpdateParent(txiter entry, txiter parent, bool add) { setEntries s; if (add && mapLinks[entry].parents.insert(parent).second) { cachedInnerUsage += memusage::IncrementalDynamicUsage(s); } else if (!add && mapLinks[entry].parents.erase(parent)) { cachedInnerUsage -= memusage::IncrementalDynamicUsage(s); } } const CTxMemPool::setEntries & CTxMemPool::GetMemPoolParents(txiter entry) const { assert(entry != mapTx.end()); txlinksMap::const_iterator it = mapLinks.find(entry); assert(it != mapLinks.end()); return it->second.parents; } const CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) const { assert(entry != mapTx.end()); txlinksMap::const_iterator it = mapLinks.find(entry); assert(it != mapLinks.end()); return it->second.children; } CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const { LOCK(cs); if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0) { return CFeeRate(int64_t(ceill(rollingMinimumFeeRate)) * SATOSHI); } int64_t time = GetTime(); if (time > lastRollingFeeUpdate + 10) { double halflife = ROLLING_FEE_HALFLIFE; if (DynamicMemoryUsage() < sizelimit / 4) { halflife /= 4; } else if (DynamicMemoryUsage() < sizelimit / 2) { halflife /= 2; } rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife); lastRollingFeeUpdate = time; } return CFeeRate(int64_t(ceill(rollingMinimumFeeRate)) * SATOSHI); } void CTxMemPool::trackPackageRemoved(const CFeeRate &rate) { AssertLockHeld(cs); if ((rate.GetFeePerK() / SATOSHI) > rollingMinimumFeeRate) { rollingMinimumFeeRate = rate.GetFeePerK() / SATOSHI; blockSinceLastRollingFeeBump = false; } } void CTxMemPool::TrimToSize(size_t sizelimit, std::vector *pvNoSpendsRemaining) { LOCK(cs); unsigned nTxnRemoved = 0; CFeeRate maxFeeRateRemoved(Amount::zero()); while (!mapTx.empty() && DynamicMemoryUsage() > sizelimit) { indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); // We set the new mempool min fee to the feerate of the removed set, // plus the "minimum reasonable fee rate" (ie some value under which we // consider txn to have 0 fee). This way, we don't allow txn to enter // mempool with feerate equal to txn which were removed with no block in // between. CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants()); removed += MEMPOOL_FULL_FEE_INCREMENT; trackPackageRemoved(removed); maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed); setEntries stage; CalculateDescendants(mapTx.project<0>(it), stage); nTxnRemoved += stage.size(); std::vector txn; if (pvNoSpendsRemaining) { txn.reserve(stage.size()); for (txiter iter : stage) { txn.push_back(iter->GetTx()); } } RemoveStaged(stage, false, MemPoolRemovalReason::SIZELIMIT); if (pvNoSpendsRemaining) { for (const CTransaction &tx : txn) { for (const CTxIn &txin : tx.vin) { if (exists(txin.prevout.GetTxId())) { continue; } if (!mapNextTx.count(txin.prevout)) { pvNoSpendsRemaining->push_back(txin.prevout); } } } } } if (maxFeeRateRemoved > CFeeRate(Amount::zero())) { LogPrint(BCLog::MEMPOOL, "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString()); } } bool CTxMemPool::TransactionWithinChainLimit(const uint256 &txid, size_t chainLimit) const { LOCK(cs); auto it = mapTx.find(txid); return it == mapTx.end() || (it->GetCountWithAncestors() < chainLimit && it->GetCountWithDescendants() < chainLimit); } SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits::max())), k1(GetRand(std::numeric_limits::max())) {} /** Maximum bytes for transactions to store for processing during reorg */ static const size_t MAX_DISCONNECTED_TX_POOL_SIZE = 20 * DEFAULT_MAX_BLOCK_SIZE; void DisconnectedBlockTransactions::addForBlock( const std::vector &vtx) { for (const auto &tx : reverse_iterate(vtx)) { // If we already added it, just skip. auto it = queuedTx.find(tx->GetId()); if (it != queuedTx.end()) { continue; } // Insert the transaction into the pool. addTransaction(tx); // Fill in the set of parents. std::unordered_set parents; for (const CTxIn &in : tx->vin) { parents.insert(in.prevout.GetTxId()); } // In order to make sure we keep things in topological order, we check // if we already know of the parent of the current transaction. If so, // we remove them from the set and then add them back. while (parents.size() > 0) { std::unordered_set worklist( std::move(parents)); parents.clear(); for (const TxId &txid : worklist) { // If we do not have that txid in the set, nothing needs to be // done. auto pit = queuedTx.find(txid); if (pit == queuedTx.end()) { continue; } // We have parent in our set, we reinsert them at the right // position. const CTransactionRef ptx = *pit; queuedTx.erase(pit); queuedTx.insert(ptx); // And we make sure ancestors are covered. for (const CTxIn &in : ptx->vin) { parents.insert(in.prevout.GetTxId()); } } } } // Keep the size under control. while (DynamicMemoryUsage() > MAX_DISCONNECTED_TX_POOL_SIZE) { // Drop the earliest entry, and remove its children from the // mempool. auto it = queuedTx.get().begin(); g_mempool.removeRecursive(**it, MemPoolRemovalReason::REORG); removeEntry(it); } } void DisconnectedBlockTransactions::importMempool(CTxMemPool &pool) { // addForBlock's algorithm sorts a vector of transactions back into // topological order. We use it in a separate object to create a valid // ordering of all mempool transactions, which we then splice in front of // the current queuedTx. This results in a valid sequence of transactions to // be reprocessed in updateMempoolForReorg. // We create vtx in order of the entry_time index to facilitate for // addForBlocks (which iterates in reverse order), as vtx probably end in // the correct ordering for queuedTx. std::vector vtx; { LOCK(pool.cs); vtx.reserve(pool.mapTx.size()); for (const CTxMemPoolEntry &e : pool.mapTx.get()) { vtx.push_back(e.GetSharedTx()); } pool.clear(); } // Use addForBlocks to sort the transactions and then splice them in front // of queuedTx DisconnectedBlockTransactions orderedTxnPool; orderedTxnPool.addForBlock(vtx); cachedInnerUsage += orderedTxnPool.cachedInnerUsage; queuedTx.get().splice( queuedTx.get().begin(), orderedTxnPool.queuedTx.get()); // We limit memory usage because we can't know if more blocks will be // disconnected while (DynamicMemoryUsage() > MAX_DISCONNECTED_TX_POOL_SIZE) { // Drop the earliest entry which, by definition, has no children removeEntry(queuedTx.get().begin()); } } void DisconnectedBlockTransactions::updateMempoolForReorg(const Config &config, bool fAddToMempool) { AssertLockHeld(cs_main); std::vector txidsUpdate; // disconnectpool's insertion_order index sorts the entries from oldest to // newest, but the oldest entry will be the last tx from the latest mined // block that was disconnected. // Iterate disconnectpool in reverse, so that we add transactions back to // the mempool starting with the earliest transaction that had been // previously seen in a block. for (const CTransactionRef &tx : reverse_iterate(queuedTx.get())) { // ignore validation errors in resurrected transactions CValidationState stateDummy; if (!fAddToMempool || tx->IsCoinBase() || !AcceptToMemoryPool(config, g_mempool, stateDummy, tx, false, nullptr, true)) { // If the transaction doesn't make it in to the mempool, remove any // transactions that depend on it (which would now be orphans). g_mempool.removeRecursive(*tx, MemPoolRemovalReason::REORG); } else if (g_mempool.exists(tx->GetId())) { txidsUpdate.push_back(tx->GetId()); } } queuedTx.clear(); // AcceptToMemoryPool/addUnchecked all assume that new mempool entries have // no in-mempool children, which is generally not true when adding // previously-confirmed transactions back to the mempool. // UpdateTransactionsFromBlock finds descendants of any transactions in the // disconnectpool that were added back and cleans up the mempool state. g_mempool.UpdateTransactionsFromBlock(txidsUpdate); // We also need to remove any now-immature transactions g_mempool.removeForReorg(config, pcoinsTip.get(), chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); // Re-limit mempool size, in case we added any transactions g_mempool.LimitSize( gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); } diff --git a/src/txmempool.h b/src/txmempool.h index da8d54d027..6c1e44634b 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -1,945 +1,944 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 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_TXMEMPOOL_H #define BITCOIN_TXMEMPOOL_H -#include "amount.h" -#include "coins.h" -#include "indirectmap.h" -#include "primitives/transaction.h" -#include "random.h" -#include "sync.h" +#include +#include +#include +#include +#include +#include #include #include #include #include - #include #include #include #include #include #include #include class CAutoFile; class CBlockIndex; class Config; inline double AllowFreeThreshold() { return (144 * COIN) / (250 * SATOSHI); } inline bool AllowFree(double dPriority) { // Large (in bytes) low-priority (new, small-coin) transactions need a fee. return dPriority > AllowFreeThreshold(); } /** * Fake height value used in Coins to signify they are only in the memory * pool(since 0.8) */ static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF; struct LockPoints { // Will be set to the blockchain height and median time past values that // would be necessary to satisfy all relative locktime constraints (BIP68) // of this tx given our view of block chain history int height; int64_t time; // As long as the current chain descends from the highest height block // containing one of the inputs used in the calculation, then the cached // values are still valid even after a reorg. CBlockIndex *maxInputBlock; LockPoints() : height(0), time(0), maxInputBlock(nullptr) {} }; class CTxMemPool; /** \class CTxMemPoolEntry * * CTxMemPoolEntry stores data about the corresponding transaction, as well as * data about all in-mempool transactions that depend on the transaction * ("descendant" transactions). * * When a new entry is added to the mempool, we update the descendant state * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) * for all ancestors of the newly added transaction. * * If updating the descendant state is skipped, we can mark the entry as * "dirty", and set nSizeWithDescendants/nModFeesWithDescendants to equal * nTxSize/nFee+feeDelta. (This can potentially happen during a reorg, where we * limit the amount of work we're willing to do to avoid consuming too much * CPU.) */ class CTxMemPoolEntry { private: CTransactionRef tx; //!< Cached to avoid expensive parent-transaction lookups Amount nFee; //!< ... and avoid recomputing tx size size_t nTxSize; //!< ... and billable size for billing size_t nTxBillableSize; //!< ... and modified size for priority size_t nModSize; //!< ... and total memory usage size_t nUsageSize; //!< Local time when entering the mempool int64_t nTime; //!< Priority when entering the mempool double entryPriority; //!< Chain height when entering the mempool unsigned int entryHeight; //!< Sum of all txin values that are already in blockchain Amount inChainInputValue; //!< keep track of transactions that spend a coinbase bool spendsCoinbase; //!< Total sigop plus P2SH sigops count int64_t sigOpCount; //!< Used for determining the priority of the transaction for mining in a //! block Amount feeDelta; //!< Track the height and time at which tx was final LockPoints lockPoints; // Information about descendants of this transaction that are in the // mempool; if we remove this transaction we must remove all of these // descendants as well. if nCountWithDescendants is 0, treat this entry as // dirty, and nSizeWithDescendants and nModFeesWithDescendants will not be // correct. //!< number of descendant transactions uint64_t nCountWithDescendants; //!< ... and size uint64_t nSizeWithDescendants; uint64_t nBillableSizeWithDescendants; //!< ... and total fees (all including us) Amount nModFeesWithDescendants; // Analogous statistics for ancestor transactions uint64_t nCountWithAncestors; uint64_t nSizeWithAncestors; uint64_t nBillableSizeWithAncestors; Amount nModFeesWithAncestors; int64_t nSigOpCountWithAncestors; public: CTxMemPoolEntry(const CTransactionRef &_tx, const Amount _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, Amount _inChainInputValue, bool spendsCoinbase, int64_t nSigOpsCost, LockPoints lp); const CTransaction &GetTx() const { return *this->tx; } CTransactionRef GetSharedTx() const { return this->tx; } /** * Fast calculation of lower bound of current priority as update from entry * priority. Only inputs that were originally in-chain will age. */ double GetPriority(unsigned int currentHeight) const; const Amount GetFee() const { return nFee; } size_t GetTxSize() const { return nTxSize; } size_t GetTxBillableSize() const { return nTxBillableSize; } int64_t GetTime() const { return nTime; } unsigned int GetHeight() const { return entryHeight; } int64_t GetSigOpCount() const { return sigOpCount; } Amount GetModifiedFee() const { return nFee + feeDelta; } size_t DynamicMemoryUsage() const { return nUsageSize; } const LockPoints &GetLockPoints() const { return lockPoints; } // Adjusts the descendant state, if this entry is not dirty. void UpdateDescendantState(int64_t modifySize, int64_t modifyBillableSize, Amount modifyFee, int64_t modifyCount); // Adjusts the ancestor state void UpdateAncestorState(int64_t modifySize, int64_t modifyBillableSize, Amount modifyFee, int64_t modifyCount, int modifySigOps); // Updates the fee delta used for mining priority score, and the // modified fees with descendants. void UpdateFeeDelta(Amount feeDelta); // Update the LockPoints after a reorg void UpdateLockPoints(const LockPoints &lp); uint64_t GetCountWithDescendants() const { return nCountWithDescendants; } uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; } uint64_t GetBillableSizeWithDescendants() const { return nBillableSizeWithDescendants; } Amount GetModFeesWithDescendants() const { return nModFeesWithDescendants; } bool GetSpendsCoinbase() const { return spendsCoinbase; } uint64_t GetCountWithAncestors() const { return nCountWithAncestors; } uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; } uint64_t GetBillableSizeWithAncestors() const { return nBillableSizeWithAncestors; } Amount GetModFeesWithAncestors() const { return nModFeesWithAncestors; } int64_t GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; } //!< Index in mempool's vTxHashes mutable size_t vTxHashesIdx; }; // Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index. struct update_descendant_state { update_descendant_state(int64_t _modifySize, int64_t _modifyBillableSize, Amount _modifyFee, int64_t _modifyCount) : modifySize(_modifySize), modifyBillableSize(_modifyBillableSize), modifyFee(_modifyFee), modifyCount(_modifyCount) {} void operator()(CTxMemPoolEntry &e) { e.UpdateDescendantState(modifySize, modifyBillableSize, modifyFee, modifyCount); } private: int64_t modifySize; int64_t modifyBillableSize; Amount modifyFee; int64_t modifyCount; }; struct update_ancestor_state { update_ancestor_state(int64_t _modifySize, int64_t _modifyBillableSize, Amount _modifyFee, int64_t _modifyCount, int64_t _modifySigOpsCost) : modifySize(_modifySize), modifyBillableSize(_modifyBillableSize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOpsCost(_modifySigOpsCost) {} void operator()(CTxMemPoolEntry &e) { e.UpdateAncestorState(modifySize, modifyBillableSize, modifyFee, modifyCount, modifySigOpsCost); } private: int64_t modifySize; int64_t modifyBillableSize; Amount modifyFee; int64_t modifyCount; int64_t modifySigOpsCost; }; struct update_fee_delta { explicit update_fee_delta(Amount _feeDelta) : feeDelta(_feeDelta) {} void operator()(CTxMemPoolEntry &e) { e.UpdateFeeDelta(feeDelta); } private: Amount feeDelta; }; struct update_lock_points { explicit update_lock_points(const LockPoints &_lp) : lp(_lp) {} void operator()(CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); } private: const LockPoints &lp; }; // extracts a transaction hash from CTxMempoolEntry or CTransactionRef struct mempoolentry_txid { typedef uint256 result_type; result_type operator()(const CTxMemPoolEntry &entry) const { return entry.GetTx().GetId(); } result_type operator()(const CTransactionRef &tx) const { return tx->GetId(); } }; /** \class CompareTxMemPoolEntryByDescendantScore * * Sort an entry by max(score/size of entry's tx, score/size with all * descendants). */ class CompareTxMemPoolEntryByDescendantScore { public: bool operator()(const CTxMemPoolEntry &a, const CTxMemPoolEntry &b) const { bool fUseADescendants = UseDescendantScore(a); bool fUseBDescendants = UseDescendantScore(b); double aModFee = (fUseADescendants ? a.GetModFeesWithDescendants() : a.GetModifiedFee()) / SATOSHI; double aSize = fUseADescendants ? a.GetSizeWithDescendants() : a.GetTxSize(); double bModFee = (fUseBDescendants ? b.GetModFeesWithDescendants() : b.GetModifiedFee()) / SATOSHI; double bSize = fUseBDescendants ? b.GetSizeWithDescendants() : b.GetTxSize(); // Avoid division by rewriting (a/b > c/d) as (a*d > c*b). double f1 = aModFee * bSize; double f2 = aSize * bModFee; if (f1 == f2) { return a.GetTime() >= b.GetTime(); } return f1 < f2; } // Calculate which score to use for an entry (avoiding division). bool UseDescendantScore(const CTxMemPoolEntry &a) const { double f1 = a.GetSizeWithDescendants() * (a.GetModifiedFee() / SATOSHI); double f2 = a.GetTxSize() * (a.GetModFeesWithDescendants() / SATOSHI); return f2 > f1; } }; /** \class CompareTxMemPoolEntryByScore * * Sort by score of entry ((fee+delta)/size) in descending order */ class CompareTxMemPoolEntryByScore { public: bool operator()(const CTxMemPoolEntry &a, const CTxMemPoolEntry &b) const { double f1 = b.GetTxSize() * (a.GetModifiedFee() / SATOSHI); double f2 = a.GetTxSize() * (b.GetModifiedFee() / SATOSHI); if (f1 == f2) { return b.GetTx().GetId() < a.GetTx().GetId(); } return f1 > f2; } }; class CompareTxMemPoolEntryByEntryTime { public: bool operator()(const CTxMemPoolEntry &a, const CTxMemPoolEntry &b) const { return a.GetTime() < b.GetTime(); } }; class CompareTxMemPoolEntryByAncestorFee { public: bool operator()(const CTxMemPoolEntry &a, const CTxMemPoolEntry &b) const { double aFees = a.GetModFeesWithAncestors() / SATOSHI; double aSize = a.GetSizeWithAncestors(); double bFees = b.GetModFeesWithAncestors() / SATOSHI; double bSize = b.GetSizeWithAncestors(); // Avoid division by rewriting (a/b > c/d) as (a*d > c*b). double f1 = aFees * bSize; double f2 = aSize * bFees; if (f1 == f2) { return a.GetTx().GetId() < b.GetTx().GetId(); } return f1 > f2; } }; // Multi_index tag names struct descendant_score {}; struct entry_time {}; struct mining_score {}; struct ancestor_score {}; /** * Information about a mempool transaction. */ struct TxMempoolInfo { /** The transaction itself */ CTransactionRef tx; /** Time the transaction entered the mempool. */ int64_t nTime; /** Feerate of the transaction. */ CFeeRate feeRate; /** The fee delta. */ Amount nFeeDelta; }; /** * Reason why a transaction was removed from the mempool, this is passed to the * notification signal. */ enum class MemPoolRemovalReason { //! Manually removed or unknown reason UNKNOWN = 0, //! Expired from mempool EXPIRY, //! Removed in size limiting SIZELIMIT, //! Removed for reorganization REORG, //! Removed for block BLOCK, //! Removed for conflict with in-block transaction CONFLICT, //! Removed for replacement REPLACED }; class SaltedTxidHasher { private: /** Salt */ const uint64_t k0, k1; public: SaltedTxidHasher(); size_t operator()(const uint256 &txid) const { return SipHashUint256(k0, k1, txid); } }; typedef std::pair TXModifier; /** * CTxMemPool stores valid-according-to-the-current-best-chain transactions that * may be included in the next block. * * Transactions are added when they are seen on the network (or created by the * local node), but not all transactions seen are added to the pool. For * example, the following new transactions will not be added to the mempool: * - a transaction which doesn't meet the minimum fee requirements. * - a new transaction that double-spends an input of a transaction already in * the pool where the new transaction does not meet the Replace-By-Fee * requirements as defined in BIP 125. * - a non-standard transaction. * * CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping: * * mapTx is a boost::multi_index that sorts the mempool on 4 criteria: * - transaction hash * - feerate [we use max(feerate of tx, feerate of tx with all descendants)] * - time in mempool * - mining score (feerate modified by any fee deltas from * PrioritiseTransaction) * * Note: the term "descendant" refers to in-mempool transactions that depend on * this one, while "ancestor" refers to in-mempool transactions that a given * transaction depends on. * * In order for the feerate sort to remain correct, we must update transactions * in the mempool when new descendants arrive. To facilitate this, we track the * set of in-mempool direct parents and direct children in mapLinks. Within each * CTxMemPoolEntry, we track the size and fees of all descendants. * * Usually when a new transaction is added to the mempool, it has no in-mempool * children (because any such children would be an orphan). So in * addUnchecked(), we: * - update a new entry's setMemPoolParents to include all in-mempool parents * - update the new entry's direct parents to include the new tx as a child * - update all ancestors of the transaction to include the new tx's size/fee * * When a transaction is removed from the mempool, we must: * - update all in-mempool parents to not track the tx in setMemPoolChildren * - update all ancestors to not include the tx's size/fees in descendant state * - update all in-mempool children to not include it as a parent * * These happen in UpdateForRemoveFromMempool(). (Note that when removing a * transaction along with its descendants, we must calculate that set of * transactions to be removed before doing the removal, or else the mempool can * be in an inconsistent state where it's impossible to walk the ancestors of a * transaction.) * * In the event of a reorg, the assumption that a newly added tx has no * in-mempool children is false. In particular, the mempool is in an * inconsistent state while new transactions are being added, because there may * be descendant transactions of a tx coming from a disconnected block that are * unreachable from just looking at transactions in the mempool (the linking * transactions may also be in the disconnected block, waiting to be added). * Because of this, there's not much benefit in trying to search for in-mempool * children in addUnchecked(). Instead, in the special case of transactions * being added from a disconnected block, we require the caller to clean up the * state, to account for in-mempool, out-of-block descendants for all the * in-block transactions by calling UpdateTransactionsFromBlock(). Note that * until this is called, the mempool state is not consistent, and in particular * mapLinks may not be correct (and therefore functions like * CalculateMemPoolAncestors() and CalculateDescendants() that rely on them to * walk the mempool are not generally safe to use). * * Computational limits: * * Updating all in-mempool ancestors of a newly added transaction can be slow, * if no bound exists on how many in-mempool ancestors there may be. * CalculateMemPoolAncestors() takes configurable limits that are designed to * prevent these calculations from being too CPU intensive. * * Adding transactions from a disconnected block can be very time consuming, * because we don't have a way to limit the number of in-mempool descendants. To * bound CPU processing, we limit the amount of work we're willing to do to * properly update the descendant information for a tx being added from a * disconnected block. If we would exceed the limit, then we instead mark the * entry as "dirty", and set the feerate for sorting purposes to be equal the * feerate of the transaction without any descendants. */ class CTxMemPool { private: //!< Value n means that n times in 2^32 we check. uint32_t nCheckFrequency; unsigned int nTransactionsUpdated; //!< sum of all mempool tx's virtual sizes. uint64_t totalTxSize; //!< sum of dynamic memory usage of all the map elements (NOT the maps //! themselves) uint64_t cachedInnerUsage; mutable int64_t lastRollingFeeUpdate; mutable bool blockSinceLastRollingFeeBump; //!< minimum fee to get into the pool, decreases exponentially mutable double rollingMinimumFeeRate; void trackPackageRemoved(const CFeeRate &rate); public: // public only for testing static const int ROLLING_FEE_HALFLIFE = 60 * 60 * 12; typedef boost::multi_index_container< CTxMemPoolEntry, boost::multi_index::indexed_by< // sorted by txid boost::multi_index::hashed_unique< mempoolentry_txid, SaltedTxidHasher>, // sorted by fee rate boost::multi_index::ordered_non_unique< boost::multi_index::tag, boost::multi_index::identity, CompareTxMemPoolEntryByDescendantScore>, // sorted by entry time boost::multi_index::ordered_non_unique< boost::multi_index::tag, boost::multi_index::identity, CompareTxMemPoolEntryByEntryTime>, // sorted by score (for mining prioritization) boost::multi_index::ordered_unique< boost::multi_index::tag, boost::multi_index::identity, CompareTxMemPoolEntryByScore>, // sorted by fee rate with ancestors boost::multi_index::ordered_non_unique< boost::multi_index::tag, boost::multi_index::identity, CompareTxMemPoolEntryByAncestorFee>>> indexed_transaction_set; mutable CCriticalSection cs; indexed_transaction_set mapTx; typedef indexed_transaction_set::nth_index<0>::type::iterator txiter; //!< All tx hashes/entries in mapTx, in random order std::vector> vTxHashes; struct CompareIteratorByHash { bool operator()(const txiter &a, const txiter &b) const { return a->GetTx().GetId() < b->GetTx().GetId(); } }; typedef std::set setEntries; const setEntries &GetMemPoolParents(txiter entry) const; const setEntries &GetMemPoolChildren(txiter entry) const; private: typedef std::map cacheMap; struct TxLinks { setEntries parents; setEntries children; }; typedef std::map txlinksMap; txlinksMap mapLinks; void UpdateParent(txiter entry, txiter parent, bool add); void UpdateChild(txiter entry, txiter child, bool add); std::vector GetSortedDepthAndScore() const; public: indirectmap mapNextTx; std::map mapDeltas; /** Create a new CTxMemPool. */ CTxMemPool(); ~CTxMemPool(); /** * If sanity-checking is turned on, check makes sure the pool is consistent * (does not contain two transactions that spend the same inputs, all inputs * are in the mapNextTx array). If sanity-checking is turned off, check does * nothing. */ void check(const CCoinsViewCache *pcoins) const; void setSanityCheck(double dFrequency = 1.0) { nCheckFrequency = dFrequency * 4294967295.0; } // addUnchecked must updated state for all ancestors of a given transaction, // to track size/count of descendant transactions. First version of // addUnchecked can be used to have it call CalculateMemPoolAncestors(), and // then invoke the second version. // Note that addUnchecked is ONLY called from ATMP outside of tests // and any other callers may break wallet's in-mempool tracking (due to // lack of CValidationInterface::TransactionAddedToMempool callbacks). bool addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry); bool addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry, setEntries &setAncestors); void removeRecursive( const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN); void removeForReorg(const Config &config, const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags); void removeConflicts(const CTransaction &tx); void removeForBlock(const std::vector &vtx, unsigned int nBlockHeight); void clear(); // lock free void _clear(); bool CompareDepthAndScore(const uint256 &hasha, const uint256 &hashb); void queryHashes(std::vector &vtxid); bool isSpent(const COutPoint &outpoint); unsigned int GetTransactionsUpdated() const; void AddTransactionsUpdated(unsigned int n); /** * Check that none of this transactions inputs are in the mempool, and thus * the tx is not dependent on other mempool transactions to be included in a * block. */ bool HasNoInputsOf(const CTransaction &tx) const; /** Affect CreateNewBlock prioritisation of transactions */ void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const Amount nFeeDelta); void ApplyDeltas(const uint256 hash, double &dPriorityDelta, Amount &nFeeDelta) const; void ClearPrioritisation(const uint256 hash); public: /** * Remove a set of transactions from the mempool. If a transaction is in * this set, then all in-mempool descendants must also be in the set, unless * this transaction is being removed for being in a block. Set * updateDescendants to true when removing a tx that was in a block, so that * any in-mempool descendants have their ancestor state updated. */ void RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN); /** * When adding transactions from a disconnected block back to the mempool, * new mempool entries may have children in the mempool (which is generally * not the case when otherwise adding transactions). * UpdateTransactionsFromBlock() will find child transactions and update the * descendant state for each transaction in txidsToUpdate (excluding any * child transactions present in txidsToUpdate, which are already accounted * for). * Note: txidsToUpdate should be the set of transactions from the * disconnected block that have been accepted back into the mempool. */ void UpdateTransactionsFromBlock(const std::vector &txidsToUpdate); /** * Try to calculate all in-mempool ancestors of entry. * (these are all calculated including the tx itself) * limitAncestorCount = max number of ancestors * limitAncestorSize = max size of ancestors * limitDescendantCount = max number of descendants any ancestor can have * limitDescendantSize = max size of descendants any ancestor can have * errString = populated with error reason if any limits are hit * fSearchForParents = whether to search a tx's vin for in-mempool parents, * or look up parents from mapLinks. Must be true for entries not in the * mempool */ bool CalculateMemPoolAncestors( const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString, bool fSearchForParents = true) const; /** * Populate setDescendants with all in-mempool descendants of hash. * Assumes that setDescendants includes all in-mempool descendants of * anything already in it. */ void CalculateDescendants(txiter it, setEntries &setDescendants) const; /** * The minimum fee to get into the mempool, which may itself not be enough * for larger-sized transactions. The incrementalRelayFee policy variable is * used to bound the time it takes the fee rate to go back down all the way * to 0. When the feerate would otherwise be half of this, it is set to 0 * instead. */ CFeeRate GetMinFee(size_t sizelimit) const; /** * Remove transactions from the mempool until its dynamic size is <= * sizelimit. pvNoSpendsRemaining, if set, will be populated with the list * of outpoints which are not in mempool which no longer have any spends in * this mempool. */ void TrimToSize(size_t sizelimit, std::vector *pvNoSpendsRemaining = nullptr); /** * Expire all transaction (and their dependencies) in the mempool older than * time. Return the number of removed transactions. */ int Expire(int64_t time); /** * Reduce the size of the mempool by expiring and then trimming the mempool. */ void LimitSize(size_t limit, unsigned long age); /** * Returns false if the transaction is in the mempool and not within the * chain limit specified. */ bool TransactionWithinChainLimit(const uint256 &txid, size_t chainLimit) const; unsigned long size() { LOCK(cs); return mapTx.size(); } uint64_t GetTotalTxSize() const { LOCK(cs); return totalTxSize; } bool exists(uint256 hash) const { LOCK(cs); return mapTx.count(hash) != 0; } bool exists(const COutPoint &outpoint) const { LOCK(cs); auto it = mapTx.find(outpoint.GetTxId()); return it != mapTx.end() && outpoint.GetN() < it->GetTx().vout.size(); } CTransactionRef get(const uint256 &hash) const; TxMempoolInfo info(const uint256 &hash) const; std::vector infoAll() const; CFeeRate estimateFee() const; size_t DynamicMemoryUsage() const; boost::signals2::signal NotifyEntryAdded; boost::signals2::signal NotifyEntryRemoved; private: /** * UpdateForDescendants is used by UpdateTransactionsFromBlock to update the * descendants for a single transaction that has been added to the mempool * but may have child transactions in the mempool, eg during a chain reorg. * setExclude is the set of descendant transactions in the mempool that must * not be accounted for (because any descendants in setExclude were added to * the mempool after the transaction being updated and hence their state is * already reflected in the parent state). * * cachedDescendants will be updated with the descendants of the transaction * being updated, so that future invocations don't need to walk the same * transaction again, if encountered in another transaction chain. */ void UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set &setExclude); /** * Update ancestors of hash to add/remove it as a descendant transaction. */ void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors); /** Set ancestor state for an entry */ void UpdateEntryForAncestors(txiter it, const setEntries &setAncestors); /** * For each transaction being removed, update ancestors and any direct * children. If updateDescendants is true, then also update in-mempool * descendants' ancestor state. */ void UpdateForRemoveFromMempool(const setEntries &entriesToRemove, bool updateDescendants); /** Sever link between specified transaction and direct children. */ void UpdateChildrenForRemoval(txiter entry); /** * Before calling removeUnchecked for a given transaction, * UpdateForRemoveFromMempool must be called on the entire (dependent) set * of transactions being removed at the same time. We use each * CTxMemPoolEntry's setMemPoolParents in order to walk ancestors of a given * transaction that is removed, so we can't remove intermediate transactions * in a chain before we've updated all the state for the removal. */ void removeUnchecked(txiter entry, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN); }; /** * CCoinsView that brings transactions from a memorypool into view. * It does not check for spendings by memory pool transactions. */ class CCoinsViewMemPool : public CCoinsViewBacked { protected: const CTxMemPool &mempool; public: CCoinsViewMemPool(CCoinsView *baseIn, const CTxMemPool &mempoolIn); bool GetCoin(const COutPoint &outpoint, Coin &coin) const override; bool HaveCoin(const COutPoint &outpoint) const override; }; // We want to sort transactions by coin age priority typedef std::pair TxCoinAgePriority; struct TxCoinAgePriorityCompare { bool operator()(const TxCoinAgePriority &a, const TxCoinAgePriority &b) { if (a.first == b.first) { // Reverse order to make sort less than return CompareTxMemPoolEntryByScore()(*(b.second), *(a.second)); } return a.first < b.first; } }; /** * DisconnectedBlockTransactions * * During the reorg, it's desirable to re-add previously confirmed transactions * to the mempool, so that anything not re-confirmed in the new chain is * available to be mined. However, it's more efficient to wait until the reorg * is complete and process all still-unconfirmed transactions at that time, * since we expect most confirmed transactions to (typically) still be * confirmed in the new chain, and re-accepting to the memory pool is expensive * (and therefore better to not do in the middle of reorg-processing). * Instead, store the disconnected transactions (in order!) as we go, remove any * that are included in blocks in the new chain, and then process the remaining * still-unconfirmed transactions at the end. * * It also enables efficient reprocessing of current mempool entries, useful * when (de)activating forks that result in in-mempool transactions becoming * invalid */ // multi_index tag names struct txid_index {}; struct insertion_order {}; class DisconnectedBlockTransactions { private: typedef boost::multi_index_container< CTransactionRef, boost::multi_index::indexed_by< // sorted by txid boost::multi_index::hashed_unique< boost::multi_index::tag, mempoolentry_txid, SaltedTxidHasher>, // sorted by order in the blockchain boost::multi_index::sequenced< boost::multi_index::tag>>> indexed_disconnected_transactions; indexed_disconnected_transactions queuedTx; uint64_t cachedInnerUsage = 0; void addTransaction(const CTransactionRef &tx) { queuedTx.insert(tx); cachedInnerUsage += RecursiveDynamicUsage(tx); } public: // It's almost certainly a logic bug if we don't clear out queuedTx before // destruction, as we add to it while disconnecting blocks, and then we // need to re-process remaining transactions to ensure mempool consistency. // For now, assert() that we've emptied out this object on destruction. // This assert() can always be removed if the reorg-processing code were // to be refactored such that this assumption is no longer true (for // instance if there was some other way we cleaned up the mempool after a // reorg, besides draining this object). ~DisconnectedBlockTransactions() { assert(queuedTx.empty()); } // Estimate the overhead of queuedTx to be 6 pointers + an allocation, as // no exact formula for boost::multi_index_contained is implemented. size_t DynamicMemoryUsage() const { return memusage::MallocUsage(sizeof(CTransactionRef) + 6 * sizeof(void *)) * queuedTx.size() + cachedInnerUsage; } const indexed_disconnected_transactions &GetQueuedTx() const { return queuedTx; } // Import mempool entries in topological order into queuedTx and clear the // mempool. Caller should call updateMempoolForReorg to reprocess these // transactions void importMempool(CTxMemPool &pool); // Add entries for a block while reconstructing the topological ordering so // they can be added back to the mempool simply. void addForBlock(const std::vector &vtx); // Remove entries based on txid_index, and update memory usage. void removeForBlock(const std::vector &vtx) { // Short-circuit in the common case of a block being added to the tip if (queuedTx.empty()) { return; } for (auto const &tx : vtx) { auto it = queuedTx.find(tx->GetId()); if (it != queuedTx.end()) { cachedInnerUsage -= RecursiveDynamicUsage(*it); queuedTx.erase(it); } } } // Remove an entry by insertion_order index, and update memory usage. void removeEntry(indexed_disconnected_transactions::index< insertion_order>::type::iterator entry) { cachedInnerUsage -= RecursiveDynamicUsage(*entry); queuedTx.get().erase(entry); } bool isEmpty() const { return queuedTx.empty(); } void clear() { cachedInnerUsage = 0; queuedTx.clear(); } /** * Make mempool consistent after a reorg, by re-adding or recursively * erasing disconnected block transactions from the mempool, and also * removing any other transactions from the mempool that are no longer valid * given the new tip/height. * * Note: we assume that disconnectpool only contains transactions that are * NOT confirmed in the current chain nor already in the mempool (otherwise, * in-mempool descendants of such transactions would be removed). * * Passing fAddToMempool=false will skip trying to add the transactions * back, and instead just erase from the mempool as needed. */ void updateMempoolForReorg(const Config &config, bool fAddToMempool); }; #endif // BITCOIN_TXMEMPOOL_H diff --git a/src/ui_interface.cpp b/src/ui_interface.cpp index 5332e64b04..f09f9df14f 100644 --- a/src/ui_interface.cpp +++ b/src/ui_interface.cpp @@ -1,27 +1,28 @@ // Copyright (c) 2010-2016 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 "ui_interface.h" -#include "util.h" +#include + +#include CClientUIInterface uiInterface; bool InitError(const std::string &str) { uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_ERROR); return false; } void InitWarning(const std::string &str) { uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING); } std::string AmountHighWarn(const std::string &optname) { return strprintf(_("%s is set very high!"), optname); } std::string AmountErrMsg(const char *const optname, const std::string &strValue) { return strprintf(_("Invalid amount for -%s=: '%s'"), optname, strValue); } diff --git a/src/uint256.cpp b/src/uint256.cpp index f08a6a7477..42f6df0d2d 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -1,72 +1,72 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 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 "uint256.h" +#include -#include "utilstrencodings.h" +#include #include #include template base_blob::base_blob(const std::vector &vch) { assert(vch.size() == sizeof(data)); memcpy(data, &vch[0], sizeof(data)); } template std::string base_blob::GetHex() const { return HexStr(std::reverse_iterator(data + sizeof(data)), std::reverse_iterator(data)); } template void base_blob::SetHex(const char *psz) { memset(data, 0, sizeof(data)); // skip leading spaces while (IsSpace(*psz)) { psz++; } // skip 0x if (psz[0] == '0' && tolower(psz[1]) == 'x') { psz += 2; } // hex string to uint const char *pbegin = psz; while (::HexDigit(*psz) != -1) { psz++; } psz--; uint8_t *p1 = (uint8_t *)data; uint8_t *pend = p1 + WIDTH; while (psz >= pbegin && p1 < pend) { *p1 = ::HexDigit(*psz--); if (psz >= pbegin) { *p1 |= uint8_t(::HexDigit(*psz--) << 4); p1++; } } } template void base_blob::SetHex(const std::string &str) { SetHex(str.c_str()); } // Explicit instantiations for base_blob<160> template base_blob<160>::base_blob(const std::vector &); template std::string base_blob<160>::GetHex() const; template std::string base_blob<160>::ToString() const; template void base_blob<160>::SetHex(const char *); template void base_blob<160>::SetHex(const std::string &); // Explicit instantiations for base_blob<256> template base_blob<256>::base_blob(const std::vector &); template std::string base_blob<256>::GetHex() const; template std::string base_blob<256>::ToString() const; template void base_blob<256>::SetHex(const char *); template void base_blob<256>::SetHex(const std::string &); diff --git a/src/uint256.h b/src/uint256.h index d5e719c5c8..7e3cff3923 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -1,173 +1,173 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 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_UINT256_H #define BITCOIN_UINT256_H -#include "crypto/common.h" +#include #include #include #include #include #include #include /** Template base class for fixed-sized opaque blobs. */ template class base_blob { protected: static constexpr int WIDTH = BITS / 8; uint8_t data[WIDTH]; public: base_blob() { memset(data, 0, sizeof(data)); } explicit base_blob(const std::vector &vch); bool IsNull() const { for (int i = 0; i < WIDTH; i++) { if (data[i] != 0) { return false; } } return true; } void SetNull() { memset(data, 0, sizeof(data)); } inline int Compare(const base_blob &other) const { for (size_t i = 0; i < sizeof(data); i++) { uint8_t a = data[sizeof(data) - 1 - i]; uint8_t b = other.data[sizeof(data) - 1 - i]; if (a > b) { return 1; } if (a < b) { return -1; } } return 0; } friend inline bool operator==(const base_blob &a, const base_blob &b) { return a.Compare(b) == 0; } friend inline bool operator!=(const base_blob &a, const base_blob &b) { return a.Compare(b) != 0; } friend inline bool operator<(const base_blob &a, const base_blob &b) { return a.Compare(b) < 0; } friend inline bool operator<=(const base_blob &a, const base_blob &b) { return a.Compare(b) <= 0; } friend inline bool operator>(const base_blob &a, const base_blob &b) { return a.Compare(b) > 0; } friend inline bool operator>=(const base_blob &a, const base_blob &b) { return a.Compare(b) >= 0; } std::string GetHex() const; void SetHex(const char *psz); void SetHex(const std::string &str); std::string ToString() const { return GetHex(); } uint8_t *begin() { return &data[0]; } uint8_t *end() { return &data[WIDTH]; } const uint8_t *begin() const { return &data[0]; } const uint8_t *end() const { return &data[WIDTH]; } unsigned int size() const { return sizeof(data); } uint64_t GetUint64(int pos) const { const uint8_t *ptr = data + pos * 8; return uint64_t(ptr[0]) | (uint64_t(ptr[1]) << 8) | (uint64_t(ptr[2]) << 16) | (uint64_t(ptr[3]) << 24) | (uint64_t(ptr[4]) << 32) | (uint64_t(ptr[5]) << 40) | (uint64_t(ptr[6]) << 48) | (uint64_t(ptr[7]) << 56); } template void Serialize(Stream &s) const { s.write((char *)data, sizeof(data)); } template void Unserialize(Stream &s) { s.read((char *)data, sizeof(data)); } }; /** * 160-bit opaque blob. * @note This type is called uint160 for historical reasons only. It is an * opaque blob of 160 bits and has no integer operations. */ class uint160 : public base_blob<160> { public: uint160() {} explicit uint160(const base_blob<160> &b) : base_blob<160>(b) {} explicit uint160(const std::vector &vch) : base_blob<160>(vch) {} }; /** * 256-bit opaque blob. * @note This type is called uint256 for historical reasons only. It is an * opaque blob of 256 bits and has no integer operations. Use arith_uint256 if * those are required. */ class uint256 : public base_blob<256> { public: uint256() {} explicit uint256(const base_blob<256> &b) : base_blob<256>(b) {} explicit uint256(const std::vector &vch) : base_blob<256>(vch) {} /** * A cheap hash function that just returns 64 bits from the result, it can * be used when the contents are considered uniformly random. It is not * appropriate when the value can easily be influenced from outside as e.g. * a network adversary could provide values to trigger worst-case behavior. */ uint64_t GetCheapHash() const { return ReadLE64(data); } }; /** * uint256 from const char *. * This is a separate function because the constructor uint256(const char*) can * result in dangerously catching uint256(0). */ inline uint256 uint256S(const char *str) { uint256 rv; rv.SetHex(str); return rv; } /** * uint256 from std::string. * This is a separate function because the constructor uint256(const std::string * &str) can result in dangerously catching uint256(0) via std::string(const * char*). */ inline uint256 uint256S(const std::string &str) { uint256 rv; rv.SetHex(str); return rv; } inline uint160 uint160S(const char *str) { uint160 rv; rv.SetHex(str); return rv; } inline uint160 uint160S(const std::string &str) { uint160 rv; rv.SetHex(str); return rv; } #endif // BITCOIN_UINT256_H diff --git a/src/undo.h b/src/undo.h index 7df53ae2ad..391df8e870 100644 --- a/src/undo.h +++ b/src/undo.h @@ -1,144 +1,144 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_UNDO_H #define BITCOIN_UNDO_H -#include "coins.h" -#include "compressor.h" -#include "consensus/consensus.h" -#include "serialize.h" +#include +#include +#include +#include class CBlock; class CBlockIndex; class CCoinsViewCache; class CValidationState; /** * Undo information for a CTxIn * * Contains the prevout's CTxOut being spent, and its metadata as well (coinbase * or not, height). The serialization contains a dummy value of zero. This is be * compatible with older versions which expect to see the transaction version * there. */ class TxInUndoSerializer { const Coin *pcoin; public: explicit TxInUndoSerializer(const Coin *pcoinIn) : pcoin(pcoinIn) {} template void Serialize(Stream &s) const { ::Serialize( s, VARINT(pcoin->GetHeight() * 2 + (pcoin->IsCoinBase() ? 1 : 0))); if (pcoin->GetHeight() > 0) { // Required to maintain compatibility with older undo format. ::Serialize(s, uint8_t(0)); } ::Serialize(s, CTxOutCompressor(REF(pcoin->GetTxOut()))); } }; class TxInUndoDeserializer { Coin *pcoin; public: explicit TxInUndoDeserializer(Coin *pcoinIn) : pcoin(pcoinIn) {} template void Unserialize(Stream &s) { uint32_t nCode = 0; ::Unserialize(s, VARINT(nCode)); uint32_t nHeight = nCode / 2; bool fCoinBase = nCode & 1; if (nHeight > 0) { // Old versions stored the version number for the last spend of a // transaction's outputs. Non-final spends were indicated with // height = 0. int nVersionDummy; ::Unserialize(s, VARINT(nVersionDummy)); } CTxOut txout; ::Unserialize(s, REF(CTxOutCompressor(REF(txout)))); *pcoin = Coin(std::move(txout), nHeight, fCoinBase); } }; static const size_t MAX_INPUTS_PER_TX = MAX_TX_SIZE / ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION); /** Restore the UTXO in a Coin at a given COutPoint */ class CTxUndo { public: // Undo information for all txins std::vector vprevout; template void Serialize(Stream &s) const { // TODO: avoid reimplementing vector serializer. uint64_t count = vprevout.size(); ::Serialize(s, COMPACTSIZE(REF(count))); for (const auto &prevout : vprevout) { ::Serialize(s, REF(TxInUndoSerializer(&prevout))); } } template void Unserialize(Stream &s) { // TODO: avoid reimplementing vector deserializer. uint64_t count = 0; ::Unserialize(s, COMPACTSIZE(count)); if (count > MAX_INPUTS_PER_TX) { throw std::ios_base::failure("Too many input undo records"); } vprevout.resize(count); for (auto &prevout : vprevout) { ::Unserialize(s, REF(TxInUndoDeserializer(&prevout))); } } }; /** Undo information for a CBlock */ class CBlockUndo { public: // For all but the coinbase std::vector vtxundo; ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream &s, Operation ser_action) { READWRITE(vtxundo); } }; enum DisconnectResult { // All good. DISCONNECT_OK, // Rolled back, but UTXO set was inconsistent with block. DISCONNECT_UNCLEAN, // Something else went wrong. DISCONNECT_FAILED, }; /** * Restore the UTXO in a Coin at a given COutPoint. * @param undo The Coin to be restored. * @param view The coins view to which to apply the changes. * @param out The out point that corresponds to the tx input. * @return A DisconnectResult */ DisconnectResult UndoCoinSpend(const Coin &undo, CCoinsViewCache &view, const COutPoint &out); /** * Undo a block from the block and the undoblock data. * See DisconnectBlock for more details. */ DisconnectResult ApplyBlockUndo(const CBlockUndo &blockUndo, const CBlock &block, const CBlockIndex *pindex, CCoinsViewCache &coins); #endif // BITCOIN_UNDO_H diff --git a/src/util.cpp b/src/util.cpp index 05031f62bb..e15ebcbad8 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,1038 +1,1038 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" +#include #endif -#include "util.h" +#include -#include "chainparamsbase.h" -#include "fs.h" -#include "random.h" -#include "serialize.h" -#include "utilstrencodings.h" -#include "utiltime.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include #include #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) #include #include #endif #ifndef WIN32 // for posix_fallocate #ifdef __linux__ #ifdef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE #endif #define _POSIX_C_SOURCE 200112L #endif // __linux__ #include #include #include #include #else #ifdef _MSC_VER #pragma warning(disable : 4786) #pragma warning(disable : 4804) #pragma warning(disable : 4805) #pragma warning(disable : 4717) #endif #ifdef _WIN32_WINNT #undef _WIN32_WINNT #endif #define _WIN32_WINNT 0x0501 #ifdef _WIN32_IE #undef _WIN32_IE #endif #define _WIN32_IE 0x0501 #define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX #endif #include /* for _commit */ #include #endif #ifdef HAVE_SYS_PRCTL_H #include #endif #ifdef HAVE_MALLOPT_ARENA_MAX #include #endif -#include -#include -#include - -#include -#include - // Application startup time (used for uptime calculation) const int64_t nStartupTime = GetTime(); const char *const BITCOIN_CONF_FILENAME = "bitcoin.conf"; const char *const BITCOIN_PID_FILENAME = "bitcoind.pid"; ArgsManager gArgs; CTranslationInterface translationInterface; /** Init OpenSSL library multithreading support */ static CCriticalSection **ppmutexOpenSSL; void locking_callback(int mode, int i, const char *file, int line) NO_THREAD_SAFETY_ANALYSIS { if (mode & CRYPTO_LOCK) { ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]); } else { LEAVE_CRITICAL_SECTION(*ppmutexOpenSSL[i]); } } // Init class CInit { public: CInit() { // Init OpenSSL library multithreading support. ppmutexOpenSSL = (CCriticalSection **)OPENSSL_malloc( CRYPTO_num_locks() * sizeof(CCriticalSection *)); for (int i = 0; i < CRYPTO_num_locks(); i++) { ppmutexOpenSSL[i] = new CCriticalSection(); } CRYPTO_set_locking_callback(locking_callback); // OpenSSL can optionally load a config file which lists optional // loadable modules and engines. We don't use them so we don't require // the config. However some of our libs may call functions which attempt // to load the config file, possibly resulting in an exit() or crash if // it is missing or corrupt. Explicitly tell OpenSSL not to try to load // the file. The result for our libs will be that the config appears to // have been loaded and there are no modules/engines available. OPENSSL_no_config(); #ifdef WIN32 // Seed OpenSSL PRNG with current contents of the screen. RAND_screen(); #endif // Seed OpenSSL PRNG with performance counter. RandAddSeed(); } ~CInit() { // Securely erase the memory used by the PRNG. RAND_cleanup(); // Shutdown OpenSSL library multithreading support. CRYPTO_set_locking_callback(nullptr); for (int i = 0; i < CRYPTO_num_locks(); i++) { delete ppmutexOpenSSL[i]; } OPENSSL_free(ppmutexOpenSSL); } } instance_of_cinit; /** * A map that contains all the currently held directory locks. After successful * locking, these will be held here until the global destructor cleans them up * and thus automatically unlocks them, or ReleaseDirectoryLocks is called. */ static std::map> dir_locks; /** Mutex to protect dir_locks. */ static std::mutex cs_dir_locks; bool LockDirectory(const fs::path &directory, const std::string lockfile_name, bool probe_only) { std::lock_guard ulock(cs_dir_locks); fs::path pathLockFile = directory / lockfile_name; // If a lock for this directory already exists in the map, don't try to // re-lock it if (dir_locks.count(pathLockFile.string())) { return true; } // Create empty lock file if it doesn't exist. FILE *file = fsbridge::fopen(pathLockFile, "a"); if (file) { fclose(file); } try { auto lock = std::make_unique( pathLockFile.string().c_str()); if (!lock->try_lock()) { return false; } if (!probe_only) { // Lock successful and we're not just probing, put it into the map dir_locks.emplace(pathLockFile.string(), std::move(lock)); } } catch (const boost::interprocess::interprocess_exception &e) { return error("Error while attempting to lock directory %s: %s", directory.string(), e.what()); } return true; } void ReleaseDirectoryLocks() { std::lock_guard ulock(cs_dir_locks); dir_locks.clear(); } bool DirIsWritable(const fs::path &directory) { fs::path tmpFile = directory / fs::unique_path(); FILE *file = fsbridge::fopen(tmpFile, "a"); if (!file) { return false; } fclose(file); remove(tmpFile); return true; } /** * Interpret a string argument as a boolean. * * The definition of atoi() requires that non-numeric string values like "foo", * return 0. This means that if a user unintentionally supplies a non-integer * argument here, the return value is always false. This means that -foo=false * does what the user probably expects, but -foo=true is well defined but does * not do what they probably expected. * * The return value of atoi() is undefined when given input not representable as * an int. On most systems this means string value between "-2147483648" and * "2147483647" are well defined (this method will return true). Setting * -txindex=2147483648 on most systems, however, is probably undefined. * * For a more extensive discussion of this topic (and a wide range of opinions * on the Right Way to change this code), see PR12713. */ static bool InterpretBool(const std::string &strValue) { if (strValue.empty()) { return true; } return (atoi(strValue) != 0); } /** Internal helper functions for ArgsManager */ class ArgsManagerHelper { public: typedef std::map> MapArgs; /** Determine whether to use config settings in the default section, * See also comments around ArgsManager::ArgsManager() below. */ static inline bool UseDefaultSection(const ArgsManager &am, const std::string &arg) { return (am.m_network == CBaseChainParams::MAIN || am.m_network_only_args.count(arg) == 0); } /** Convert regular argument into the network-specific setting */ static inline std::string NetworkArg(const ArgsManager &am, const std::string &arg) { assert(arg.length() > 1 && arg[0] == '-'); return "-" + am.m_network + "." + arg.substr(1); } /** Find arguments in a map and add them to a vector */ static inline void AddArgs(std::vector &res, const MapArgs &map_args, const std::string &arg) { auto it = map_args.find(arg); if (it != map_args.end()) { res.insert(res.end(), it->second.begin(), it->second.end()); } } /** * Return true/false if an argument is set in a map, and also * return the first (or last) of the possibly multiple values it has */ static inline std::pair GetArgHelper(const MapArgs &map_args, const std::string &arg, bool getLast = false) { auto it = map_args.find(arg); if (it == map_args.end() || it->second.empty()) { return std::make_pair(false, std::string()); } if (getLast) { return std::make_pair(true, it->second.back()); } else { return std::make_pair(true, it->second.front()); } } /** * Get the string value of an argument, returning a pair of a boolean * indicating the argument was found, and the value for the argument * if it was found (or the empty string if not found). */ static inline std::pair GetArg(const ArgsManager &am, const std::string &arg) { LOCK(am.cs_args); std::pair found_result(false, std::string()); // We pass "true" to GetArgHelper in order to return the last // argument value seen from the command line (so "bitcoind -foo=bar // -foo=baz" gives GetArg(am,"foo")=={true,"baz"} found_result = GetArgHelper(am.m_override_args, arg, true); if (found_result.first) { return found_result; } // But in contrast we return the first argument seen in a config file, // so "foo=bar \n foo=baz" in the config file gives // GetArg(am,"foo")={true,"bar"} if (!am.m_network.empty()) { found_result = GetArgHelper(am.m_config_args, NetworkArg(am, arg)); if (found_result.first) { return found_result; } } if (UseDefaultSection(am, arg)) { found_result = GetArgHelper(am.m_config_args, arg); if (found_result.first) { return found_result; } } return found_result; } /* Special test for -testnet and -regtest args, because we don't want to be * confused by craziness like "[regtest] testnet=1" */ static inline bool GetNetBoolArg(const ArgsManager &am, const std::string &net_arg) { std::pair found_result(false, std::string()); found_result = GetArgHelper(am.m_override_args, net_arg, true); if (!found_result.first) { found_result = GetArgHelper(am.m_config_args, net_arg, true); if (!found_result.first) { // not set return false; } } // is set, so evaluate return InterpretBool(found_result.second); } }; /** * Interpret -nofoo as if the user supplied -foo=0. * * This method also tracks when the -no form was supplied, and if so, checks * whether there was a double-negative (-nofoo=0 -> -foo=1). * * If there was not a double negative, it removes the "no" from the key, and * returns true, indicating the caller should clear the args vector to indicate * a negated option. * * If there was a double negative, it removes "no" from the key, sets the value * to "1" and returns false. * * If there was no "no", it leaves key and value untouched and returns false. * * Where an option was negated can be later checked using the IsArgNegated() * method. One use case for this is to have a way to disable options that are * not normally boolean (e.g. using -nodebuglogfile to request that debug log * output is not sent to any file at all). */ static bool InterpretNegatedOption(std::string &key, std::string &val) { assert(key[0] == '-'); size_t option_index = key.find('.'); if (option_index == std::string::npos) { option_index = 1; } else { ++option_index; } if (key.substr(option_index, 2) == "no") { bool bool_val = InterpretBool(val); key.erase(option_index, 2); if (!bool_val) { // Double negatives like -nofoo=0 are supported (but discouraged) LogPrintf( "Warning: parsed potentially confusing double-negative %s=%s\n", key, val); val = "1"; } else { return true; } } return false; } ArgsManager::ArgsManager() : /* These options would cause cross-contamination if values for mainnet * were used while running on regtest/testnet (or vice-versa). * Setting them as section_only_args ensures that sharing a config file * between mainnet and regtest/testnet won't cause problems due to these * parameters by accident. */ m_network_only_args{ "-addnode", "-connect", "-port", "-bind", "-rpcport", "-rpcbind", "-wallet", } { // nothing to do } void ArgsManager::WarnForSectionOnlyArgs() { // if there's no section selected, don't worry if (m_network.empty()) { return; } // if it's okay to use the default section for this network, don't worry if (m_network == CBaseChainParams::MAIN) { return; } for (const auto &arg : m_network_only_args) { std::pair found_result; // if this option is overridden it's fine found_result = ArgsManagerHelper::GetArgHelper(m_override_args, arg); if (found_result.first) { continue; } // if there's a network-specific value for this option, it's fine found_result = ArgsManagerHelper::GetArgHelper( m_config_args, ArgsManagerHelper::NetworkArg(*this, arg)); if (found_result.first) { continue; } // if there isn't a default value for this option, it's fine found_result = ArgsManagerHelper::GetArgHelper(m_config_args, arg); if (!found_result.first) { continue; } // otherwise, issue a warning LogPrintf("Warning: Config setting for %s only applied on %s network " "when in [%s] section.\n", arg, m_network, m_network); } } void ArgsManager::SelectConfigNetwork(const std::string &network) { m_network = network; } void ArgsManager::ParseParameters(int argc, const char *const argv[]) { LOCK(cs_args); m_override_args.clear(); for (int i = 1; i < argc; i++) { std::string key(argv[i]); std::string val; size_t is_index = key.find('='); if (is_index != std::string::npos) { val = key.substr(is_index + 1); key.erase(is_index); } #ifdef WIN32 std::transform(key.begin(), key.end(), key.begin(), ::tolower); if (key[0] == '/') { key[0] = '-'; } #endif if (key[0] != '-') { break; } // Transform --foo to -foo if (key.length() > 1 && key[1] == '-') { key.erase(0, 1); } // Check for -nofoo if (InterpretNegatedOption(key, val)) { m_override_args[key].clear(); } else { m_override_args[key].push_back(val); } } } std::vector ArgsManager::GetArgs(const std::string &strArg) const { std::vector result = {}; // special case if (IsArgNegated(strArg)) { return result; } LOCK(cs_args); ArgsManagerHelper::AddArgs(result, m_override_args, strArg); if (!m_network.empty()) { ArgsManagerHelper::AddArgs( result, m_config_args, ArgsManagerHelper::NetworkArg(*this, strArg)); } if (ArgsManagerHelper::UseDefaultSection(*this, strArg)) { ArgsManagerHelper::AddArgs(result, m_config_args, strArg); } return result; } bool ArgsManager::IsArgSet(const std::string &strArg) const { // special case if (IsArgNegated(strArg)) { return true; } return ArgsManagerHelper::GetArg(*this, strArg).first; } bool ArgsManager::IsArgNegated(const std::string &strArg) const { LOCK(cs_args); const auto &ov = m_override_args.find(strArg); if (ov != m_override_args.end()) { return ov->second.empty(); } if (!m_network.empty()) { const auto &cfs = m_config_args.find(ArgsManagerHelper::NetworkArg(*this, strArg)); if (cfs != m_config_args.end()) { return cfs->second.empty(); } } const auto &cf = m_config_args.find(strArg); if (cf != m_config_args.end()) { return cf->second.empty(); } return false; } std::string ArgsManager::GetArg(const std::string &strArg, const std::string &strDefault) const { if (IsArgNegated(strArg)) { return "0"; } std::pair found_res = ArgsManagerHelper::GetArg(*this, strArg); if (found_res.first) { return found_res.second; } return strDefault; } int64_t ArgsManager::GetArg(const std::string &strArg, int64_t nDefault) const { if (IsArgNegated(strArg)) { return 0; } std::pair found_res = ArgsManagerHelper::GetArg(*this, strArg); if (found_res.first) { return atoi64(found_res.second); } return nDefault; } bool ArgsManager::GetBoolArg(const std::string &strArg, bool fDefault) const { if (IsArgNegated(strArg)) { return false; } std::pair found_res = ArgsManagerHelper::GetArg(*this, strArg); if (found_res.first) { return InterpretBool(found_res.second); } return fDefault; } bool ArgsManager::SoftSetArg(const std::string &strArg, const std::string &strValue) { LOCK(cs_args); if (IsArgSet(strArg)) { return false; } ForceSetArg(strArg, strValue); return true; } bool ArgsManager::SoftSetBoolArg(const std::string &strArg, bool fValue) { if (fValue) { return SoftSetArg(strArg, std::string("1")); } else { return SoftSetArg(strArg, std::string("0")); } } void ArgsManager::ForceSetArg(const std::string &strArg, const std::string &strValue) { LOCK(cs_args); m_override_args[strArg] = {strValue}; } /** * This function is only used for testing purpose so * so we should not worry about element uniqueness and * integrity of mapMultiArgs data structure */ void ArgsManager::ForceSetMultiArg(const std::string &strArg, const std::string &strValue) { LOCK(cs_args); m_override_args[strArg].push_back(strValue); } void ArgsManager::ClearArg(const std::string &strArg) { LOCK(cs_args); m_override_args.erase(strArg); m_config_args.erase(strArg); } bool HelpRequested(const ArgsManager &args) { return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help"); } static const int screenWidth = 79; static const int optIndent = 2; static const int msgIndent = 7; std::string HelpMessageGroup(const std::string &message) { return std::string(message) + std::string("\n\n"); } std::string HelpMessageOpt(const std::string &option, const std::string &message) { return std::string(optIndent, ' ') + std::string(option) + std::string("\n") + std::string(msgIndent, ' ') + FormatParagraph(message, screenWidth - msgIndent, msgIndent) + std::string("\n\n"); } static std::string FormatException(const std::exception *pex, const char *pszThread) { #ifdef WIN32 char pszModule[MAX_PATH] = ""; GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule)); #else const char *pszModule = "bitcoin"; #endif if (pex) { return strprintf("EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread); } else { return strprintf("UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); } } void PrintExceptionContinue(const std::exception *pex, const char *pszThread) { std::string message = FormatException(pex, pszThread); LogPrintf("\n\n************************\n%s\n", message); fprintf(stderr, "\n\n************************\n%s\n", message.c_str()); } fs::path GetDefaultDataDir() { // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin // Mac: ~/Library/Application Support/Bitcoin // Unix: ~/.bitcoin #ifdef WIN32 // Windows return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin"; #else fs::path pathRet; char *pszHome = getenv("HOME"); if (pszHome == nullptr || strlen(pszHome) == 0) { pathRet = fs::path("/"); } else { pathRet = fs::path(pszHome); } #ifdef MAC_OSX // Mac return pathRet / "Library/Application Support/Bitcoin"; #else // Unix return pathRet / ".bitcoin"; #endif #endif } static fs::path pathCached; static fs::path pathCachedNetSpecific; static CCriticalSection csPathCached; const fs::path &GetDataDir(bool fNetSpecific) { LOCK(csPathCached); fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached; // This can be called during exceptions by LogPrintf(), so we cache the // value so we don't have to do memory allocations after that. if (!path.empty()) { return path; } if (gArgs.IsArgSet("-datadir")) { path = fs::system_complete(gArgs.GetArg("-datadir", "")); if (!fs::is_directory(path)) { path = ""; return path; } } else { path = GetDefaultDataDir(); } if (fNetSpecific) { path /= BaseParams().DataDir(); } if (fs::create_directories(path)) { // This is the first run, create wallets subdirectory too fs::create_directories(path / "wallets"); } return path; } void ClearDatadirCache() { LOCK(csPathCached); pathCached = fs::path(); pathCachedNetSpecific = fs::path(); } fs::path GetConfigFile(const std::string &confPath) { fs::path pathConfigFile(confPath); if (!pathConfigFile.is_complete()) { pathConfigFile = GetDataDir(false) / pathConfigFile; } return pathConfigFile; } void ArgsManager::ReadConfigStream(std::istream &stream) { LOCK(cs_args); std::set setOptions; setOptions.insert("*"); for (boost::program_options::detail::config_file_iterator it(stream, setOptions), end; it != end; ++it) { std::string strKey = std::string("-") + it->string_key; std::string strValue = it->value[0]; if (InterpretNegatedOption(strKey, strValue)) { m_config_args[strKey].clear(); } else { m_config_args[strKey].push_back(strValue); } } } void ArgsManager::ReadConfigFile(const std::string &confPath) { { LOCK(cs_args); m_config_args.clear(); } fs::ifstream stream(GetConfigFile(confPath)); // ok to not have a config file if (stream.good()) { ReadConfigStream(stream); } // If datadir is changed in .conf file: ClearDatadirCache(); if (!fs::is_directory(GetDataDir(false))) { throw std::runtime_error( strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str())); } } std::string ArgsManager::GetChainName() const { bool fRegTest = ArgsManagerHelper::GetNetBoolArg(*this, "-regtest"); bool fTestNet = ArgsManagerHelper::GetNetBoolArg(*this, "-testnet"); if (fTestNet && fRegTest) { throw std::runtime_error( "Invalid combination of -regtest and -testnet."); } if (fRegTest) { return CBaseChainParams::REGTEST; } if (fTestNet) { return CBaseChainParams::TESTNET; } return CBaseChainParams::MAIN; } #ifndef WIN32 fs::path GetPidFile() { fs::path pathPidFile(gArgs.GetArg("-pid", BITCOIN_PID_FILENAME)); if (!pathPidFile.is_complete()) { pathPidFile = GetDataDir() / pathPidFile; } return pathPidFile; } void CreatePidFile(const fs::path &path, pid_t pid) { FILE *file = fsbridge::fopen(path, "w"); if (file) { fprintf(file, "%d\n", pid); fclose(file); } } #endif bool RenameOver(fs::path src, fs::path dest) { #ifdef WIN32 return MoveFileExA(src.string().c_str(), dest.string().c_str(), MOVEFILE_REPLACE_EXISTING) != 0; #else int rc = std::rename(src.string().c_str(), dest.string().c_str()); return (rc == 0); #endif /* WIN32 */ } /** * Ignores exceptions thrown by Boost's create_directories if the requested * directory exists. Specifically handles case where path p exists, but it * wasn't possible for the user to write to the parent directory. */ bool TryCreateDirectories(const fs::path &p) { try { return fs::create_directories(p); } catch (const fs::filesystem_error &) { if (!fs::exists(p) || !fs::is_directory(p)) { throw; } } // create_directory didn't create the directory, it had to have existed // already. return false; } void FileCommit(FILE *file) { // Harmless if redundantly called. fflush(file); #ifdef WIN32 HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); FlushFileBuffers(hFile); #else #if defined(__linux__) || defined(__NetBSD__) fdatasync(fileno(file)); #elif defined(__APPLE__) && defined(F_FULLFSYNC) fcntl(fileno(file), F_FULLFSYNC, 0); #else fsync(fileno(file)); #endif #endif } bool TruncateFile(FILE *file, unsigned int length) { #if defined(WIN32) return _chsize(_fileno(file), length) == 0; #else return ftruncate(fileno(file), length) == 0; #endif } /** * This function tries to raise the file descriptor limit to the requested * number. It returns the actual file descriptor limit (which may be more or * less than nMinFD) */ int RaiseFileDescriptorLimit(int nMinFD) { #if defined(WIN32) return 2048; #else struct rlimit limitFD; if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) { if (limitFD.rlim_cur < (rlim_t)nMinFD) { limitFD.rlim_cur = nMinFD; if (limitFD.rlim_cur > limitFD.rlim_max) { limitFD.rlim_cur = limitFD.rlim_max; } setrlimit(RLIMIT_NOFILE, &limitFD); getrlimit(RLIMIT_NOFILE, &limitFD); } return limitFD.rlim_cur; } // getrlimit failed, assume it's fine. return nMinFD; #endif } /** * This function tries to make a particular range of a file allocated * (corresponding to disk space) it is advisory, and the range specified in the * arguments will never contain live data. */ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { #if defined(WIN32) // Windows-specific version. HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); LARGE_INTEGER nFileSize; int64_t nEndPos = (int64_t)offset + length; nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF; nFileSize.u.HighPart = nEndPos >> 32; SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN); SetEndOfFile(hFile); #elif defined(MAC_OSX) // OSX specific version. fstore_t fst; fst.fst_flags = F_ALLOCATECONTIG; fst.fst_posmode = F_PEOFPOSMODE; fst.fst_offset = 0; fst.fst_length = (off_t)offset + length; fst.fst_bytesalloc = 0; if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) { fst.fst_flags = F_ALLOCATEALL; fcntl(fileno(file), F_PREALLOCATE, &fst); } ftruncate(fileno(file), fst.fst_length); #elif defined(__linux__) // Version using posix_fallocate. off_t nEndPos = (off_t)offset + length; posix_fallocate(fileno(file), 0, nEndPos); #else // Fallback version // TODO: just write one byte per block static const char buf[65536] = {}; fseek(file, offset, SEEK_SET); while (length > 0) { unsigned int now = 65536; if (length < now) { now = length; } // Allowed to fail; this function is advisory anyway. fwrite(buf, 1, now, file); length -= now; } #endif } #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate) { char pszPath[MAX_PATH] = ""; if (SHGetSpecialFolderPathA(nullptr, pszPath, nFolder, fCreate)) { return fs::path(pszPath); } LogPrintf( "SHGetSpecialFolderPathA() failed, could not obtain requested path.\n"); return fs::path(""); } #endif void runCommand(const std::string &strCommand) { if (strCommand.empty()) { return; } int nErr = ::system(strCommand.c_str()); if (nErr) { LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr); } } void RenameThread(const char *name) { #if defined(PR_SET_NAME) // Only the first 15 characters are used (16 - NUL terminator) ::prctl(PR_SET_NAME, name, 0, 0, 0); #elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) pthread_set_name_np(pthread_self(), name); #elif defined(MAC_OSX) pthread_setname_np(name); #else // Prevent warnings for unused parameters... (void)name; #endif } void SetupEnvironment() { #ifdef HAVE_MALLOPT_ARENA_MAX // glibc-specific: On 32-bit systems set the number of arenas to 1. By // default, since glibc 2.10, the C library will create up to two heap // arenas per core. This is known to cause excessive virtual address space // usage in our usage. Work around it by setting the maximum number of // arenas to 1. if (sizeof(void *) == 4) { mallopt(M_ARENA_MAX, 1); } #endif // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale may // be invalid, in which case the "C" locale is used as fallback. #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && \ !defined(__OpenBSD__) try { // Raises a runtime error if current locale is invalid. std::locale(""); } catch (const std::runtime_error &) { setenv("LC_ALL", "C", 1); } #endif // The path locale is lazy initialized and to avoid deinitialization errors // in multithreading environments, it is set explicitly by the main thread. // A dummy locale is used to extract the internal default locale, used by // fs::path, which is then used to explicitly imbue the path. std::locale loc = fs::path::imbue(std::locale::classic()); fs::path::imbue(loc); } bool SetupNetworking() { #ifdef WIN32 // Initialize Windows Sockets. WSADATA wsadata; int ret = WSAStartup(MAKEWORD(2, 2), &wsadata); if (ret != NO_ERROR || LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2) { return false; } #endif return true; } int GetNumCores() { return boost::thread::physical_concurrency(); } std::string CopyrightHolders(const std::string &strPrefix) { return strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION)); } // Obtain the application startup time (used for uptime calculation) int64_t GetStartupTime() { return nStartupTime; } diff --git a/src/util.h b/src/util.h index a65752c2c2..dd8509ff93 100644 --- a/src/util.h +++ b/src/util.h @@ -1,285 +1,285 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. /** * Server/client environment: argument handling, config file parsing, * thread wrappers, startup time */ #ifndef BITCOIN_UTIL_H #define BITCOIN_UTIL_H #if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" +#include #endif -#include "compat.h" -#include "fs.h" -#include "logging.h" -#include "sync.h" -#include "tinyformat.h" -#include "utiltime.h" +#include +#include +#include +#include +#include +#include + +#include +#include // for boost::thread_interrupted #include #include #include #include #include #include #include #include -#include -#include // for boost::thread_interrupted - // Application startup time (used for uptime calculation) int64_t GetStartupTime(); /** Signals for translation. */ class CTranslationInterface { public: /** Translate a message to the native language of the user. */ boost::signals2::signal Translate; }; extern CTranslationInterface translationInterface; extern const char *const BITCOIN_CONF_FILENAME; extern const char *const BITCOIN_PID_FILENAME; /** * Translation function: Call Translate signal on UI interface, which returns a * boost::optional result. If no translation slot is registered, nothing is * returned, and simply return the input. */ inline std::string _(const char *psz) { boost::optional rv = translationInterface.Translate(psz); return rv ? (*rv) : psz; } void SetupEnvironment(); bool SetupNetworking(); template bool error(const char *fmt, const Args &... args) { LogPrintf("ERROR: " + tfm::format(fmt, args...) + "\n"); return false; } void PrintExceptionContinue(const std::exception *pex, const char *pszThread); void FileCommit(FILE *file); bool TruncateFile(FILE *file, unsigned int length); int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); bool RenameOver(fs::path src, fs::path dest); bool LockDirectory(const fs::path &directory, const std::string lockfile_name, bool probe_only = false); bool DirIsWritable(const fs::path &directory); /** * Release all directory locks. This is used for unit testing only, at runtime * the global destructor will take care of the locks. */ void ReleaseDirectoryLocks(); bool TryCreateDirectories(const fs::path &p); fs::path GetDefaultDataDir(); const fs::path &GetDataDir(bool fNetSpecific = true); void ClearDatadirCache(); fs::path GetConfigFile(const std::string &confPath); #ifndef WIN32 fs::path GetPidFile(); void CreatePidFile(const fs::path &path, pid_t pid); #endif #ifdef WIN32 fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif void runCommand(const std::string &strCommand); inline bool IsSwitchChar(char c) { #ifdef WIN32 return c == '-' || c == '/'; #else return c == '-'; #endif } class ArgsManager { protected: friend class ArgsManagerHelper; mutable CCriticalSection cs_args; std::map> m_override_args; std::map> m_config_args; std::string m_network; std::set m_network_only_args; void ReadConfigStream(std::istream &stream); public: ArgsManager(); /** * Select the network in use */ void SelectConfigNetwork(const std::string &network); void ParseParameters(int argc, const char *const argv[]); void ReadConfigFile(const std::string &confPath); /** * Log warnings for options in m_section_only_args when they are specified * in the default section but not overridden on the command line or in a * network-specific section in the config file. */ void WarnForSectionOnlyArgs(); /** * Return a vector of strings of the given argument * * @param strArg Argument to get (e.g. "-foo") * @return command-line arguments */ std::vector GetArgs(const std::string &strArg) const; /** * Return true if the given argument has been manually set. * * @param strArg Argument to get (e.g. "-foo") * @return true if the argument has been set */ bool IsArgSet(const std::string &strArg) const; /** * Return true if the argument was originally passed as a negated option, * i.e. -nofoo. * * @param strArg Argument to get (e.g. "-foo") * @return true if the argument was passed negated */ bool IsArgNegated(const std::string &strArg) const; /** * Return string argument or default value. * * @param strArg Argument to get (e.g. "-foo") * @param default (e.g. "1") * @return command-line argument or default value */ std::string GetArg(const std::string &strArg, const std::string &strDefault) const; /** * Return integer argument or default value. * * @param strArg Argument to get (e.g. "-foo") * @param default (e.g. 1) * @return command-line argument (0 if invalid number) or default value */ int64_t GetArg(const std::string &strArg, int64_t nDefault) const; /** * Return boolean argument or default value. * * @param strArg Argument to get (e.g. "-foo") * @param default (true or false) * @return command-line argument or default value */ bool GetBoolArg(const std::string &strArg, bool fDefault) const; /** * Set an argument if it doesn't already have a value. * * @param strArg Argument to set (e.g. "-foo") * @param strValue Value (e.g. "1") * @return true if argument gets set, false if it already had a value */ bool SoftSetArg(const std::string &strArg, const std::string &strValue); /** * Set a boolean argument if it doesn't already have a value. * * @param strArg Argument to set (e.g. "-foo") * @param fValue Value (e.g. false) * @return true if argument gets set, false if it already had a value */ bool SoftSetBoolArg(const std::string &strArg, bool fValue); // Forces a arg setting, used only in testing void ForceSetArg(const std::string &strArg, const std::string &strValue); // Forces a multi arg setting, used only in testing void ForceSetMultiArg(const std::string &strArg, const std::string &strValue); /** * Looks for -regtest, -testnet and returns the appropriate BIP70 chain * name. * @return CBaseChainParams::MAIN by default; raises runtime error if an * invalid combination is given. */ std::string GetChainName() const; // Remove an arg setting, used only in testing void ClearArg(const std::string &strArg); }; extern ArgsManager gArgs; /** * @return true if help has been requested via a command-line arg */ bool HelpRequested(const ArgsManager &args); /** * Format a string to be used as group of options in help messages. * * @param message Group name (e.g. "RPC server options:") * @return the formatted string */ std::string HelpMessageGroup(const std::string &message); /** * Format a string to be used as option description in help messages. * * @param option Option message (e.g. "-rpcuser=") * @param message Option description (e.g. "Username for JSON-RPC connections") * @return the formatted string */ std::string HelpMessageOpt(const std::string &option, const std::string &message); /** * Return the number of physical cores available on the current system. * @note This does not count virtual cores, such as those provided by * HyperThreading when boost is newer than 1.56. */ int GetNumCores(); void RenameThread(const char *name); /** * .. and a wrapper that just calls func once */ template void TraceThread(const char *name, Callable func) { std::string s = strprintf("bitcoin-%s", name); RenameThread(s.c_str()); try { LogPrintf("%s thread start\n", name); func(); LogPrintf("%s thread exit\n", name); } catch (const boost::thread_interrupted &) { LogPrintf("%s thread interrupt\n", name); throw; } catch (const std::exception &e) { PrintExceptionContinue(&e, name); throw; } catch (...) { PrintExceptionContinue(nullptr, name); throw; } } std::string CopyrightHolders(const std::string &strPrefix); #endif // BITCOIN_UTIL_H diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index f4d10ca37a..032b9ff852 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -1,80 +1,80 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2015 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 "utilmoneystr.h" +#include -#include "primitives/transaction.h" -#include "tinyformat.h" -#include "utilstrencodings.h" +#include +#include +#include std::string FormatMoney(const Amount amt) { // Note: not using straight sprintf here because we do NOT want localized // number formatting. Amount amt_abs = amt > Amount::zero() ? amt : -amt; std::string str = strprintf("%d.%08d", amt_abs / COIN, (amt_abs % COIN) / SATOSHI); // Right-trim excess zeros before the decimal point: int nTrim = 0; for (int i = str.size() - 1; (str[i] == '0' && isdigit(str[i - 2])); --i) { ++nTrim; } if (nTrim) { str.erase(str.size() - nTrim, nTrim); } if (amt < Amount::zero()) { str.insert((unsigned int)0, 1, '-'); } return str; } bool ParseMoney(const std::string &str, Amount &nRet) { return ParseMoney(str.c_str(), nRet); } bool ParseMoney(const char *pszIn, Amount &nRet) { std::string strWhole; Amount nUnits = Amount::zero(); const char *p = pszIn; while (IsSpace(*p)) { p++; } for (; *p; p++) { if (*p == '.') { p++; Amount nMult = 10 * CENT; while (isdigit(*p) && (nMult > Amount::zero())) { nUnits += (*p++ - '0') * nMult; nMult /= 10; } break; } if (IsSpace(*p)) { break; } if (!isdigit(*p)) { return false; } strWhole.insert(strWhole.end(), *p); } for (; *p; p++) { if (!IsSpace(*p)) { return false; } } // guard against 63 bit overflow if (strWhole.size() > 10) { return false; } if (nUnits < Amount::zero() || nUnits > COIN) { return false; } Amount nWhole = atoi64(strWhole) * COIN; nRet = nWhole + Amount(nUnits); return true; } diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h index f7634fc9b1..e56cf4ce2b 100644 --- a/src/utilmoneystr.h +++ b/src/utilmoneystr.h @@ -1,21 +1,21 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. /** * Money parsing/formatting utilities. */ #ifndef BITCOIN_UTILMONEYSTR_H #define BITCOIN_UTILMONEYSTR_H +#include + #include #include -#include "amount.h" - std::string FormatMoney(const Amount n); bool ParseMoney(const std::string &str, Amount &nRet); bool ParseMoney(const char *pszIn, Amount &nRet); #endif // BITCOIN_UTILMONEYSTR_H diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 4185dacaae..db00a60366 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -1,817 +1,817 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 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 "utilstrencodings.h" +#include -#include "tinyformat.h" +#include #include #include #include #include #include static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; static const std::string SAFE_CHARS[] = { // SAFE_CHARS_DEFAULT CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_UA_COMMENT CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_FILENAME CHARS_ALPHA_NUM + ".-_", }; std::string SanitizeString(const std::string &str, int rule) { std::string strResult; for (std::string::size_type i = 0; i < str.size(); i++) { if (SAFE_CHARS[rule].find(str[i]) != std::string::npos) { strResult.push_back(str[i]); } } return strResult; } const signed char p_util_hexdigit[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; signed char HexDigit(char c) { return p_util_hexdigit[(uint8_t)c]; } bool IsHex(const std::string &str) { for (std::string::const_iterator it(str.begin()); it != str.end(); ++it) { if (HexDigit(*it) < 0) { return false; } } return (str.size() > 0) && (str.size() % 2 == 0); } bool IsHexNumber(const std::string &str) { size_t starting_location = 0; if (str.size() > 2 && *str.begin() == '0' && *(str.begin() + 1) == 'x') { starting_location = 2; } for (auto c : str.substr(starting_location)) { if (HexDigit(c) < 0) { return false; } } // Return false for empty string or "0x". return (str.size() > starting_location); } std::vector ParseHex(const char *psz) { // convert hex dump to vector std::vector vch; while (true) { while (IsSpace(*psz)) { psz++; } signed char c = HexDigit(*psz++); if (c == (signed char)-1) { break; } uint8_t n = (c << 4); c = HexDigit(*psz++); if (c == (signed char)-1) { break; } n |= c; vch.push_back(n); } return vch; } std::vector ParseHex(const std::string &str) { return ParseHex(str.c_str()); } void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { size_t colon = in.find_last_of(':'); // if a : is found, and it either follows a [...], or no other : is in the // string, treat it as port separator bool fHaveColon = colon != in.npos; bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); // if there is a colon, and // in[0]=='[', colon is not 0, // so in[colon-1] is safe bool fMultiColon = fHaveColon && (in.find_last_of(':', colon - 1) != in.npos); if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) { int32_t n; if (ParseInt32(in.substr(colon + 1), &n) && n > 0 && n < 0x10000) { in = in.substr(0, colon); portOut = n; } } if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') { hostOut = in.substr(1, in.size() - 2); } else { hostOut = in; } } std::string EncodeBase64(const uint8_t *pch, size_t len) { static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; std::string strRet = ""; strRet.reserve((len + 2) / 3 * 4); int mode = 0, left = 0; const uint8_t *pchEnd = pch + len; while (pch < pchEnd) { int enc = *(pch++); switch (mode) { case 0: // we have no bits strRet += pbase64[enc >> 2]; left = (enc & 3) << 4; mode = 1; break; case 1: // we have two bits strRet += pbase64[left | (enc >> 4)]; left = (enc & 15) << 2; mode = 2; break; case 2: // we have four bits strRet += pbase64[left | (enc >> 6)]; strRet += pbase64[enc & 63]; mode = 0; break; } } if (mode) { strRet += pbase64[left]; strRet += '='; if (mode == 1) { strRet += '='; } } return strRet; } std::string EncodeBase64(const std::string &str) { return EncodeBase64((const uint8_t *)str.c_str(), str.size()); } std::vector DecodeBase64(const char *p, bool *pfInvalid) { static const int decode64_table[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; if (pfInvalid) { *pfInvalid = false; } std::vector vchRet; vchRet.reserve(strlen(p) * 3 / 4); int mode = 0; int left = 0; while (1) { int dec = decode64_table[(uint8_t)*p]; if (dec == -1) { break; } p++; switch (mode) { case 0: // we have no bits and get 6 left = dec; mode = 1; break; case 1: // we have 6 bits and keep 4 vchRet.push_back((left << 2) | (dec >> 4)); left = dec & 15; mode = 2; break; case 2: // we have 4 bits and get 6, we keep 2 vchRet.push_back((left << 4) | (dec >> 2)); left = dec & 3; mode = 3; break; case 3: // we have 2 bits and get 6 vchRet.push_back((left << 6) | dec); mode = 0; break; } } if (pfInvalid) { switch (mode) { case 0: // 4n base64 characters processed: ok break; case 1: // 4n+1 base64 character processed: impossible *pfInvalid = true; break; case 2: // 4n+2 base64 characters processed: require '==' if (left || p[0] != '=' || p[1] != '=' || decode64_table[(uint8_t)p[2]] != -1) { *pfInvalid = true; } break; case 3: // 4n+3 base64 characters processed: require '=' if (left || p[0] != '=' || decode64_table[(uint8_t)p[1]] != -1) { *pfInvalid = true; } break; } } return vchRet; } std::string DecodeBase64(const std::string &str) { std::vector vchRet = DecodeBase64(str.c_str()); return (vchRet.size() == 0) ? std::string() : std::string((const char *)&vchRet[0], vchRet.size()); } std::string EncodeBase32(const uint8_t *pch, size_t len) { static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; std::string strRet = ""; strRet.reserve((len + 4) / 5 * 8); int mode = 0, left = 0; const uint8_t *pchEnd = pch + len; while (pch < pchEnd) { int enc = *(pch++); switch (mode) { case 0: // we have no bits strRet += pbase32[enc >> 3]; left = (enc & 7) << 2; mode = 1; break; case 1: // we have three bits strRet += pbase32[left | (enc >> 6)]; strRet += pbase32[(enc >> 1) & 31]; left = (enc & 1) << 4; mode = 2; break; case 2: // we have one bit strRet += pbase32[left | (enc >> 4)]; left = (enc & 15) << 1; mode = 3; break; case 3: // we have four bits strRet += pbase32[left | (enc >> 7)]; strRet += pbase32[(enc >> 2) & 31]; left = (enc & 3) << 3; mode = 4; break; case 4: // we have two bits strRet += pbase32[left | (enc >> 5)]; strRet += pbase32[enc & 31]; mode = 0; } } static const int nPadding[5] = {0, 6, 4, 3, 1}; if (mode) { strRet += pbase32[left]; for (int n = 0; n < nPadding[mode]; n++) { strRet += '='; } } return strRet; } std::string EncodeBase32(const std::string &str) { return EncodeBase32((const uint8_t *)str.c_str(), str.size()); } std::vector DecodeBase32(const char *p, bool *pfInvalid) { static const int decode32_table[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; if (pfInvalid) { *pfInvalid = false; } std::vector vchRet; vchRet.reserve((strlen(p)) * 5 / 8); int mode = 0; int left = 0; while (1) { int dec = decode32_table[(uint8_t)*p]; if (dec == -1) { break; } p++; switch (mode) { case 0: // we have no bits and get 5 left = dec; mode = 1; break; case 1: // we have 5 bits and keep 2 vchRet.push_back((left << 3) | (dec >> 2)); left = dec & 3; mode = 2; break; case 2: // we have 2 bits and keep 7 left = left << 5 | dec; mode = 3; break; case 3: // we have 7 bits and keep 4 vchRet.push_back((left << 1) | (dec >> 4)); left = dec & 15; mode = 4; break; case 4: // we have 4 bits, and keep 1 vchRet.push_back((left << 4) | (dec >> 1)); left = dec & 1; mode = 5; break; case 5: // we have 1 bit, and keep 6 left = left << 5 | dec; mode = 6; break; case 6: // we have 6 bits, and keep 3 vchRet.push_back((left << 2) | (dec >> 3)); left = dec & 7; mode = 7; break; case 7: // we have 3 bits, and keep 0 vchRet.push_back((left << 5) | dec); mode = 0; break; } } if (pfInvalid) switch (mode) { case 0: // 8n base32 characters processed: ok break; case 1: // 8n+1 base32 characters processed: impossible case 3: // +3 case 6: // +6 *pfInvalid = true; break; case 2: // 8n+2 base32 characters processed: require '======' if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(uint8_t)p[6]] != -1) { *pfInvalid = true; } break; case 4: // 8n+4 base32 characters processed: require '====' if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(uint8_t)p[4]] != -1) { *pfInvalid = true; } break; case 5: // 8n+5 base32 characters processed: require '===' if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(uint8_t)p[3]] != -1) { *pfInvalid = true; } break; case 7: // 8n+7 base32 characters processed: require '=' if (left || p[0] != '=' || decode32_table[(uint8_t)p[1]] != -1) { *pfInvalid = true; } break; } return vchRet; } std::string DecodeBase32(const std::string &str) { std::vector vchRet = DecodeBase32(str.c_str()); return (vchRet.size() == 0) ? std::string() : std::string((const char *)&vchRet[0], vchRet.size()); } static bool ParsePrechecks(const std::string &str) { // No empty string allowed if (str.empty()) { return false; } // No padding allowed if (str.size() >= 1 && (IsSpace(str[0]) || IsSpace(str[str.size() - 1]))) { return false; } // No embedded NUL characters allowed if (str.size() != strlen(str.c_str())) { return false; } return true; } bool ParseInt32(const std::string &str, int32_t *out) { if (!ParsePrechecks(str)) { return false; } char *endp = nullptr; // strtol will not set errno if valid errno = 0; long int n = strtol(str.c_str(), &endp, 10); if (out) { *out = (int32_t)n; } // Note that strtol returns a *long int*, so even if strtol doesn't report a // over/underflow we still have to check that the returned value is within // the range of an *int32_t*. On 64-bit platforms the size of these types // may be different. return endp && *endp == 0 && !errno && n >= std::numeric_limits::min() && n <= std::numeric_limits::max(); } bool ParseInt64(const std::string &str, int64_t *out) { if (!ParsePrechecks(str)) { return false; } char *endp = nullptr; // strtoll will not set errno if valid errno = 0; long long int n = strtoll(str.c_str(), &endp, 10); if (out) { *out = (int64_t)n; } // Note that strtoll returns a *long long int*, so even if strtol doesn't // report a over/underflow we still have to check that the returned value is // within the range of an *int64_t*. return endp && *endp == 0 && !errno && n >= std::numeric_limits::min() && n <= std::numeric_limits::max(); } bool ParseUInt32(const std::string &str, uint32_t *out) { if (!ParsePrechecks(str)) { return false; } // Reject negative values, unfortunately strtoul accepts these by default if // they fit in the range if (str.size() >= 1 && str[0] == '-') { return false; } char *endp = nullptr; // strtoul will not set errno if valid errno = 0; unsigned long int n = strtoul(str.c_str(), &endp, 10); if (out) { *out = (uint32_t)n; } // Note that strtoul returns a *unsigned long int*, so even if it doesn't // report a over/underflow we still have to check that the returned value is // within the range of an *uint32_t*. On 64-bit platforms the size of these // types may be different. return endp && *endp == 0 && !errno && n <= std::numeric_limits::max(); } bool ParseUInt64(const std::string &str, uint64_t *out) { if (!ParsePrechecks(str)) { return false; } // Reject negative values, unfortunately strtoull accepts these by default // if they fit in the range if (str.size() >= 1 && str[0] == '-') { return false; } char *endp = nullptr; // strtoull will not set errno if valid errno = 0; unsigned long long int n = strtoull(str.c_str(), &endp, 10); if (out) { *out = (uint64_t)n; } // Note that strtoull returns a *unsigned long long int*, so even if it // doesn't report a over/underflow we still have to check that the returned // value is within the range of an *uint64_t*. return endp && *endp == 0 && !errno && n <= std::numeric_limits::max(); } bool ParseDouble(const std::string &str, double *out) { if (!ParsePrechecks(str)) { return false; } // No hexadecimal floats allowed if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') { return false; } std::istringstream text(str); text.imbue(std::locale::classic()); double result; text >> result; if (out) { *out = result; } return text.eof() && !text.fail(); } std::string FormatParagraph(const std::string &in, size_t width, size_t indent) { std::stringstream out; size_t ptr = 0; size_t indented = 0; while (ptr < in.size()) { size_t lineend = in.find_first_of('\n', ptr); if (lineend == std::string::npos) { lineend = in.size(); } const size_t linelen = lineend - ptr; const size_t rem_width = width - indented; if (linelen <= rem_width) { out << in.substr(ptr, linelen + 1); ptr = lineend + 1; indented = 0; } else { size_t finalspace = in.find_last_of(" \n", ptr + rem_width); if (finalspace == std::string::npos || finalspace < ptr) { // No place to break; just include the entire word and move on finalspace = in.find_first_of("\n ", ptr); if (finalspace == std::string::npos) { // End of the string, just add it and break out << in.substr(ptr); break; } } out << in.substr(ptr, finalspace - ptr) << "\n"; if (in[finalspace] == '\n') { indented = 0; } else if (indent) { out << std::string(indent, ' '); indented = indent; } ptr = finalspace + 1; } } return out.str(); } std::string i64tostr(int64_t n) { return strprintf("%d", n); } std::string itostr(int n) { return strprintf("%d", n); } int64_t atoi64(const char *psz) { #ifdef _MSC_VER return _atoi64(psz); #else return strtoll(psz, nullptr, 10); #endif } int64_t atoi64(const std::string &str) { #ifdef _MSC_VER return _atoi64(str.c_str()); #else return strtoll(str.c_str(), nullptr, 10); #endif } int atoi(const std::string &str) { return atoi(str.c_str()); } /** * Upper bound for mantissa. * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit * integer. Larger integers cannot consist of arbitrary combinations of 0-9: * * 999999999999999999 1^18-1 * 9223372036854775807 (1<<63)-1 (max int64_t) * 9999999999999999999 1^19-1 (would overflow) */ static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL; /** Helper function for ParseFixedPoint */ static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros) { if (ch == '0') { ++mantissa_tzeros; } else { for (int i = 0; i <= mantissa_tzeros; ++i) { // overflow if (mantissa > (UPPER_BOUND / 10LL)) { return false; } mantissa *= 10; } mantissa += ch - '0'; mantissa_tzeros = 0; } return true; } bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out) { int64_t mantissa = 0; int64_t exponent = 0; int mantissa_tzeros = 0; bool mantissa_sign = false; bool exponent_sign = false; int ptr = 0; int end = val.size(); int point_ofs = 0; if (ptr < end && val[ptr] == '-') { mantissa_sign = true; ++ptr; } if (ptr < end) { if (val[ptr] == '0') { // pass single 0 ++ptr; } else if (val[ptr] >= '1' && val[ptr] <= '9') { while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros)) { // overflow return false; } ++ptr; } } else { // missing expected digit return false; } } else { // empty string or loose '-' return false; } if (ptr < end && val[ptr] == '.') { ++ptr; if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros)) { // overflow return false; } ++ptr; ++point_ofs; } } else { // missing expected digit return false; } } if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E')) { ++ptr; if (ptr < end && val[ptr] == '+') { ++ptr; } else if (ptr < end && val[ptr] == '-') { exponent_sign = true; ++ptr; } if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { if (exponent > (UPPER_BOUND / 10LL)) { // overflow return false; } exponent = exponent * 10 + val[ptr] - '0'; ++ptr; } } else { // missing expected digit return false; } } if (ptr != end) { // trailing garbage return false; } // finalize exponent if (exponent_sign) { exponent = -exponent; } exponent = exponent - point_ofs + mantissa_tzeros; // finalize mantissa if (mantissa_sign) { mantissa = -mantissa; } // convert to one 64-bit fixed-point value exponent += decimals; if (exponent < 0) { // cannot represent values smaller than 10^-decimals return false; } if (exponent >= 18) { // cannot represent values larger than or equal to 10^(18-decimals) return false; } for (int i = 0; i < exponent; ++i) { if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL)) { // overflow return false; } mantissa *= 10; } if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND) { // overflow return false; } if (amount_out) { *amount_out = mantissa; } return true; } void Downcase(std::string &str) { std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return ToLower(c); }); } std::string Capitalize(std::string str) { if (str.empty()) return str; str[0] = ToUpper(str.front()); return str; } diff --git a/src/utiltime.cpp b/src/utiltime.cpp index e4bc744bcf..5b6f298ee9 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -1,83 +1,83 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" +#include #endif -#include "utiltime.h" - -#include +#include #include #include +#include + //!< For unit testing static std::atomic nMockTime(0); int64_t GetTime() { int64_t mocktime = nMockTime.load(std::memory_order_relaxed); if (mocktime) { return mocktime; } time_t now = time(nullptr); assert(now > 0); return now; } void SetMockTime(int64_t nMockTimeIn) { nMockTime.store(nMockTimeIn, std::memory_order_relaxed); } int64_t GetMockTime() { return nMockTime.load(std::memory_order_relaxed); } int64_t GetTimeMillis() { int64_t now = (boost::posix_time::microsec_clock::universal_time() - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))) .total_milliseconds(); assert(now > 0); return now; } int64_t GetTimeMicros() { int64_t now = (boost::posix_time::microsec_clock::universal_time() - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))) .total_microseconds(); assert(now > 0); return now; } int64_t GetSystemTimeInSeconds() { return GetTimeMicros() / 1000000; } void MilliSleep(int64_t n) { boost::this_thread::sleep_for(boost::chrono::milliseconds(n)); } std::string DateTimeStrFormat(const char *pszFormat, int64_t nTime) { static std::locale classic(std::locale::classic()); // std::locale takes ownership of the pointer std::locale loc(classic, new boost::posix_time::time_facet(pszFormat)); std::stringstream ss; ss.imbue(loc); ss << boost::posix_time::from_time_t(nTime); return ss.str(); } std::string FormatISO8601DateTime(int64_t nTime) { return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); } std::string FormatISO8601Date(int64_t nTime) { return DateTimeStrFormat("%Y-%m-%d", nTime); } std::string FormatISO8601Time(int64_t nTime) { return DateTimeStrFormat("%H:%M:%SZ", nTime); } diff --git a/src/validation.cpp b/src/validation.cpp index b31793b312..08e33de344 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1,5720 +1,5720 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "validation.h" - -#include "arith_uint256.h" -#include "blockindexworkcomparator.h" -#include "blockvalidity.h" -#include "chainparams.h" -#include "checkpoints.h" -#include "checkqueue.h" -#include "config.h" -#include "consensus/activation.h" -#include "consensus/consensus.h" -#include "consensus/merkle.h" -#include "consensus/tx_verify.h" -#include "consensus/validation.h" -#include "fs.h" -#include "hash.h" -#include "init.h" -#include "policy/fees.h" -#include "policy/policy.h" -#include "pow.h" -#include "primitives/block.h" -#include "primitives/transaction.h" -#include "random.h" -#include "reverse_iterator.h" -#include "script/script.h" -#include "script/scriptcache.h" -#include "script/sigcache.h" -#include "script/standard.h" -#include "timedata.h" -#include "tinyformat.h" -#include "txdb.h" -#include "txmempool.h" -#include "ui_interface.h" -#include "undo.h" -#include "util.h" -#include "utilmoneystr.h" -#include "utilstrencodings.h" -#include "validationinterface.h" -#include "warnings.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include