Backports 0.15 pr1 (#2590)

* Merge #9744: Remove unused module from rpc-tests

a432aa0 Remove unused module from rpc-tests (Takashi Mitsuta)

* Merge #9696: [trivial] Fix recently introduced typos in comments

0c9b9b7 [trivial] Fix recently introduced typos in comments (practicalswift)

* Merge #9657: Improve rpc-tests.py

a6a3e58 Various review markups for rpc-tests.py improvements (John Newbery)
3de3ccd Refactor rpc-tests.py (John Newbery)
afd38e7 Improve rpc-tests.py arguments (John Newbery)
91bffff Use argparse in rpc_tests.py (John Newbery)
1581ecb Use configparser in rpc-tests.py (John Newbery)

* Merge #9724: Qt/Intro: Add explanation of IBD process

f6d18f5 Qt/Intro: Explain a bit more what will happen first time (Luke Dashjr)
50c5657 Qt/Intro: Storage shouldn't grow significantly with pruning enabled (Luke Dashjr)
9adb694 Qt/Intro: Move sizeWarningLabel text into C++ code (Luke Dashjr)

* Merge #9794: Minor update to qrencode package builder

1bfe6b4 Use package name variable inside $(package)_file_name variable (Mitchell Cash)

* Merge #9726: netbase: Do not print an error on connection timeouts through proxy

3ddfe29 netbase: Do not print an error on connection timeouts through proxy (Wladimir J. van der Laan)
13f6085 netbase: Make InterruptibleRecv return an error code instead of bool (Wladimir J. van der Laan)

* Merge #9727: Remove fallbacks for boost_filesystem < v3

056aba2 Remove fallbacks for boost_filesystem < v3 (Wladimir J. van der Laan)

* Merge #9485: ZMQ example using python3 and asyncio

b471daf Adddress nits, use asyncio signal handling, create_task (Bob McElrath)
4bb7d1b Add python version checks and 3.4 example (Bob McElrath)
5406d51 Rewrite to not use Polling wrapper for asyncio, link to python2.7 example (Bob McElrath)
5ea5368 ZMQ example using python3 and asyncio (Bob McElrath)

* Merge #9807: RPC doc fix-ups.

851f6a3 [qa][doc] Correct rpc test options in readme (fanquake)
41e7219 [trivial] Add tests_config.ini to .gitignore (fanquake)

* Dashify

Co-Authored-By: PastaPastaPasta <pasta@dashboost.org>

* Change file permissions

* update travis.yml -parallel -> --jobs
This commit is contained in:
PastaPastaPasta 2019-01-03 03:18:47 -06:00 committed by UdjinM6
parent f95aae2b30
commit a49f4123e5
28 changed files with 451 additions and 268 deletions

1
.gitignore vendored
View File

@ -109,6 +109,7 @@ linux-coverage-build
linux-build linux-build
win32-build win32-build
qa/pull-tester/tests_config.py qa/pull-tester/tests_config.py
qa/pull-tester/tests_config.ini
qa/cache/* qa/cache/*
!src/leveldb*/Makefile !src/leveldb*/Makefile

View File

@ -73,7 +73,7 @@ script:
- if [ $SECONDS -gt 1200 ]; then export DEPENDS_TIMEOUT="true"; false; fi # The "false" here ensures that the build is marked as failed even though the whole script returns 0 - if [ $SECONDS -gt 1200 ]; then export DEPENDS_TIMEOUT="true"; false; fi # The "false" here ensures that the build is marked as failed even though the whole script returns 0
- test "$DEPENDS_TIMEOUT" != "true" && $DOCKER_RUN_IN_BUILDER ./ci/build_src.sh - test "$DEPENDS_TIMEOUT" != "true" && $DOCKER_RUN_IN_BUILDER ./ci/build_src.sh
- test "$DEPENDS_TIMEOUT" != "true" && $DOCKER_RUN_IN_BUILDER ./ci/test_unittests.sh - test "$DEPENDS_TIMEOUT" != "true" && $DOCKER_RUN_IN_BUILDER ./ci/test_unittests.sh
- test "$DEPENDS_TIMEOUT" != "true" && $DOCKER_RUN_IN_BUILDER ./ci/test_integrationtests.sh -parallel=3 - test "$DEPENDS_TIMEOUT" != "true" && $DOCKER_RUN_IN_BUILDER ./ci/test_integrationtests.sh --jobs=3
- test "$DEPENDS_TIMEOUT" != "true" && if [ "$DOCKER_BUILD" = "true" ]; then BUILD_DIR=build-ci/dashcore-$BUILD_TARGET ./docker/build-docker.sh; fi - test "$DEPENDS_TIMEOUT" != "true" && if [ "$DOCKER_BUILD" = "true" ]; then BUILD_DIR=build-ci/dashcore-$BUILD_TARGET ./docker/build-docker.sh; fi
after_script: after_script:
- echo $TRAVIS_COMMIT_RANGE - echo $TRAVIS_COMMIT_RANGE

View File

@ -224,9 +224,6 @@ EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc-
CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER)
# This file is problematic for out-of-tree builds if it exists.
DISTCLEANFILES = qa/pull-tester/tests_config.pyc
.INTERMEDIATE: $(COVERAGE_INFO) .INTERMEDIATE: $(COVERAGE_INFO)
DISTCHECK_CONFIGURE_FLAGS = --enable-man DISTCHECK_CONFIGURE_FLAGS = --enable-man

View File

@ -1113,7 +1113,7 @@ AC_SUBST(ZMQ_LIBS)
AC_SUBST(PROTOBUF_LIBS) AC_SUBST(PROTOBUF_LIBS)
AC_SUBST(QR_LIBS) AC_SUBST(QR_LIBS)
AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py])
AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py]) AC_CONFIG_FILES([qa/pull-tester/tests_config.ini],[chmod +x qa/pull-tester/tests_config.ini])
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh]) AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
AC_CONFIG_LINKS([qa/pull-tester/rpc-tests.py:qa/pull-tester/rpc-tests.py]) AC_CONFIG_LINKS([qa/pull-tester/rpc-tests.py:qa/pull-tester/rpc-tests.py])

