From c5adf8f267b2b4b633af2738c8f21005d4382496 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 6 Jan 2017 10:42:27 +0100 Subject: [PATCH 01/34] [Qt] Show more significant warning if we fall back to the default fee --- src/qt/forms/sendcoinsdialog.ui | 20 ++++++++++++++++++++ src/qt/sendcoinsdialog.cpp | 2 ++ 2 files changed, 22 insertions(+) diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index ca8ecffafea..2eb3276a8de 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -759,11 +759,31 @@ + + + + Using the fallbackfee can result in sending a transaction that will take serval hours or days (or never) to confirm. Consider choosing your fee manually or wait until your have validated the complete chain. + + + color: rgb(255, 150, 0); +font-weight: bold; + + + Warning: Fee estimation is currently not possible. + + + false + + + Qt::Horizontal + + QSizePolicy::MinimumExpanding + 40 diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 5aeda7a30df..6180107b0e4 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -655,6 +655,7 @@ void SendCoinsDialog::updateSmartFeeLabel() std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB"); ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...) ui->labelFeeEstimation->setText(""); + ui->fallbackFeeWarningLabel->setVisible(true); } else { @@ -662,6 +663,7 @@ void SendCoinsDialog::updateSmartFeeLabel() std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB"); ui->labelSmartFee2->hide(); ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks)); + ui->fallbackFeeWarningLabel->setVisible(false); } updateFeeMinimizedLabel(); From e2073424fd5a185781750347fbfbb0c108ef66fd Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Mon, 9 Jan 2017 11:13:37 -0500 Subject: [PATCH 02/34] Fix CCheckQueue IsIdle (potential) race condition and remove dangerous constructors. --- src/checkqueue.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/checkqueue.h b/src/checkqueue.h index 32e25d5c8c6..ea12df66dd0 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -127,6 +127,9 @@ private: } public: + //! Mutex to ensure only one concurrent CCheckQueueControl + boost::mutex ControlMutex; + //! Create a new check queue CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {} @@ -161,12 +164,6 @@ public: { } - bool IsIdle() - { - boost::unique_lock lock(mutex); - return (nTotal == nIdle && nTodo == 0 && fAllOk == true); - } - }; /** @@ -177,16 +174,18 @@ template class CCheckQueueControl { private: - CCheckQueue* pqueue; + CCheckQueue * const pqueue; bool fDone; public: - CCheckQueueControl(CCheckQueue* pqueueIn) : pqueue(pqueueIn), fDone(false) + CCheckQueueControl() = delete; + CCheckQueueControl(const CCheckQueueControl&) = delete; + CCheckQueueControl& operator=(const CCheckQueueControl&) = delete; + explicit CCheckQueueControl(CCheckQueue * const pqueueIn) : pqueue(pqueueIn), fDone(false) { // passed queue is supposed to be unused, or NULL if (pqueue != NULL) { - bool isIdle = pqueue->IsIdle(); - assert(isIdle); + ENTER_CRITICAL_SECTION(pqueue->ControlMutex); } } @@ -209,6 +208,9 @@ public: { if (!fDone) Wait(); + if (pqueue != NULL) { + LEAVE_CRITICAL_SECTION(pqueue->ControlMutex); + } } }; From 96c7f2c3458950061b057fcd3daaf47b57e6bac7 Mon Sep 17 00:00:00 2001 From: Jeremy Rubin Date: Sat, 7 Jan 2017 19:51:23 -0500 Subject: [PATCH 03/34] Add CheckQueue Tests --- src/Makefile.test.include | 1 + src/test/checkqueue_tests.cpp | 442 ++++++++++++++++++++++++++++++++++ 2 files changed, 443 insertions(+) create mode 100644 src/test/checkqueue_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 27b456240e6..26b1b1067f7 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -67,6 +67,7 @@ BITCOIN_TESTS =\ test/blockencodings_tests.cpp \ test/bloom_tests.cpp \ test/bswap_tests.cpp \ + test/checkqueue_tests.cpp \ test/coins_tests.cpp \ test/compress_tests.cpp \ test/crypto_tests.cpp \ diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp new file mode 100644 index 00000000000..d89f9b770bc --- /dev/null +++ b/src/test/checkqueue_tests.cpp @@ -0,0 +1,442 @@ +// Copyright (c) 2012-2017 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 "util.h" +#include "utiltime.h" +#include "validation.h" + +#include "test/test_bitcoin.h" +#include "checkqueue.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "random.h" + +// BasicTestingSetup not sufficient because nScriptCheckThreads is not set +// otherwise. +BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, TestingSetup) + +static const int QUEUE_BATCH_SIZE = 128; + +struct FakeCheck { + bool operator()() + { + return true; + } + void swap(FakeCheck& x){}; +}; + +struct FakeCheckCheckCompletion { + static std::atomic n_calls; + bool operator()() + { + ++n_calls; + return true; + } + void swap(FakeCheckCheckCompletion& x){}; +}; + +struct FailingCheck { + bool fails; + FailingCheck(bool fails) : fails(fails){}; + FailingCheck() : fails(true){}; + bool operator()() + { + return !fails; + } + void swap(FailingCheck& x) + { + std::swap(fails, x.fails); + }; +}; + +struct UniqueCheck { + static std::mutex m; + static std::unordered_multiset results; + size_t check_id; + UniqueCheck(size_t check_id_in) : check_id(check_id_in){}; + UniqueCheck() : check_id(0){}; + bool operator()() + { + std::lock_guard l(m); + results.insert(check_id); + return true; + } + void swap(UniqueCheck& x) { std::swap(x.check_id, check_id); }; +}; + + +struct MemoryCheck { + static std::atomic fake_allocated_memory; + bool b {false}; + bool operator()() + { + return true; + } + MemoryCheck(){}; + MemoryCheck(const MemoryCheck& x) + { + // We have to do this to make sure that destructor calls are paired + // + // Really, copy constructor should be deletable, but CCheckQueue breaks + // if it is deleted because of internal push_back. + fake_allocated_memory += b; + }; + MemoryCheck(bool b_) : b(b_) + { + fake_allocated_memory += b; + }; + ~MemoryCheck(){ + fake_allocated_memory -= b; + + }; + void swap(MemoryCheck& x) { std::swap(b, x.b); }; +}; + +struct FrozenCleanupCheck { + static std::atomic nFrozen; + static std::condition_variable cv; + static std::mutex m; + // Freezing can't be the default initialized behavior given how the queue + // swaps in default initialized Checks. + bool should_freeze {false}; + bool operator()() + { + return true; + } + FrozenCleanupCheck() {} + ~FrozenCleanupCheck() + { + if (should_freeze) { + std::unique_lock l(m); + nFrozen = 1; + cv.notify_one(); + cv.wait(l, []{ return nFrozen == 0;}); + } + } + void swap(FrozenCleanupCheck& x){std::swap(should_freeze, x.should_freeze);}; +}; + +// Static Allocations +std::mutex FrozenCleanupCheck::m{}; +std::atomic FrozenCleanupCheck::nFrozen{0}; +std::condition_variable FrozenCleanupCheck::cv{}; +std::mutex UniqueCheck::m; +std::unordered_multiset UniqueCheck::results; +std::atomic FakeCheckCheckCompletion::n_calls{0}; +std::atomic MemoryCheck::fake_allocated_memory{0}; + +// Queue Typedefs +typedef CCheckQueue Correct_Queue; +typedef CCheckQueue Standard_Queue; +typedef CCheckQueue Failing_Queue; +typedef CCheckQueue Unique_Queue; +typedef CCheckQueue Memory_Queue; +typedef CCheckQueue FrozenCleanup_Queue; + + +/** This test case checks that the CCheckQueue works properly + * with each specified size_t Checks pushed. + */ +void Correct_Queue_range(std::vector range) +{ + auto small_queue = std::unique_ptr(new Correct_Queue {QUEUE_BATCH_SIZE}); + boost::thread_group tg; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{small_queue->Thread();}); + } + // Make vChecks here to save on malloc (this test can be slow...) + std::vector vChecks; + for (auto i : range) { + size_t total = i; + FakeCheckCheckCompletion::n_calls = 0; + CCheckQueueControl control(small_queue.get()); + while (total) { + vChecks.resize(std::min(total, (size_t) GetRand(10))); + total -= vChecks.size(); + control.Add(vChecks); + } + BOOST_REQUIRE(control.Wait()); + if (FakeCheckCheckCompletion::n_calls != i) { + BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i); + BOOST_TEST_MESSAGE("Failure on trial " << i << " expected, got " << FakeCheckCheckCompletion::n_calls); + } + } + tg.interrupt_all(); + tg.join_all(); +} + +/** Test that 0 checks is correct + */ +BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero) +{ + std::vector range; + range.push_back((size_t)0); + Correct_Queue_range(range); +} +/** Test that 1 check is correct + */ +BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_One) +{ + std::vector range; + range.push_back((size_t)1); + Correct_Queue_range(range); +} +/** Test that MAX check is correct + */ +BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Max) +{ + std::vector range; + range.push_back(100000); + Correct_Queue_range(range); +} +/** Test that random numbers of checks are correct + */ +BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random) +{ + std::vector range; + range.reserve(100000/1000); + for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)GetRand(std::min((size_t)1000, ((size_t)100000) - i)))) + range.push_back(i); + Correct_Queue_range(range); +} + + +/** Test that failing checks are caught */ +BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure) +{ + auto fail_queue = std::unique_ptr(new Failing_Queue {QUEUE_BATCH_SIZE}); + + boost::thread_group tg; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{fail_queue->Thread();}); + } + + for (size_t i = 0; i < 1001; ++i) { + CCheckQueueControl control(fail_queue.get()); + size_t remaining = i; + while (remaining) { + size_t r = GetRand(10); + + std::vector vChecks; + vChecks.reserve(r); + for (size_t k = 0; k < r && remaining; k++, remaining--) + vChecks.emplace_back(remaining == 1); + control.Add(vChecks); + } + bool success = control.Wait(); + if (i > 0) { + BOOST_REQUIRE(!success); + } else if (i == 0) { + BOOST_REQUIRE(success); + } + } + tg.interrupt_all(); + tg.join_all(); +} +// Test that a block validation which fails does not interfere with +// future blocks, ie, the bad state is cleared. +BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure) +{ + auto fail_queue = std::unique_ptr(new Failing_Queue {QUEUE_BATCH_SIZE}); + boost::thread_group tg; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{fail_queue->Thread();}); + } + + for (auto times = 0; times < 10; ++times) { + for (bool end_fails : {true, false}) { + CCheckQueueControl control(fail_queue.get()); + { + std::vector vChecks; + vChecks.resize(100, false); + vChecks[99] = end_fails; + control.Add(vChecks); + } + bool r =control.Wait(); + BOOST_REQUIRE(r || end_fails); + } + } + tg.interrupt_all(); + tg.join_all(); +} + +// Test that unique checks are actually all called individually, rather than +// just one check being called repeatedly. Test that checks are not called +// more than once as well +BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) +{ + auto queue = std::unique_ptr(new Unique_Queue {QUEUE_BATCH_SIZE}); + boost::thread_group tg; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{queue->Thread();}); + + } + + size_t COUNT = 100000; + size_t total = COUNT; + { + CCheckQueueControl control(queue.get()); + while (total) { + size_t r = GetRand(10); + std::vector vChecks; + for (size_t k = 0; k < r && total; k++) + vChecks.emplace_back(--total); + control.Add(vChecks); + } + } + bool r = true; + BOOST_REQUIRE_EQUAL(UniqueCheck::results.size(), COUNT); + for (size_t i = 0; i < COUNT; ++i) + r = r && UniqueCheck::results.count(i) == 1; + BOOST_REQUIRE(r); + tg.interrupt_all(); + tg.join_all(); +} + + +// Test that blocks which might allocate lots of memory free their memory agressively. +// +// This test attempts to catch a pathological case where by lazily freeing +// checks might mean leaving a check un-swapped out, and decreasing by 1 each +// time could leave the data hanging across a sequence of blocks. +BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) +{ + auto queue = std::unique_ptr(new Memory_Queue {QUEUE_BATCH_SIZE}); + boost::thread_group tg; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{queue->Thread();}); + } + for (size_t i = 0; i < 1000; ++i) { + size_t total = i; + { + CCheckQueueControl control(queue.get()); + while (total) { + size_t r = GetRand(10); + std::vector vChecks; + for (size_t k = 0; k < r && total; k++) { + total--; + // Each iteration leaves data at the front, back, and middle + // to catch any sort of deallocation failure + vChecks.emplace_back(total == 0 || total == i || total == i/2); + } + control.Add(vChecks); + } + } + BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0); + } + tg.interrupt_all(); + tg.join_all(); +} + +// Test that a new verification cannot occur until all checks +// have been destructed +BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup) +{ + auto queue = std::unique_ptr(new FrozenCleanup_Queue {QUEUE_BATCH_SIZE}); + boost::thread_group tg; + bool fails = false; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{queue->Thread();}); + } + std::thread t0([&]() { + CCheckQueueControl control(queue.get()); + std::vector vChecks(1); + // Freezing can't be the default initialized behavior given how the queue + // swaps in default initialized Checks (otherwise freezing destructor + // would get called twice). + vChecks[0].should_freeze = true; + control.Add(vChecks); + control.Wait(); // Hangs here + }); + { + std::unique_lock l(FrozenCleanupCheck::m); + // Wait until the queue has finished all jobs and frozen + FrozenCleanupCheck::cv.wait(l, [](){return FrozenCleanupCheck::nFrozen == 1;}); + // Try to get control of the queue a bunch of times + for (auto x = 0; x < 100 && !fails; ++x) { + fails = queue->ControlMutex.try_lock(); + } + // Unfreeze + FrozenCleanupCheck::nFrozen = 0; + } + // Awaken frozen destructor + FrozenCleanupCheck::cv.notify_one(); + // Wait for control to finish + t0.join(); + tg.interrupt_all(); + tg.join_all(); + BOOST_REQUIRE(!fails); +} + + +/** Test that CCheckQueueControl is threadsafe */ +BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks) +{ + auto queue = std::unique_ptr(new Standard_Queue{QUEUE_BATCH_SIZE}); + { + boost::thread_group tg; + std::atomic nThreads {0}; + std::atomic fails {0}; + for (size_t i = 0; i < 3; ++i) { + tg.create_thread( + [&]{ + CCheckQueueControl control(queue.get()); + // While sleeping, no other thread should execute to this point + auto observed = ++nThreads; + MilliSleep(10); + fails += observed != nThreads; + }); + } + tg.join_all(); + BOOST_REQUIRE_EQUAL(fails, 0); + } + { + boost::thread_group tg; + std::mutex m; + bool has_lock {false}; + bool has_tried {false}; + bool done {false}; + bool done_ack {false}; + std::condition_variable cv; + { + std::unique_lock l(m); + tg.create_thread([&]{ + CCheckQueueControl control(queue.get()); + std::unique_lock l(m); + has_lock = true; + cv.notify_one(); + cv.wait(l, [&]{return has_tried;}); + done = true; + cv.notify_one(); + // Wait until the done is acknowledged + // + cv.wait(l, [&]{return done_ack;}); + }); + // Wait for thread to get the lock + cv.wait(l, [&](){return has_lock;}); + bool fails = false; + for (auto x = 0; x < 100 && !fails; ++x) { + fails = queue->ControlMutex.try_lock(); + } + has_tried = true; + cv.notify_one(); + cv.wait(l, [&](){return done;}); + // Acknowledge the done + done_ack = true; + cv.notify_one(); + BOOST_REQUIRE(!fails); + } + tg.join_all(); + } +} +BOOST_AUTO_TEST_SUITE_END() + From 3e4d7bfcb7d9f6d88b6120f44bb6cb7fa93d7adf Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 17 Feb 2017 08:18:32 +0000 Subject: [PATCH 04/34] Qt/Send: Figure a decent warning colour from theme --- src/qt/forms/sendcoinsdialog.ui | 8 +++++--- src/qt/sendcoinsdialog.cpp | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 2eb3276a8de..ca2da6bf372 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -764,9 +764,11 @@ Using the fallbackfee can result in sending a transaction that will take serval hours or days (or never) to confirm. Consider choosing your fee manually or wait until your have validated the complete chain. - - color: rgb(255, 150, 0); -font-weight: bold; + + + 75 + true + Warning: Fee estimation is currently not possible. diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 6180107b0e4..d39f92dda3a 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -656,6 +656,9 @@ void SendCoinsDialog::updateSmartFeeLabel() ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...) ui->labelFeeEstimation->setText(""); ui->fallbackFeeWarningLabel->setVisible(true); + int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness(); + QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14)); + ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }"); } else { From 7abe7bbf61d90dc003647f2cc5019e4652182399 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 17 Feb 2017 08:41:57 +0000 Subject: [PATCH 05/34] Qt/Send: Give fallback fee a reasonable indent --- src/qt/sendcoinsdialog.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index d39f92dda3a..39f8285014a 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -22,6 +22,7 @@ #include "txmempool.h" #include "wallet/wallet.h" +#include #include #include #include @@ -659,6 +660,7 @@ void SendCoinsDialog::updateSmartFeeLabel() int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness(); QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14)); ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }"); + ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(ui->fallbackFeeWarningLabel->font()).width("x")); } else { From d28d58382076c77dc7f8ec59997c5ce2fde99f70 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 3 Apr 2017 16:31:51 -0400 Subject: [PATCH 06/34] Bugfix: PrioritiseTransaction updates the mempool tx counter The mempool's nTransactionsUpdated is used by getblocktemplate to trigger new invocations of CreateNewBlock(). Github-Pull: #10196 Rebased-From: 909306cde3770ed7019e7b635e24cedbd9de66ce --- src/txmempool.cpp | 1 + src/txmempool.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 91040fb9b21..72547b58282 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -945,6 +945,7 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const std::string str BOOST_FOREACH(txiter descendantIt, setDescendants) { mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0)); } + ++nTransactionsUpdated; } } LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta)); diff --git a/src/txmempool.h b/src/txmempool.h index db1a02455f8..12c9e59f5f0 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -432,7 +432,7 @@ class CTxMemPool { private: uint32_t nCheckFrequency; //!< Value n means that n times in 2^32 we check. - unsigned int nTransactionsUpdated; + unsigned int nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation CBlockPolicyEstimator* minerPolicyEstimator; uint64_t totalTxSize; //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141. From 71463a7d18bb143da62e790f9194193dfaf8f320 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Tue, 18 Apr 2017 12:52:08 -0400 Subject: [PATCH 07/34] [qa] Test prioritise_transaction / getblocktemplate interaction Github-Pull: #10196 Rebased-From: 6a61424c9eed072ae8d79d68aac71f525c1608b5 --- qa/rpc-tests/prioritise_transaction.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py index b7459c80cbd..16874a6b53b 100755 --- a/qa/rpc-tests/prioritise_transaction.py +++ b/qa/rpc-tests/prioritise_transaction.py @@ -16,7 +16,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework): def __init__(self): super().__init__() self.setup_clean_chain = True - self.num_nodes = 1 + self.num_nodes = 2 self.txouts = gen_return_txouts() @@ -25,8 +25,11 @@ class PrioritiseTransactionTest(BitcoinTestFramework): self.is_network_split = False self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-printpriority=1"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-printpriority=1"])) + connect_nodes(self.nodes[0], 1) self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] + def run_test(self): utxo_count = 90 utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], utxo_count) @@ -139,5 +142,16 @@ class PrioritiseTransactionTest(BitcoinTestFramework): assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id) assert(tx2_id in self.nodes[0].getrawmempool()) + # Test that calling prioritisetransaction is sufficient to trigger + # getblocktemplate to (eventually) return a new block. + mock_time = int(time.time()) + self.nodes[0].setmocktime(mock_time) + template = self.nodes[0].getblocktemplate() + self.nodes[0].prioritisetransaction(txid, 0, -int(self.relayfee*COIN)) + self.nodes[0].setmocktime(mock_time+10) + new_template = self.nodes[0].getblocktemplate() + + assert(template != new_template) + if __name__ == '__main__': PrioritiseTransactionTest().main() From ef810c4cd440dec00a651b944d74ed4ae85603c2 Mon Sep 17 00:00:00 2001 From: practicalswift Date: Thu, 16 Mar 2017 09:05:30 +0100 Subject: [PATCH 08/34] [trivial] Fix a typo (introduced two days ago) in the default fee warning Github-Pull: #10008 Rebased-From: a3ca43bb32520fdc049bc2112a29a554188126cc --- src/qt/forms/sendcoinsdialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index ca2da6bf372..f13b0d9cf92 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -762,7 +762,7 @@ - Using the fallbackfee can result in sending a transaction that will take serval hours or days (or never) to confirm. Consider choosing your fee manually or wait until your have validated the complete chain. + Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until your have validated the complete chain. From c94e262d4bf64f75e97d478a5a2e8d75067d43e3 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 3 May 2017 09:54:35 -0400 Subject: [PATCH 09/34] Update contrib/debian to latest Ubuntu PPA upload. This: * Partially reverts 9f68ed6 (which fixed spelling in a changelog, though generally changelogs should be append-only). * Disables UPnP support (PPA has not had it for a while, and I still don't trust miniupnpc, plus it seems uneccessary - its been a while since we needed to care about Bitcoin-Qt home users getting their inbound ports auto-mapped). * Enables ZMQ. * Forces GUI to Qt4 to fix various issues people have been seeing on Ubuntu and elsewhere with Qt5. * Reverts 70899d70b (Bitcoin does not enable "instant payments", not is transaction management "carried out collectively by the network", for whatever "transaction management" means, finally Bitcoin Core is not the only way to use the Bitcoin currency, as seemingly implied in the description). Github-Pull: #10328 Rebased-From: 997021986e02f8e59024ffca6437857d9d17f396 --- contrib/debian/changelog | 107 +++++++++++++++++++++++++++++++++++++-- contrib/debian/control | 50 +++++++++--------- contrib/debian/rules | 2 +- 3 files changed, 131 insertions(+), 28 deletions(-) diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 110bfe03eff..4f73f6042c5 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,104 @@ +bitcoin (0.14.1-trusty1) trusty; urgency=medium + + * New upstream release. + + -- Matt Corallo (BlueMatt) Sat, 22 Apr 2017 17:10:00 -0400 + +bitcoin (0.14.0-trusty1) trusty; urgency=medium + + * New upstream release. + + -- Matt Corallo (BlueMatt) Wed, 08 Mar 2017 10:30:00 -0500 + +bitcoin (0.13.2-trusty1) trusty; urgency=medium + + * New upstream release. + + -- Matt Corallo (BlueMatt) Thu, 05 Jan 2017 09:59:00 -0500 + +bitcoin (0.13.1-trusty2) trusty; urgency=medium + + * Revert to Qt4, due to https://github.com/bitcoin/bitcoin/issues/9038 + + -- Matt Corallo (BlueMatt) Mon, 31 Oct 2016 11:16:00 -0400 + +bitcoin (0.13.1-trusty1) trusty; urgency=medium + + * New upstream release. + * Backport updated bitcoin-qt.desktop from upstream master + * Add zmq dependency + * Switch to Qt5 (breaks precise, but that was already broken by C++11) + + -- Matt Corallo (BlueMatt) Thu, 27 Oct 2016 17:32:00 -0400 + +bitcoin (0.13.0-trusty1) trusty; urgency=medium + + * New upstream release. + + -- Matt Corallo (BlueMatt) Sun, 04 Sep 2016 22:09:00 -0400 + +bitcoin (0.12.1-trusty1) trusty; urgency=medium + + * New upstream release. + + -- Matt Corallo (BlueMatt) Mon, 18 Apr 2016 14:26:00 -0700 + +bitcoin (0.12.0-trusty6) trusty; urgency=medium + + * Fix program-options dep. + + -- Matt Corallo (BlueMatt) Fri, 25 Mar 2016 21:41:00 -0700 + +bitcoin (0.12.0-trusty5) trusty; urgency=medium + + * Test explicit --with-gui + + -- Matt Corallo (BlueMatt) Tue, 23 Feb 2015 23:25:00 -0800 + +bitcoin (0.12.0-trusty4) trusty; urgency=medium + + * Fix libevent-dev dep. + + -- Matt Corallo (BlueMatt) Tue, 23 Feb 2015 23:25:00 -0800 + +bitcoin (0.12.0-trusty3) trusty; urgency=medium + + * Fix precise boost dep. + + -- Matt Corallo (BlueMatt) Tue, 23 Feb 2015 19:55:00 -0800 + +bitcoin (0.12.0-trusty2) trusty; urgency=medium + + * Fix libevent dep. + + -- Matt Corallo (BlueMatt) Tue, 23 Feb 2015 19:53:00 -0800 + +bitcoin (0.12.0-trusty1) trusty; urgency=medium + + * New upstream release + * Various updates to contrib/debian were merged, a few were not + + -- Matt Corallo (BlueMatt) Tue, 23 Feb 2015 19:29:00 -0800 + +bitcoin (0.11.2-trusty1) trusty; urgency=low + + * New upstream release. + + -- Matt Corallo (BlueMatt) Fri, 13 Nov 2015 18:39:00 -0800 + +bitcoin (0.11.1-trusty2) trusty; urgency=low + + * Remove minupnpc builddep. + + -- Matt Corallo (BlueMatt) Wed, 14 Oct 2015 23:06:00 -1000 + +bitcoin (0.11.1-trusty1) trusty; urgency=high + + * New upstream release. + * Disable all UPnP support. + + -- Matt Corallo (BlueMatt) Wed, 14 Oct 2015 13:57:00 -1000 + bitcoin (0.11.0-precise1) precise; urgency=medium * New upstream release. @@ -179,7 +280,7 @@ bitcoin (0.5.3-natty0) natty; urgency=low bitcoin (0.5.2-natty1) natty; urgency=low * Remove mentions on anonymity in package descriptions and manpage. - These should never have been there, bitcoin isn't anonymous without + These should never have been there, bitcoin isnt anonymous without a ton of work that virtually no users will ever be willing and capable of doing @@ -220,7 +321,7 @@ bitcoin (0.5.0~rc1-natty1) natty; urgency=low * Add test_bitcoin to build test * Fix clean - * Remove unnecessary build-dependancies + * Remove uneccessary build-dependancies -- Matt Corallo Wed, 26 Oct 2011 14:37:18 -0400 @@ -380,7 +481,7 @@ bitcoin (0.3.20.01~dfsg-1) unstable; urgency=low bitcoin (0.3.19~dfsg-6) unstable; urgency=low - * Fix override aggressive optimizations. + * Fix override agressive optimizations. * Fix tighten build-dependencies to really fit backporting to Lenny: + Add fallback build-dependency on libdb4.6++-dev. + Tighten unversioned Boost build-dependencies to recent versions, diff --git a/contrib/debian/control b/contrib/debian/control index fce6bc0118f..8cb703e1bc0 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -1,27 +1,29 @@ Source: bitcoin Section: utils Priority: optional -Maintainer: Jonas Smedegaard -Uploaders: Micah Anderson +Maintainer: Matt Corallo +Uploaders: Matt Corallo Build-Depends: debhelper, devscripts, automake, libtool, bash-completion, - libboost-system-dev (>> 1.35) | libboost-system1.35-dev, libdb4.8++-dev, libssl-dev, pkg-config, - libminiupnpc8-dev | libminiupnpc-dev (>> 1.6), - libboost-filesystem-dev (>> 1.35) | libboost-filesystem1.35-dev, - libboost-program-options-dev (>> 1.35) | libboost-program-options1.35-dev, - libboost-thread-dev (>> 1.35) | libboost-thread1.35-dev, - libboost-test-dev (>> 1.35) | libboost-test1.35-dev, + libevent-dev, + libboost-system1.48-dev | libboost-system-dev (>> 1.35), + libboost-filesystem1.48-dev | libboost-filesystem-dev (>> 1.35), + libboost-program-options1.48-dev | libboost-program-options-dev (>> 1.35), + libboost-thread1.48-dev | libboost-thread-dev (>> 1.35), + libboost-test1.48-dev | libboost-test-dev (>> 1.35), + libboost-chrono1.48-dev | libboost-chrono-dev (>> 1.35), qt4-qmake, libqt4-dev, libqrencode-dev, libprotobuf-dev, protobuf-compiler, - python + python, + libzmq3-dev Standards-Version: 3.9.2 Homepage: https://bitcoincore.org/ Vcs-Git: git://github.com/bitcoin/bitcoin.git @@ -31,11 +33,11 @@ Package: bitcoind Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer network based digital currency - daemon - Bitcoin is an experimental new digital currency that enables instant - payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer - technology to operate with no central authority: managing transactions - and issuing money are carried out collectively by the network. Bitcoin Core - is the name of the open source software which enables the use of this currency. + Bitcoin is a free open source peer-to-peer electronic cash system that + is completely decentralized, without the need for a central server or + trusted parties. Users hold the crypto keys to their own money and + transact directly with each other, with the help of a P2P network to + check for double-spending. . This package provides the daemon, bitcoind, and the CLI tool bitcoin-cli to interact with the daemon. @@ -44,11 +46,11 @@ Package: bitcoin-qt Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer network based digital currency - Qt GUI - Bitcoin is an experimental new digital currency that enables instant - payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer - technology to operate with no central authority: managing transactions - and issuing money are carried out collectively by the network. Bitcoin Core - is the name of the open source software which enables the use of this currency. + Bitcoin is a free open source peer-to-peer electronic cash system that + is completely decentralized, without the need for a central server or + trusted parties. Users hold the crypto keys to their own money and + transact directly with each other, with the help of a P2P network to + check for double-spending. . This package provides Bitcoin-Qt, a GUI for Bitcoin based on Qt. @@ -56,11 +58,11 @@ Package: bitcoin-tx Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: peer-to-peer digital currency - standalone transaction tool - Bitcoin is an experimental new digital currency that enables instant - payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer - technology to operate with no central authority: managing transactions - and issuing money are carried out collectively by the network. Bitcoin Core - is the name of the open source software which enables the use of this currency. + Bitcoin is a free open source peer-to-peer electronic cash system that + is completely decentralized, without the need for a central server or + trusted parties. Users hold the crypto keys to their own money and + transact directly with each other, with the help of a P2P network to + check for double-spending. . This package provides bitcoin-tx, a command-line transaction creation tool which can be used without a bitcoin daemon. Some means of diff --git a/contrib/debian/rules b/contrib/debian/rules index 3896d2caa31..8db0b2dba58 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -15,7 +15,7 @@ override_dh_auto_clean: # Yea, autogen should be run on the source archive, but I like doing git archive override_dh_auto_configure: ./autogen.sh - ./configure + ./configure --without-miniupnpc --with-gui=qt4 override_dh_auto_test: make check From 2ea035832f0ba56db046eff318d3b91f097e1ca4 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 4 May 2017 17:13:41 -0400 Subject: [PATCH 10/34] Bump minimum boost version in contrib/debian Github-Pull: #10328 Rebased-From: a8e928699a6ab612459e836ba24af143eae37b0f --- contrib/debian/changelog | 6 ++++++ contrib/debian/control | 12 ++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 4f73f6042c5..f38d6da83ac 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +bitcoin (0.14.1-trusty2) trusty; urgency=medium + + * Bump minimum boost version in deps. + + -- Matt Corallo (BlueMatt) Thu, 04 May 2017 17:12:00 -0400 + bitcoin (0.14.1-trusty1) trusty; urgency=medium * New upstream release. diff --git a/contrib/debian/control b/contrib/debian/control index 8cb703e1bc0..53dd4faf417 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -12,12 +12,12 @@ Build-Depends: debhelper, libssl-dev, pkg-config, libevent-dev, - libboost-system1.48-dev | libboost-system-dev (>> 1.35), - libboost-filesystem1.48-dev | libboost-filesystem-dev (>> 1.35), - libboost-program-options1.48-dev | libboost-program-options-dev (>> 1.35), - libboost-thread1.48-dev | libboost-thread-dev (>> 1.35), - libboost-test1.48-dev | libboost-test-dev (>> 1.35), - libboost-chrono1.48-dev | libboost-chrono-dev (>> 1.35), + libboost-system1.48-dev | libboost-system-dev (>> 1.47), + libboost-filesystem1.48-dev | libboost-filesystem-dev (>> 1.47), + libboost-program-options1.48-dev | libboost-program-options-dev (>> 1.47), + libboost-thread1.48-dev | libboost-thread-dev (>> 1.47), + libboost-test1.48-dev | libboost-test-dev (>> 1.47), + libboost-chrono1.48-dev | libboost-chrono-dev (>> 1.47), qt4-qmake, libqt4-dev, libqrencode-dev, From e9a0d89bf7593a1ae7ac9b059793281f0b754540 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 4 May 2017 17:15:16 -0400 Subject: [PATCH 11/34] Build with QT5 on Debian-based systems using contrib/debian Github-Pull: #10328 Rebased-From: c5071e1f03085b4025f2a33fb2c3079d823d660c --- contrib/debian/changelog | 6 ++++++ contrib/debian/control | 4 ++-- contrib/debian/rules | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/contrib/debian/changelog b/contrib/debian/changelog index f38d6da83ac..1bef910398c 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +bitcoin (0.14.1-trusty3) trusty; urgency=medium + + * Build with qt5 if we are on a non-Ubuntu (ie non-Unity) distro. + + -- Matt Corallo (BlueMatt) Thu, 04 May 2017 17:13:00 -0400 + bitcoin (0.14.1-trusty2) trusty; urgency=medium * Bump minimum boost version in deps. diff --git a/contrib/debian/control b/contrib/debian/control index 53dd4faf417..523b4f936b3 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -18,8 +18,8 @@ Build-Depends: debhelper, libboost-thread1.48-dev | libboost-thread-dev (>> 1.47), libboost-test1.48-dev | libboost-test-dev (>> 1.47), libboost-chrono1.48-dev | libboost-chrono-dev (>> 1.47), - qt4-qmake, - libqt4-dev, + qt4-qmake, libqt4-dev, + qttools5-dev-tools, qttools5-dev, libqrencode-dev, libprotobuf-dev, protobuf-compiler, python, diff --git a/contrib/debian/rules b/contrib/debian/rules index 8db0b2dba58..354f15f320e 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -12,10 +12,12 @@ override_dh_auto_clean: if [ -f Makefile ]; then $(MAKE) distclean; fi rm -rf Makefile.in aclocal.m4 configure src/Makefile.in src/bitcoin-config.h.in src/build-aux src/qt/Makefile.in src/qt/test/Makefile.in src/test/Makefile.in +QT=$(shell dpkg-vendor --derives-from Ubuntu && echo qt4 || echo qt5) + # Yea, autogen should be run on the source archive, but I like doing git archive override_dh_auto_configure: ./autogen.sh - ./configure --without-miniupnpc --with-gui=qt4 + ./configure --without-miniupnpc --with-gui=$(QT) override_dh_auto_test: make check From 6ad45b8f8bd1f33842160d109d391deae0d615e7 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 5 May 2017 13:29:18 -0400 Subject: [PATCH 12/34] Re-enable upnp support in contrib/debian Github-Pull: #10328 Rebased-From: 91700aa1df57c1a9209284e743224119396604d5 --- contrib/debian/changelog | 6 ++++++ contrib/debian/control | 1 + contrib/debian/rules | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/contrib/debian/changelog b/contrib/debian/changelog index 1bef910398c..33dab9b6388 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,9 @@ +bitcoin (0.14.1-trusty4) trusty; urgency=medium + + * Re-enable UPnP support. + + -- Matt Corallo (BlueMatt) Fri, 05 May 2017 13:28:00 -0400 + bitcoin (0.14.1-trusty3) trusty; urgency=medium * Build with qt5 if we are on a non-Ubuntu (ie non-Unity) distro. diff --git a/contrib/debian/control b/contrib/debian/control index 523b4f936b3..0d6ad25e249 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -18,6 +18,7 @@ Build-Depends: debhelper, libboost-thread1.48-dev | libboost-thread-dev (>> 1.47), libboost-test1.48-dev | libboost-test-dev (>> 1.47), libboost-chrono1.48-dev | libboost-chrono-dev (>> 1.47), + libminiupnpc8-dev | libminiupnpc-dev, qt4-qmake, libqt4-dev, qttools5-dev-tools, qttools5-dev, libqrencode-dev, diff --git a/contrib/debian/rules b/contrib/debian/rules index 354f15f320e..6885e385212 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -17,7 +17,7 @@ QT=$(shell dpkg-vendor --derives-from Ubuntu && echo qt4 || echo qt5) # Yea, autogen should be run on the source archive, but I like doing git archive override_dh_auto_configure: ./autogen.sh - ./configure --without-miniupnpc --with-gui=$(QT) + ./configure --with-gui=$(QT) override_dh_auto_test: make check From 3ad00b4b32842e005af6378fd71eb9e293804cef Mon Sep 17 00:00:00 2001 From: John Newbery Date: Tue, 7 Feb 2017 14:27:57 -0500 Subject: [PATCH 13/34] Return correct error codes in bumpfee(). The bumpfee() RPC was returning misleading or incorrect error codes (for example RPC_INVALID_ADDRESS_OR_KEY when the transaction was not BIP125 replacable). This commit fixes those error codes: - RPC_INVALID_ADDRESS_OR_KEY if an invalid address was provided: - Invalid change address given - RPC_INVALID_PARAMETER if a single (non-address/key) parameter is incorrect - confTarget and totalFee options should not both be set. - Invalid confTarget - Insufficient totalFee (cannot be less than required fee) - RPC_WALLET_ERROR for any other error - Transaction has descendants in the wallet - Transaction has descendants in the mempool - Transaction has been mined, or is conflicted with a mined transaction - Transaction is not BIP 125 replaceable - Transaction has already been bumped - Transaction contains inputs that don't belong to the wallet - Transaction has multiple change outputs - Transaction does not have a change output - Fee is higher than maxTxFee - New fee rate is less than the minimum fee rate - Change output is too small. This commit also updates the test cases to explicitly test the error code. Github-Pull: #9853 Rebased-From: 6d07c62322f60eb2702c6654e994fc353bcfcf8c --- qa/rpc-tests/bumpfee.py | 18 ++++++++---------- src/wallet/rpcwallet.cpp | 24 ++++++++++++------------ 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/qa/rpc-tests/bumpfee.py b/qa/rpc-tests/bumpfee.py index ac282796c14..7ed2beb176e 100755 --- a/qa/rpc-tests/bumpfee.py +++ b/qa/rpc-tests/bumpfee.py @@ -129,7 +129,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address): def test_nonrbf_bumpfee_fails(peer_node, dest_address): # cannot replace a non RBF transaction (from node which did not enable RBF) not_rbfid = create_fund_sign_send(peer_node, {dest_address: 0.00090000}) - assert_raises_message(JSONRPCException, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid) + assert_raises_jsonrpc(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid) def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address): @@ -149,7 +149,7 @@ def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address): signedtx = rbf_node.signrawtransaction(rawtx) signedtx = peer_node.signrawtransaction(signedtx["hex"]) rbfid = rbf_node.sendrawtransaction(signedtx["hex"]) - assert_raises_message(JSONRPCException, "Transaction contains inputs that don't belong to this wallet", + assert_raises_jsonrpc(-4, "Transaction contains inputs that don't belong to this wallet", rbf_node.bumpfee, rbfid) @@ -160,7 +160,7 @@ def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address) tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000}) tx = rbf_node.signrawtransaction(tx) txid = rbf_node.sendrawtransaction(tx["hex"]) - assert_raises_message(JSONRPCException, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) + assert_raises_jsonrpc(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) def test_small_output_fails(rbf_node, dest_address): @@ -175,7 +175,7 @@ def test_small_output_fails(rbf_node, dest_address): Decimal("0.00100000"), {dest_address: 0.00080000, get_change_address(rbf_node): Decimal("0.00010000")}) - assert_raises_message(JSONRPCException, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 20001}) + assert_raises_jsonrpc(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 20001}) def test_dust_to_fee(rbf_node, dest_address): @@ -210,7 +210,7 @@ def test_rebumping(rbf_node, dest_address): rbf_node.settxfee(Decimal("0.00001000")) rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000}) bumped = rbf_node.bumpfee(rbfid, {"totalFee": 1000}) - assert_raises_message(JSONRPCException, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 2000}) + assert_raises_jsonrpc(-4, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 2000}) rbf_node.bumpfee(bumped["txid"], {"totalFee": 2000}) @@ -218,7 +218,7 @@ def test_rebumping_not_replaceable(rbf_node, dest_address): # check that re-bumping a non-replaceable bump tx fails rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000}) bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False}) - assert_raises_message(JSONRPCException, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], + assert_raises_jsonrpc(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], {"totalFee": 20000}) @@ -269,7 +269,7 @@ def test_bumpfee_metadata(rbf_node, dest_address): def test_locked_wallet_fails(rbf_node, dest_address): rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000}) rbf_node.walletlock() - assert_raises_message(JSONRPCException, "Please enter the wallet passphrase with walletpassphrase first.", + assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first.", rbf_node.bumpfee, rbfid) @@ -316,9 +316,7 @@ def submit_block_with_tx(node, tx): block.rehash() block.hashMerkleRoot = block.calc_merkle_root() block.solve() - error = node.submitblock(bytes_to_hex_str(block.serialize(True))) - if error is not None: - raise Exception(error) + node.submitblock(bytes_to_hex_str(block.serialize(True))) return block diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5cf1592376f..c141c0ca159 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2603,7 +2603,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) CBitcoinAddress address(options["changeAddress"].get_str()); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid bitcoin address"); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address"); changeAddress = address.Get(); } @@ -2756,33 +2756,33 @@ UniValue bumpfee(const JSONRPCRequest& request) CWalletTx& wtx = pwalletMain->mapWallet[hash]; if (pwalletMain->HasWalletSpend(hash)) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the wallet"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction has descendants in the wallet"); } { LOCK(mempool.cs); auto it = mempool.mapTx.find(hash); if (it != mempool.mapTx.end() && it->GetCountWithDescendants() > 1) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the mempool"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction has descendants in the mempool"); } } if (wtx.GetDepthInMainChain() != 0) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction has been mined, or is conflicted with a mined transaction"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction has been mined, or is conflicted with a mined transaction"); } if (!SignalsOptInRBF(wtx)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction is not BIP 125 replaceable"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction is not BIP 125 replaceable"); } if (wtx.mapValue.count("replaced_by_txid")) { - throw JSONRPCError(RPC_INVALID_REQUEST, strprintf("Cannot bump transaction %s which was already bumped by transaction %s", hash.ToString(), wtx.mapValue.at("replaced_by_txid"))); + throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Cannot bump transaction %s which was already bumped by transaction %s", hash.ToString(), wtx.mapValue.at("replaced_by_txid"))); } // check that original tx consists entirely of our inputs // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee) if (!pwalletMain->IsAllFromMe(wtx, ISMINE_SPENDABLE)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction contains inputs that don't belong to this wallet"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction contains inputs that don't belong to this wallet"); } // figure out which output was change @@ -2791,13 +2791,13 @@ UniValue bumpfee(const JSONRPCRequest& request) for (size_t i = 0; i < wtx.tx->vout.size(); ++i) { if (pwalletMain->IsChange(wtx.tx->vout[i])) { if (nOutput != -1) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction has multiple change outputs"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction has multiple change outputs"); } nOutput = i; } } if (nOutput == -1) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction does not have a change output"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction does not have a change output"); } // Calculate the expected size of the new transaction. @@ -2888,7 +2888,7 @@ UniValue bumpfee(const JSONRPCRequest& request) // Check that in all cases the new fee doesn't violate maxTxFee if (nNewFee > maxTxFee) { - throw JSONRPCError(RPC_MISC_ERROR, + throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)", FormatMoney(nNewFee), FormatMoney(maxTxFee))); } @@ -2900,7 +2900,7 @@ UniValue bumpfee(const JSONRPCRequest& request) // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment. CFeeRate minMempoolFeeRate = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) { - throw JSONRPCError(RPC_MISC_ERROR, strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK()))); + throw JSONRPCError(RPC_WALLET_ERROR, strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK()))); } // Now modify the output to increase the fee. @@ -2910,7 +2910,7 @@ UniValue bumpfee(const JSONRPCRequest& request) CMutableTransaction tx(*(wtx.tx)); CTxOut* poutput = &(tx.vout[nOutput]); if (poutput->nValue < nDelta) { - throw JSONRPCError(RPC_MISC_ERROR, "Change output is too small to bump the fee"); + throw JSONRPCError(RPC_WALLET_ERROR, "Change output is too small to bump the fee"); } // If the output would become dust, discard it (converting the dust to fee) From fe51c8924e62bf146a722f632324c99c2f97bc75 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 9 Feb 2017 16:39:18 -0500 Subject: [PATCH 14/34] Return correct error codes in blockchain.cpp. RPCs in blockchain.cpp were returning misleading or incorrect error codes (for example getblock() returning RPC_INTERNAL_ERROR when the block had been pruned). This commit fixes those error codes: - RPC_INTERNAL_ERROR should not be returned for application-level errors, only for genuine internal errors such as corrupted data. - RPC_METHOD_NOT_FOUND should not be returned in response to a JSON request for an existing method. Those error codes have been replaced with RPC_MISC_ERROR or RPC_INVALID_PARAMETER as appropriate. Github-Pull: #9853 Rebased-From: c1190963b388590dc0a346bf625c7e84f69cee8d --- qa/rpc-tests/p2p-acceptblock.py | 30 +++++++++--------------------- qa/rpc-tests/pruning.py | 31 +++++++++++-------------------- src/rpc/blockchain.cpp | 17 +++++++++++------ 3 files changed, 31 insertions(+), 47 deletions(-) diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py index 015ec34effa..4ebf2766202 100755 --- a/qa/rpc-tests/p2p-acceptblock.py +++ b/qa/rpc-tests/p2p-acceptblock.py @@ -199,11 +199,8 @@ class AcceptBlockTest(BitcoinTestFramework): assert_equal(x['status'], "headers-only") # But this block should be accepted by node0 since it has more work. - try: - self.nodes[0].getblock(blocks_h3[0].hash) - print("Unrequested more-work block accepted from non-whitelisted peer") - except: - raise AssertionError("Unrequested more work block was not processed") + self.nodes[0].getblock(blocks_h3[0].hash) + print("Unrequested more-work block accepted from non-whitelisted peer") # Node1 should have accepted and reorged. assert_equal(self.nodes[1].getblockcount(), 3) @@ -227,26 +224,17 @@ class AcceptBlockTest(BitcoinTestFramework): tips[j] = next_block time.sleep(2) - for x in all_blocks: - try: - self.nodes[0].getblock(x.hash) - if x == all_blocks[287]: - raise AssertionError("Unrequested block too far-ahead should have been ignored") - except: - if x == all_blocks[287]: - print("Unrequested block too far-ahead not processed") - else: - raise AssertionError("Unrequested block with more work should have been accepted") + # Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead + for x in all_blocks[:-1]: + self.nodes[0].getblock(x.hash) + assert_raises_jsonrpc(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash) headers_message.headers.pop() # Ensure the last block is unrequested white_node.send_message(headers_message) # Send headers leading to tip white_node.send_message(msg_block(tips[1])) # Now deliver the tip - try: - white_node.sync_with_ping() - self.nodes[1].getblock(tips[1].hash) - print("Unrequested block far ahead of tip accepted from whitelisted peer") - except: - raise AssertionError("Unrequested block from whitelisted peer not accepted") + white_node.sync_with_ping() + self.nodes[1].getblock(tips[1].hash) + print("Unrequested block far ahead of tip accepted from whitelisted peer") # 5. Test handling of unrequested block on the node that didn't process # Should still not be processed (even though it has a child that has more diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py index 1e6d4191869..3308bd1dc5e 100755 --- a/qa/rpc-tests/pruning.py +++ b/qa/rpc-tests/pruning.py @@ -186,11 +186,8 @@ class PruneTest(BitcoinTestFramework): def reorg_back(self): # Verify that a block on the old main chain fork has been pruned away - try: - self.nodes[2].getblock(self.forkhash) - raise AssertionError("Old block wasn't pruned so can't test redownload") - except JSONRPCException as e: - print("Will need to redownload block",self.forkheight) + assert_raises_jsonrpc(-1, "Block not available (pruned data)", self.nodes[2].getblock, self.forkhash) + print("Will need to redownload block",self.forkheight) # Verify that we have enough history to reorg back to the fork point # Although this is more than 288 blocks, because this chain was written more recently @@ -235,7 +232,7 @@ class PruneTest(BitcoinTestFramework): # at this point, node has 995 blocks and has not yet run in prune mode node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0"], timewait=900) assert_equal(node.getblockcount(), 995) - assert_raises_message(JSONRPCException, "not in prune mode", node.pruneblockchain, 500) + assert_raises_jsonrpc(-1, "not in prune mode", node.pruneblockchain, 500) self.stop_node(node_number) # now re-start in manual pruning mode @@ -267,14 +264,14 @@ class PruneTest(BitcoinTestFramework): return os.path.isfile(self.options.tmpdir + "/node{}/regtest/blocks/blk{:05}.dat".format(node_number, index)) # should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000) - assert_raises_message(JSONRPCException, "Blockchain is too short for pruning", node.pruneblockchain, height(500)) + assert_raises_jsonrpc(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500)) # mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight) node.generate(6) assert_equal(node.getblockchaininfo()["blocks"], 1001) # negative heights should raise an exception - assert_raises_message(JSONRPCException, "Negative", node.pruneblockchain, -10) + assert_raises_jsonrpc(-8, "Negative", node.pruneblockchain, -10) # height=100 too low to prune first block file so this is a no-op prune(100) @@ -320,12 +317,9 @@ class PruneTest(BitcoinTestFramework): def wallet_test(self): # check that the pruning node's wallet is still in good shape print("Stop and start pruning node to trigger wallet rescan") - try: - self.stop_node(2) - start_node(2, self.options.tmpdir, ["-debug=1","-prune=550"]) - print("Success") - except Exception as detail: - raise AssertionError("Wallet test: unable to re-start the pruning node") + self.stop_node(2) + start_node(2, self.options.tmpdir, ["-debug=1","-prune=550"]) + print("Success") # check that wallet loads loads successfully when restarting a pruned node after IBD. # this was reported to fail in #7494. @@ -333,12 +327,9 @@ class PruneTest(BitcoinTestFramework): connect_nodes(self.nodes[0], 5) nds = [self.nodes[0], self.nodes[5]] sync_blocks(nds, wait=5, timeout=300) - try: - self.stop_node(5) #stop and start to trigger rescan - start_node(5, self.options.tmpdir, ["-debug=1","-prune=550"]) - print ("Success") - except Exception as detail: - raise AssertionError("Wallet test: unable to re-start node5") + self.stop_node(5) #stop and start to trigger rescan + start_node(5, self.options.tmpdir, ["-debug=1","-prune=550"]) + print ("Success") def run_test(self): print("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)") diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 7b69c81ff9c..6080650f898 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -744,10 +744,15 @@ UniValue getblock(const JSONRPCRequest& request) CBlockIndex* pblockindex = mapBlockIndex[hash]; if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); + throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); - if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) + // Block not found on disk. This could be because we have the block + // header in our index but don't have the block (for example if a + // non-whitelisted node sends us an unrequested long chain of valid + // blocks, we add the headers to our index, but don't accept the + // block). + throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk"); if (!fVerbose) { @@ -829,7 +834,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request) + HelpExampleRpc("pruneblockchain", "1000")); if (!fPruneMode) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Cannot prune blocks because node is not in prune mode."); + throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode."); LOCK(cs_main); @@ -843,7 +848,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request) // Add a 2 hour buffer to include blocks which might have had old timestamps CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - 7200); if (!pindex) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block with at least the specified timestamp."); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp."); } heightParam = pindex->nHeight; } @@ -851,7 +856,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request) unsigned int height = (unsigned int) heightParam; unsigned int chainHeight = (unsigned int) chainActive.Height(); if (chainHeight < Params().PruneAfterHeight()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Blockchain is too short for pruning."); + throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning."); else if (height > chainHeight) throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height."); else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { From 18c109ddb10e8f2e1075ee4078519cfefd4de47d Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 9 Feb 2017 16:27:28 -0500 Subject: [PATCH 15/34] Return correct error codes in removeprunedfunds(). The removeprunedfunds() RPC was returning misleading or incorrect error codes (for example RPC_INTERNAL_ERROR when the transaction was not found in the wallet). This commit fixes those error codes: - RPC_INTERNAL_ERROR should not be returned for application-level errors, only for genuine internal errors such as corrupted data. This error code has been replaced with RPC_WALLET_ERROR. This commit also updates the test cases to explicitly test the error code. Github-Pull: #9853 Rebased-From: 960bc7f778d8dd618e65f1e37ec734e2d4734051 --- qa/rpc-tests/importprunedfunds.py | 14 ++------------ src/wallet/rpcdump.cpp | 4 ++-- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py index 0dee8ad4ec9..b289f9be575 100755 --- a/qa/rpc-tests/importprunedfunds.py +++ b/qa/rpc-tests/importprunedfunds.py @@ -76,12 +76,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework): self.sync_all() #Import with no affiliated address - try: - self.nodes[1].importprunedfunds(rawtxn1, proof1) - except JSONRPCException as e: - assert('No addresses' in e.error['message']) - else: - assert(False) + assert_raises_jsonrpc(-5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1) balance1 = self.nodes[1].getbalance("", 0, True) assert_equal(balance1, Decimal(0)) @@ -112,12 +107,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework): assert_equal(address_info['ismine'], True) #Remove transactions - try: - self.nodes[1].removeprunedfunds(txnid1) - except JSONRPCException as e: - assert('does not exist' in e.error['message']) - else: - assert(False) + assert_raises_jsonrpc(-8, "Transaction does not exist in wallet.", self.nodes[1].removeprunedfunds, txnid1) balance1 = self.nodes[1].getbalance("*", 0, True) assert_equal(balance1, Decimal('0.075')) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index cd6ec207f90..dc61a4505ed 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -340,11 +340,11 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) vector vHashOut; if(pwalletMain->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction."); + throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction."); } if(vHashOut.empty()) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet."); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet."); } return NullUniValue; From 4943d7a9feb8e4f5461622f548032e53eb714175 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Tue, 7 Feb 2017 12:57:37 -0500 Subject: [PATCH 16/34] Return correct error codes in setban(). The setban() RPC was returning misleading or incorrect error codes (for example RPC_CLIENT_NODE_ALREADY_ADDED when an invalid IP address was entered). This commit fixes those error codes: - RPC_CLIENT_INVALID_IP_OR_SUBNET should be returned if the client enters an invalid IP address or subnet. This commit also updates the test cases to explicitly test the error code. This commit also adds a testcase for trying to setban on an invalid subnet. Github-Pull: #9853 Rebased-From: a012087667edb35a36f25ae06b42b1644d80e649 --- qa/rpc-tests/nodehandling.py | 14 ++++++-------- src/rpc/net.cpp | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py index 7313c79b54f..634dba7c8e6 100755 --- a/qa/rpc-tests/nodehandling.py +++ b/qa/rpc-tests/nodehandling.py @@ -32,15 +32,13 @@ class NodeHandlingTest (BitcoinTestFramework): assert_equal(len(self.nodes[2].listbanned()), 0) self.nodes[2].setban("127.0.0.0/24", "add") assert_equal(len(self.nodes[2].listbanned()), 1) - try: - self.nodes[2].setban("127.0.0.1", "add") #throws exception because 127.0.0.1 is within range 127.0.0.0/24 - except: - pass + # This will throw an exception because 127.0.0.1 is within range 127.0.0.0/24 + assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[2].setban, "127.0.0.1", "add") + # This will throw an exception because 127.0.0.1/42 is not a real subnet + assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[2].setban, "127.0.0.1/42", "add") assert_equal(len(self.nodes[2].listbanned()), 1) #still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 - try: - self.nodes[2].setban("127.0.0.1", "remove") - except: - pass + # This will throw an exception because 127.0.0.1 was not added above + assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[2].setban, "127.0.0.1", "remove") assert_equal(len(self.nodes[2].listbanned()), 1) self.nodes[2].setban("127.0.0.0/24", "remove") assert_equal(len(self.nodes[2].listbanned()), 0) diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 8706b429515..42f5db94f94 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -506,7 +506,7 @@ UniValue setban(const JSONRPCRequest& request) LookupSubNet(request.params[0].get_str().c_str(), subNet); if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) ) - throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet"); + throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet"); if (strCommand == "add") { @@ -526,7 +526,7 @@ UniValue setban(const JSONRPCRequest& request) else if(strCommand == "remove") { if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) )) - throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed"); + throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned."); } return NullUniValue; } From f5efe82a832a050d1e8f483904913d238dde2e93 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 9 Feb 2017 15:48:39 -0500 Subject: [PATCH 17/34] Return correct error codes in fundrawtransaction(). The fundrawtransaction() RPC was returning misleading or incorrect error codes (for example RPC_INTERNAL_ERROR when funding the transaction failed). This commit fixes those error codes: - RPC_INTERNAL_ERROR should not be returned for application-level errors, only for genuine internal errors such as corrupted data. That error code has been replaced with RPC_WALLET_ERROR. This commit also updates the test cases to explicitly test the error code. Github-Pull: #9853 Rebased-From: dab804c18a427901684ebe936b2069a97e04a268 --- qa/rpc-tests/fundrawtransaction.py | 40 +++++------------------------- qa/rpc-tests/rawtransactions.py | 21 +++++++--------- src/wallet/rpcwallet.cpp | 2 +- 3 files changed, 16 insertions(+), 47 deletions(-) diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py index cdea390e224..511faf740eb 100755 --- a/qa/rpc-tests/fundrawtransaction.py +++ b/qa/rpc-tests/fundrawtransaction.py @@ -186,12 +186,7 @@ class RawTransactionsTest(BitcoinTestFramework): dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) - try: - self.nodes[2].fundrawtransaction(rawtx, {'foo': 'bar'}) - raise AssertionError("Accepted invalid option foo") - except JSONRPCException as e: - assert("Unexpected key foo" in e.error['message']) - + assert_raises_jsonrpc(-3, "Unexpected key foo", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'}) ############################################################ # test a fundrawtransaction with an invalid change address # @@ -204,12 +199,7 @@ class RawTransactionsTest(BitcoinTestFramework): dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) - try: - self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': 'foobar'}) - raise AssertionError("Accepted invalid bitcoin address") - except JSONRPCException as e: - assert("changeAddress must be a valid bitcoin address" in e.error['message']) - + assert_raises_jsonrpc(-5, "changeAddress must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'}) ############################################################ # test a fundrawtransaction with a provided change address # @@ -223,12 +213,7 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) change = self.nodes[2].getnewaddress() - try: - rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 2}) - except JSONRPCException as e: - assert('changePosition out of bounds' == e.error['message']) - else: - assert(False) + assert_raises_jsonrpc(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2}) rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0}) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) out = dec_tx['vout'][0] @@ -337,12 +322,7 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) - try: - rawtxfund = self.nodes[2].fundrawtransaction(rawtx) - raise AssertionError("Spent more than available") - except JSONRPCException as e: - assert("Insufficient" in e.error['message']) - + assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx) ############################################################ #compare fee of a standard pubkeyhash transaction @@ -498,21 +478,13 @@ class RawTransactionsTest(BitcoinTestFramework): rawTx = self.nodes[1].createrawtransaction(inputs, outputs) # fund a transaction that requires a new key for the change output # creating the key must be impossible because the wallet is locked - try: - fundedTx = self.nodes[1].fundrawtransaction(rawTx) - raise AssertionError("Wallet unlocked without passphrase") - except JSONRPCException as e: - assert('Keypool ran out' in e.error['message']) + assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[1].fundrawtransaction, rawtx) #refill the keypool self.nodes[1].walletpassphrase("test", 100) self.nodes[1].walletlock() - try: - self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2) - raise AssertionError("Wallet unlocked without passphrase") - except JSONRPCException as e: - assert('walletpassphrase' in e.error['message']) + assert_raises_jsonrpc(-13, "walletpassphrase", self.nodes[1].sendtoaddress, self.nodes[0].getnewaddress(), 1.2) oldBalance = self.nodes[0].getbalance() diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py index 33a6f2b0cca..2e27bbabb03 100755 --- a/qa/rpc-tests/rawtransactions.py +++ b/qa/rpc-tests/rawtransactions.py @@ -61,13 +61,8 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = self.nodes[2].createrawtransaction(inputs, outputs) rawtx = self.nodes[2].signrawtransaction(rawtx) - try: - rawtx = self.nodes[2].sendrawtransaction(rawtx['hex']) - except JSONRPCException as e: - assert("Missing inputs" in e.error['message']) - else: - assert(False) - + # This will raise an exception since there are missing inputs + assert_raises_jsonrpc(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex']) ######################### # RAW TX MULTISIG TESTS # @@ -161,13 +156,13 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex']) # 6. invalid parameters - supply txid and string "Flase" - assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, "Flase") + assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, "Flase") # 7. invalid parameters - supply txid and empty array - assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, []) + assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, []) # 8. invalid parameters - supply txid and empty dict - assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, {}) + assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, {}) inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}] outputs = { self.nodes[0].getnewaddress() : 1 } @@ -175,13 +170,15 @@ class RawTransactionsTest(BitcoinTestFramework): decrawtx= self.nodes[0].decoderawtransaction(rawtx) assert_equal(decrawtx['vin'][0]['sequence'], 1000) + # 9. invalid parameters - sequence number out of range inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : -1}] outputs = { self.nodes[0].getnewaddress() : 1 } - assert_raises(JSONRPCException, self.nodes[0].createrawtransaction, inputs, outputs) + assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) + # 10. invalid parameters - sequence number out of range inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967296}] outputs = { self.nodes[0].getnewaddress() : 1 } - assert_raises(JSONRPCException, self.nodes[0].createrawtransaction, inputs, outputs) + assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967294}] outputs = { self.nodes[0].getnewaddress() : 1 } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c141c0ca159..7cc03201650 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2657,7 +2657,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) string strFailReason; if(!pwalletMain->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, setSubtractFeeFromOutputs, reserveChangeKey, changeAddress)) - throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason); + throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); UniValue result(UniValue::VOBJ); result.push_back(Pair("hex", EncodeHexTx(tx))); From c25d0a8739cfcb736ddbf4a5204f25830842eb46 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 8 Mar 2017 14:23:16 -0500 Subject: [PATCH 18/34] Update release notes to include RPC error code changes. Github-Pull: #9853 Rebased-From: adaa281da12bcc697779f97973cea6b103eec4ab --- doc/release-notes.md | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index 1fbade55a73..248c2f15258 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -30,6 +30,55 @@ frequently tested on them. Notable changes =============== +Low-level RPC changes +--------------------- + +- Error codes have been updated to be more accurate for the following error cases: + - `getblock` now returns RPC_MISC_ERROR if the block can't be found on disk (for + example if the block has been pruned). Previously returned RPC_INTERNAL_ERROR. + - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned + because the node is not in pruned mode. Previously returned RPC_METHOD_NOT_FOUND. + - `pruneblockchain` now returns RPC_INVALID_PARAMETER if the blocks cannot be pruned + because the supplied timestamp is too late. Previously returned RPC_INTERNAL_ERROR. + - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned + because the blockchain is too short. Previously returned RPC_INTERNAL_ERROR. + - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the supplied IP address + or subnet is invalid. Previously returned RPC_CLIENT_NODE_ALREADY_ADDED. + - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the user tries to unban + a node that has not previously been banned. Previously returned RPC_MISC_ERROR. + - `removeprunedfunds` now returns RPC_WALLET_ERROR if bitcoind is unable to remove + the transaction. Previously returned RPC_INTERNAL_ERROR. + - `removeprunedfunds` now returns RPC_INVALID_PARAMETER if the transaction does not + exist in the wallet. Previously returned RPC_INTERNAL_ERROR. + - `fundrawtransaction` now returns RPC_INVALID_ADDRESS_OR_KEY if an invalid change + address is provided. Previously returned RPC_INVALID_PARAMETER. + - `fundrawtransaction` now returns RPC_WALLET_ERROR if bitcoind is unable to create + the transaction. The error message provides further details. Previously returned + RPC_INTERNAL_ERROR. + - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has + descendants in the wallet. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has + descendants in the mempool. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has + has been mined or conflicts with a mined transaction. Previously returned + RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction is not + BIP 125 replaceable. Previously returned RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has already + been bumped by a different transaction. Previously returned RPC_INVALID_REQUEST. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction contains + inputs which don't belong to this wallet. Previously returned RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has multiple change + outputs. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has no change + output. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too high. Previously returned + RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too low. Previously returned + RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the change output is too small to bump the + fee. Previously returned RPC_MISC_ERROR. + miniupnp CVE-2017-8798 ---------------------------- From 5bc75bb8eea566258ddd9c858e2cf6361318d777 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 19 Apr 2017 11:07:44 -0400 Subject: [PATCH 19/34] [tests] fix nodehandling.py flake8 warnings Github-Pull: #10143 Rebased-From: d6564a26f4afc28d7d1a24b94946916387c9bf24 --- qa/rpc-tests/nodehandling.py | 48 ++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py index 634dba7c8e6..95dec42fe09 100755 --- a/qa/rpc-tests/nodehandling.py +++ b/qa/rpc-tests/nodehandling.py @@ -6,13 +6,19 @@ # # Test node handling # - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * - +import time import urllib.parse -class NodeHandlingTest (BitcoinTestFramework): +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import (assert_equal, + assert_raises_jsonrpc, + connect_nodes_bi, + p2p_port, + start_node, + stop_node, + ) + +class NodeHandlingTest(BitcoinTestFramework): def __init__(self): super().__init__() @@ -23,10 +29,10 @@ class NodeHandlingTest (BitcoinTestFramework): ########################### # setban/listbanned tests # ########################### - assert_equal(len(self.nodes[2].getpeerinfo()), 4) #we should have 4 nodes at this point + assert_equal(len(self.nodes[2].getpeerinfo()), 4) # we should have 4 nodes at this point self.nodes[2].setban("127.0.0.1", "add") - time.sleep(3) #wait till the nodes are disconected - assert_equal(len(self.nodes[2].getpeerinfo()), 0) #all nodes must be disconnected at this point + time.sleep(3) # wait till the nodes are disconected + assert_equal(len(self.nodes[2].getpeerinfo()), 0) # all nodes must be disconnected at this point assert_equal(len(self.nodes[2].listbanned()), 1) self.nodes[2].clearbanned() assert_equal(len(self.nodes[2].listbanned()), 0) @@ -36,7 +42,7 @@ class NodeHandlingTest (BitcoinTestFramework): assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[2].setban, "127.0.0.1", "add") # This will throw an exception because 127.0.0.1/42 is not a real subnet assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[2].setban, "127.0.0.1/42", "add") - assert_equal(len(self.nodes[2].listbanned()), 1) #still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 + assert_equal(len(self.nodes[2].listbanned()), 1) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 # This will throw an exception because 127.0.0.1 was not added above assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[2].setban, "127.0.0.1", "remove") assert_equal(len(self.nodes[2].listbanned()), 1) @@ -45,16 +51,16 @@ class NodeHandlingTest (BitcoinTestFramework): self.nodes[2].clearbanned() assert_equal(len(self.nodes[2].listbanned()), 0) - ##test persisted banlist + # test persisted banlist self.nodes[2].setban("127.0.0.0/32", "add") self.nodes[2].setban("127.0.0.0/24", "add") - self.nodes[2].setban("192.168.0.1", "add", 1) #ban for 1 seconds - self.nodes[2].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) #ban for 1000 seconds + self.nodes[2].setban("192.168.0.1", "add", 1) # ban for 1 seconds + self.nodes[2].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds listBeforeShutdown = self.nodes[2].listbanned() - assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) #must be here - time.sleep(2) #make 100% sure we expired 192.168.0.1 node time + assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) # must be here + time.sleep(2) # make 100% sure we expired 192.168.0.1 node time - #stop node + # stop node stop_node(self.nodes[2], 2) self.nodes[2] = start_node(2, self.options.tmpdir) @@ -67,17 +73,17 @@ class NodeHandlingTest (BitcoinTestFramework): # RPC disconnectnode test # ########################### url = urllib.parse.urlparse(self.nodes[1].url) - self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1))) - time.sleep(2) #disconnecting a node needs a little bit of time + self.nodes[0].disconnectnode(url.hostname + ":" + str(p2p_port(1))) + time.sleep(2) # disconnecting a node needs a little bit of time for node in self.nodes[0].getpeerinfo(): - assert(node['addr'] != url.hostname+":"+str(p2p_port(1))) + assert(node['addr'] != url.hostname + ":" + str(p2p_port(1))) - connect_nodes_bi(self.nodes,0,1) #reconnect the node + connect_nodes_bi(self.nodes, 0, 1) # reconnect the node found = False for node in self.nodes[0].getpeerinfo(): - if node['addr'] == url.hostname+":"+str(p2p_port(1)): + if node['addr'] == url.hostname + ":" + str(p2p_port(1)): found = True assert(found) if __name__ == '__main__': - NodeHandlingTest ().main () + NodeHandlingTest().main() From bfd1cf6713f1f44b88b135c995b9ddb9e99ff7aa Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 19 Apr 2017 11:25:31 -0400 Subject: [PATCH 20/34] [tests] disconnectban test - only use two nodes Github-Pull: #10143 Rebased-From: 395561becfa612fedec74fd841cb4f28afdc23d7 --- qa/rpc-tests/nodehandling.py | 60 ++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py index 95dec42fe09..ec32cb069fb 100755 --- a/qa/rpc-tests/nodehandling.py +++ b/qa/rpc-tests/nodehandling.py @@ -22,53 +22,61 @@ class NodeHandlingTest(BitcoinTestFramework): def __init__(self): super().__init__() - self.num_nodes = 4 + self.num_nodes = 2 self.setup_clean_chain = False + def setup_network(self): + self.nodes = self.setup_nodes() + connect_nodes_bi(self.nodes, 0, 1) + def run_test(self): ########################### # setban/listbanned tests # ########################### - assert_equal(len(self.nodes[2].getpeerinfo()), 4) # we should have 4 nodes at this point - self.nodes[2].setban("127.0.0.1", "add") + assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point + self.nodes[1].setban("127.0.0.1", "add") time.sleep(3) # wait till the nodes are disconected - assert_equal(len(self.nodes[2].getpeerinfo()), 0) # all nodes must be disconnected at this point - assert_equal(len(self.nodes[2].listbanned()), 1) - self.nodes[2].clearbanned() - assert_equal(len(self.nodes[2].listbanned()), 0) - self.nodes[2].setban("127.0.0.0/24", "add") - assert_equal(len(self.nodes[2].listbanned()), 1) + assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point + assert_equal(len(self.nodes[1].listbanned()), 1) + self.nodes[1].clearbanned() + assert_equal(len(self.nodes[1].listbanned()), 0) + self.nodes[1].setban("127.0.0.0/24", "add") + assert_equal(len(self.nodes[1].listbanned()), 1) # This will throw an exception because 127.0.0.1 is within range 127.0.0.0/24 - assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[2].setban, "127.0.0.1", "add") + assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[1].setban, "127.0.0.1", "add") # This will throw an exception because 127.0.0.1/42 is not a real subnet - assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[2].setban, "127.0.0.1/42", "add") - assert_equal(len(self.nodes[2].listbanned()), 1) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 + assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[1].setban, "127.0.0.1/42", "add") + assert_equal(len(self.nodes[1].listbanned()), 1) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 # This will throw an exception because 127.0.0.1 was not added above - assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[2].setban, "127.0.0.1", "remove") - assert_equal(len(self.nodes[2].listbanned()), 1) - self.nodes[2].setban("127.0.0.0/24", "remove") - assert_equal(len(self.nodes[2].listbanned()), 0) - self.nodes[2].clearbanned() - assert_equal(len(self.nodes[2].listbanned()), 0) + assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[1].setban, "127.0.0.1", "remove") + assert_equal(len(self.nodes[1].listbanned()), 1) + self.nodes[1].setban("127.0.0.0/24", "remove") + assert_equal(len(self.nodes[1].listbanned()), 0) + self.nodes[1].clearbanned() + assert_equal(len(self.nodes[1].listbanned()), 0) # test persisted banlist - self.nodes[2].setban("127.0.0.0/32", "add") - self.nodes[2].setban("127.0.0.0/24", "add") - self.nodes[2].setban("192.168.0.1", "add", 1) # ban for 1 seconds - self.nodes[2].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds - listBeforeShutdown = self.nodes[2].listbanned() + self.nodes[1].setban("127.0.0.0/32", "add") + self.nodes[1].setban("127.0.0.0/24", "add") + self.nodes[1].setban("192.168.0.1", "add", 1) # ban for 1 seconds + self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds + listBeforeShutdown = self.nodes[1].listbanned() assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) # must be here time.sleep(2) # make 100% sure we expired 192.168.0.1 node time # stop node - stop_node(self.nodes[2], 2) + stop_node(self.nodes[1], 1) - self.nodes[2] = start_node(2, self.options.tmpdir) - listAfterShutdown = self.nodes[2].listbanned() + self.nodes[1] = start_node(1, self.options.tmpdir) + listAfterShutdown = self.nodes[1].listbanned() assert_equal("127.0.0.0/24", listAfterShutdown[0]['address']) assert_equal("127.0.0.0/32", listAfterShutdown[1]['address']) assert_equal("/19" in listAfterShutdown[2]['address'], True) + # Clear ban lists + self.nodes[1].clearbanned() + connect_nodes_bi(self.nodes, 0, 1) + ########################### # RPC disconnectnode test # ########################### From 98bd0c338b1886d12ea3d90597ab0438acbc07ff Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 19 Apr 2017 12:42:39 -0400 Subject: [PATCH 21/34] [tests] disconnect_ban: use wait_until instead of sleep Github-Pull: #10143 Rebased-From: 12de2f252c8f48e05c579cb679866a68af8c660e --- qa/rpc-tests/nodehandling.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py index ec32cb069fb..f540d3aa958 100755 --- a/qa/rpc-tests/nodehandling.py +++ b/qa/rpc-tests/nodehandling.py @@ -6,9 +6,9 @@ # # Test node handling # -import time import urllib.parse +from test_framework.mininode import wait_until from test_framework.test_framework import BitcoinTestFramework from test_framework.util import (assert_equal, assert_raises_jsonrpc, @@ -35,7 +35,7 @@ class NodeHandlingTest(BitcoinTestFramework): ########################### assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point self.nodes[1].setban("127.0.0.1", "add") - time.sleep(3) # wait till the nodes are disconected + wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0) assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point assert_equal(len(self.nodes[1].listbanned()), 1) self.nodes[1].clearbanned() @@ -61,10 +61,9 @@ class NodeHandlingTest(BitcoinTestFramework): self.nodes[1].setban("192.168.0.1", "add", 1) # ban for 1 seconds self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds listBeforeShutdown = self.nodes[1].listbanned() - assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) # must be here - time.sleep(2) # make 100% sure we expired 192.168.0.1 node time + assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) + wait_until(lambda: len(self.nodes[1].listbanned()) == 3) - # stop node stop_node(self.nodes[1], 1) self.nodes[1] = start_node(1, self.options.tmpdir) @@ -82,7 +81,7 @@ class NodeHandlingTest(BitcoinTestFramework): ########################### url = urllib.parse.urlparse(self.nodes[1].url) self.nodes[0].disconnectnode(url.hostname + ":" + str(p2p_port(1))) - time.sleep(2) # disconnecting a node needs a little bit of time + wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1) for node in self.nodes[0].getpeerinfo(): assert(node['addr'] != url.hostname + ":" + str(p2p_port(1))) From 04226938a3c675faaca81906ae9ff7a936bcb6a7 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 19 Apr 2017 13:35:51 -0400 Subject: [PATCH 22/34] [tests] disconnect_ban: remove dependency on urllib Github-Pull: #10143 Rebased-From: 5cc3ee24d29397737f2746d78b19a2509c0dedbb --- qa/rpc-tests/nodehandling.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py index f540d3aa958..df6e2bc6af3 100755 --- a/qa/rpc-tests/nodehandling.py +++ b/qa/rpc-tests/nodehandling.py @@ -6,14 +6,12 @@ # # Test node handling # -import urllib.parse from test_framework.mininode import wait_until from test_framework.test_framework import BitcoinTestFramework from test_framework.util import (assert_equal, assert_raises_jsonrpc, connect_nodes_bi, - p2p_port, start_node, stop_node, ) @@ -79,18 +77,13 @@ class NodeHandlingTest(BitcoinTestFramework): ########################### # RPC disconnectnode test # ########################### - url = urllib.parse.urlparse(self.nodes[1].url) - self.nodes[0].disconnectnode(url.hostname + ":" + str(p2p_port(1))) + address1 = self.nodes[0].getpeerinfo()[0]['addr'] + self.nodes[0].disconnectnode(address=address1) wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1) - for node in self.nodes[0].getpeerinfo(): - assert(node['addr'] != url.hostname + ":" + str(p2p_port(1))) + assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1] connect_nodes_bi(self.nodes, 0, 1) # reconnect the node - found = False - for node in self.nodes[0].getpeerinfo(): - if node['addr'] == url.hostname + ":" + str(p2p_port(1)): - found = True - assert(found) + assert [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1] if __name__ == '__main__': NodeHandlingTest().main() From d289b564e3ae125cb54c3d9157a13e7bad48c5f5 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 19 Apr 2017 12:49:11 -0400 Subject: [PATCH 23/34] [net] listbanned RPC and QT should show correct banned subnets Github-Pull: #10234 Rebased-From: 77c54b270dd3b469d662c8f69e06f7b00fc4136d --- src/net.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index 1752c7707a7..5bc886c3408 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -413,10 +413,10 @@ void CConnman::DumpBanlist() CBanDB bandb; banmap_t banmap; - SetBannedSetDirty(false); GetBanned(banmap); - if (!bandb.Write(banmap)) - SetBannedSetDirty(true); + if (bandb.Write(banmap)) { + SetBannedSetDirty(false); + } LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); @@ -536,6 +536,8 @@ bool CConnman::Unban(const CSubNet &subNet) { void CConnman::GetBanned(banmap_t &banMap) { LOCK(cs_setBanned); + // Sweep the banlist so expired bans are not returned + SweepBanned(); banMap = setBanned; //create a thread safe copy } From ee1a60d15609930954b1b85da7f33774711123cd Mon Sep 17 00:00:00 2001 From: John Newbery Date: Tue, 25 Apr 2017 10:11:31 -0400 Subject: [PATCH 24/34] [tests] update disconnect_ban.py test case to work with listbanned Github-Pull: #10234 Rebased-From: d6732d832aa901e733e63799260d409821a2c37a --- qa/rpc-tests/nodehandling.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py index df6e2bc6af3..61be27ae2b6 100755 --- a/qa/rpc-tests/nodehandling.py +++ b/qa/rpc-tests/nodehandling.py @@ -33,7 +33,7 @@ class NodeHandlingTest(BitcoinTestFramework): ########################### assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point self.nodes[1].setban("127.0.0.1", "add") - wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0) + assert wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10) assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point assert_equal(len(self.nodes[1].listbanned()), 1) self.nodes[1].clearbanned() @@ -60,7 +60,7 @@ class NodeHandlingTest(BitcoinTestFramework): self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds listBeforeShutdown = self.nodes[1].listbanned() assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) - wait_until(lambda: len(self.nodes[1].listbanned()) == 3) + assert wait_until(lambda: len(self.nodes[1].listbanned()) == 3, timeout=10) stop_node(self.nodes[1], 1) @@ -79,7 +79,7 @@ class NodeHandlingTest(BitcoinTestFramework): ########################### address1 = self.nodes[0].getpeerinfo()[0]['addr'] self.nodes[0].disconnectnode(address=address1) - wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1) + assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1] connect_nodes_bi(self.nodes, 0, 1) # reconnect the node From e23cef0c9469cc360e603a614bb3f0b22c6656bf Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 13 Apr 2017 02:33:04 -0700 Subject: [PATCH 25/34] Fix some empty vector references streams.h has some methods that can be tricked into dereferencing null pointers or end() iterators. Fix this. Github-Pull: #10250 Rebased-From: f478d98fe49d3c0c0f2c79b3f8d9dbfc1aafd407 --- src/streams.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/streams.h b/src/streams.h index 1d3b55c91ef..e49a9e35469 100644 --- a/src/streams.h +++ b/src/streams.h @@ -248,7 +248,8 @@ public: void insert(iterator it, std::vector::const_iterator first, std::vector::const_iterator last) { - assert(last - first >= 0); + if (last == first) return; + assert(last - first > 0); if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) { // special case for inserting at the front when there's room @@ -261,7 +262,8 @@ public: void insert(iterator it, const char* first, const char* last) { - assert(last - first >= 0); + if (last == first) return; + assert(last - first > 0); if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) { // special case for inserting at the front when there's room @@ -339,6 +341,8 @@ public: void read(char* pch, size_t nSize) { + if (nSize == 0) return; + // Read from the beginning of the buffer unsigned int nReadPosNext = nReadPos + nSize; if (nReadPosNext >= vch.size()) From ff13f592c5813b18340a6e9e65abb4e356aac400 Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Mon, 24 Apr 2017 08:48:12 +0900 Subject: [PATCH 26/34] [wallet] Make sure pindex is non-null before possibly referencing in LogPrintf call. Github-Pull: #10265 Rebased-From: c36ea693ee16611e0337aec682d1ce80b90e1bd3 --- src/wallet/wallet.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 3e93a56d563..2697a3769ac 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1572,6 +1572,10 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f { if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((GuessVerificationProgress(chainParams.TxData(), pindex) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); + if (GetTime() >= nNow + 60) { + nNow = GetTime(); + LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex)); + } CBlock block; if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) { @@ -1585,10 +1589,6 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f ret = nullptr; } pindex = chainActive.Next(pindex); - if (GetTime() >= nNow + 60) { - nNow = GetTime(); - LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex)); - } } ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI } From 28b8b8b6038c45ce2dc2e7dc11f88dc834ddd19a Mon Sep 17 00:00:00 2001 From: Thomas Snider Date: Thu, 23 Mar 2017 14:07:51 -0700 Subject: [PATCH 27/34] [wallet] Securely erase potentially sensitive keys/values Github-Pull: #10308 Rebased-From: 6c914ac176624468c66febdb1ad0e24ff2118a5f --- src/support/cleanse.h | 1 + src/wallet/db.h | 41 +++++++++++++++++++++-------------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/support/cleanse.h b/src/support/cleanse.h index 3e02aa8fd1f..f020216c730 100644 --- a/src/support/cleanse.h +++ b/src/support/cleanse.h @@ -8,6 +8,7 @@ #include +// Attempt to overwrite data in the specified memory span. void memory_cleanse(void *ptr, size_t len); #endif // BITCOIN_SUPPORT_CLEANSE_H diff --git a/src/wallet/db.h b/src/wallet/db.h index b4ce044e7f5..ea562003230 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -126,22 +126,23 @@ protected: Dbt datValue; datValue.set_flags(DB_DBT_MALLOC); int ret = pdb->get(activeTxn, &datKey, &datValue, 0); - memset(datKey.get_data(), 0, datKey.get_size()); - if (datValue.get_data() == NULL) - return false; + memory_cleanse(datKey.get_data(), datKey.get_size()); + bool success = false; + if (datValue.get_data() != NULL) { + // Unserialize value + try { + CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION); + ssValue >> value; + success = true; + } catch (const std::exception&) { + // In this case success remains 'false' + } - // Unserialize value - try { - CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION); - ssValue >> value; - } catch (const std::exception&) { - return false; + // Clear and free memory + memory_cleanse(datValue.get_data(), datValue.get_size()); + free(datValue.get_data()); } - - // Clear and free memory - memset(datValue.get_data(), 0, datValue.get_size()); - free(datValue.get_data()); - return (ret == 0); + return ret == 0 && success; } template @@ -168,8 +169,8 @@ protected: int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE)); // Clear memory in case it was a private key - memset(datKey.get_data(), 0, datKey.get_size()); - memset(datValue.get_data(), 0, datValue.get_size()); + memory_cleanse(datKey.get_data(), datKey.get_size()); + memory_cleanse(datValue.get_data(), datValue.get_size()); return (ret == 0); } @@ -191,7 +192,7 @@ protected: int ret = pdb->del(activeTxn, &datKey, 0); // Clear memory - memset(datKey.get_data(), 0, datKey.get_size()); + memory_cleanse(datKey.get_data(), datKey.get_size()); return (ret == 0 || ret == DB_NOTFOUND); } @@ -211,7 +212,7 @@ protected: int ret = pdb->exists(activeTxn, &datKey, 0); // Clear memory - memset(datKey.get_data(), 0, datKey.get_size()); + memory_cleanse(datKey.get_data(), datKey.get_size()); return (ret == 0); } @@ -254,8 +255,8 @@ protected: ssValue.write((char*)datValue.get_data(), datValue.get_size()); // Clear and free memory - memset(datKey.get_data(), 0, datKey.get_size()); - memset(datValue.get_data(), 0, datValue.get_size()); + memory_cleanse(datKey.get_data(), datKey.get_size()); + memory_cleanse(datValue.get_data(), datValue.get_size()); free(datKey.get_data()); free(datValue.get_data()); return 0; From 87a21d5922f3cdc7a7e21090dc7078e0774c1c1f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 23 May 2017 10:04:14 -0700 Subject: [PATCH 28/34] Fix: make CCoinsViewDbCursor::Seek work for missing keys Thanks to Suhas Daftuar for figuring this out. Github-Pull: #10445 Rebased-From: 822755a424d0abfa408dc34313f4aca4b816f54f --- src/txdb.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/txdb.cpp b/src/txdb.cpp index 1a30bb58ad8..662e7cb06d3 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -98,7 +98,11 @@ CCoinsViewCursor *CCoinsViewDB::Cursor() const that restriction. */ i->pcursor->Seek(DB_COINS); // Cache key of first record - i->pcursor->GetKey(i->keyTmp); + if (i->pcursor->Valid()) { + i->pcursor->GetKey(i->keyTmp); + } else { + i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false + } return i; } From 692dbb0288d6582e311a47951ff4afd63ea9d90c Mon Sep 17 00:00:00 2001 From: fanquake Date: Sun, 23 Apr 2017 08:47:12 +0800 Subject: [PATCH 29/34] [doc] Minor corrections to osx dependencies Github-Pull: #10260 Rebased-From: 661caf83b3dcae6376e59b6cae07f0a2a4d37fe9 --- doc/build-osx.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/build-osx.md b/doc/build-osx.md index a15bcd012c6..32d7dbd69e7 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -11,14 +11,14 @@ Install the OS X command line tools: When the popup appears, click `Install`. -Then install [Homebrew](http://brew.sh). +Then install [Homebrew](https://brew.sh). Dependencies ---------------------- - brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf --c++11 qt5 libevent + brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf qt libevent -In case you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG +If you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG brew install librsvg From 3612219f9a18a2bd1ddebb1b90f556aa29586bfd Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 25 May 2017 01:56:03 +0000 Subject: [PATCH 30/34] contrib/init/bitcoind.openrcconf: Don't disable wallet by default It's harmless if it goes unused, and confused when a wallet is desired Github-Pull: #10451 Rebased-From: afc693dea695b75721db55d0decee3b11dcb3625 --- contrib/init/bitcoind.openrcconf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/init/bitcoind.openrcconf b/contrib/init/bitcoind.openrcconf index 0cbff6d30d2..f70e25cb5fd 100644 --- a/contrib/init/bitcoind.openrcconf +++ b/contrib/init/bitcoind.openrcconf @@ -23,7 +23,7 @@ #BITCOIND_NICE=0 # Additional options (avoid -conf and -datadir, use flags above) -BITCOIND_OPTS="-disablewallet" +#BITCOIND_OPTS="" # The timeout in seconds OpenRC will wait for bitcoind to terminate # after a SIGTERM has been raised. From d2ec96909acc3eda76ee507456d8f3722a965921 Mon Sep 17 00:00:00 2001 From: Mikerah Date: Sat, 22 Apr 2017 07:22:17 -0400 Subject: [PATCH 31/34] Fixed typo in documentation for merkleblock.h Github-Pull: #10258 Rebased-From: dd07068d6b11e738bc954c998800b5660d160959 --- src/merkleblock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkleblock.h b/src/merkleblock.h index 73cbf670ee9..de4c5c8d29e 100644 --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -23,7 +23,7 @@ * storing a bit for each traversed node, signifying whether the node is the * parent of at least one matched leaf txid (or a matched txid itself). In * case we are at the leaf level, or this bit is 0, its merkle node hash is - * stored, and its children are not explorer further. Otherwise, no hash is + * stored, and its children are not explored further. Otherwise, no hash is * stored, but we recurse into both (or the only) child branch. During * decoding, the same depth-first traversal is performed, consuming bits and * hashes as they written during encoding. From 12adedff0bf813f2a2e790f422e41cc8d84cfc99 Mon Sep 17 00:00:00 2001 From: CryptAxe Date: Mon, 1 May 2017 14:18:30 -0700 Subject: [PATCH 32/34] Trivial: remove extra character from comment Github-Pull: #10309 Rebased-From: 3503716f1e37a0cc3ab13c8f4e774061ff4ae2f8 --- src/merkleblock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index e3f3e4621ad..78d7cd60010 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -65,7 +65,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve } else { // calculate left hash uint256 left = CalcHash(height-1, pos*2, vTxid), right; - // calculate right hash if not beyond the end of the array - copy left hash otherwise1 + // calculate right hash if not beyond the end of the array - copy left hash otherwise if (pos*2+1 < CalcTreeWidth(height-1)) right = CalcHash(height-1, pos*2+1, vTxid); else From 76f9cf9ac9916f9a29b3f236225d49501ccf230a Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 1 Jun 2017 10:38:29 +0200 Subject: [PATCH 33/34] contrib: Update location of seeds.txt Update the steps for updating the hardcoded seed nodes to point to the new filename on @sipa's server, and add command to decompress it. Ref: #10163 Github-Pull: #10495 Rebased-From: ac9cd953d91e2448d24851b2f4973c7be8f4c3cd --- contrib/seeds/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/seeds/README.md b/contrib/seeds/README.md index afe902fd7f0..139c03181fc 100644 --- a/contrib/seeds/README.md +++ b/contrib/seeds/README.md @@ -8,7 +8,7 @@ and remove old versions as necessary. The seeds compiled into the release are created from sipa's DNS seed data, like this: - curl -s http://bitcoin.sipa.be/seeds.txt > seeds_main.txt + curl -s http://bitcoin.sipa.be/seeds.txt.gz | gzip -dc > seeds_main.txt python3 makeseeds.py < seeds_main.txt > nodes_main.txt python3 generate-seeds.py . > ../../src/chainparamsseeds.h From ff274d3b00737d9f93c85c0bcff51f1f548354b6 Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Sat, 6 May 2017 12:51:01 +0900 Subject: [PATCH 34/34] [doc] Add hint about getmempoolentry to getrawmempool help. Github-Pull: #10310 Rebased-From: 3a0a5bc2341ea6a453306f6fe1c065b937294cfb --- src/rpc/blockchain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 6080650f898..fd8f52a5cb0 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -417,6 +417,7 @@ UniValue getrawmempool(const JSONRPCRequest& request) throw runtime_error( "getrawmempool ( verbose )\n" "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" + "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n" "\nArguments:\n" "1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n" "\nResult: (for verbose = false):\n"