aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qa/README.md20
-rwxr-xr-xqa/pull-tester/rpc-tests.py86
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py6
-rw-r--r--qa/rpc-tests/test_framework/util.py28
-rwxr-xr-xqa/rpc-tests/walletbackup.py2
-rw-r--r--src/Makefile.bench.include3
-rw-r--r--src/bench/rollingbloom.cpp43
-rw-r--r--src/bloom.cpp40
-rw-r--r--src/bloom.h13
-rw-r--r--src/main.cpp23
-rw-r--r--src/main.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp53
-rw-r--r--src/qt/sendcoinsdialog.h22
-rw-r--r--src/test/bloom_tests.cpp5
-rw-r--r--src/test/coins_tests.cpp3
-rw-r--r--src/txmempool.cpp4
16 files changed, 244 insertions, 109 deletions
diff --git a/qa/README.md b/qa/README.md
index 3e0a526d13..c7e574ff70 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -19,15 +19,25 @@ sudo apt-get install python3-zmq
Running tests
=============
-You can run any single test by calling `qa/pull-tester/rpc-tests.py <testname>`.
+You can run any single test by calling
-Or you can run any combination of tests by calling `qa/pull-tester/rpc-tests.py <testname1> <testname2> <testname3> ...`
+ qa/pull-tester/rpc-tests.py <testname>
-Run the regression test suite with `qa/pull-tester/rpc-tests.py`
+Or you can run any combination of tests by calling
-Run all possible tests with `qa/pull-tester/rpc-tests.py -extended`
+ qa/pull-tester/rpc-tests.py <testname1> <testname2> <testname3> ...
-Possible options:
+Run the regression test suite with
+
+ qa/pull-tester/rpc-tests.py
+
+Run all possible tests with
+
+ qa/pull-tester/rpc-tests.py -extended
+
+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:
```
-h, --help show this help message and exit
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index 15153b7f58..10c3799b86 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -31,6 +31,14 @@ import re
from tests_config import *
+BOLD = ("","")
+if os.name == 'posix':
+ # primitive formatting on supported
+ # terminal via ANSI escape sequences:
+ BOLD = ('\033[0m', '\033[1m')
+
+RPC_TESTS_DIR = BUILDDIR + '/qa/rpc-tests/'
+
#If imported values are not defined then set to zero (or disabled)
if 'ENABLE_WALLET' not in vars():
ENABLE_WALLET=0
@@ -43,29 +51,29 @@ if 'ENABLE_ZMQ' not in vars():
ENABLE_COVERAGE=0
-#Create a set to store arguments and create the passOn string
+#Create a set to store arguments and create the passon string
opts = set()
-passOn = ""
-p = re.compile("^--")
+passon_args = ""
+PASSON_REGEX = re.compile("^--")
-bold = ("","")
-if (os.name == 'posix'):
- bold = ('\033[0m', '\033[1m')
+print_help = False
for arg in sys.argv[1:]:
+ if arg == "--help" or arg == "-h" or arg == "-?":
+ print_help = True
+ break
if arg == '--coverage':
ENABLE_COVERAGE = 1
- elif (p.match(arg) or arg == "-h"):
- passOn += " " + arg
+ elif PASSON_REGEX.match(arg):
+ passon_args += " " + arg
else:
opts.add(arg)
#Set env vars
-buildDir = BUILDDIR
if "BITCOIND" not in os.environ:
- os.environ["BITCOIND"] = buildDir + '/src/bitcoind' + EXEEXT
+ os.environ["BITCOIND"] = BUILDDIR + '/src/bitcoind' + EXEEXT
if "BITCOINCLI" not in os.environ:
- os.environ["BITCOINCLI"] = buildDir + '/src/bitcoin-cli' + EXEEXT
+ os.environ["BITCOINCLI"] = BUILDDIR + '/src/bitcoin-cli' + EXEEXT
if EXEEXT == ".exe" and "-win" not in opts:
# https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
@@ -82,9 +90,9 @@ if ENABLE_ZMQ:
try:
import zmq
except ImportError as e:
- print("ERROR: \"import zmq\" failed. Set ENABLE_ZMQ=0 or " \
+ print("WARNING: \"import zmq\" failed. Set ENABLE_ZMQ=0 or " \
"to run zmq tests, see dependency info in /qa/README.md.")
- raise e
+ ENABLE_ZMQ=0
#Tests
testScripts = [
@@ -153,48 +161,34 @@ testScriptsExt = [
]
def runtests():
+ test_list = []
+ if '-extended' in opts:
+ test_list = testScripts + testScriptsExt
+ elif len(opts) == 0 or (len(opts) == 1 and "-win" in opts):
+ test_list = testScripts
+ else:
+ for t in testScripts + testScriptsExt:
+ if t in opts or re.sub(".py$", "", t) in opts:
+ test_list.append(t)
+
+ if print_help:
+ # Only print help of the first script and exit
+ subprocess.check_call(RPC_TESTS_DIR + test_list[0] + ' -h', shell=True)
+ sys.exit(0)
+
coverage = None
if ENABLE_COVERAGE:
coverage = RPCCoverage()
print("Initializing coverage directory at %s\n" % coverage.dir)
-
- rpcTestDir = buildDir + '/qa/rpc-tests/'
- run_extended = '-extended' in opts
- cov_flag = coverage.flag if coverage else ''
- flags = " --srcdir %s/src %s %s" % (buildDir, cov_flag, passOn)
+ flags = " --srcdir %s/src %s %s" % (BUILDDIR, coverage.flag if coverage else '', passon_args)
#Run Tests
- for i in range(len(testScripts)):
- if (len(opts) == 0
- or (len(opts) == 1 and "-win" in opts )
- or run_extended
- or testScripts[i] in opts
- or re.sub(".py$", "", testScripts[i]) in opts ):
-
- print("Running testscript %s%s%s ..." % (bold[1], testScripts[i], bold[0]))
- time0 = time.time()
- subprocess.check_call(
- rpcTestDir + testScripts[i] + flags, shell=True)
- print("Duration: %s s\n" % (int(time.time() - time0)))
-
- # exit if help is called so we print just one set of
- # instructions
- p = re.compile(" -h| --help")
- if p.match(passOn):
- sys.exit(0)
-
- # Run Extended Tests
- for i in range(len(testScriptsExt)):
- if (run_extended or testScriptsExt[i] in opts
- or re.sub(".py$", "", testScriptsExt[i]) in opts):
-
- print(
- "Running 2nd level testscript "
- + "%s%s%s ..." % (bold[1], testScriptsExt[i], bold[0]))
+ for t in test_list:
+ print("Running testscript %s%s%s ..." % (BOLD[1], t, BOLD[0]))
time0 = time.time()
subprocess.check_call(
- rpcTestDir + testScriptsExt[i] + flags, shell=True)
+ RPC_TESTS_DIR + t + flags, shell=True)
print("Duration: %s s\n" % (int(time.time() - time0)))
if coverage:
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
index ed12e1efb6..4e72463096 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -102,7 +102,7 @@ class BitcoinTestFramework(object):
help="Leave bitcoinds and test.* datadir on exit or error")
parser.add_option("--noshutdown", dest="noshutdown", default=False, action="store_true",
help="Don't stop bitcoinds after the test execution")
- parser.add_option("--srcdir", dest="srcdir", default="../../src",
+ parser.add_option("--srcdir", dest="srcdir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../../src"),
help="Source directory containing bitcoind/bitcoin-cli (default: %default)")
parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
help="Root directory for datadirs")
@@ -115,7 +115,7 @@ class BitcoinTestFramework(object):
if self.options.trace_rpc:
import logging
- logging.basicConfig(level=logging.DEBUG)
+ logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
if self.options.coveragedir:
enable_coverage(self.options.coveragedir)
@@ -148,6 +148,8 @@ class BitcoinTestFramework(object):
except Exception as e:
print("Unexpected exception caught during testing: " + repr(e))
traceback.print_tb(sys.exc_info()[2])
+ except KeyboardInterrupt as e:
+ print("Exiting after " + repr(e))
if not self.options.noshutdown:
print("Stopping nodes")
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index ea3931cef3..6dc685ea1b 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -16,6 +16,7 @@ from binascii import hexlify, unhexlify
from base64 import b64encode
from decimal import Decimal, ROUND_DOWN
import json
+import http.client
import random
import shutil
import subprocess
@@ -28,6 +29,13 @@ from .authproxy import AuthServiceProxy, JSONRPCException
COVERAGE_DIR = None
+# The maximum number of nodes a single test can spawn
+MAX_NODES = 8
+# Don't assign rpc or p2p ports lower than this
+PORT_MIN = 11000
+# The number of ports to "reserve" for p2p and rpc, each
+PORT_RANGE = 5000
+
#Set Mocktime default to OFF.
#MOCKTIME is only needed for scripts that use the
#cached version of the blockchain. If the cached
@@ -82,9 +90,11 @@ def get_rpc_proxy(url, node_number, timeout=None):
def p2p_port(n):
- return 11000 + n + os.getpid()%999
+ assert(n <= MAX_NODES)
+ return PORT_MIN + n + (MAX_NODES * os.getpid()) % (PORT_RANGE - 1 - MAX_NODES)
+
def rpc_port(n):
- return 12000 + n + os.getpid()%999
+ return PORT_MIN + PORT_RANGE + n + (MAX_NODES * os.getpid()) % (PORT_RANGE -1 - MAX_NODES)
def check_json_precision():
"""Make sure json library being used does not lose precision converting BTC values"""
@@ -292,8 +302,8 @@ def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None):
"""
Start multiple bitcoinds, return RPC connections to them
"""
- if extra_args is None: extra_args = [ None for i in range(num_nodes) ]
- if binary is None: binary = [ None for i in range(num_nodes) ]
+ if extra_args is None: extra_args = [ None for _ in range(num_nodes) ]
+ if binary is None: binary = [ None for _ in range(num_nodes) ]
rpcs = []
try:
for i in range(num_nodes):
@@ -307,13 +317,19 @@ def log_filename(dirname, n_node, logname):
return os.path.join(dirname, "node"+str(n_node), "regtest", logname)
def stop_node(node, i):
- node.stop()
+ try:
+ node.stop()
+ except http.client.CannotSendRequest as e:
+ print("WARN: Unable to stop node: " + repr(e))
bitcoind_processes[i].wait()
del bitcoind_processes[i]
def stop_nodes(nodes):
for node in nodes:
- node.stop()
+ try:
+ node.stop()
+ except http.client.CannotSendRequest as e:
+ print("WARN: Unable to stop node: " + repr(e))
del nodes[:] # Emptying array closes connections as a side effect
def set_node_times(nodes, t):
diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py
index 418f3103e3..c3d53669c9 100755
--- a/qa/rpc-tests/walletbackup.py
+++ b/qa/rpc-tests/walletbackup.py
@@ -37,7 +37,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from random import randint
import logging
-logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO)
+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout)
class WalletBackupTest(BitcoinTestFramework):
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 8e7b59b461..24e2b3e0c8 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -7,7 +7,8 @@ bench_bench_bitcoin_SOURCES = \
bench/bench_bitcoin.cpp \
bench/bench.cpp \
bench/bench.h \
- bench/Examples.cpp
+ bench/Examples.cpp \
+ bench/rollingbloom.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/rollingbloom.cpp b/src/bench/rollingbloom.cpp
new file mode 100644
index 0000000000..73c02cf718
--- /dev/null
+++ b/src/bench/rollingbloom.cpp
@@ -0,0 +1,43 @@
+// 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"
+
+static void RollingBloom(benchmark::State& state)
+{
+ CRollingBloomFilter filter(120000, 0.000001);
+ std::vector<unsigned char> data(32);
+ uint32_t count = 0;
+ uint32_t nEntriesPerGeneration = (120000 + 1) / 2;
+ uint32_t countnow = 0;
+ uint64_t match = 0;
+ while (state.KeepRunning()) {
+ count++;
+ data[0] = count;
+ data[1] = count >> 8;
+ data[2] = count >> 16;
+ data[3] = count >> 24;
+ if (countnow == nEntriesPerGeneration) {
+ int64_t b = GetTimeMicros();
+ filter.insert(data);
+ int64_t e = GetTimeMicros();
+ std::cout << "RollingBloom-refresh,1," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "\n";
+ countnow = 0;
+ } else {
+ filter.insert(data);
+ }
+ countnow++;
+ data[0] = count >> 24;
+ data[1] = count >> 16;
+ data[2] = count >> 8;
+ data[3] = count;
+ match += filter.contains(data);
+ }
+}
+
+BENCHMARK(RollingBloom);
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 4e6f0e5d2d..fd328e8e96 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -234,14 +234,18 @@ CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate)
*/
uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)));
data.clear();
- /* We store up to 16 'bits' per data element. */
- data.resize((nFilterBits + 15) / 16);
+ /* For each data element we need to store 2 bits. If both bits are 0, the
+ * bit is treated as unset. If the bits are (01), (10), or (11), the bit is
+ * treated as set in generation 1, 2, or 3 respectively.
+ * These bits are stored in separate integers: position P corresponds to bit
+ * (P & 63) of the integers data[(P >> 6) * 2] and data[(P >> 6) * 2 + 1]. */
+ data.resize(((nFilterBits + 63) / 64) << 1);
reset();
}
/* Similar to CBloomFilter::Hash */
-inline unsigned int CRollingBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const {
- return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (data.size() * 16);
+static inline uint32_t RollingBloomHash(unsigned int nHashNum, uint32_t nTweak, const std::vector<unsigned char>& vDataToHash) {
+ return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash);
}
void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
@@ -252,18 +256,25 @@ void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
if (nGeneration == 4) {
nGeneration = 1;
}
+ uint64_t nGenerationMask1 = -(uint64_t)(nGeneration & 1);
+ uint64_t nGenerationMask2 = -(uint64_t)(nGeneration >> 1);
/* Wipe old entries that used this generation number. */
- for (uint32_t p = 0; p < data.size() * 16; p++) {
- if (get(p) == nGeneration) {
- put(p, 0);
- }
+ for (uint32_t p = 0; p < data.size(); p += 2) {
+ uint64_t p1 = data[p], p2 = data[p + 1];
+ uint64_t mask = (p1 ^ nGenerationMask1) | (p2 ^ nGenerationMask2);
+ data[p] = p1 & mask;
+ data[p + 1] = p2 & mask;
}
}
nEntriesThisGeneration++;
for (int n = 0; n < nHashFuncs; n++) {
- uint32_t h = Hash(n, vKey);
- put(h, nGeneration);
+ uint32_t h = RollingBloomHash(n, nTweak, vKey);
+ int bit = h & 0x3F;
+ uint32_t pos = (h >> 6) % data.size();
+ /* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */
+ data[pos & ~1] = (data[pos & ~1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration & 1)) << bit;
+ data[pos | 1] = (data[pos | 1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration >> 1)) << bit;
}
}
@@ -276,8 +287,11 @@ void CRollingBloomFilter::insert(const uint256& hash)
bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
for (int n = 0; n < nHashFuncs; n++) {
- uint32_t h = Hash(n, vKey);
- if (get(h) == 0) {
+ uint32_t h = RollingBloomHash(n, nTweak, vKey);
+ int bit = h & 0x3F;
+ uint32_t pos = (h >> 6) % data.size();
+ /* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */
+ if (!(((data[pos & ~1] | data[pos | 1]) >> bit) & 1)) {
return false;
}
}
@@ -295,7 +309,7 @@ void CRollingBloomFilter::reset()
nTweak = GetRand(std::numeric_limits<unsigned int>::max());
nEntriesThisGeneration = 0;
nGeneration = 1;
- for (std::vector<uint32_t>::iterator it = data.begin(); it != data.end(); it++) {
+ for (std::vector<uint64_t>::iterator it = data.begin(); it != data.end(); it++) {
*it = 0;
}
}
diff --git a/src/bloom.h b/src/bloom.h
index b0ad8b875d..ad6de625d8 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -135,20 +135,9 @@ private:
int nEntriesPerGeneration;
int nEntriesThisGeneration;
int nGeneration;
- std::vector<uint32_t> data;
+ std::vector<uint64_t> data;
unsigned int nTweak;
int nHashFuncs;
-
- unsigned int Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const;
-
- inline int get(uint32_t position) const {
- return (data[(position >> 4) % data.size()] >> (2 * (position & 0xF))) & 0x3;
- }
-
- inline void put(uint32_t position, uint32_t val) {
- uint32_t& cell = data[(position >> 4) % data.size()];
- cell = (cell & ~(((uint32_t)3) << (2 * (position & 0xF)))) | (val << (2 * (position & 0xF)));
- }
};
#endif // BITCOIN_BLOOM_H
diff --git a/src/main.cpp b/src/main.cpp
index 92a38f230f..ebe91f7fa9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1593,7 +1593,7 @@ bool fLargeWorkForkFound = false;
bool fLargeWorkInvalidChainFound = false;
CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
-static void AlertNotify(const std::string& strMessage, bool fThread)
+static void AlertNotify(const std::string& strMessage)
{
uiInterface.NotifyAlertChanged();
std::string strCmd = GetArg("-alertnotify", "");
@@ -1607,10 +1607,7 @@ static void AlertNotify(const std::string& strMessage, bool fThread)
safeStatus = singleQuote+safeStatus+singleQuote;
boost::replace_all(strCmd, "%s", safeStatus);
- if (fThread)
- boost::thread t(runCommand, strCmd); // thread runs free
- else
- runCommand(strCmd);
+ boost::thread t(runCommand, strCmd); // thread runs free
}
void CheckForkWarningConditions()
@@ -1632,7 +1629,7 @@ void CheckForkWarningConditions()
{
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
pindexBestForkBase->phashBlock->ToString() + std::string("'");
- AlertNotify(warning, true);
+ AlertNotify(warning);
}
if (pindexBestForkTip && pindexBestForkBase)
{
@@ -1744,7 +1741,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
}
}
-void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight)
+void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight)
{
// mark inputs spent
if (!tx.IsCoinBase()) {
@@ -1770,10 +1767,10 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
inputs.ModifyNewCoins(tx.GetHash(), tx.IsCoinBase())->FromTx(tx, nHeight);
}
-void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight)
+void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
{
CTxUndo txundo;
- UpdateCoins(tx, state, inputs, txundo, nHeight);
+ UpdateCoins(tx, inputs, txundo, nHeight);
}
bool CScriptCheck::operator()() {
@@ -2163,7 +2160,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
if (!strWarning.empty())
{
strMiscWarning = strWarning;
- AlertNotify(strWarning, true);
+ AlertNotify(strWarning);
lastAlertTime = now;
}
}
@@ -2385,7 +2382,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (i > 0) {
blockundo.vtxundo.push_back(CTxUndo());
}
- UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
+ UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
@@ -2598,7 +2595,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
if (state == THRESHOLD_ACTIVE) {
strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
if (!fWarned) {
- AlertNotify(strMiscWarning, true);
+ AlertNotify(strMiscWarning);
fWarned = true;
}
} else {
@@ -2620,7 +2617,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect");
if (!fWarned) {
- AlertNotify(strMiscWarning, true);
+ AlertNotify(strMiscWarning);
fWarned = true;
}
}
diff --git a/src/main.h b/src/main.h
index bdf7f5a687..3cc16fd8f4 100644
--- a/src/main.h
+++ b/src/main.h
@@ -338,7 +338,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL);
/** Apply the effects of this transaction on the UTXO set represented by view */
-void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight);
+void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 780a6c9709..54ebd25833 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -26,6 +26,9 @@
#include <QScrollBar>
#include <QSettings>
#include <QTextDocument>
+#include <QTimer>
+
+#define SEND_CONFIRM_DELAY 3
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
@@ -311,10 +314,10 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append(QString("<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span>")
.arg(alternativeUnits.join(" " + tr("or") + "<br />")));
- QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
- questionString.arg(formatted.join("<br />")),
- QMessageBox::Yes | QMessageBox::Cancel,
- QMessageBox::Cancel);
+ SendConfirmationDialog confirmationDialog(tr("Confirm send coins"),
+ questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this);
+ confirmationDialog.exec();
+ QMessageBox::StandardButton retval = (QMessageBox::StandardButton)confirmationDialog.result();
if(retval != QMessageBox::Yes)
{
@@ -828,3 +831,45 @@ void SendCoinsDialog::coinControlUpdateLabels()
ui->labelCoinControlInsuffFunds->hide();
}
}
+
+SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int secDelay,
+ QWidget *parent) :
+ QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(secDelay)
+{
+ setDefaultButton(QMessageBox::Cancel);
+ yesButton = button(QMessageBox::Yes);
+ updateYesButton();
+ connect(&countDownTimer, SIGNAL(timeout()), this, SLOT(countDown()));
+}
+
+int SendConfirmationDialog::exec()
+{
+ updateYesButton();
+ countDownTimer.start(1000);
+ return QMessageBox::exec();
+}
+
+void SendConfirmationDialog::countDown()
+{
+ secDelay--;
+ updateYesButton();
+
+ if(secDelay <= 0)
+ {
+ countDownTimer.stop();
+ }
+}
+
+void SendConfirmationDialog::updateYesButton()
+{
+ if(secDelay > 0)
+ {
+ yesButton->setEnabled(false);
+ yesButton->setText(tr("Yes") + " (" + QString::number(secDelay) + ")");
+ }
+ else
+ {
+ yesButton->setEnabled(true);
+ yesButton->setText(tr("Yes"));
+ }
+}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index ec171734fa..be4f2ee44b 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -8,7 +8,9 @@
#include "walletmodel.h"
#include <QDialog>
+#include <QMessageBox>
#include <QString>
+#include <QTimer>
class ClientModel;
class OptionsModel;
@@ -100,4 +102,24 @@ Q_SIGNALS:
void message(const QString &title, const QString &message, unsigned int style);
};
+
+
+class SendConfirmationDialog : public QMessageBox
+{
+ Q_OBJECT
+
+public:
+ SendConfirmationDialog(const QString &title, const QString &text, int secDelay = 0, QWidget *parent = 0);
+ int exec();
+
+private Q_SLOTS:
+ void countDown();
+ void updateYesButton();
+
+private:
+ QAbstractButton *yesButton;
+ QTimer countDownTimer;
+ int secDelay;
+};
+
#endif // BITCOIN_QT_SENDCOINSDIALOG_H
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 9557000ddc..042fad42da 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -514,11 +514,14 @@ BOOST_AUTO_TEST_CASE(rolling_bloom)
if (i >= 100)
BOOST_CHECK(rb1.contains(data[i-100]));
rb1.insert(data[i]);
+ BOOST_CHECK(rb1.contains(data[i]));
}
// Insert 999 more random entries:
for (int i = 0; i < 999; i++) {
- rb1.insert(RandomData());
+ std::vector<unsigned char> d = RandomData();
+ rb1.insert(d);
+ BOOST_CHECK(rb1.contains(d));
}
// Sanity check to make sure the filter isn't just filling up:
nHits = 0;
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 129ce04e0b..e692326559 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -297,8 +297,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
CCoins &coins = result[tx.GetHash()];
coins.FromTx(tx, height);
- CValidationState dummy;
- UpdateCoins(tx, dummy, *(stack.back()), height);
+ UpdateCoins(tx, *(stack.back()), height);
}
// Once every 1000 iterations and at the end, verify the full cache.
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index a6070f5264..aa5df6ca4e 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -720,7 +720,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
else {
CValidationState state;
assert(CheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL));
- UpdateCoins(tx, state, mempoolDuplicate, 1000000);
+ UpdateCoins(tx, mempoolDuplicate, 1000000);
}
}
unsigned int stepsSinceLastRemove = 0;
@@ -734,7 +734,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(stepsSinceLastRemove < waitingOnDependants.size());
} else {
assert(CheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, NULL));
- UpdateCoins(entry->GetTx(), state, mempoolDuplicate, 1000000);
+ UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000);
stepsSinceLastRemove = 0;
}
}