View File

@ -1,34 +1,64 @@
#!/usr/bin/env python #!/usr/bin/env python3
# Copyright (c) 2014-2016 The Bitcoin Core developers # Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
ZMQ example using python3's asyncio
Dash should be started with the command line arguments:
dashd-testnet -daemon \
-zmqpubhashblock=tcp://127.0.0.1:28332 \
-zmqpubrawtx=tcp://127.0.0.1:28332 \
-zmqpubhashtx=tcp://127.0.0.1:28332 \
-zmqpubhashblock=tcp://127.0.0.1:28332
We use the asyncio library here. `self.handle()` installs itself as a
future at the end of the function. Since it never returns with the event
loop having an empty stack of futures, this creates an infinite loop. An
alternative is to wrap the contents of `handle` inside `while True`.
A blocking example using python 2.7 can be obtained from the git history:
https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py
"""
import binascii import binascii
import asyncio
import zmq import zmq
import zmq.asyncio
import signal
import struct import struct
import sys
if not (sys.version_info.major >= 3 and sys.version_info.minor >= 5):
print("This example only works with Python 3.5 and greater")
exit(1)
port = 28332 port = 28332
zmqContext = zmq.Context() class ZMQHandler():
zmqSubSocket = zmqContext.socket(zmq.SUB) def __init__(self):
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock") self.loop = zmq.asyncio.install()
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx") self.zmqContext = zmq.asyncio.Context()
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtxlock")
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashgovernancevote")
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashgovernanceobject")
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashinstantsenddoublespend")
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawblock")
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawtx")
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawtxlock")
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawgovernancevote")
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawgovernanceobject")
zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawinstantsenddoublespend")
zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
try: self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
while True: self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock")
msg = zmqSubSocket.recv_multipart() self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx")
topic = str(msg[0].decode("utf-8")) self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtxlock")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashgovernancevote")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashgovernanceobject")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashinstantsenddoublespend")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtxlock")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawgovernancevote")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawgovernanceobject")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawinstantsenddoublespend")
self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
async def handle(self) :
msg = await self.zmqSubSocket.recv_multipart()
topic = msg[0]
body = msg[1] body = msg[1]
sequence = "Unknown" sequence = "Unknown"
@ -36,42 +66,53 @@ try:
msgSequence = struct.unpack('<I', msg[-1])[-1] msgSequence = struct.unpack('<I', msg[-1])[-1]
sequence = str(msgSequence) sequence = str(msgSequence)
if topic == "hashblock": if topic == b"hashblock":
print('- HASH BLOCK ('+sequence+') -') print('- HASH BLOCK ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
elif topic == "hashtx": elif topic == b"hashtx":
print ('- HASH TX ('+sequence+') -') print ('- HASH TX ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
elif topic == "hashtxlock": elif topic == b"hashtxlock":
print('- HASH TX LOCK ('+sequence+') -') print('- HASH TX LOCK ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
elif topic == "rawblock": elif topic == b"rawblock":
print('- RAW BLOCK HEADER ('+sequence+') -') print('- RAW BLOCK HEADER ('+sequence+') -')
print(binascii.hexlify(body[:80]).decode("utf-8")) print(binascii.hexlify(body[:80]).decode("utf-8"))
elif topic == "rawtx": elif topic == b"rawtx":
print('- RAW TX ('+sequence+') -') print('- RAW TX ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
elif topic == "rawtxlock": elif topic == b"rawtxlock":
print('- RAW TX LOCK ('+sequence+') -') print('- RAW TX LOCK ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
elif topic == "rawinstantsenddoublespend": elif topic == b"rawinstantsenddoublespend":
print('- RAW IS DOUBLE SPEND ('+sequence+') -') print('- RAW IS DOUBLE SPEND ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
elif topic == "hashgovernancevote": elif topic == b"hashgovernancevote":
print('- HASH GOVERNANCE VOTE ('+sequence+') -') print('- HASH GOVERNANCE VOTE ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
elif topic == "hashgovernanceobject": elif topic == b"hashgovernanceobject":
print('- HASH GOVERNANCE OBJECT ('+sequence+') -') print('- HASH GOVERNANCE OBJECT ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
elif topic == "rawgovernancevote": elif topic == b"rawgovernancevote":
print('- RAW GOVERNANCE VOTE ('+sequence+') -') print('- RAW GOVERNANCE VOTE ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
elif topic == "rawgovernanceobject": elif topic == b"rawgovernanceobject":
print('- RAW GOVERNANCE OBJECT ('+sequence+') -') print('- RAW GOVERNANCE OBJECT ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
elif topic == "hashinstantsenddoublespend": elif topic == b"hashinstantsenddoublespend":
print('- HASH IS DOUBLE SPEND ('+sequence+') -') print('- HASH IS DOUBLE SPEND ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8")) print(binascii.hexlify(body).decode("utf-8"))
# schedule ourselves to receive the next message
asyncio.ensure_future(self.handle())
except KeyboardInterrupt: def start(self):
zmqContext.destroy() self.loop.add_signal_handler(signal.SIGINT, self.stop)
self.loop.create_task(self.handle())
self.loop.run_forever()
def stop(self):
self.loop.stop()
self.zmqContext.destroy()
daemon = ZMQHandler()
daemon.start()

121
contrib/zmq/zmq_sub3.4.py Executable file
View File

@ -0,0 +1,121 @@
#!/usr/bin/env python3
# Copyright (c) 2014-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.
"""
ZMQ example using python3's asyncio
Dash should be started with the command line arguments:
dashd -testnet -daemon \
-zmqpubhashblock=tcp://127.0.0.1:28332 \
-zmqpubrawtx=tcp://127.0.0.1:28332 \
-zmqpubhashtx=tcp://127.0.0.1:28332 \
-zmqpubhashblock=tcp://127.0.0.1:28332
We use the asyncio library here. `self.handle()` installs itself as a
future at the end of the function. Since it never returns with the event
loop having an empty stack of futures, this creates an infinite loop. An
alternative is to wrap the contents of `handle` inside `while True`.
The `@asyncio.coroutine` decorator and the `yield from` syntax found here
was introduced in python 3.4 and has been deprecated in favor of the `async`
and `await` keywords respectively.
A blocking example using python 2.7 can be obtained from the git history:
https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py
"""
import binascii
import asyncio
import zmq
import zmq.asyncio
import signal
import struct
import sys
if not (sys.version_info.major >= 3 and sys.version_info.minor >= 4):
print("This example only works with Python 3.4 and greater")
exit(1)
port = 28332
class ZMQHandler():
def __init__(self):
self.loop = zmq.asyncio.install()
self.zmqContext = zmq.asyncio.Context()
self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtxlock")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashgovernancevote")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashgovernanceobject")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashinstantsenddoublespend")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtxlock")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawgovernancevote")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawgovernanceobject")
self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawinstantsenddoublespend")
self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
@asyncio.coroutine
def handle(self) :
msg = yield from self.zmqSubSocket.recv_multipart()
topic = msg[0]
body = msg[1]
sequence = "Unknown";
if len(msg[-1]) == 4:
msgSequence = struct.unpack('<I', msg[-1])[-1]
sequence = str(msgSequence)
if topic == b"hashblock":
print('- HASH BLOCK ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
elif topic == b"hashtx":
print ('- HASH TX ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
elif topic == b"hashtxlock":
print('- HASH TX LOCK ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
elif topic == b"rawblock":
print('- RAW BLOCK HEADER ('+sequence+') -')
print(binascii.hexlify(body[:80]).decode("utf-8"))
elif topic == b"rawtx":
print('- RAW TX ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
elif topic == b"rawtxlock":
print('- RAW TX LOCK ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
elif topic == b"rawinstantsenddoublespend":
print('- RAW IS DOUBLE SPEND ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
elif topic == b"hashgovernancevote":
print('- HASH GOVERNANCE VOTE ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
elif topic == b"hashgovernanceobject":
print('- HASH GOVERNANCE OBJECT ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
elif topic == b"rawgovernancevote":
print('- RAW GOVERNANCE VOTE ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
elif topic == b"rawgovernanceobject":
print('- RAW GOVERNANCE OBJECT ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
elif topic == b"hashinstantsenddoublespend":
print('- HASH IS DOUBLE SPEND ('+sequence+') -')
print(binascii.hexlify(body).decode("utf-8"))
# schedule ourselves to receive the next message
asyncio.ensure_future(self.handle())
def start(self):
self.loop.add_signal_handler(signal.SIGINT, self.stop)
self.loop.create_task(self.handle())
self.loop.run_forever()
def stop(self):
self.loop.stop()
self.zmqContext.destroy()
daemon = ZMQHandler()
daemon.start()

View File

@ -1,7 +1,7 @@
package=qrencode package=qrencode
$(package)_version=3.4.4 $(package)_version=3.4.4
$(package)_download_path=https://fukuchi.org/works/qrencode/ $(package)_download_path=https://fukuchi.org/works/qrencode/
$(package)_file_name=qrencode-$(qrencode_version).tar.bz2 $(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19cde1fa5 $(package)_sha256_hash=efe5188b1ddbcbf98763b819b146be6a90481aac30cfc8d858ab78a19cde1fa5
define $(package)_set_vars define $(package)_set_vars

View File

@ -39,12 +39,12 @@ Run the regression test suite with
Run all possible tests with Run all possible tests with
qa/pull-tester/rpc-tests.py -extended qa/pull-tester/rpc-tests.py --extended
By default, tests will be run in parallel. To specify how many jobs to run, By default, tests will be run in parallel. To specify how many jobs to run,
append `-parallel=n` (default n=4). append `--jobs=n` (default n=4).
If you want to create a basic coverage report for the rpc test suite, append `--coverage`. 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: Possible options, which apply to each individual test run:
@ -83,5 +83,5 @@ killall dashd
Writing tests Writing tests
============= =============
You are encouraged to write tests for new or existing features. You are encouraged to write tests for new or existing features.
Further information about the test framework and individual rpc Further information about the test framework and individual RPC
tests is found in [qa/rpc-tests](/qa/rpc-tests). tests is found in [qa/rpc-tests](/qa/rpc-tests).

View File

@ -2,25 +2,21 @@
# Copyright (c) 2014-2016 The Bitcoin Core developers # Copyright (c) 2014-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
""" """
Run Regression Test Suite rpc-tests.py - run regression test suite
This module calls down into individual test cases via subprocess. It will This module calls down into individual test cases via subprocess. It will
forward all unrecognized arguments onto the individual test scripts, other forward all unrecognized arguments onto the individual test scripts.
than:
- `-extended`: run the "extended" test suite in addition to the basic one. RPC tests are disabled on Windows by default. Use --force to run them anyway.
- `-win`: signal that this is running in a Windows environment, and we
should run the tests.
- `--coverage`: this generates a basic coverage report for the RPC
interface.
For a description of arguments recognized by test scripts, see For a description of arguments recognized by test scripts, see
`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`. `qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`.
""" """
import argparse
import configparser
import os import os
import time import time
import shutil import shutil
@ -29,86 +25,9 @@ import subprocess
import tempfile import tempfile
import re import re
sys.path.append("qa/pull-tester/") BASE_SCRIPTS= [
from tests_config import * # Scripts that are run by the travis build process.
# Longest test should go first, to favor running tests in parallel
BOLD = ("","")
if os.name == 'posix':
# primitive formatting on supported
# terminal via ANSI escape sequences:
BOLD = ('\033[0m', '\033[1m')
RPC_TESTS_DIR = SRCDIR + '/qa/rpc-tests/'
#If imported values are not defined then set to zero (or disabled)
if 'ENABLE_WALLET' not in vars():
ENABLE_WALLET=0
if 'ENABLE_BITCOIND' not in vars():
ENABLE_BITCOIND=0
if 'ENABLE_UTILS' not in vars():
ENABLE_UTILS=0
if 'ENABLE_ZMQ' not in vars():
ENABLE_ZMQ=0
# python-zmq may not be installed. Handle this gracefully and with some helpful info
if ENABLE_ZMQ:
try:
import zmq
except ImportError:
print("WARNING: \"import zmq\" failed. Setting ENABLE_ZMQ=0. " \
"To run zmq tests, see dependency info in /qa/README.md.")
ENABLE_ZMQ=0
ENABLE_COVERAGE=0
#Create a set to store arguments and create the passon string
opts = set()
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 == "-?":
print_help = True
break
if arg == '--coverage':
ENABLE_COVERAGE = 1
elif PASSON_REGEX.match(arg):
passon_args.append(arg)
elif PARALLEL_REGEX.match(arg):
run_parallel = int(arg.split(sep='=', maxsplit=1)[1])
else:
opts.add(arg)
#Set env vars
if "DASHD" not in os.environ:
os.environ["DASHD"] = BUILDDIR + '/src/dashd' + EXEEXT
if EXEEXT == ".exe" and "-win" not in opts:
# https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
# https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
print("Win tests currently disabled by default. Use -win option to enable")
sys.exit(0)
if not (ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled")
sys.exit(0)
# python3-zmq may not be installed. Handle this gracefully and with some helpful info
if ENABLE_ZMQ:
try:
import zmq
except ImportError:
print("ERROR: \"import zmq\" failed. Set ENABLE_ZMQ=0 or "
"to run zmq tests, see dependency info in /qa/README.md.")
# ENABLE_ZMQ=0
raise
testScripts = [
# longest test should go first, to favor running tests in parallel
'dip3-deterministicmns.py', # NOTE: needs dash_hash to pass 'dip3-deterministicmns.py', # NOTE: needs dash_hash to pass
'wallet-hd.py', 'wallet-hd.py',
'walletbackup.py', 'walletbackup.py',
@ -173,10 +92,15 @@ testScripts = [
'p2p-compactblocks.py', 'p2p-compactblocks.py',
'sporks.py', 'sporks.py',
] ]
if ENABLE_ZMQ:
testScripts.append('zmq_test.py')
testScriptsExt = [ ZMQ_SCRIPTS = [
# ZMQ test can only be run if Dash Core was built with zmq-enabled.
# call rpc_tests.py with -nozmq to explicitly exclude these tests.
"zmq_test.py"]
EXTENDED_SCRIPTS = [
# These tests are not run by the travis build process.
# Longest test should go first, to favor running tests in parallel
# 'pruning.py', # Prune mode is incompatible with -txindex. # 'pruning.py', # Prune mode is incompatible with -txindex.
# vv Tests less than 20m vv # vv Tests less than 20m vv
'smartfees.py', 'smartfees.py',
@ -204,44 +128,126 @@ testScriptsExt = [
'p2p-acceptblock.py', # NOTE: needs dash_hash to pass 'p2p-acceptblock.py', # NOTE: needs dash_hash to pass
] ]
ALL_SCRIPTS = BASE_SCRIPTS + ZMQ_SCRIPTS + EXTENDED_SCRIPTS
def runtests(): def main():
test_list = [] # Parse arguments and pass through unrecognised args
if '-extended' in opts: parser = argparse.ArgumentParser(add_help=False,
test_list = testScripts + testScriptsExt usage='%(prog)s [rpc-test.py options] [script options] [scripts]',
elif len(opts) == 0 or (len(opts) == 1 and "-win" in opts): description=__doc__,
test_list = testScripts epilog='''
else: Help text and arguments for individual test script:''',
for t in testScripts + testScriptsExt: formatter_class=argparse.RawTextHelpFormatter)
if t in opts or re.sub(".py$", "", t) in opts: parser.add_argument('--coverage', action='store_true', help='generate a basic coverage report for the RPC interface')
test_list.append(t) parser.add_argument('--extended', action='store_true', help='run the extended test suite in addition to the basic tests')
parser.add_argument('--force', '-f', action='store_true', help='run tests even on platforms where they are disabled by default (e.g. windows).')
parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit')
parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.')
parser.add_argument('--nozmq', action='store_true', help='do not run the zmq tests')
args, unknown_args = parser.parse_known_args()
if print_help: # Create a set to store arguments and create the passon string
# Only print help of the first script and exit tests = set(arg for arg in unknown_args if arg[:2] != "--")
subprocess.check_call((RPC_TESTS_DIR + test_list[0]).split() + ['-h']) passon_args = [arg for arg in unknown_args if arg[:2] == "--"]
# Read config generated by configure.
config = configparser.ConfigParser()
config.read_file(open(os.path.dirname(__file__) + "/tests_config.ini"))
enable_wallet = config["components"].getboolean("ENABLE_WALLET")
enable_utils = config["components"].getboolean("ENABLE_UTILS")
enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND")
enable_zmq = config["components"].getboolean("ENABLE_ZMQ") and not args.nozmq
if config["environment"]["EXEEXT"] == ".exe" and not args.force:
# https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
# https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
print("Tests currently disabled on Windows by default. Use --force option to enable")
sys.exit(0) sys.exit(0)
if not (enable_wallet and enable_utils and enable_bitcoind):
print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled")
print("Rerun `configure` with -enable-wallet, -with-utils and -with-daemon and rerun make")
sys.exit(0)
# python3-zmq may not be installed. Handle this gracefully and with some helpful info
if enable_zmq:
try:
import zmq
except ImportError:
print("ERROR: \"import zmq\" failed. Use -nozmq to run without the ZMQ tests."
"To run zmq tests, see dependency info in /qa/README.md.")
raise
# Build list of tests
if tests:
# Individual tests have been specified. Run specified tests that exist
# in the ALL_SCRIPTS list. Accept the name with or without .py extension.
test_list = [t for t in ALL_SCRIPTS if
(t in tests or re.sub(".py$", "", t) in tests)]
if not test_list:
print("No valid test scripts specified. Check that your test is in one "
"of the test lists in rpc-tests.py or run rpc-tests.py with no arguments to run all tests")
print("Scripts not found:")
print(tests)
sys.exit(0)
else:
# No individual tests have been specified. Run base tests, and
# optionally ZMQ tests and extended tests.
test_list = BASE_SCRIPTS
if enable_zmq:
test_list += ZMQ_SCRIPTS
if args.extended:
test_list += EXTENDED_SCRIPTS
# TODO: BASE_SCRIPTS and EXTENDED_SCRIPTS are sorted by runtime
# (for parallel running efficiency). This combined list will is no
# longer sorted.
if args.help:
# Print help for rpc-tests.py, then print help of the first script and exit.
parser.print_help()
subprocess.check_call((config["environment"]["SRCDIR"] + '/qa/rpc-tests/' + test_list[0]).split() + ['-h'])
sys.exit(0)
run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], args.jobs, args.coverage, passon_args)
def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=False, args=[]):
BOLD = ("","")
if os.name == 'posix':
# primitive formatting on supported
# terminal via ANSI escape sequences:
BOLD = ('\033[0m', '\033[1m')
#Set env vars
if "BITCOIND" not in os.environ:
os.environ["BITCOIND"] = build_dir + '/src/dashd' + exeext
tests_dir = src_dir + '/qa/rpc-tests/'
flags = ["--srcdir=" + src_dir] + args
flags.append("--cachedir=%s/qa/cache" % build_dir)
if enable_coverage:
coverage = RPCCoverage()
flags.append(coverage.flag)
print("Initializing coverage directory at %s\n" % coverage.dir)
else:
coverage = None coverage = None
if ENABLE_COVERAGE: if len(test_list) > 1 and jobs > 1:
coverage = RPCCoverage()
print("Initializing coverage directory at %s\n" % coverage.dir)
flags = ["--srcdir=%s/src" % BUILDDIR] + passon_args
flags.append("--cachedir=%s/qa/cache" % BUILDDIR)
if coverage:
flags.append(coverage.flag)
if len(test_list) > 1 and run_parallel > 1:
# Populate cache # Populate cache
subprocess.check_output([RPC_TESTS_DIR + 'create_cache.py'] + flags) subprocess.check_output([tests_dir + 'create_cache.py'] + flags)
#Run Tests #Run Tests
max_len_name = len(max(test_list, key=len)) all_passed = True
time_sum = 0 time_sum = 0
time0 = time.time() time0 = time.time()
job_queue = RPCTestHandler(run_parallel, test_list, flags)
job_queue = RPCTestHandler(jobs, tests_dir, test_list, flags)
max_len_name = len(max(test_list, key=len))
results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "PASSED", "DURATION") + BOLD[0] 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)): for _ in range(len(test_list)):
(name, stdout, stderr, passed, duration) = job_queue.get_next() (name, stdout, stderr, passed, duration) = job_queue.get_next()
all_passed = all_passed and passed all_passed = all_passed and passed
@ -250,8 +256,10 @@ def runtests():
print('\n' + BOLD[1] + name + BOLD[0] + ":") print('\n' + BOLD[1] + name + BOLD[0] + ":")
print('' if passed else stdout + '\n', end='') print('' if passed else stdout + '\n', end='')
print('' if stderr == '' else 'stderr:\n' + stderr + '\n', end='') print('' if stderr == '' else 'stderr:\n' + stderr + '\n', end='')
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)) print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration))
results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration)
results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0] 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(results)
print("\nRuntime: %s s" % (int(time.time() - time0))) print("\nRuntime: %s s" % (int(time.time() - time0)))
@ -264,15 +272,15 @@ def runtests():
sys.exit(not all_passed) sys.exit(not all_passed)
class RPCTestHandler: class RPCTestHandler:
""" """
Trigger the testscrips passed in via the list. Trigger the testscrips passed in via the list.
""" """
def __init__(self, num_tests_parallel, test_list=None, flags=None): def __init__(self, num_tests_parallel, tests_dir, test_list=None, flags=None):
assert(num_tests_parallel >= 1) assert(num_tests_parallel >= 1)
self.num_jobs = num_tests_parallel self.num_jobs = num_tests_parallel
self.tests_dir = tests_dir
self.test_list = test_list self.test_list = test_list
self.flags = flags self.flags = flags
self.num_running = 0 self.num_running = 0
@ -292,7 +300,7 @@ class RPCTestHandler:
log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
self.jobs.append((t, self.jobs.append((t,
time.time(), time.time(),
subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags + port_seed, subprocess.Popen((self.tests_dir + t).split() + self.flags + port_seed,
universal_newlines=True, universal_newlines=True,
stdout=log_stdout, stdout=log_stdout,
stderr=log_stderr), stderr=log_stderr),
@ -357,10 +365,10 @@ class RPCCoverage(object):
""" """
# This is shared from `qa/rpc-tests/test-framework/coverage.py` # This is shared from `qa/rpc-tests/test-framework/coverage.py`
REFERENCE_FILENAME = 'rpc_interface.txt' reference_filename = 'rpc_interface.txt'
COVERAGE_FILE_PREFIX = 'coverage.' coverage_file_prefix = 'coverage.'
coverage_ref_filename = os.path.join(self.dir, REFERENCE_FILENAME) coverage_ref_filename = os.path.join(self.dir, reference_filename)
coverage_filenames = set() coverage_filenames = set()
all_cmds = set() all_cmds = set()
covered_cmds = set() covered_cmds = set()
@ -373,7 +381,7 @@ class RPCCoverage(object):
for root, dirs, files in os.walk(self.dir): for root, dirs, files in os.walk(self.dir):
for filename in files: for filename in files:
if filename.startswith(COVERAGE_FILE_PREFIX): if filename.startswith(coverage_file_prefix):
coverage_filenames.add(os.path.join(root, filename)) coverage_filenames.add(os.path.join(root, filename))
for filename in coverage_filenames: for filename in coverage_filenames:
@ -384,4 +392,4 @@ class RPCCoverage(object):
if __name__ == '__main__': if __name__ == '__main__':
runtests() main()

View File

@ -0,0 +1,18 @@
# Copyright (c) 2013-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.
# These environment variables are set by the build process and read by
# rpc-tests.py
[environment]
SRCDIR=@abs_top_srcdir@
BUILDDIR=@abs_top_builddir@
EXEEXT=@EXEEXT@
[components]
# Which components are enabled. These are commented out by `configure` if they were disabled when running config.
@ENABLE_WALLET_TRUE@ENABLE_WALLET=true
@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=true
@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=true
@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true

View File

@ -1,14 +0,0 @@
#!/usr/bin/env python3
# Copyright (c) 2013-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.
SRCDIR="@abs_top_srcdir@"
BUILDDIR="@abs_top_builddir@"
EXEEXT="@EXEEXT@"
# These will turn into comments if they were disabled when configuring.
@ENABLE_WALLET_TRUE@ENABLE_WALLET=1
@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=1
@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=1
@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=1

View File

@ -5,7 +5,7 @@
from test_framework.test_framework import ComparisonTestFramework from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import * from test_framework.util import *
from test_framework.mininode import ToHex, CTransaction, NetworkThread from test_framework.mininode import ToHex, NetworkThread
from test_framework.blocktools import create_coinbase, create_block from test_framework.blocktools import create_coinbase, create_block
from test_framework.comptool import TestInstance, TestManager from test_framework.comptool import TestInstance, TestManager
from test_framework.script import * from test_framework.script import *

View File

@ -9,8 +9,6 @@
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import * from test_framework.util import *
from test_framework.script import *
from test_framework.mininode import *
from test_framework.blocktools import * from test_framework.blocktools import *
SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31) SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)

View File

@ -7,7 +7,6 @@ from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import * from test_framework.util import *
from test_framework.blocktools import create_block, create_coinbase from test_framework.blocktools import create_block, create_coinbase
from test_framework.siphash import siphash256
from test_framework.script import CScript, OP_TRUE from test_framework.script import CScript, OP_TRUE
''' '''

View File

@ -3,17 +3,11 @@
# Distributed under the MIT software license, see the accompanying # Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import ( from test_framework.util import (
assert_equal, assert_equal,
assert_raises_jsonrpc, assert_raises_jsonrpc,
assert_is_hex_string,
assert_is_hash_string,
start_nodes, start_nodes,
connect_nodes_bi,
) )

View File

@ -6,9 +6,7 @@
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import ( from test_framework.util import (
start_nodes, start_nodes,
start_node,
assert_equal, assert_equal,
connect_nodes_bi,
) )

View File

@ -1174,7 +1174,7 @@ bool AppInitParameterInteraction()
int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0))); return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
// incremental relay fee sets the minimimum feerate increase necessary for BIP 125 replacement in the mempool // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
// and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting. // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
if (IsArgSet("-incrementalrelayfee")) if (IsArgSet("-incrementalrelayfee"))
{ {

View File

@ -198,6 +198,14 @@ struct timeval MillisToTimeval(int64_t nTimeout)
return timeout; return timeout;
} }
enum class IntrRecvError {
OK,
Timeout,
Disconnected,
NetworkError,
Interrupted
};
/** /**
* Read bytes from socket. This will either read the full number of bytes requested * Read bytes from socket. This will either read the full number of bytes requested
* or return False on error or timeout. * or return False on error or timeout.
@ -209,7 +217,7 @@ struct timeval MillisToTimeval(int64_t nTimeout)
* *
* @note This function requires that hSocket is in non-blocking mode. * @note This function requires that hSocket is in non-blocking mode.
*/ */
bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket) static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSocket)
{ {
int64_t curTime = GetTimeMillis(); int64_t curTime = GetTimeMillis();
int64_t endTime = curTime + timeout; int64_t endTime = curTime + timeout;
@ -222,12 +230,12 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
len -= ret; len -= ret;
data += ret; data += ret;
} else if (ret == 0) { // Unexpected disconnection } else if (ret == 0) { // Unexpected disconnection
return false; return IntrRecvError::Disconnected;
} else { // Other error or blocking } else { // Other error or blocking
int nErr = WSAGetLastError(); int nErr = WSAGetLastError();
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) { if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
if (!IsSelectableSocket(hSocket)) { if (!IsSelectableSocket(hSocket)) {
return false; return IntrRecvError::NetworkError;
} }
struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait)); struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));
fd_set fdset; fd_set fdset;
@ -235,17 +243,17 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
FD_SET(hSocket, &fdset); FD_SET(hSocket, &fdset);
int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval); int nRet = select(hSocket + 1, &fdset, NULL, NULL, &tval);
if (nRet == SOCKET_ERROR) { if (nRet == SOCKET_ERROR) {
return false; return IntrRecvError::NetworkError;
} }
} else { } else {
return false; return IntrRecvError::NetworkError;
} }
} }
if (interruptSocks5Recv) if (interruptSocks5Recv)
return false; return IntrRecvError::Interrupted;
curTime = GetTimeMillis(); curTime = GetTimeMillis();
} }
return len == 0; return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
} }
struct ProxyCredentials struct ProxyCredentials
@ -272,6 +280,7 @@ std::string Socks5ErrorString(int err)
/** Connect using SOCKS5 (as described in RFC1928) */ /** Connect using SOCKS5 (as described in RFC1928) */
static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket) static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
{ {
IntrRecvError recvr;
LogPrint("net", "SOCKS5 connecting %s\n", strDest); LogPrint("net", "SOCKS5 connecting %s\n", strDest);
if (strDest.size() > 255) { if (strDest.size() > 255) {
CloseSocket(hSocket); CloseSocket(hSocket);
@ -294,7 +303,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return error("Error sending to proxy"); return error("Error sending to proxy");
} }
char pchRet1[2]; char pchRet1[2];
if (!InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port); LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
return false; return false;
@ -320,7 +329,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
} }
LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
char pchRetA[2]; char pchRetA[2];
if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
return error("Error reading proxy authentication response"); return error("Error reading proxy authentication response");
} }
@ -349,9 +358,16 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return error("Error sending to proxy"); return error("Error sending to proxy");
} }
char pchRet2[4]; char pchRet2[4];
if (!InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) { if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
return error("Error reading proxy response"); if (recvr == IntrRecvError::Timeout) {
/* If a timeout happens here, this effectively means we timed out while connecting
* to the remote node. This is very common for Tor, so do not print an
* error message. */
return false;
} else {
return error("Error while reading proxy response");
}
} }
if (pchRet2[0] != 0x05) { if (pchRet2[0] != 0x05) {
CloseSocket(hSocket); CloseSocket(hSocket);
@ -370,26 +386,26 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
char pchRet3[256]; char pchRet3[256];
switch (pchRet2[3]) switch (pchRet2[3])
{ {
case 0x01: ret = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break; case 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
case 0x04: ret = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break; case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
case 0x03: case 0x03:
{ {
ret = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket); recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
if (!ret) { if (recvr != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
return error("Error reading from proxy"); return error("Error reading from proxy");
} }
int nRecv = pchRet3[0]; int nRecv = pchRet3[0];
ret = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket); recvr = InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, hSocket);
break; break;
} }
default: CloseSocket(hSocket); return error("Error: malformed proxy response"); default: CloseSocket(hSocket); return error("Error: malformed proxy response");
} }
if (!ret) { if (recvr != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
return error("Error reading from proxy"); return error("Error reading from proxy");
} }
if (!InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket); CloseSocket(hSocket);
return error("Error reading from proxy"); return error("Error reading from proxy");
} }

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>674</width> <width>674</width>
<height>363</height> <height>415</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -55,9 +55,6 @@
</item> </item>
<item> <item>
<widget class="QLabel" name="sizeWarningLabel"> <widget class="QLabel" name="sizeWarningLabel">
<property name="text">
<string>%1 will download and store a copy of the Dash block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory.</string>
</property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -203,6 +200,36 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="QLabel" name="lblExplanation1">
<property name="text">
<string>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblExplanation2">
<property name="text">
<string>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblExplanation3">
<property name="text">
<string>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">

View File

@ -38,9 +38,7 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
#if BOOST_FILESYSTEM_VERSION >= 3
#include <boost/filesystem/detail/utf8_codecvt_facet.hpp> #include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
#endif
#include <boost/scoped_array.hpp> #include <boost/scoped_array.hpp>
#include <QAbstractItemView> #include <QAbstractItemView>
@ -68,9 +66,7 @@
#include <QFontDatabase> #include <QFontDatabase>
#endif #endif
#if BOOST_FILESYSTEM_VERSION >= 3
static boost::filesystem::detail::utf8_codecvt_facet utf8; static boost::filesystem::detail::utf8_codecvt_facet utf8;
#endif
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
extern double NSAppKitVersionNumber; extern double NSAppKitVersionNumber;
@ -952,7 +948,6 @@ void setClipboard(const QString& str)
QApplication::clipboard()->setText(str, QClipboard::Selection); QApplication::clipboard()->setText(str, QClipboard::Selection);
} }
#if BOOST_FILESYSTEM_VERSION >= 3
boost::filesystem::path qstringToBoostPath(const QString &path) boost::filesystem::path qstringToBoostPath(const QString &path)
{ {
return boost::filesystem::path(path.toStdString(), utf8); return boost::filesystem::path(path.toStdString(), utf8);
@ -962,18 +957,6 @@ QString boostPathToQString(const boost::filesystem::path &path)
{ {
return QString::fromStdString(path.string(utf8)); return QString::fromStdString(path.string(utf8));
} }
#else
#warning Conversion between boost path and QString can use invalid character encoding with boost_filesystem v2 and older
boost::filesystem::path qstringToBoostPath(const QString &path)
{
return boost::filesystem::path(path.toStdString());
}
QString boostPathToQString(const boost::filesystem::path &path)
{
return QString::fromStdString(path.string());
}
#endif
QString formatDurationStr(int secs) QString formatDurationStr(int secs)
{ {

View File

@ -125,16 +125,34 @@ Intro::Intro(QWidget *parent) :
ui->setupUi(this); ui->setupUi(this);
ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME))); ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME)));
ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME))); ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME)));
ui->lblExplanation1->setText(ui->lblExplanation1->text()
.arg(tr(PACKAGE_NAME))
.arg(BLOCK_CHAIN_SIZE)
.arg(2014)
.arg(tr("Dash"))
);
ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(tr(PACKAGE_NAME)));
uint64_t pruneTarget = std::max<int64_t>(0, GetArg("-prune", 0)); uint64_t pruneTarget = std::max<int64_t>(0, GetArg("-prune", 0));
requiredSpace = BLOCK_CHAIN_SIZE; requiredSpace = BLOCK_CHAIN_SIZE;
QString storageRequiresMsg = tr("At least %1 GB of data will be stored in this directory, and it will grow over time.");
if (pruneTarget) { if (pruneTarget) {
uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES); uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
if (prunedGBs <= requiredSpace) { if (prunedGBs <= requiredSpace) {
requiredSpace = prunedGBs; requiredSpace = prunedGBs;
storageRequiresMsg = tr("Approximately %1 GB of data will be stored in this directory.");
} }
ui->lblExplanation3->setVisible(true);
} else {
ui->lblExplanation3->setVisible(false);
} }
requiredSpace += CHAIN_STATE_SIZE; requiredSpace += CHAIN_STATE_SIZE;
ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(tr(PACKAGE_NAME)).arg(requiredSpace)); ui->sizeWarningLabel->setText(
tr("%1 will download and store a copy of the Bitcoin block chain.").arg(tr(PACKAGE_NAME)) + " " +
storageRequiresMsg.arg(requiredSpace) + " " +
tr("The wallet will also be stored in this directory.")
);
startThread(); startThread();
} }

View File

@ -22,7 +22,7 @@ public:
std::string paramName; //!< parameter name std::string paramName; //!< parameter name
}; };
/** /**
* Specifiy a (method, idx, name) here if the argument is a non-string RPC * Specify a (method, idx, name) here if the argument is a non-string RPC
* argument and needs to be converted from JSON. * argument and needs to be converted from JSON.
* *
* @note Parameter indexes start from 0. * @note Parameter indexes start from 0.

View File

@ -11,23 +11,5 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
boost::filesystem::path GetTempPath() { boost::filesystem::path GetTempPath() {
#if BOOST_FILESYSTEM_VERSION == 3
return boost::filesystem::temp_directory_path(); return boost::filesystem::temp_directory_path();
#else
// TODO: remove when we don't support filesystem v2 anymore
boost::filesystem::path path;
#ifdef WIN32
char pszPath[MAX_PATH] = "";
if (GetTempPathA(MAX_PATH, pszPath))
path = boost::filesystem::path(pszPath);
#else
path = boost::filesystem::path("/tmp");
#endif
if (path.empty() || !boost::filesystem::is_directory(path)) {
LogPrintf("GetTempPath(): failed to find temp path\n");
return boost::filesystem::path("");
}
return path;
#endif
} }

View File

@ -11,7 +11,7 @@
/** /**
* GetTimeMicros() and GetTimeMillis() both return the system time, but in * GetTimeMicros() and GetTimeMillis() both return the system time, but in
* different units. GetTime() returns the sytem time in seconds, but also * different units. GetTime() returns the system time in seconds, but also
* supports mocktime, where the time can be specified by the user, eg for * supports mocktime, where the time can be specified by the user, eg for
* testing (eg with the setmocktime rpc, or -mocktime argument). * testing (eg with the setmocktime rpc, or -mocktime argument).
* *

View File

@ -1444,7 +1444,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// Helps prevent CPU exhaustion attacks. // Helps prevent CPU exhaustion attacks.
// Skip script verification when connecting blocks under the // Skip script verification when connecting blocks under the
// assumedvalid block. Assuming the assumedvalid block is valid this // assumevalid block. Assuming the assumevalid block is valid this
// is safe because block merkle hashes are still computed and checked, // is safe because block merkle hashes are still computed and checked,
// Of course, if an assumed valid block is invalid due to false scriptSigs // Of course, if an assumed valid block is invalid due to false scriptSigs
// this optimization would allow an invalid chain to be accepted. // this optimization would allow an invalid chain to be accepted.
@ -2831,12 +2831,12 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
bool fInitialDownload; bool fInitialDownload;
{ {
LOCK(cs_main); LOCK(cs_main);
{ // TODO: Tempoarily ensure that mempool removals are notified before { // TODO: Temporarily ensure that mempool removals are notified before
// connected transactions. This shouldn't matter, but the abandoned // connected transactions. This shouldn't matter, but the abandoned
// state of transactions in our wallet is currently cleared when we // state of transactions in our wallet is currently cleared when we
// receive another notification and there is a race condition where // receive another notification and there is a race condition where
// notification of a connected conflict might cause an outside process // notification of a connected conflict might cause an outside process
// to abandon a transaction and then have it inadvertantly cleared by // to abandon a transaction and then have it inadvertently cleared by
// the notification that the conflicted transaction was evicted. // the notification that the conflicted transaction was evicted.
MemPoolConflictRemovalTracker mrt(mempool); MemPoolConflictRemovalTracker mrt(mempool);
CBlockIndex *pindexOldTip = chainActive.Tip(); CBlockIndex *pindexOldTip = chainActive.Tip();
@ -2865,7 +2865,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
} // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified } // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
// Transactions in the connnected block are notified // Transactions in the connected block are notified
for (const auto& pair : connectTrace.blocksConnected) { for (const auto& pair : connectTrace.blocksConnected) {
assert(pair.second); assert(pair.second);
const CBlock& block = *(pair.second); const CBlock& block = *(pair.second);

View File

@ -63,7 +63,7 @@ struct CMainSignals {
boost::signals2::signal<void (const CBlockIndex *, bool fInitialDownload)> NotifyHeaderTip; boost::signals2::signal<void (const CBlockIndex *, bool fInitialDownload)> NotifyHeaderTip;
/** Notifies listeners of updated block chain tip */ /** Notifies listeners of updated block chain tip */
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip; boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
/** A posInBlock value for SyncTransaction calls for tranactions not /** A posInBlock value for SyncTransaction calls for transactions not
* included in connected blocks such as transactions removed from mempool, * included in connected blocks such as transactions removed from mempool,
* accepted to mempool or appearing in disconnected blocks.*/ * accepted to mempool or appearing in disconnected blocks.*/
static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1; static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1;

View File

@ -1219,7 +1219,7 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
* TODO: One exception to this is that the abandoned state is cleared under the * TODO: One exception to this is that the abandoned state is cleared under the
* assumption that any further notification of a transaction that was considered * assumption that any further notification of a transaction that was considered
* abandoned is an indication that it is not safe to be considered abandoned. * abandoned is an indication that it is not safe to be considered abandoned.
* Abandoned state should probably be more carefuly tracked via different * Abandoned state should probably be more carefully tracked via different
* posInBlock signals or by checking mempool presence when necessary. * posInBlock signals or by checking mempool presence when necessary.
*/ */
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate) bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
@ -5221,11 +5221,7 @@ bool CWallet::BackupWallet(const std::string& strDest)
pathDest /= strWalletFile; pathDest /= strWalletFile;
try { try {
#if BOOST_VERSION >= 104000
boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists); boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
#else
boost::filesystem::copy_file(pathSrc, pathDest);
#endif
LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string()); LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string());
return true; return true;
} catch (const boost::filesystem::filesystem_error& e) { } catch (const boost::filesystem::filesystem_error& e) {