diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/Makefile.qt.include | 2 | ||||
-rw-r--r-- | src/coins.cpp | 6 | ||||
-rw-r--r-- | src/init.cpp | 1 | ||||
-rw-r--r-- | src/main.cpp | 54 | ||||
-rw-r--r-- | src/qt/forms/helpmessagedialog.ui | 20 | ||||
-rw-r--r-- | src/qt/utilitydialog.cpp | 88 | ||||
-rw-r--r-- | src/test/pmt_tests.cpp | 10 |
8 files changed, 131 insertions, 54 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 1ef88f0680..1f9a1621a7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -37,7 +37,7 @@ $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: -noinst_LIBRARIES = \ +EXTRA_LIBRARIES = \ crypto/libbitcoin_crypto.a \ libbitcoin_util.a \ libbitcoin_common.a \ @@ -46,7 +46,7 @@ noinst_LIBRARIES = \ libbitcoin_cli.a if ENABLE_WALLET BITCOIN_INCLUDES += $(BDB_CPPFLAGS) -noinst_LIBRARIES += libbitcoin_wallet.a +EXTRA_LIBRARIES += libbitcoin_wallet.a endif if BUILD_BITCOIN_LIBS diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 1192b7bd4e..cdd8f8d08d 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -1,5 +1,5 @@ bin_PROGRAMS += qt/bitcoin-qt -noinst_LIBRARIES += qt/libbitcoinqt.a +EXTRA_LIBRARIES += qt/libbitcoinqt.a # bitcoin qt core # QT_TS = \ diff --git a/src/coins.cpp b/src/coins.cpp index ef4f96fdee..d79e29951b 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -92,7 +92,6 @@ bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const { CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { assert(!hasModifier); - hasModifier = true; std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); if (ret.second) { if (!base->GetCoins(txid, ret.first->second.coins)) { @@ -233,7 +232,10 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const return tx.ComputePriority(dResult); } -CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_) : cache(cache_), it(it_) {} +CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_) : cache(cache_), it(it_) { + assert(!cache.hasModifier); + cache.hasModifier = true; +} CCoinsModifier::~CCoinsModifier() { diff --git a/src/init.cpp b/src/init.cpp index 1b0c909b96..03d67f0aa3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -323,6 +323,7 @@ std::string HelpMessage(HelpMessageMode mode) if (GetBoolArg("-help-debug", false)) { strUsage += " -limitfreerelay=<n> " + strprintf(_("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:%u)"), 15) + "\n"; + strUsage += " -relaypriority " + strprintf(_("Require high priority for relaying free or low-fee transactions (default:%u)"), 1) + "\n"; strUsage += " -maxsigcachesize=<n> " + strprintf(_("Limit size of signature cache to <n> entries (default: %u)"), 50000) + "\n"; } strUsage += " -minrelaytxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())) + "\n"; diff --git a/src/main.cpp b/src/main.cpp index 0067e9a2b2..e1a0973352 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -625,34 +625,11 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) bool IsStandardTx(const CTransaction& tx, string& reason) { - AssertLockHeld(cs_main); if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) { reason = "version"; return false; } - // Treat non-final transactions as non-standard to prevent a specific type - // of double-spend attack, as well as DoS attacks. (if the transaction - // can't be mined, the attacker isn't expending resources broadcasting it) - // Basically we don't want to propagate transactions that can't be included in - // the next block. - // - // However, IsFinalTx() is confusing... Without arguments, it uses - // chainActive.Height() to evaluate nLockTime; when a block is accepted, chainActive.Height() - // is set to the value of nHeight in the block. However, when IsFinalTx() - // is called within CBlock::AcceptBlock(), the height of the block *being* - // evaluated is what is used. Thus if we want to know if a transaction can - // be part of the *next* block, we need to call IsFinalTx() with one more - // than chainActive.Height(). - // - // Timestamps on the other hand don't get any special treatment, because we - // can't know what timestamp the next block will have, and there aren't - // timestamp applications where it matters. - if (!IsFinalTx(tx, chainActive.Height() + 1)) { - reason = "non-final"; - return false; - } - // Extremely large transactions with lots of inputs can cost the network // almost as much to process as they cost the sender in fees, because // computing signature hashes is O(ninputs*txsize). Limiting transactions @@ -941,6 +918,26 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa error("AcceptToMemoryPool : nonstandard transaction: %s", reason), REJECT_NONSTANDARD, reason); + // Only accept nLockTime-using transactions that can be mined in the next + // block; we don't want our mempool filled up with transactions that can't + // be mined yet. + // + // However, IsFinalTx() is confusing... Without arguments, it uses + // chainActive.Height() to evaluate nLockTime; when a block is accepted, + // chainActive.Height() is set to the value of nHeight in the block. + // However, when IsFinalTx() is called within CBlock::AcceptBlock(), the + // height of the block *being* evaluated is what is used. Thus if we want + // to know if a transaction can be part of the *next* block, we need to + // call IsFinalTx() with one more than chainActive.Height(). + // + // Timestamps on the other hand don't get any special treatment, because we + // can't know what timestamp the next block will have, and there aren't + // timestamp applications where it matters. + if (!IsFinalTx(tx, chainActive.Height() + 1)) + return state.DoS(0, + error("AcceptToMemoryPool : non-final"), + REJECT_NONSTANDARD, "non-final"); + // is it already in the memory pool? uint256 hash = tx.GetHash(); if (pool.exists(hash)) @@ -1030,6 +1027,11 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa hash.ToString(), nFees, txMinFee), REJECT_INSUFFICIENTFEE, "insufficient fee"); + // Require that free transactions have sufficient priority to be mined in the next block. + if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { + return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); + } + // Continuously rate-limit free (really, very-low-fee) transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. @@ -1049,7 +1051,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // At default rate it would take over a month to fill 1GB if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000) return state.DoS(0, error("AcceptToMemoryPool : free transaction rejected by rate limiter"), - REJECT_INSUFFICIENTFEE, "insufficient priority"); + REJECT_INSUFFICIENTFEE, "rate limited free transaction"); LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); dFreeCount += nSize; } @@ -1882,6 +1884,7 @@ enum FlushStateMode { bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { LOCK(cs_main); static int64_t nLastWrite = 0; + try { if ((mode == FLUSH_STATE_ALWAYS) || ((mode == FLUSH_STATE_PERIODIC || mode == FLUSH_STATE_IF_NEEDED) && pcoinsTip->GetCacheSize() > nCoinCacheSize) || (mode == FLUSH_STATE_PERIODIC && GetTimeMicros() > nLastWrite + DATABASE_WRITE_INTERVAL * 1000000)) { @@ -1921,6 +1924,9 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { } nLastWrite = GetTimeMicros(); } + } catch (const std::runtime_error& e) { + return state.Abort(std::string("System error while flushing: ") + e.what()); + } return true; } diff --git a/src/qt/forms/helpmessagedialog.ui b/src/qt/forms/helpmessagedialog.ui index 81dbd90b12..9ace9afd79 100644 --- a/src/qt/forms/helpmessagedialog.ui +++ b/src/qt/forms/helpmessagedialog.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>800</width> - <height>400</height> + <width>585</width> + <height>225</height> </rect> </property> <property name="font"> @@ -35,6 +35,13 @@ <item> <layout class="QVBoxLayout" name="verticalLayout"> <item> + <widget class="QTextEdit" name="helpMessage"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item> <widget class="QScrollArea" name="scrollArea"> <property name="verticalScrollBarPolicy"> <enum>Qt::ScrollBarAlwaysOn</enum> @@ -47,19 +54,22 @@ <rect> <x>0</x> <y>0</y> - <width>659</width> - <height>348</height> + <width>447</width> + <height>68</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QLabel" name="helpMessageLabel"> + <widget class="QLabel" name="aboutMessage"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> </property> <property name="textFormat"> <enum>Qt::PlainText</enum> </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> <property name="openExternalLinks"> <bool>true</bool> </property> diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index e6cec8173e..9ee408179d 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -18,6 +18,8 @@ #include <QCloseEvent> #include <QLabel> #include <QRegExp> +#include <QTextTable> +#include <QTextCursor> #include <QVBoxLayout> /** "Help message" or "About" dialog box */ @@ -52,28 +54,82 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : // Replace newlines with HTML breaks licenseInfoHTML.replace("\n\n", "<br><br>"); - ui->helpMessageLabel->setTextFormat(Qt::RichText); + ui->aboutMessage->setTextFormat(Qt::RichText); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); text = version + "\n" + licenseInfo; - ui->helpMessageLabel->setText(version + "<br><br>" + licenseInfoHTML); - ui->helpMessageLabel->setWordWrap(true); + ui->aboutMessage->setText(version + "<br><br>" + licenseInfoHTML); + ui->aboutMessage->setWordWrap(true); + ui->helpMessage->setVisible(false); } else { setWindowTitle(tr("Command-line options")); - QString header = tr("Usage:") + "\n" + - " bitcoin-qt [" + tr("command-line options") + "] " + "\n"; + QTextCursor cursor(ui->helpMessage->document()); + cursor.insertText(version); + cursor.insertBlock(); + cursor.insertText(tr("Usage:") + '\n' + + " bitcoin-qt [" + tr("command-line options") + "]\n"); + + cursor.insertBlock(); + QTextTableFormat tf; + tf.setBorderStyle(QTextFrameFormat::BorderStyle_None); + tf.setCellPadding(2); + QVector<QTextLength> widths; + widths << QTextLength(QTextLength::PercentageLength, 20); + widths << QTextLength(QTextLength::PercentageLength, 80); + tf.setColumnWidthConstraints(widths); + QTextTable *table = cursor.insertTable(2, 2, tf); QString coreOptions = QString::fromStdString(HelpMessage(HMM_BITCOIN_QT)); - - QString uiOptions = tr("UI options") + ":\n" + - " -choosedatadir " + tr("Choose data directory on startup (default: 0)") + "\n" + - " -lang=<lang> " + tr("Set language, for example \"de_DE\" (default: system locale)") + "\n" + - " -min " + tr("Start minimized") + "\n" + - " -rootcertificates=<file> " + tr("Set SSL root certificates for payment request (default: -system-)") + "\n" + - " -splash " + tr("Show splash screen on startup (default: 1)"); - - ui->helpMessageLabel->setFont(GUIUtil::bitcoinAddressFont()); - text = version + "\n" + header + "\n" + coreOptions + "\n" + uiOptions; - ui->helpMessageLabel->setText(text); + bool first = true; + QTextCharFormat bold; + bold.setFontWeight(QFont::Bold); + // note that coreOptions is not translated. + foreach (const QString &line, coreOptions.split('\n')) { + if (!first) { + table->appendRows(1); + cursor.movePosition(QTextCursor::NextRow); + } + first = false; + + if (line.startsWith(" ")) { + int index = line.indexOf(' ', 3); + if (index > 0) { + cursor.insertText(line.left(index).trimmed()); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(line.mid(index).trimmed()); + continue; + } + } + cursor.movePosition(QTextCursor::NextCell, QTextCursor::KeepAnchor); + table->mergeCells(cursor); + cursor.insertText(line.trimmed(), bold); + } + + table->appendRows(6); + cursor.movePosition(QTextCursor::NextRow); + cursor.insertText(tr("UI options") + ":", bold); + cursor.movePosition(QTextCursor::NextRow); + cursor.insertText("-choosedatadir"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Choose data directory on startup (default: 0)")); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("-lang=<lang>"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Set language, for example \"de_DE\" (default: system locale)")); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("-min"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Start minimized")); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("-rootcertificates=<file>"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Set SSL root certificates for payment request (default: -system-)")); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("-splash"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText(tr("Show splash screen on startup (default: 1)")); + + ui->helpMessage->moveCursor(QTextCursor::Start); + ui->scrollArea->setVisible(false); } } diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 372cf3b306..4406b08e56 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -8,6 +8,7 @@ #include "uint256.h" #include "arith_uint256.h" #include "version.h" +#include "random.h" #include <vector> @@ -21,8 +22,8 @@ class CPartialMerkleTreeTester : public CPartialMerkleTree public: // flip one bit in one of the hashes - this should break the authentication void Damage() { - unsigned int n = rand() % vHash.size(); - int bit = rand() % 256; + unsigned int n = insecure_rand() % vHash.size(); + int bit = insecure_rand() % 256; *(vHash[n].begin() + (bit>>3)) ^= 1<<(bit&7); } }; @@ -31,6 +32,7 @@ BOOST_AUTO_TEST_SUITE(pmt_tests) BOOST_AUTO_TEST_CASE(pmt_test1) { + seed_insecure_rand(false); static const unsigned int nTxCounts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095}; for (int n = 0; n < 12; n++) { @@ -40,7 +42,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1) CBlock block; for (unsigned int j=0; j<nTx; j++) { CMutableTransaction tx; - tx.nLockTime = rand(); // actual transaction data doesn't matter; just make the nLockTime's unique + tx.nLockTime = j; // actual transaction data doesn't matter; just make the nLockTime's unique block.vtx.push_back(CTransaction(tx)); } @@ -61,7 +63,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1) std::vector<bool> vMatch(nTx, false); std::vector<uint256> vMatchTxid1; for (unsigned int j=0; j<nTx; j++) { - bool fInclude = (rand() & ((1 << (att/2)) - 1)) == 0; + bool fInclude = (insecure_rand() & ((1 << (att/2)) - 1)) == 0; vMatch[j] = fInclude; if (fInclude) vMatchTxid1.push_back(vTxid[j]); |