diff options
33 files changed, 296 insertions, 85 deletions
diff --git a/qa/README.md b/qa/README.md index c7e574ff70..7489eb5130 100644 --- a/qa/README.md +++ b/qa/README.md @@ -35,6 +35,9 @@ Run all possible tests with qa/pull-tester/rpc-tests.py -extended +By default, tests will be run in parallel if you want to specify how many +tests should be run in parallel, append `-paralell=n` (default n=4). + If you want to create a basic coverage report for the rpc test suite, append `--coverage`. Possible options, which apply to each individual test run: diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 10c3799b86..f810f89a59 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -53,10 +53,12 @@ ENABLE_COVERAGE=0 #Create a set to store arguments and create the passon string opts = set() -passon_args = "" +passon_args = [] PASSON_REGEX = re.compile("^--") +PARALLEL_REGEX = re.compile('^-parallel=') print_help = False +run_parallel = 4 for arg in sys.argv[1:]: if arg == "--help" or arg == "-h" or arg == "-?": @@ -65,7 +67,9 @@ for arg in sys.argv[1:]: if arg == '--coverage': ENABLE_COVERAGE = 1 elif PASSON_REGEX.match(arg): - passon_args += " " + arg + passon_args.append(arg) + elif PARALLEL_REGEX.match(arg): + run_parallel = int(arg.split(sep='=', maxsplit=1)[1]) else: opts.add(arg) @@ -96,6 +100,7 @@ if ENABLE_ZMQ: #Tests testScripts = [ + 'walletbackup.py', 'bip68-112-113-p2p.py', 'wallet.py', 'listtransactions.py', @@ -116,7 +121,6 @@ testScripts = [ 'merkle_blocks.py', 'fundrawtransaction.py', 'signrawtransactions.py', - 'walletbackup.py', 'nodehandling.py', 'reindex.py', 'decodescript.py', @@ -131,7 +135,7 @@ testScripts = [ 'abandonconflict.py', 'p2p-versionbits-warning.py', 'importprunedfunds.py', - 'signmessages.py' + 'signmessages.py', ] if ENABLE_ZMQ: testScripts.append('zmq_test.py') @@ -160,6 +164,7 @@ testScriptsExt = [ 'pruning.py', # leave pruning last as it takes a REALLY long time ] + def runtests(): test_list = [] if '-extended' in opts: @@ -173,7 +178,7 @@ def runtests(): if print_help: # Only print help of the first script and exit - subprocess.check_call(RPC_TESTS_DIR + test_list[0] + ' -h', shell=True) + subprocess.check_call((RPC_TESTS_DIR + test_list[0]).split() + ['-h']) sys.exit(0) coverage = None @@ -181,15 +186,34 @@ def runtests(): if ENABLE_COVERAGE: coverage = RPCCoverage() print("Initializing coverage directory at %s\n" % coverage.dir) - flags = " --srcdir %s/src %s %s" % (BUILDDIR, coverage.flag if coverage else '', passon_args) + flags = ["--srcdir=%s/src" % BUILDDIR] + passon_args + if coverage: + flags.append(coverage.flag) + + if len(test_list) > 1: + # Populate cache + subprocess.check_output([RPC_TESTS_DIR + 'create_cache.py'] + flags) #Run Tests - for t in test_list: - print("Running testscript %s%s%s ..." % (BOLD[1], t, BOLD[0])) - time0 = time.time() - subprocess.check_call( - RPC_TESTS_DIR + t + flags, shell=True) - print("Duration: %s s\n" % (int(time.time() - time0))) + max_len_name = len(max(test_list, key=len)) + time_sum = 0 + time0 = time.time() + job_queue = RPCTestHandler(run_parallel, test_list, flags) + results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "PASSED", "DURATION") + BOLD[0] + all_passed = True + for _ in range(len(test_list)): + (name, stdout, stderr, passed, duration) = job_queue.get_next() + all_passed = all_passed and passed + time_sum += duration + + print('\n' + BOLD[1] + name + BOLD[0] + ":") + print(stdout) + print('stderr:\n' if not stderr == '' else '', stderr) + results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration) + print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration)) + results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0] + print(results) + print("\nRuntime: %s s" % (int(time.time() - time0))) if coverage: coverage.report_rpc_coverage() @@ -197,6 +221,49 @@ def runtests(): print("Cleaning up coverage data") coverage.cleanup() + sys.exit(not all_passed) + + +class RPCTestHandler: + """ + Trigger the testscrips passed in via the list. + """ + + def __init__(self, num_tests_parallel, test_list=None, flags=None): + assert(num_tests_parallel >= 1) + self.num_jobs = num_tests_parallel + self.test_list = test_list + self.flags = flags + self.num_running = 0 + self.jobs = [] + + def get_next(self): + while self.num_running < self.num_jobs and self.test_list: + # Add tests + self.num_running += 1 + t = self.test_list.pop(0) + port_seed = ["--portseed=%s" % len(self.test_list)] + self.jobs.append((t, + time.time(), + subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags + port_seed, + universal_newlines=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE))) + if not self.jobs: + raise IndexError('%s from empty list' % __name__) + while True: + # Return first proc that finishes + time.sleep(.5) + for j in self.jobs: + (name, time0, proc) = j + if proc.poll() is not None: + (stdout, stderr) = proc.communicate(timeout=3) + passed = stderr == "" and proc.returncode == 0 + self.num_running -= 1 + self.jobs.remove(j) + return name, stdout, stderr, passed, int(time.time() - time0) + print('.', end='', flush=True) + class RPCCoverage(object): """ @@ -215,7 +282,7 @@ class RPCCoverage(object): """ def __init__(self): self.dir = tempfile.mkdtemp(prefix="coverage") - self.flag = '--coveragedir %s' % self.dir + self.flag = '--coveragedir=%s' % self.dir def report_rpc_coverage(self): """ diff --git a/qa/rpc-tests/bip9-softforks.py b/qa/rpc-tests/bip9-softforks.py index e9b659d508..a8fb878dcb 100755 --- a/qa/rpc-tests/bip9-softforks.py +++ b/qa/rpc-tests/bip9-softforks.py @@ -3,6 +3,7 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +from test_framework.blockstore import BlockStore from test_framework.test_framework import ComparisonTestFramework from test_framework.util import * from test_framework.mininode import CTransaction, NetworkThread @@ -167,11 +168,13 @@ class BIP9SoftForksTest(ComparisonTestFramework): yield TestInstance([[block, False]]) # Restart all + self.test.block_store.close() stop_nodes(self.nodes) wait_bitcoinds() shutil.rmtree(self.options.tmpdir) self.setup_chain() self.setup_network() + self.test.block_store = BlockStore(self.options.tmpdir) self.test.clear_all_connections() self.test.add_all_connections(self.nodes) NetworkThread().start() # Start up network handling in another thread diff --git a/qa/rpc-tests/create_cache.py b/qa/rpc-tests/create_cache.py new file mode 100755 index 0000000000..b6161e0917 --- /dev/null +++ b/qa/rpc-tests/create_cache.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Helper script to create the cache +# (see BitcoinTestFramework.setup_chain) +# + +from test_framework.test_framework import BitcoinTestFramework + +class CreateCache(BitcoinTestFramework): + + def setup_network(self): + # Don't setup any test nodes + self.options.noshutdown = True + + def run_test(self): + pass + +if __name__ == '__main__': + CreateCache().main() diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py index 4e72463096..3480de6c6e 100755 --- a/qa/rpc-tests/test_framework/test_framework.py +++ b/qa/rpc-tests/test_framework/test_framework.py @@ -5,10 +5,10 @@ # Base class for RPC testing -# Add python-bitcoinrpc to module search path: +import logging +import optparse import os import sys - import shutil import tempfile import traceback @@ -25,8 +25,9 @@ from .util import ( enable_coverage, check_json_precision, initialize_chain_clean, + PortSeed, ) -from .authproxy import AuthServiceProxy, JSONRPCException +from .authproxy import JSONRPCException class BitcoinTestFramework(object): @@ -95,7 +96,6 @@ class BitcoinTestFramework(object): self.setup_network(False) def main(self): - import optparse parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", @@ -108,18 +108,21 @@ class BitcoinTestFramework(object): help="Root directory for datadirs") parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true", help="Print out all RPC calls as they are made") + parser.add_option("--portseed", dest="port_seed", default=os.getpid(), type='int', + help="The seed to use for assigning port numbers (default: current process id)") parser.add_option("--coveragedir", dest="coveragedir", help="Write tested RPC commands into this directory") self.add_options(parser) (self.options, self.args) = parser.parse_args() if self.options.trace_rpc: - import logging logging.basicConfig(level=logging.DEBUG, stream=sys.stdout) if self.options.coveragedir: enable_coverage(self.options.coveragedir) + PortSeed.n = self.options.port_seed + os.environ['PATH'] = self.options.srcdir+":"+self.options.srcdir+"/qt:"+os.environ['PATH'] check_json_precision() diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 6dc685ea1b..6784177aaa 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -8,7 +8,6 @@ # Helpful routines for regression testing # -# Add python-bitcoinrpc to module search path: import os import sys @@ -36,6 +35,11 @@ PORT_MIN = 11000 # The number of ports to "reserve" for p2p and rpc, each PORT_RANGE = 5000 + +class PortSeed: + # Must be initialized with a unique integer for each process + n = None + #Set Mocktime default to OFF. #MOCKTIME is only needed for scripts that use the #cached version of the blockchain. If the cached @@ -91,10 +95,10 @@ def get_rpc_proxy(url, node_number, timeout=None): def p2p_port(n): assert(n <= MAX_NODES) - return PORT_MIN + n + (MAX_NODES * os.getpid()) % (PORT_RANGE - 1 - MAX_NODES) + return PORT_MIN + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES) def rpc_port(n): - return PORT_MIN + PORT_RANGE + n + (MAX_NODES * os.getpid()) % (PORT_RANGE -1 - MAX_NODES) + return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES) def check_json_precision(): """Make sure json library being used does not lose precision converting BTC values""" diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 24e2b3e0c8..65fd24e051 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -8,7 +8,8 @@ bench_bench_bitcoin_SOURCES = \ bench/bench.cpp \ bench/bench.h \ bench/Examples.cpp \ - bench/rollingbloom.cpp + bench/rollingbloom.cpp \ + bench/crypto_hash.cpp bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp new file mode 100644 index 0000000000..6b753f6308 --- /dev/null +++ b/src/bench/crypto_hash.cpp @@ -0,0 +1,53 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <iostream> + +#include "bench.h" +#include "bloom.h" +#include "utiltime.h" +#include "crypto/ripemd160.h" +#include "crypto/sha1.h" +#include "crypto/sha256.h" +#include "crypto/sha512.h" + +/* Number of bytes to hash per iteration */ +static const uint64_t BUFFER_SIZE = 1000*1000; + +static void RIPEMD160(benchmark::State& state) +{ + uint8_t hash[CRIPEMD160::OUTPUT_SIZE]; + std::vector<uint8_t> in(BUFFER_SIZE,0); + while (state.KeepRunning()) + CRIPEMD160().Write(begin_ptr(in), in.size()).Finalize(hash); +} + +static void SHA1(benchmark::State& state) +{ + uint8_t hash[CSHA1::OUTPUT_SIZE]; + std::vector<uint8_t> in(BUFFER_SIZE,0); + while (state.KeepRunning()) + CSHA1().Write(begin_ptr(in), in.size()).Finalize(hash); +} + +static void SHA256(benchmark::State& state) +{ + uint8_t hash[CSHA256::OUTPUT_SIZE]; + std::vector<uint8_t> in(BUFFER_SIZE,0); + while (state.KeepRunning()) + CSHA256().Write(begin_ptr(in), in.size()).Finalize(hash); +} + +static void SHA512(benchmark::State& state) +{ + uint8_t hash[CSHA512::OUTPUT_SIZE]; + std::vector<uint8_t> in(BUFFER_SIZE,0); + while (state.KeepRunning()) + CSHA512().Write(begin_ptr(in), in.size()).Finalize(hash); +} + +BENCHMARK(RIPEMD160); +BENCHMARK(SHA1); +BENCHMARK(SHA256); +BENCHMARK(SHA512); diff --git a/src/init.cpp b/src/init.cpp index b06f448a00..d19ca530b3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -37,9 +37,7 @@ #include "utilmoneystr.h" #include "validationinterface.h" #ifdef ENABLE_WALLET -#include "wallet/db.h" #include "wallet/wallet.h" -#include "wallet/walletdb.h" #endif #include <stdint.h> #include <stdio.h> @@ -125,7 +123,7 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; // shutdown thing. // -volatile bool fRequestShutdown = false; +volatile sig_atomic_t fRequestShutdown = false; void StartShutdown() { @@ -986,9 +984,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (fPrintToDebugLog) OpenDebugLog(); -#ifdef ENABLE_WALLET - LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); -#endif if (!fLogTimestamps) LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime())); LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); diff --git a/src/main.cpp b/src/main.cpp index ebe91f7fa9..09f82312a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1005,7 +1005,7 @@ std::string FormatStateMessage(const CValidationState &state) } bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, - bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, + bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, std::vector<uint256>& vHashTxnToUncache) { const uint256 hash = tx.GetHash(); @@ -1170,9 +1170,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp); unsigned int nSize = entry.GetTxSize(); - if (txFeeRate) { - *txFeeRate = CFeeRate(nFees, nSize); - } // Check that the transaction doesn't have an excessive number of // sigops, making it impossible to mine. Since the coinbase transaction @@ -1421,10 +1418,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C } bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit, const CAmount nAbsurdFee) + bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee) { std::vector<uint256> vHashTxToUncache; - bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, txFeeRate, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache); + bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, nAbsurdFee, vHashTxToUncache); if (!res) { BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache) pcoinsTip->Uncache(hashTx); @@ -2651,7 +2648,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara // ignore validation errors in resurrected transactions list<CTransaction> removed; CValidationState stateDummy; - if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, NULL, true)) { + if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) { mempool.removeRecursive(tx, removed); } else if (mempool.exists(tx.GetHash())) { vHashUpdate.push_back(tx.GetHash()); @@ -3008,7 +3005,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C return true; } -bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { +bool ResetBlockFailureFlags(CBlockIndex *pindex) { AssertLockHeld(cs_main); int nHeight = pindex->nHeight; @@ -4956,10 +4953,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->setAskFor.erase(inv.hash); mapAlreadyAskedFor.erase(inv.hash); - CFeeRate txFeeRate = CFeeRate(0); - if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, &txFeeRate)) { + if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { mempool.check(pcoinsTip); - RelayTransaction(tx, txFeeRate); + RelayTransaction(tx); vWorkQueue.push_back(inv.hash); LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n", @@ -4990,10 +4986,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (setMisbehaving.count(fromPeer)) continue; - CFeeRate orphanFeeRate = CFeeRate(0); - if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2, &orphanFeeRate)) { + if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) { LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); - RelayTransaction(orphanTx, orphanFeeRate); + RelayTransaction(orphanTx); vWorkQueue.push_back(orphanHash); vEraseQueue.push_back(orphanHash); } @@ -5046,7 +5041,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int nDoS = 0; if (!state.IsInvalid(nDoS) || nDoS == 0) { LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id); - RelayTransaction(tx, txFeeRate); + RelayTransaction(tx); } else { LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state)); } diff --git a/src/main.h b/src/main.h index 3cc16fd8f4..576f73b5f2 100644 --- a/src/main.h +++ b/src/main.h @@ -295,7 +295,7 @@ void PruneAndFlush(); /** (try to) add transaction to memory pool **/ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, CFeeRate* txFeeRate, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0); + bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0); /** Convert CValidationState to a human-readable message for logging */ std::string FormatStateMessage(const CValidationState &state); @@ -464,7 +464,7 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex); /** Remove invalidity status from a block and its descendants. */ -bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex); +bool ResetBlockFailureFlags(CBlockIndex *pindex); /** The currently-connected chain of blocks (protected by cs_main). */ extern CChain chainActive; diff --git a/src/net.cpp b/src/net.cpp index 5e810a0f15..aa5b47340a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2069,7 +2069,7 @@ public: instance_of_cnetcleanup; -void RelayTransaction(const CTransaction& tx, CFeeRate feerate) +void RelayTransaction(const CTransaction& tx) { CInv inv(MSG_TX, tx.GetHash()); { @@ -783,7 +783,7 @@ public: class CTransaction; -void RelayTransaction(const CTransaction& tx, CFeeRate feerate); +void RelayTransaction(const CTransaction& tx); /** Access to the (IP) address database (peers.dat) */ class CAddrDB diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 9c21bb24ce..6218ab6ab0 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -370,6 +370,7 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) splash->setAttribute(Qt::WA_DeleteOnClose); splash->show(); connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*))); + connect(this, SIGNAL(requestedShutdown()), splash, SLOT(close())); } void BitcoinApplication::startThread() diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b00cdfcaf2..9984486364 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -474,6 +474,16 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) } #endif // ENABLE_WALLET unitDisplayControl->setOptionsModel(clientModel->getOptionsModel()); + + OptionsModel* optionsModel = clientModel->getOptionsModel(); + if(optionsModel) + { + // be aware of the tray icon disable state change reported by the OptionsModel object. + connect(optionsModel,SIGNAL(hideTrayIconChanged(bool)),this,SLOT(setTrayIconVisible(bool))); + + // initialize the disable state of the tray icon with the current value in the model. + setTrayIconVisible(optionsModel->getHideTrayIcon()); + } } else { // Disable possibility to show main window via action toggleHideAction->setEnabled(false); @@ -535,7 +545,7 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle) QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText(); trayIcon->setToolTip(toolTip); trayIcon->setIcon(networkStyle->getTrayAndWindowIcon()); - trayIcon->show(); + trayIcon->hide(); #endif notificator = new Notificator(QApplication::applicationName(), trayIcon, this); @@ -1044,6 +1054,14 @@ void BitcoinGUI::showProgress(const QString &title, int nProgress) progressDialog->setValue(nProgress); } +void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon) +{ + if (trayIcon) + { + trayIcon->setVisible(!fHideTrayIcon); + } +} + static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style) { bool modal = (style & CClientUIInterface::MODAL); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 871ca1ba34..27ef11c75c 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -218,6 +218,9 @@ private Q_SLOTS: /** Show progress dialog e.g. for verifychain */ void showProgress(const QString &title, int nProgress); + + /** When hideTrayIcon setting is changed in OptionsModel hide or show the icon accordingly. */ + void setTrayIconVisible(bool); }; class UnitDisplayStatusBarControl : public QLabel diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index c712e6ea01..0b29201872 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -505,6 +505,16 @@ </attribute> <layout class="QVBoxLayout" name="verticalLayout_Window"> <item> + <widget class="QCheckBox" name="hideTrayIcon"> + <property name="toolTip"> + <string>&Hide the icon from the system tray.</string> + </property> + <property name="text"> + <string>Hide tray icon</string> + </property> + </widget> + </item> + <item> <widget class="QCheckBox" name="minimizeToTray"> <property name="toolTip"> <string>Show only a tray icon after minimizing the window.</string> diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 95a3fa8d21..f2db398899 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -198,6 +198,7 @@ void OptionsDialog::setMapper() /* Window */ #ifndef Q_OS_MAC + mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon); mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray); mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose); #endif @@ -243,6 +244,19 @@ void OptionsDialog::on_cancelButton_clicked() reject(); } +void OptionsDialog::on_hideTrayIcon_stateChanged(int fState) +{ + if(fState) + { + ui->minimizeToTray->setChecked(false); + ui->minimizeToTray->setEnabled(false); + } + else + { + ui->minimizeToTray->setEnabled(true); + } +} + void OptionsDialog::showRestartWarning(bool fPersistent) { ui->statusLabel->setStyleSheet("QLabel { color: red; }"); diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index e944fb9ee9..41b56d1386 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -49,6 +49,8 @@ private Q_SLOTS: void on_resetButton_clicked(); void on_okButton_clicked(); void on_cancelButton_clicked(); + + void on_hideTrayIcon_stateChanged(int fState); void showRestartWarning(bool fPersistent = false); void clearStatusLabel(); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index d091bb9e61..cc2cbc0e66 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -51,9 +51,14 @@ void OptionsModel::Init(bool resetSettings) // These are Qt-only settings: // Window + if (!settings.contains("fHideTrayIcon")) + settings.setValue("fHideTrayIcon", false); + fHideTrayIcon = settings.value("fHideTrayIcon").toBool(); + Q_EMIT hideTrayIconChanged(fHideTrayIcon); + if (!settings.contains("fMinimizeToTray")) settings.setValue("fMinimizeToTray", false); - fMinimizeToTray = settings.value("fMinimizeToTray").toBool(); + fMinimizeToTray = settings.value("fMinimizeToTray").toBool() && !fHideTrayIcon; if (!settings.contains("fMinimizeOnClose")) settings.setValue("fMinimizeOnClose", false); @@ -166,6 +171,8 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const { case StartAtStartup: return GUIUtil::GetStartOnSystemStartup(); + case HideTrayIcon: + return fHideTrayIcon; case MinimizeToTray: return fMinimizeToTray; case MapPortUPnP: @@ -242,6 +249,11 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in case StartAtStartup: successful = GUIUtil::SetStartOnSystemStartup(value.toBool()); break; + case HideTrayIcon: + fHideTrayIcon = value.toBool(); + settings.setValue("fHideTrayIcon", fHideTrayIcon); + Q_EMIT hideTrayIconChanged(fHideTrayIcon); + break; case MinimizeToTray: fMinimizeToTray = value.toBool(); settings.setValue("fMinimizeToTray", fMinimizeToTray); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 841711dd2d..3b491ceac2 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -28,6 +28,7 @@ public: enum OptionID { StartAtStartup, // bool + HideTrayIcon, // bool MinimizeToTray, // bool MapPortUPnP, // bool MinimizeOnClose, // bool @@ -58,6 +59,7 @@ public: void setDisplayUnit(const QVariant &value); /* Explicit getters */ + bool getHideTrayIcon() { return fHideTrayIcon; } bool getMinimizeToTray() { return fMinimizeToTray; } bool getMinimizeOnClose() { return fMinimizeOnClose; } int getDisplayUnit() { return nDisplayUnit; } @@ -72,6 +74,7 @@ public: private: /* Qt-only settings */ + bool fHideTrayIcon; bool fMinimizeToTray; bool fMinimizeOnClose; QString language; @@ -87,6 +90,7 @@ private: Q_SIGNALS: void displayUnitChanged(int unit); void coinControlFeaturesChanged(bool); + void hideTrayIconChanged(bool); }; #endif // BITCOIN_QT_OPTIONSMODEL_H diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 6960415e2e..cf3c73c4df 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -973,7 +973,6 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp) std::string strHash = params[0].get_str(); uint256 hash(uint256S(strHash)); - CValidationState state; { LOCK(cs_main); @@ -981,12 +980,11 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); CBlockIndex* pblockindex = mapBlockIndex[hash]; - ReconsiderBlock(state, pblockindex); + ResetBlockFailureFlags(pblockindex); } - if (state.IsValid()) { - ActivateBestChain(state, Params()); - } + CValidationState state; + ActivateBestChain(state, Params()); if (!state.IsValid()) { throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index de8cd68f66..bec7ebe55f 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -819,12 +819,11 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) const CCoins* existingCoins = view.AccessCoins(hashTx); bool fHaveMempool = mempool.exists(hashTx); bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; - CFeeRate txFeeRate = CFeeRate(0); if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets CValidationState state; bool fMissingInputs; - if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, &txFeeRate, false, nMaxRawTxFee)) { + if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, nMaxRawTxFee)) { if (state.IsInvalid()) { throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); } else { @@ -837,7 +836,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) } else if (fHaveChain) { throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); } - RelayTransaction(tx, txFeeRate); + RelayTransaction(tx); return hashTx.GetHex(); } diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 184ddc28ab..52777b61f9 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -79,6 +79,7 @@ void CScheduler::serviceQueue() } } --nThreadsServicingQueue; + newTaskScheduled.notify_one(); } void CScheduler::stop(bool drain) diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json index e75b7825ed..757d94b526 100644 --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -700,6 +700,8 @@ ["0x17 0x3014020002107777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Zero-length R is correctly encoded"], ["0x17 0x3014021077777777777777777777777777777777020001", "0 CHECKSIG NOT", "", "OK", "Zero-length S is correctly encoded for DERSIG"], ["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701", "0 CHECKSIG NOT", "", "OK", "Negative S is correctly encoded"], + +["2147483648", "NOP3", "CHECKSEQUENCEVERIFY", "OK", "CSV passes if stack top bit 1 << 31 is set"], ["", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "Test the test: we should have an empty stack after scriptSig evaluation"], [" ", "DEPTH", "P2SH,STRICTENC", "EVAL_FALSE", "and multiple spaces should not change that."], @@ -855,7 +857,7 @@ ["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], ["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"], -["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], +["1", "NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], ["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], ["Ensure 100% coverage of discouraged NOPS"], @@ -1820,5 +1822,12 @@ "P2SH with CLEANSTACK" ], +["CHECKSEQUENCEVERIFY tests"], +["", "NOP3", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"], +["-1", "NOP3", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"], +["0x0100", "NOP3", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"], +["0", "NOP3", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"], +["4294967296", "NOP3", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", + "CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"], ["The End"] ] diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index 9acd0e2430..aa12dfbd54 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -40,7 +40,6 @@ static void MicroSleep(uint64_t n) #endif } -#if 0 /* Disabled for now because there is a race condition issue in this test - see #6540 */ BOOST_AUTO_TEST_CASE(manythreads) { seed_insecure_rand(false); @@ -116,6 +115,5 @@ BOOST_AUTO_TEST_CASE(manythreads) } BOOST_CHECK_EQUAL(counterSum, 200); } -#endif BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 237b26329b..c29e30792a 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx) LOCK(cs_main); CValidationState state; - return AcceptToMemoryPool(mempool, state, tx, false, NULL, NULL, true, 0); + return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, 0); } BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) diff --git a/src/util.cpp b/src/util.cpp index 3f0f8be544..80f2193016 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -113,7 +113,7 @@ string strMiscWarning; bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; bool fLogIPs = DEFAULT_LOGIPS; -volatile bool fReopenDebugLog = false; +volatile sig_atomic_t fReopenDebugLog = false; CTranslationInterface translationInterface; /** Init OpenSSL library multithreading support */ diff --git a/src/util.h b/src/util.h index 45e81ab67f..88a00d3ca1 100644 --- a/src/util.h +++ b/src/util.h @@ -28,6 +28,10 @@ #include <boost/signals2/signal.hpp> #include <boost/thread/exceptions.hpp> +#ifndef WIN32 +#include <signal.h> +#endif + static const bool DEFAULT_LOGTIMEMICROS = false; static const bool DEFAULT_LOGIPS = false; static const bool DEFAULT_LOGTIMESTAMPS = true; @@ -50,7 +54,7 @@ extern std::string strMiscWarning; extern bool fLogTimestamps; extern bool fLogTimeMicros; extern bool fLogIPs; -extern volatile bool fReopenDebugLog; +extern volatile sig_atomic_t fReopenDebugLog; extern CTranslationInterface translationInterface; extern const char * const BITCOIN_CONF_FILENAME; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 29d7138547..6b942e29d7 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -368,6 +368,7 @@ void CWallet::Flush(bool shutdown) bool CWallet::Verify() { + LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); LogPrintf("Using wallet %s\n", walletFile); @@ -729,7 +730,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD // Write to disk if (fInsertedNew || fUpdated) - if (!wtx.WriteToDisk(pwalletdb)) + if (!pwalletdb->WriteTx(wtx)) return false; // Break debit/credit balance caches: @@ -829,7 +830,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx) wtx.nIndex = -1; wtx.setAbandoned(); wtx.MarkDirty(); - wtx.WriteToDisk(&walletdb); + walletdb.WriteTx(wtx); NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED); // Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0)); @@ -891,7 +892,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) wtx.nIndex = -1; wtx.hashBlock = hashBlock; wtx.MarkDirty(); - wtx.WriteToDisk(&walletdb); + walletdb.WriteTx(wtx); // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0)); while (iter != mapTxSpends.end() && iter->first.hash == now) { @@ -1186,12 +1187,6 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived, } } - -bool CWalletTx::WriteToDisk(CWalletDB *pwalletdb) -{ - return pwalletdb->WriteTx(GetHash(), *this); -} - /** * Scan the block chain (starting in pindexStart) for transactions * from or to us. If fUpdate is true, found transactions that already @@ -1277,9 +1272,7 @@ bool CWalletTx::RelayWalletTransaction() { if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) { LogPrintf("Relaying wtx %s\n", GetHash().ToString()); - CFeeRate feeRate; - mempool.lookupFeeRate(GetHash(), feeRate); - RelayTransaction((CTransaction)*this, feeRate); + RelayTransaction((CTransaction)*this); return true; } } @@ -3194,7 +3187,7 @@ bool CWallet::InitLoadWallet() copyTo->fFromMe = copyFrom->fFromMe; copyTo->strFromAccount = copyFrom->strFromAccount; copyTo->nOrderPos = copyFrom->nOrderPos; - copyTo->WriteToDisk(&walletdb); + walletdb.WriteTx(*copyTo); } } } @@ -3336,5 +3329,5 @@ int CMerkleTx::GetBlocksToMaturity() const bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee) { CValidationState state; - return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, NULL, false, nAbsurdFee); + return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index c3bd343edd..cc568c3749 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -394,8 +394,6 @@ public: bool InMempool() const; bool IsTrusted() const; - bool WriteToDisk(CWalletDB *pwalletdb); - int64_t GetTxTime() const; int GetRequestCount() const; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f2b5408e92..48579b2821 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -55,10 +55,10 @@ bool CWalletDB::ErasePurpose(const string& strPurpose) return Erase(make_pair(string("purpose"), strPurpose)); } -bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx) +bool CWalletDB::WriteTx(const CWalletTx& wtx) { nWalletDBUpdated++; - return Write(std::make_pair(std::string("tx"), hash), wtx); + return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx); } bool CWalletDB::EraseTx(uint256 hash) @@ -291,7 +291,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet) if (pwtx) { - if (!WriteTx(pwtx->GetHash(), *pwtx)) + if (!WriteTx(*pwtx)) return DB_LOAD_FAIL; } else @@ -315,7 +315,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet) // Since we're changing the order, write it back if (pwtx) { - if (!WriteTx(pwtx->GetHash(), *pwtx)) + if (!WriteTx(*pwtx)) return DB_LOAD_FAIL; } else @@ -698,7 +698,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value' BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade) - WriteTx(hash, pwallet->mapWallet[hash]); + WriteTx(pwallet->mapWallet[hash]); // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000)) diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index fe6c366343..5345c0907e 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -87,7 +87,7 @@ public: bool WritePurpose(const std::string& strAddress, const std::string& purpose); bool ErasePurpose(const std::string& strAddress); - bool WriteTx(uint256 hash, const CWalletTx& wtx); + bool WriteTx(const CWalletTx& wtx); bool EraseTx(uint256 hash); bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta); |