diff options
100 files changed, 2626 insertions, 940 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5c1138b812..62ebc7917a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,26 @@ Contributing to Bitcoin Core ============================ -The Bitcoin Core project operates an open contributor model where anyone is welcome to contribute towards development in the form of peer review, testing and patches. This document explains the practical process and guidelines for contributing. +The Bitcoin Core project operates an open contributor model where anyone is +welcome to contribute towards development in the form of peer review, testing +and patches. This document explains the practical process and guidelines for +contributing. -Firstly in terms of structure, there is no particular concept of “Core developers” in the sense of privileged people. Open source often naturally revolves around meritocracy where longer term contributors gain more trust from the developer community. However, some hierarchy is necessary for practical purposes. As such there are repository “maintainers” who are responsible for merging pull requests as well as a “lead maintainer” who is responsible for the release cycle, overall merging, moderation and appointment of maintainers. +Firstly in terms of structure, there is no particular concept of "Core +developers" in the sense of privileged people. Open source often naturally +revolves around meritocracy where longer term contributors gain more trust from +the developer community. However, some hierarchy is necessary for practical +purposes. As such there are repository "maintainers" who are responsible for +merging pull requests as well as a "lead maintainer" who is responsible for the +release cycle, overall merging, moderation and appointment of maintainers. Contributor Workflow -------------------- -The codebase is maintained using the “contributor workflow” where everyone without exception contributes patch proposals using “pull requests”. This facilitates social contribution, easy testing and peer review. +The codebase is maintained using the "contributor workflow" where everyone +without exception contributes patch proposals using "pull requests". This +facilitates social contribution, easy testing and peer review. To contribute a patch, the workflow is as follows: @@ -17,35 +28,56 @@ To contribute a patch, the workflow is as follows: - Create topic branch - Commit patches -The project coding conventions in the [developer notes](doc/developer-notes.md) must be adhered to. +The project coding conventions in the [developer notes](doc/developer-notes.md) +must be adhered to. -In general [commits should be atomic](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention) and diffs should be easy to read. For this reason do not mix any formatting fixes or code moves with actual code changes. +In general [commits should be atomic](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention) +and diffs should be easy to read. For this reason do not mix any formatting +fixes or code moves with actual code changes. -Commit messages should be verbose by default consisting of a short subject line (50 chars max), a blank line and detailed explanatory text as separate paragraph(s); unless the title alone is self-explanatory (like "Corrected typo in main.cpp") then a single title line is sufficient. Commit messages should be helpful to people reading your code in the future, so explain the reasoning for your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/). +Commit messages should be verbose by default consisting of a short subject line +(50 chars max), a blank line and detailed explanatory text as separate +paragraph(s); unless the title alone is self-explanatory (like "Corrected typo +in main.cpp") then a single title line is sufficient. Commit messages should be +helpful to people reading your code in the future, so explain the reasoning for +your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/). -If a particular commit references another issue, please add the reference, for example `refs #1234`, or `fixes #4321`. Using the `fixes` or `closes` keywords will cause the corresponding issue to be closed when the pull request is merged. +If a particular commit references another issue, please add the reference, for +example `refs #1234`, or `fixes #4321`. Using the `fixes` or `closes` keywords +will cause the corresponding issue to be closed when the pull request is merged. -Please refer to the [Git manual](https://git-scm.com/doc) for more information about Git. +Please refer to the [Git manual](https://git-scm.com/doc) for more information +about Git. - Push changes to your fork - Create pull request -The title of the pull request should be prefixed by the component or area that the pull request affects. Examples: +The title of the pull request should be prefixed by the component or area that +the pull request affects. Examples: Consensus: Add new opcode for BIP-XXXX OP_CHECKAWESOMESIG Net: Automatically create hidden service, listen on Tor Qt: Add feed bump button Trivial: Fix typo in main.cpp -If a pull request is specifically not to be considered for merging (yet) please prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists) in the body of the pull request to indicate tasks are pending. +If a pull request is specifically not to be considered for merging (yet) please +prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists) +in the body of the pull request to indicate tasks are pending. -The body of the pull request should contain enough description about what the patch does together with any justification/reasoning. You should include references to any discussions (for example other tickets or mailing list discussions). +The body of the pull request should contain enough description about what the +patch does together with any justification/reasoning. You should include +references to any discussions (for example other tickets or mailing list +discussions). -At this stage one should expect comments and review from other contributors. You can add more commits to your pull request by committing them locally and pushing to your fork until you have satisfied all feedback. +At this stage one should expect comments and review from other contributors. You +can add more commits to your pull request by committing them locally and pushing +to your fork until you have satisfied all feedback. Squashing Commits --------------------------- -If your pull request is accepted for merging, you may be asked by a maintainer to squash and or [rebase](https://git-scm.com/docs/git-rebase) your commits before it will be merged. The basic squashing workflow is shown below. +If your pull request is accepted for merging, you may be asked by a maintainer +to squash and or [rebase](https://git-scm.com/docs/git-rebase) your commits +before it will be merged. The basic squashing workflow is shown below. git checkout your_branch_name git rebase -i HEAD~n @@ -55,67 +87,111 @@ If your pull request is accepted for merging, you may be asked by a maintainer t # save and quit git push -f # (force push to GitHub) -The length of time required for peer review is unpredictable and will vary from pull request to pull request. +The length of time required for peer review is unpredictable and will vary from +pull request to pull request. Pull Request Philosophy ----------------------- -Patchsets should always be focused. For example, a pull request could add a feature, fix a bug, or refactor code; but not a mixture. Please also avoid super pull requests which attempt to do too much, are overly large, or overly complex as this makes review difficult. +Patchsets should always be focused. For example, a pull request could add a +feature, fix a bug, or refactor code; but not a mixture. Please also avoid super +pull requests which attempt to do too much, are overly large, or overly complex +as this makes review difficult. ###Features -When adding a new feature, thought must be given to the long term technical debt and maintenance that feature may require after inclusion. Before proposing a new feature that will require maintenance, please consider if you are willing to maintain it (including bug fixing). If features get orphaned with no maintainer in the future, they may be removed by the Repository Maintainer. +When adding a new feature, thought must be given to the long term technical debt +and maintenance that feature may require after inclusion. Before proposing a new +feature that will require maintenance, please consider if you are willing to +maintain it (including bug fixing). If features get orphaned with no maintainer +in the future, they may be removed by the Repository Maintainer. ###Refactoring -Refactoring is a necessary part of any software project's evolution. The following guidelines cover refactoring pull requests for the project. +Refactoring is a necessary part of any software project's evolution. The +following guidelines cover refactoring pull requests for the project. -There are three categories of refactoring, code only moves, code style fixes, code refactoring. In general refactoring pull requests should not mix these three kinds of activity in order to make refactoring pull requests easy to review and uncontroversial. In all cases, refactoring PRs must not change the behaviour of code within the pull request (bugs must be preserved as is). +There are three categories of refactoring, code only moves, code style fixes, +code refactoring. In general refactoring pull requests should not mix these +three kinds of activity in order to make refactoring pull requests easy to +review and uncontroversial. In all cases, refactoring PRs must not change the +behaviour of code within the pull request (bugs must be preserved as is). -Project maintainers aim for a quick turnaround on refactoring pull requests, so where possible keep them short, uncomplex and easy to verify. +Project maintainers aim for a quick turnaround on refactoring pull requests, so +where possible keep them short, uncomplex and easy to verify. "Decision Making" Process ------------------------- -The following applies to code changes to the Bitcoin Core project (and related projects such as libsecp256k1), and is not to be confused with overall Bitcoin Network Protocol consensus changes. +The following applies to code changes to the Bitcoin Core project (and related +projects such as libsecp256k1), and is not to be confused with overall Bitcoin +Network Protocol consensus changes. -Whether a pull request is merged into Bitcoin Core rests with the project merge maintainers and ultimately the project lead. +Whether a pull request is merged into Bitcoin Core rests with the project merge +maintainers and ultimately the project lead. -Maintainers will take into consideration if a patch is in line with the general principles of the project; meets the minimum standards for inclusion; and will judge the general consensus of contributors. +Maintainers will take into consideration if a patch is in line with the general +principles of the project; meets the minimum standards for inclusion; and will +judge the general consensus of contributors. In general, all pull requests must: - - have a clear use case, fix a demonstrable bug or serve the greater good of the project (for example refactoring for modularisation); + - have a clear use case, fix a demonstrable bug or serve the greater good of + the project (for example refactoring for modularisation); - be well peer reviewed; - have unit tests and functional tests where appropriate; - follow code style guidelines; - not break the existing test suite; - - where bugs are fixed, where possible, there should be unit tests demonstrating the bug and also proving the fix. This helps prevent regression. + - where bugs are fixed, where possible, there should be unit tests + demonstrating the bug and also proving the fix. This helps prevent regression. -Patches that change Bitcoin consensus rules are considerably more involved than normal because they affect the entire ecosystem and so must be preceded by extensive mailing list discussions and have a numbered BIP. While each case will be different, one should be prepared to expend more time and effort than for other kinds of patches because of increased peer review and consensus building requirements. +Patches that change Bitcoin consensus rules are considerably more involved than +normal because they affect the entire ecosystem and so must be preceded by +extensive mailing list discussions and have a numbered BIP. While each case will +be different, one should be prepared to expend more time and effort than for +other kinds of patches because of increased peer review and consensus building +requirements. ###Peer Review -Anyone may participate in peer review which is expressed by comments in the pull request. Typically reviewers will review the code for obvious errors, as well as test out the patch set and opine on the technical merits of the patch. Project maintainers take into account the peer review when determining if there is consensus to merge a pull request (remember that discussions may have been spread out over github, mailing list and IRC discussions). The following language is used within pull-request comments: +Anyone may participate in peer review which is expressed by comments in the pull +request. Typically reviewers will review the code for obvious errors, as well as +test out the patch set and opine on the technical merits of the patch. Project +maintainers take into account the peer review when determining if there is +consensus to merge a pull request (remember that discussions may have been +spread out over github, mailing list and IRC discussions). The following +language is used within pull-request comments: - ACK means "I have tested the code and I agree it should be merged"; - - NACK means "I disagree this should be merged", and must be accompanied by sound technical justification. NACKs without accompanying reasoning may be disregarded; - - utACK means "I have not tested the code, but I have reviewed it and it looks OK, I agree it can be merged"; + - NACK means "I disagree this should be merged", and must be accompanied by + sound technical justification. NACKs without accompanying reasoning may be disregarded; + - utACK means "I have not tested the code, but I have reviewed it and it looks + OK, I agree it can be merged"; - Concept ACK means "I agree in the general principle of this pull request"; - Nit refers to trivial, often non-blocking issues. Reviewers should include the commit hash which they reviewed in their comments. -Project maintainers reserve the right to weigh the opinions of peer reviewers using common sense judgement and also may weight based on meritocracy: Those that have demonstrated a deeper commitment and understanding towards the project (over time) or have clear domain expertise may naturally have more weight, as one would expect in all walks of life. - -Where a patch set affects consensus critical code, the bar will be set much higher in terms of discussion and peer review requirements, keeping in mind that mistakes could be very costly to the wider community. This includes refactoring of consensus critical code. - -Where a patch set proposes to change the Bitcoin consensus, it must have been discussed extensively on the mailing list and IRC, be accompanied by a widely discussed BIP and have a generally widely perceived technical consensus of being a worthwhile change based on the judgement of the maintainers. +Project maintainers reserve the right to weigh the opinions of peer reviewers +using common sense judgement and also may weight based on meritocracy: Those +that have demonstrated a deeper commitment and understanding towards the project +(over time) or have clear domain expertise may naturally have more weight, as +one would expect in all walks of life. + +Where a patch set affects consensus critical code, the bar will be set much +higher in terms of discussion and peer review requirements, keeping in mind that +mistakes could be very costly to the wider community. This includes refactoring +of consensus critical code. + +Where a patch set proposes to change the Bitcoin consensus, it must have been +discussed extensively on the mailing list and IRC, be accompanied by a widely +discussed BIP and have a generally widely perceived technical consensus of being +a worthwhile change based on the judgement of the maintainers. Release Policy diff --git a/configure.ac b/configure.ac index 335609f5e5..607adec4f4 100644 --- a/configure.ac +++ b/configure.ac @@ -69,7 +69,8 @@ AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) AC_PATH_TOOL(GCOV, gcov) AC_PATH_PROG(LCOV, lcov) -AC_PATH_PROGS([PYTHON], [python3 python2.7 python2 python]) +dnl Python 3.x is supported from 3.4 on (see https://github.com/bitcoin/bitcoin/issues/7893) +AC_PATH_PROGS([PYTHON], [python3.6 python3.5 python3.4 python3 python2.7 python2 python]) AC_PATH_PROG(GENHTML, genhtml) AC_PATH_PROG([GIT], [git]) AC_PATH_PROG(CCACHE,ccache) @@ -358,8 +359,15 @@ case $host in TARGET_OS=linux LEVELDB_TARGET_FLAGS="-DOS_LINUX" ;; + *freebsd*) + LEVELDB_TARGET_FLAGS="-DOS_FREEBSD" + ;; + *openbsd*) + LEVELDB_TARGET_FLAGS="-DOS_OPENBSD" + ;; *) OTHER_OS=`echo ${host_os} | awk '{print toupper($0)}'` + AC_MSG_WARN([Guessing LevelDB OS as OS_${OTHER_OS}, please check whether this is correct, if not add an entry to configure.ac.]) LEVELDB_TARGET_FLAGS="-DOS_${OTHER_OS}" ;; esac diff --git a/contrib/README.md b/contrib/README.md index a23b197cc6..3e3c83da5f 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -45,6 +45,9 @@ Scripts and notes for Mac builds. ### [RPM](/contrib/rpm) ### RPM spec file for building bitcoin-core on RPM based distributions +### [Gitian-build](/contrib/gitian-build.sh) ### +Script for running full gitian builds. + Test and Verify Tools --------------------- diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md index bb8b9246b8..af5c000b03 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -51,8 +51,9 @@ maintained: * for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master) * for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork) * for `src/univalue`: https://github.com/bitcoin-core/univalue.git (branch master) +* for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master) -Usage: `git-subtree-check.sh DIR COMMIT` +Usage: `git-subtree-check.sh DIR (COMMIT)` `COMMIT` may be omitted, in which case `HEAD` is used. diff --git a/contrib/devtools/fix-copyright-headers.py b/contrib/devtools/fix-copyright-headers.py index b6414a551f..54836bd83f 100755 --- a/contrib/devtools/fix-copyright-headers.py +++ b/contrib/devtools/fix-copyright-headers.py @@ -1,5 +1,5 @@ -#!/usr/bin/env python -''' +#!/usr/bin/env python3 +""" Run this script to update all the copyright headers of files that were changed this year. @@ -10,37 +10,58 @@ For example: it will change it to // Copyright (c) 2009-2015 The Bitcoin Core developers -''' -import os +""" +import subprocess import time import re -year = time.gmtime()[0] -CMD_GIT_DATE = 'git log --format=@%%at -1 %s | date +"%%Y" -u -f -' -CMD_REGEX= "perl -pi -e 's/(20\d\d)(?:-20\d\d)? The Bitcoin/$1-%s The Bitcoin/' %s" -REGEX_CURRENT= re.compile("%s The Bitcoin" % year) -CMD_LIST_FILES= "find %s | grep %s" +CMD_GIT_LIST_FILES = ['git', 'ls-files'] +CMD_GIT_DATE = ['git', 'log', '--format=%ad', '--date=short', '-1'] +CMD_PERL_REGEX = ['perl', '-pi', '-e'] +REGEX_TEMPLATE = 's/(20\\d\\d)(?:-20\\d\\d)? The Bitcoin/$1-%s The Bitcoin/' -FOLDERS = ["./qa", "./src"] +FOLDERS = ["qa/", "src/"] EXTENSIONS = [".cpp",".h", ".py"] + def get_git_date(file_path): - r = os.popen(CMD_GIT_DATE % file_path) - for l in r: - # Result is one line, so just return - return l.replace("\n","") - return "" - -n=1 -for folder in FOLDERS: - for extension in EXTENSIONS: - for file_path in os.popen(CMD_LIST_FILES % (folder, extension)): - file_path = os.getcwd() + file_path[1:-1] - if file_path.endswith(extension): - git_date = get_git_date(file_path) - if str(year) == git_date: - # Only update if current year is not found - if REGEX_CURRENT.search(open(file_path, "r").read()) is None: - print n,"Last git edit", git_date, "-", file_path - os.popen(CMD_REGEX % (year,file_path)) + d = subprocess.run(CMD_GIT_DATE + [file_path], + stdout=subprocess.PIPE, + check=True, + universal_newlines=True).stdout + # yyyy-mm-dd + return d.split('-')[0] + + +def skip_file(file_path): + for ext in EXTENSIONS: + if file_path.endswith(ext): + return False + else: + return True + +if __name__ == "__main__": + year = str(time.gmtime()[0]) + regex_current = re.compile("%s The Bitcoin" % year) + n = 1 + for folder in FOLDERS: + for file_path in subprocess.run( + CMD_GIT_LIST_FILES + [folder], + stdout=subprocess.PIPE, + check=True, + universal_newlines=True + ).stdout.split("\n"): + if skip_file(file_path): + # print(file_path, "(skip)") + continue + git_date = get_git_date(file_path) + if not year == git_date: + # print(file_path, year, "(skip)") + continue + if regex_current.search(open(file_path, "r").read()) is not None: + # already up to date + # print(file_path, year, "(skip)") + continue + print(n, file_path, "(update to %s)" % year) + subprocess.run(CMD_PERL_REGEX + [REGEX_TEMPLATE % year, file_path], check=True) n = n + 1 diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh new file mode 100755 index 0000000000..ee47d138f3 --- /dev/null +++ b/contrib/gitian-build.sh @@ -0,0 +1,388 @@ +# What to do +sign=false +verify=false +build=false +setupenv=false + +# Systems to build +linux=true +windows=true +osx=true + +# Other Basic variables +SIGNER= +VERSION= +commit=false +url=https://github.com/bitcoin/bitcoin +proc=2 +mem=2000 +lxc=true +osslTarUrl=http://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz +osslPatchUrl=https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch +scriptName=$(basename -- "$0") +signProg="gpg --detach-sign" +commitFiles=true + +# Help Message +read -d '' usage <<- EOF +Usage: $scriptName [-c|u|v|b|s|B|o|h|j|m|] signer version + +Run this script from the directory containing the bitcoin, gitian-builder, gitian.sigs, and bitcoin-detached-sigs. + +Arguments: +signer GPG signer to sign each build assert file +version Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified + +Options: +-c|--commit Indicate that the version argument is for a commit or branch +-u|--url Specify the URL of the repository. Default is https://github.com/bitcoin/bitcoin +-v|--verify Verify the gitian build +-b|--build Do a gitiain build +-s|--sign Make signed binaries for Windows and Mac OSX +-B|--buildsign Build both signed and unsigned binaries +-o|--os Specify which Operating Systems the build is for. Default is lwx. l for linux, w for windows, x for osx +-j Number of processes to use. Default 2 +-m Memory to allocate in MiB. Default 2000 +--kvm Use KVM instead of LXC +--setup Setup the gitian building environment. Uses KVM. If you want to use lxc, use the --lxc option. Only works on Debian-based systems (Ubuntu, Debian) +--detach-sign Create the assert file for detached signing. Will not commit anything. +--no-commit Do not commit anything to git +-h|--help Print this help message +EOF + +# Get options and arguments +while :; do + case $1 in + # Verify + -v|--verify) + verify=true + ;; + # Build + -b|--build) + build=true + ;; + # Sign binaries + -s|--sign) + sign=true + ;; + # Build then Sign + -B|--buildsign) + sign=true + build=true + ;; + # PGP Signer + -S|--signer) + if [ -n "$2" ] + then + SIGNER=$2 + shift + else + echo 'Error: "--signer" requires a non-empty argument.' + exit 1 + fi + ;; + # Operating Systems + -o|--os) + if [ -n "$2" ] + then + linux=false + windows=false + osx=false + if [[ "$2" = *"l"* ]] + then + linux=true + fi + if [[ "$2" = *"w"* ]] + then + windows=true + fi + if [[ "$2" = *"x"* ]] + then + osx=true + fi + shift + else + echo 'Error: "--os" requires an argument containing an l (for linux), w (for windows), or x (for Mac OSX)\n' + exit 1 + fi + ;; + # Help message + -h|--help) + echo "$usage" + exit 0 + ;; + # Commit or branch + -c|--commit) + commit=true + ;; + # Number of Processes + -j) + if [ -n "$2" ] + then + proc=$2 + shift + else + echo 'Error: "-j" requires an argument' + exit 1 + fi + ;; + # Memory to allocate + -m) + if [ -n "$2" ] + then + mem=$2 + shift + else + echo 'Error: "-m" requires an argument' + exit 1 + fi + ;; + # URL + -u) + if [ -n "$2" ] + then + url=$2 + shift + else + echo 'Error: "-u" requires an argument' + exit 1 + fi + ;; + # kvm + --kvm) + lxc=false + ;; + # Detach sign + --detach-sign) + signProg="true" + commitFiles=false + ;; + # Commit files + --no-commit) + commitFiles=false + ;; + # Setup + --setup) + setup=true + ;; + *) # Default case: If no more options then break out of the loop. + break + esac + shift +done + +# Set up LXC +if [[ $lxc = true ]] +then + export USE_LXC=1 + export LXC_BRIDGE=lxcbr0 + sudo ifconfig lxcbr0 up 10.0.2.2 +fi + +# Check for OSX SDK +if [[ ! -e "gitian-builder/inputs/MacOSX10.11.sdk.tar.gz" && $osx == true ]] +then + echo "Cannot build for OSX, SDK does not exist. Will build for other OSes" + osx=false +fi + +# Get signer +if [[ -n"$1" ]] +then + SIGNER=$1 + shift +fi + +# Get version +if [[ -n "$1" ]] +then + VERSION=$1 + COMMIT=$VERSION + shift +fi + +# Check that a signer is specified +if [[ $SIGNER == "" ]] +then + echo "$scriptName: Missing signer." + echo "Try $scriptName --help for more information" + exit 1 +fi + +# Check that a version is specified +if [[ $VERSION == "" ]] +then + echo "$scriptName: Missing version." + echo "Try $scriptName --help for more information" + exit 1 +fi + +# Add a "v" if no -c +if [[ $commit = false ]] +then + COMMIT="v${VERSION}" +fi +echo ${COMMIT} + +# Setup build environment +if [[ $setup = true ]] +then + sudo apt-get install ruby apache2 git apt-cacher-ng python-vm-builder qemu-kvm qemu-utils + git clone https://github.com/bitcoin-core/gitian.sigs.git + git clone https://github.com/bitcoin-core/bitcoin-detached-sigs.git + git clone https://github.com/devrandom/gitian-builder.git + pushd ./gitian-builder + if [[ -n "$USE_LXC" ]] + then + sudo apt-get install lxc + bin/make-base-vm --suite trusty --arch amd64 --lxc + else + bin/make-base-vm --suite trusty --arch amd64 + fi + popd +fi + +# Set up build +pushd ./bitcoin +git fetch +git checkout ${COMMIT} +popd + +# Build +if [[ $build = true ]] +then + # Make output folder + mkdir -p ./bitcoin-binaries/${VERSION} + + # Build Dependencies + echo "" + echo "Building Dependencies" + echo "" + pushd ./gitian-builder + mkdir -p inputs + wget -N -P inputs $osslPatchUrl + wget -N -P inputs $osslTarUrl + make -C ../bitcoin/depends download SOURCES_PATH=`pwd`/cache/common + + # Linux + if [[ $linux = true ]] + then + echo "" + echo "Compiling ${VERSION} Linux" + echo "" + ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml + mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/${VERSION} + fi + # Windows + if [[ $windows = true ]] + then + echo "" + echo "Compiling ${VERSION} Windows" + echo "" + ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win.yml + mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz + mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../bitcoin-binaries/${VERSION} + fi + # Mac OSX + if [[ $osx = true ]] + then + echo "" + echo "Compiling ${VERSION} Mac OSX" + echo "" + ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml + mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz + mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../bitcoin-binaries/${VERSION} + fi + popd + + if [[ $commitFiles = true ]] + then + # Commit to gitian.sigs repo + echo "" + echo "Committing ${VERSION} Unsigned Sigs" + echo "" + pushd gitian.sigs + git add ${VERSION}-linux/${SIGNER} + git add ${VERSION}-win-unsigned/${SIGNER} + git add ${VERSION}-osx-unsigned/${SIGNER} + git commit -a -m "Add ${VERSION} unsigned sigs for ${SIGNER}" + popd + fi +fi + +# Verify the build +if [[ $verify = true ]] +then + # Linux + pushd ./gitian-builder + echo "" + echo "Verifying v${VERSION} Linux" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml + # Windows + echo "" + echo "Verifying v${VERSION} Windows" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-win.yml + # Mac OSX + echo "" + echo "Verifying v${VERSION} Mac OSX" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml + # Signed Windows + echo "" + echo "Verifying v${VERSION} Signed Windows" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml + # Signed Mac OSX + echo "" + echo "Verifying v${VERSION} Signed Mac OSX" + echo "" + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml + popd +fi + +# Sign binaries +if [[ $sign = true ]] +then + + pushd ./gitian-builder + # Sign Windows + if [[ $windows = true ]] + then + echo "" + echo "Signing ${VERSION} Windows" + echo "" + ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml + mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/${VERSION} + mv build/out/bitcoin-*win32-setup.exe ../bitcoin-binaries/${VERSION} + fi + # Sign Mac OSX + if [[ $osx = true ]] + then + echo "" + echo "Signing ${VERSION} Mac OSX" + echo "" + ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml + ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml + mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/${VERSION}/bitcoin-${VERSION}-osx.dmg + fi + popd + + if [[ $commitFiles = true ]] + then + # Commit Sigs + pushd gitian.sigs + echo "" + echo "Committing ${VERSION} Signed Sigs" + echo "" + git add ${VERSION}-win-signed/${SIGNER} + git add ${VERSION}-osx-signed/${SIGNER} + git commit -a -m "Add ${VERSION} signed binary sigs for ${SIGNER}" + popd + fi +fi diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh new file mode 100755 index 0000000000..46d2d825d4 --- /dev/null +++ b/contrib/macdeploy/extract-osx-sdk.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -e + +INPUTFILE="Xcode_7.3.1.dmg" +HFSFILENAME="5.hfs" +SDKDIR="Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk" + +7z x "${INPUTFILE}" "${HFSFILENAME}" +SDKNAME="$(basename "${SDKDIR}")" +SDKDIRINODE=$(ifind -n "${SDKDIR}" "${HFSFILENAME}") +fls "${HFSFILENAME}" -rpF ${SDKDIRINODE} | + while read type inode filename; do + inode="${inode::-1}" + if [ "${filename:0:14}" = "usr/share/man/" ]; then + continue + fi + filename="${SDKNAME}/$filename" + echo "Extracting $filename ..." + mkdir -p "$(dirname "$filename")" + if [ "$type" = "l/l" ]; then + ln -s "$(icat "${HFSFILENAME}" $inode)" "$filename" + else + icat "${HFSFILENAME}" $inode >"$filename" + fi +done +echo "Building ${SDKNAME}.tar.gz ..." +MTIME="$(istat "${HFSFILENAME}" "${SDKDIRINODE}" | perl -nle 'm/Content Modified:\s+(.*?)\s\(/ && print $1')" +find "${SDKNAME}" | sort | tar --no-recursion --mtime="${MTIME}" --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > "${SDKNAME}.tar.gz" +echo 'All done!' diff --git a/contrib/verifybinaries/README.md b/contrib/verifybinaries/README.md index 8970f3daa4..ed3e14fb6c 100644 --- a/contrib/verifybinaries/README.md +++ b/contrib/verifybinaries/README.md @@ -1,13 +1,33 @@ ### Verify Binaries + +#### Preparation: + +Make sure you obtain the proper release signing key and verify the fingerprint with several independent sources. + +```sh +$ gpg --fingerprint "Bitcoin Core binary release signing key" +pub 4096R/36C2E964 2015-06-24 [expires: 2017-02-13] + Key fingerprint = 01EA 5486 DE18 A882 D4C2 6845 90C8 019E 36C2 E964 +uid Wladimir J. van der Laan (Bitcoin Core binary release signing key) <laanwj@gmail.com> +``` + +#### Usage: + This script attempts to download the signature file `SHA256SUMS.asc` from https://bitcoin.org. It first checks if the signature passes, and then downloads the files specified in the file, and checks if the hashes of these files match those that are specified in the signature file. The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2. -Usage: ```sh ./verify.sh bitcoin-core-0.11.2 ./verify.sh bitcoin-core-0.12.0 +./verify.sh bitcoin-core-0.13.0-rc3 +``` + +If you do not want to keep the downloaded binaries, specify anything as the second parameter. + +```sh +./verify.sh bitcoin-core-0.13.0 delete ``` diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh index 657c3bd33c..e22b911743 100755 --- a/contrib/verifybinaries/verify.sh +++ b/contrib/verifybinaries/verify.sh @@ -14,11 +14,11 @@ function clean_up { done } -WORKINGDIR="/tmp/bitcoin" +WORKINGDIR="/tmp/bitcoin_verify_binaries" TMPFILE="hashes.tmp" SIGNATUREFILENAME="SHA256SUMS.asc" -RCSUBDIR="test/" +RCSUBDIR="test" BASEDIR="https://bitcoin.org/bin/" VERSIONPREFIX="bitcoin-core-" RCVERSIONSTRING="rc" @@ -43,7 +43,7 @@ if [ -n "$1" ]; then # and simultaneously add RCSUBDIR to BASEDIR, where we will look for SIGNATUREFILENAME if [[ $VERSION == *"$RCVERSIONSTRING"* ]]; then BASEDIR="$BASEDIR${VERSION/%-$RCVERSIONSTRING*}/" - BASEDIR="$BASEDIR$RCSUBDIR" + BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSIONSTRING${VERSION: -1}/" else BASEDIR="$BASEDIR$VERSION/" fi @@ -93,7 +93,7 @@ fi FILES=$(awk '{print $2}' "$TMPFILE") #and download these one by one -for file in in $FILES +for file in $FILES do wget --quiet -N "$BASEDIR$file" done @@ -108,11 +108,16 @@ if [ $? -eq 1 ]; then exit 1 elif [ $? -gt 1 ]; then echo "Error executing 'diff'" - exit 2 + exit 2 fi -#everything matches! clean up the mess -clean_up $FILES $SIGNATUREFILENAME $TMPFILE +if [ -n "$2" ]; then + echo "Clean up the binaries" + clean_up $FILES $SIGNATUREFILENAME $TMPFILE +else + echo "Keep the binaries in $WORKINGDIR" + clean_up $TMPFILE +fi echo -e "Verified hashes of \n$FILES" diff --git a/depends/packages/qt46.mk b/depends/packages/qt46.mk deleted file mode 100644 index 8fb30a5c44..0000000000 --- a/depends/packages/qt46.mk +++ /dev/null @@ -1,66 +0,0 @@ -PACKAGE=qt46 -$(package)_version=4.6.4 -$(package)_download_path=http://download.qt-project.org/archive/qt/4.6/ -$(package)_file_name=qt-everywhere-opensource-src-$($(package)_version).tar.gz -$(package)_sha256_hash=9ad4d46c721b53a429ed5a2eecfd3c239a9ab566562f183f99d3125f1a234250 -$(package)_dependencies=openssl freetype dbus libX11 xproto libXext libICE libSM -$(package)_patches=stlfix.patch - -define $(package)_set_vars -$(package)_config_opts = -prefix $(host_prefix) -headerdir $(host_prefix)/include/qt4 -bindir $(build_prefix)/bin -$(package)_config_opts += -release -no-separate-debug-info -opensource -confirm-license -$(package)_config_opts += -stl -qt-zlib - -$(package)_config_opts += -nomake examples -nomake tests -nomake tools -nomake translations -nomake demos -nomake docs -$(package)_config_opts += -no-audio-backend -no-glib -no-nis -no-cups -no-iconv -no-gif -no-pch -$(package)_config_opts += -no-xkb -no-xrender -no-xrandr -no-xfixes -no-xcursor -no-xinerama -no-xsync -no-xinput -no-mitshm -no-xshape -$(package)_config_opts += -no-libtiff -no-fontconfig -openssl-linked -$(package)_config_opts += -no-sql-db2 -no-sql-ibase -no-sql-oci -no-sql-tds -no-sql-mysql -$(package)_config_opts += -no-sql-odbc -no-sql-psql -no-sql-sqlite -no-sql-sqlite2 -$(package)_config_opts += -no-xmlpatterns -no-multimedia -no-phonon -no-scripttools -no-declarative -$(package)_config_opts += -no-phonon-backend -no-webkit -no-javascript-jit -no-script -$(package)_config_opts += -no-svg -no-libjpeg -no-libtiff -no-libpng -no-libmng -no-qt3support -no-opengl - -$(package)_config_opts_x86_64_linux += -platform linux-g++-64 -$(package)_config_opts_i686_linux = -platform linux-g++-32 -$(package)_build_env = QT_RCC_TEST=1 -endef - -define $(package)_preprocess_cmds - sed -i.old "s|/include /usr/include||" config.tests/unix/freetype/freetype.pri && \ - sed -i.old "s|src_plugins.depends = src_gui src_sql src_svg|src_plugins.depends = src_gui src_sql|" src/src.pro && \ - sed -i.old "s|\.lower(|\.toLower(|g" src/network/ssl/qsslsocket_openssl.cpp && \ - sed -i.old "s|Key_BackSpace|Key_Backspace|" src/gui/itemviews/qabstractitemview.cpp && \ - sed -i.old "s|/usr/X11R6/lib64|$(host_prefix)/lib|" mkspecs/*/*.conf && \ - sed -i.old "s|/usr/X11R6/lib|$(host_prefix)/lib|" mkspecs/*/*.conf && \ - sed -i.old "s|/usr/X11R6/include|$(host_prefix)/include|" mkspecs/*/*.conf && \ - sed -i.old "s|QMAKE_LFLAGS_SHLIB\t+= -shared|QMAKE_LFLAGS_SHLIB\t+= -shared -Wl,--exclude-libs,ALL|" mkspecs/common/g++.conf && \ - sed -i.old "/SSLv2_client_method/d" src/network/ssl/qsslsocket_openssl.cpp src/network/ssl/qsslsocket_openssl_symbols.cpp && \ - sed -i.old "/SSLv2_server_method/d" src/network/ssl/qsslsocket_openssl.cpp src/network/ssl/qsslsocket_openssl_symbols.cpp && \ - patch -p1 < $($(package)_patch_dir)/stlfix.patch -endef - -define $(package)_config_cmds - export PKG_CONFIG_SYSROOT_DIR=/ && \ - export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \ - export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \ - export CPATH=$(host_prefix)/include && \ - OPENSSL_LIBS='-L$(host_prefix)/lib -lssl -lcrypto' ./configure $($(package)_config_opts) && \ - cd tools/linguist/lrelease; ../../../bin/qmake -o Makefile lrelease.pro -endef - -define $(package)_build_cmds - export CPATH=$(host_prefix)/include && \ - $(MAKE) -C src && \ - $(MAKE) -C tools/linguist/lrelease -endef - -define $(package)_stage_cmds - $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) install && \ - $(MAKE) -C tools/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install -endef - -define $(package)_postprocess_cmds - rm -rf mkspecs/ lib/cmake/ lib/*.prl lib/*.la && \ - find native/bin -type f -exec mv {} {}-qt4 \; -endef diff --git a/depends/patches/qt46/stlfix.patch b/depends/patches/qt46/stlfix.patch deleted file mode 100644 index f8f6fb04b0..0000000000 --- a/depends/patches/qt46/stlfix.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- old/config.tests/unix/stl/stltest.cpp 2011-06-23 03:45:23.000000000 -0400 -+++ new/config.tests/unix/stl/stltest.cpp 2014-08-28 00:54:04.154837604 -0400 -@@ -49,6 +49,7 @@ - #include <vector> - #include <algorithm> - #include <iostream> -+#include <cstddef> - - // something mean to see if the compiler and C++ standard lib are good enough - template<class K, class T> diff --git a/doc/README_osx.md b/doc/README_osx.md index 6a5c672277..2a4460478c 100644 --- a/doc/README_osx.md +++ b/doc/README_osx.md @@ -36,11 +36,26 @@ Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.1 ``` Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file. -To create a tarball suitable for Gitian input, mount the dmg in OS X, then create it with: +To create a tarball suitable for Gitian input, there are two options: + +Using Mac OS X, you can mount the dmg, and then create it with: ``` + $ hdiutil attach Xcode_7.3.1.dmg $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk ``` +Alternatively, you can use 7zip and SleuthKit to extract the files one by one. +The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure +the dmg file is in the current directory, and then run the script. You may wish +to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when +you've confirmed the extraction succeeded. + +```bash +apt-get install p7zip-full sleuthkit +contrib/macdeploy/extract-osx-sdk.sh +rm -rf 5.hfs MacOSX10.11.sdk +``` + The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries which are created using these tools. The build process has been designed to avoid including the SDK's files in Gitian's outputs. All interim tarballs are diff --git a/doc/REST-interface.md b/doc/REST-interface.md index bf669235e3..7fbb174030 100644 --- a/doc/REST-interface.md +++ b/doc/REST-interface.md @@ -3,6 +3,8 @@ Unauthenticated REST Interface The REST API can be enabled with the `-rest` option. +The interface runs on the same port as the JSON-RPC interface, by default port 8332 for mainnet and port 18332 for testnet. + Supported API ------------- diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md index d923301467..55283d6dce 100644 --- a/doc/build-openbsd.md +++ b/doc/build-openbsd.md @@ -1,6 +1,6 @@ OpenBSD build guide ====================== -(updated for OpenBSD 5.7) +(updated for OpenBSD 5.9) This guide describes how to build bitcoind and command-line utilities on OpenBSD. @@ -15,11 +15,10 @@ Run the following as root to install the base dependencies for building: pkg_add gmake libtool libevent pkg_add autoconf # (select highest version, e.g. 2.69) pkg_add automake # (select highest version, e.g. 1.15) -pkg_add python # (select version 2.7.x, not 3.x) -ln -sf /usr/local/bin/python2.7 /usr/local/bin/python2 +pkg_add python # (select highest version, e.g. 3.5) ``` -The default C++ compiler that comes with OpenBSD 5.7 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core. It is possible to patch it up to compile, but with the planned transition to C++11 this is a losing battle. So here we will be installing a newer compiler. +The default C++ compiler that comes with OpenBSD 5.9 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core, primarily as it has no C++11 support, but even before there were issues. So here we will be installing a newer compiler. GCC ------- @@ -27,7 +26,7 @@ GCC You can install a newer version of gcc with: ```bash -pkg_add g++ # (select newest 4.x version, e.g. 4.9.2) +pkg_add g++ # (select newest 4.x version, e.g. 4.9.3) ``` This compiler will not overwrite the system compiler, it will be installed as `egcc` and `eg++` in `/usr/local/bin`. @@ -49,18 +48,15 @@ BOOST_PREFIX="${BITCOIN_ROOT}/boost" mkdir -p $BOOST_PREFIX # Fetch the source and verify that it is not tampered with -wget http://heanet.dl.sourceforge.net/project/boost/boost/1.59.0/boost_1_59_0.tar.bz2 -echo '727a932322d94287b62abb1bd2d41723eec4356a7728909e38adb65ca25241ca boost_1_59_0.tar.bz2' | sha256 -c -# MUST output: (SHA256) boost_1_59_0.tar.bz2: OK -tar -xjf boost_1_59_0.tar.bz2 +curl -o boost_1_61_0.tar.bz2 http://heanet.dl.sourceforge.net/project/boost/boost/1.61.0/boost_1_61_0.tar.bz2 +echo 'a547bd06c2fd9a71ba1d169d9cf0339da7ebf4753849a8f7d6fdb8feee99b640 boost_1_61_0.tar.bz2' | sha256 -c +# MUST output: (SHA256) boost_1_61_0.tar.bz2: OK +tar -xjf boost_1_61_0.tar.bz2 -# Boost 1.59 needs two small patches for OpenBSD -cd boost_1_59_0 +# Boost 1.61 needs one small patch for OpenBSD +cd boost_1_61_0 # Also here: https://gist.githubusercontent.com/laanwj/bf359281dc319b8ff2e1/raw/92250de8404b97bb99d72ab898f4a8cb35ae1ea3/patch-boost_test_impl_execution_monitor_ipp.patch patch -p0 < /usr/ports/devel/boost/patches/patch-boost_test_impl_execution_monitor_ipp -# https://github.com/boostorg/filesystem/commit/90517e459681790a091566dce27ca3acabf9a70c -sed 's/__OPEN_BSD__/__OpenBSD__/g' < libs/filesystem/src/path.cpp > libs/filesystem/src/path.cpp.tmp -mv libs/filesystem/src/path.cpp.tmp libs/filesystem/src/path.cpp # Build w/ minimum configuration necessary for bitcoin echo 'using gcc : : eg++ : <cxxflags>"-fvisibility=hidden -fPIC" <linkflags>"" <archiver>"ar" <striper>"strip" <ranlib>"ranlib" <rc>"" : ;' > user-config.jam @@ -84,7 +80,7 @@ BDB_PREFIX="${BITCOIN_ROOT}/db4" mkdir -p $BDB_PREFIX # Fetch the source and verify that it is not tampered with -wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' +curl -o db-4.8.30.NC.tar.gz 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' echo '12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz' | sha256 -c # MUST output: (SHA256) db-4.8.30.NC.tar.gz: OK tar -xzf db-4.8.30.NC.tar.gz @@ -93,9 +89,25 @@ tar -xzf db-4.8.30.NC.tar.gz cd db-4.8.30.NC/build_unix/ # Note: Do a static build so that it can be embedded into the executable, instead of having to find a .so at runtime ../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX CC=egcc CXX=eg++ CPP=ecpp -make install +make install # do NOT use -jX, this is broken ``` +### Resource limits + +The standard ulimit restrictions in OpenBSD are very strict: + + data(kbytes) 1572864 + +This is, unfortunately, no longer enough to compile some `.cpp` files in the project, +at least with gcc 4.9.3 (see issue https://github.com/bitcoin/bitcoin/issues/6658). +If your user is in the `staff` group the limit can be raised with: + + ulimit -d 3000000 + +The change will only affect the current shell and processes spawned by it. To +make the change system-wide, change `datasize-cur` and `datasize-max` in +`/etc/login.conf`, and reboot. + ### Building Bitcoin Core **Important**: use `gmake`, not `make`. The non-GNU `make` will exit with a horrible error. @@ -123,7 +135,7 @@ To configure without wallet: Build and run the tests: ```bash -gmake +gmake # can use -jX here for parallelism gmake check ``` diff --git a/doc/build-unix.md b/doc/build-unix.md index bd89978cc2..62e3e793e9 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -293,9 +293,10 @@ These steps can be performed on, for example, an Ubuntu VM. The depends system will also work on other Linux distributions, however the commands for installing the toolchain will be different. -First install the toolchain: +Make sure you install the build requirements mentioned above. +Then, install the toolchain and curl: - sudo apt-get install g++-arm-linux-gnueabihf + sudo apt-get install g++-arm-linux-gnueabihf curl To build executables for ARM: diff --git a/doc/build-windows.md b/doc/build-windows.md index 2b9233d1e1..129774491b 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -16,9 +16,11 @@ These steps can be performed on, for example, an Ubuntu VM. The depends system will also work on other Linux distributions, however the commands for installing the toolchain will be different. -First install the toolchains: +Make sure you install the build requirements mentioned in +[build-unix.md](/doc/build-unix.md). +Then, install the toolchains and curl: - sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev g++-mingw-w64-x86-64 mingw-w64-x86-64-dev + sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev g++-mingw-w64-x86-64 mingw-w64-x86-64-dev curl To build executables for Windows 32-bit: diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 95c46b05fe..70c0690ba3 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -14,6 +14,7 @@ gradually. - No indentation for public/protected/private or for namespaces. - No extra spaces inside parenthesis; don't do ( this ) - No space after function names; one space after if, for and while. + - `++i` is preferred over `i++`. Block style example: ```c++ @@ -24,7 +25,7 @@ class Class bool Function(char* psz, int n) { // Comment summarising what this section of code does - for (int i = 0; i < n; i++) { + for (int i = 0; i < n; ++i) { // When something fails, return early if (!Something()) return false; @@ -231,9 +232,9 @@ General Bitcoin Core - *Rationale*: Makes sure that they pass thorough testing, and that the tester will keep passing on the master branch. Otherwise all new pull requests will start failing the tests, resulting in confusion and mayhem - + - *Explanation*: If the test suite is to be updated for a change, this has to - be done first + be done first Wallet ------- diff --git a/doc/release-notes.md b/doc/release-notes.md index b99192ae97..58994a6839 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -41,6 +41,14 @@ report issues about Windows XP to the issue tracker. Notable changes =============== +Low-level RPC changes +---------------------- + +- `importprunedfunds` only accepts two required arguments. Some versions accept + an optional third arg, which was always ignored. Make sure to never pass more + than two arguments. + + 0.14.0 Change log ================= @@ -51,6 +59,12 @@ git merge commit are mentioned. ### RPC and REST +UTXO set query (`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n>/.../<txid>-<n>.<bin|hex|json>`) responses +were changed to return status code HTTP_BAD_REQUEST (400) instead of HTTP_INTERNAL_SERVER_ERROR (500) when requests +contain invalid parameters. + +The first boolean argument to `getaddednodeinfo` has been removed. This is an incompatible change. + ### Configuration and command-line options ### Block and transaction handling diff --git a/doc/release-notes/release-notes-0.12.1.md b/doc/release-notes/release-notes-0.12.1.md new file mode 100644 index 0000000000..610cd481de --- /dev/null +++ b/doc/release-notes/release-notes-0.12.1.md @@ -0,0 +1,198 @@ +Bitcoin Core version 0.12.1 is now available from: + + <https://bitcoin.org/bin/bitcoin-core-0.12.1/> + +This is a new minor version release, including the BIP9, BIP68 and BIP112 +softfork, various bugfixes and updated translations. + +Please report bugs using the issue tracker at github: + + <https://github.com/bitcoin/bitcoin/issues> + +Upgrading and downgrading +========================= + +How to Upgrade +-------------- + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) or +bitcoind/bitcoin-qt (on Linux). + +Downgrade warning +----------------- + +### Downgrade to a version < 0.12.0 + +Because release 0.12.0 and later will obfuscate the chainstate on every +fresh sync or reindex, the chainstate is not backwards-compatible with +pre-0.12 versions of Bitcoin Core or other software. + +If you want to downgrade after you have done a reindex with 0.12.0 or later, +you will need to reindex when you first start Bitcoin Core version 0.11 or +earlier. + +Notable changes +=============== + +First version bits BIP9 softfork deployment +------------------------------------------- + +This release includes a soft fork deployment to enforce [BIP68][], +[BIP112][] and [BIP113][] using the [BIP9][] deployment mechanism. + +The deployment sets the block version number to 0x20000001 between +midnight 1st May 2016 and midnight 1st May 2017 to signal readiness for +deployment. The version number consists of 0x20000000 to indicate version +bits together with setting bit 0 to indicate support for this combined +deployment, shown as "csv" in the `getblockchaininfo` RPC call. + +For more information about the soft forking change, please see +<https://github.com/bitcoin/bitcoin/pull/7648> + +This specific backport pull-request can be viewed at +<https://github.com/bitcoin/bitcoin/pull/7543> + +[BIP9]: https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki +[BIP68]: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki +[BIP112]: https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki +[BIP113]: https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki + +BIP68 soft fork to enforce sequence locks for relative locktime +--------------------------------------------------------------- + +[BIP68][] introduces relative lock-time consensus-enforced semantics of +the sequence number field to enable a signed transaction input to remain +invalid for a defined period of time after confirmation of its corresponding +outpoint. + +For more information about the implementation, see +<https://github.com/bitcoin/bitcoin/pull/7184> + +BIP112 soft fork to enforce OP_CHECKSEQUENCEVERIFY +-------------------------------------------------- + +[BIP112][] redefines the existing OP_NOP3 as OP_CHECKSEQUENCEVERIFY (CSV) +for a new opcode in the Bitcoin scripting system that in combination with +[BIP68][] allows execution pathways of a script to be restricted based +on the age of the output being spent. + +For more information about the implementation, see +<https://github.com/bitcoin/bitcoin/pull/7524> + +BIP113 locktime enforcement soft fork +------------------------------------- + +Bitcoin Core 0.11.2 previously introduced mempool-only locktime +enforcement using GetMedianTimePast(). This release seeks to +consensus enforce the rule. + +Bitcoin transactions currently may specify a locktime indicating when +they may be added to a valid block. Current consensus rules require +that blocks have a block header time greater than the locktime specified +in any transaction in that block. + +Miners get to choose what time they use for their header time, with the +consensus rule being that no node will accept a block whose time is more +than two hours in the future. This creates a incentive for miners to +set their header times to future values in order to include locktimed +transactions which weren't supposed to be included for up to two more +hours. + +The consensus rules also specify that valid blocks may have a header +time greater than that of the median of the 11 previous blocks. This +GetMedianTimePast() time has a key feature we generally associate with +time: it can't go backwards. + +[BIP113][] specifies a soft fork enforced in this release that +weakens this perverse incentive for individual miners to use a future +time by requiring that valid blocks have a computed GetMedianTimePast() +greater than the locktime specified in any transaction in that block. + +Mempool inclusion rules currently require transactions to be valid for +immediate inclusion in a block in order to be accepted into the mempool. +This release begins applying the BIP113 rule to received transactions, +so transaction whose time is greater than the GetMedianTimePast() will +no longer be accepted into the mempool. + +**Implication for miners:** you will begin rejecting transactions that +would not be valid under BIP113, which will prevent you from producing +invalid blocks when BIP113 is enforced on the network. Any +transactions which are valid under the current rules but not yet valid +under the BIP113 rules will either be mined by other miners or delayed +until they are valid under BIP113. Note, however, that time-based +locktime transactions are more or less unseen on the network currently. + +**Implication for users:** GetMedianTimePast() always trails behind the +current time, so a transaction locktime set to the present time will be +rejected by nodes running this release until the median time moves +forward. To compensate, subtract one hour (3,600 seconds) from your +locktimes to allow those transactions to be included in mempools at +approximately the expected time. + +For more information about the implementation, see +<https://github.com/bitcoin/bitcoin/pull/6566> + +Miscellaneous +------------- + +The p2p alert system is off by default. To turn on, use `-alert` with +startup configuration. + +0.12.1 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### RPC and other APIs +- #7739 `7ffc2bd` Add abandoned status to listtransactions (jonasschnelli) + +### Block and transaction handling +- #7543 `834aaef` Backport BIP9, BIP68 and BIP112 with softfork (btcdrak) + +### P2P protocol and network code +- #7804 `90f1d24` Track block download times per individual block (sipa) +- #7832 `4c3a00d` Reduce block timeout to 10 minutes (laanwj) + +### Validation +- #7821 `4226aac` init: allow shutdown during 'Activating best chain...' (laanwj) +- #7835 `46898e7` Version 2 transactions remain non-standard until CSV activates (sdaftuar) + +### Build system +- #7487 `00d57b4` Workaround Travis-side CI issues (luke-jr) +- #7606 `a10da9a` No need to set -L and --location for curl (MarcoFalke) +- #7614 `ca8f160` Add curl to packages (now needed for depends) (luke-jr) +- #7776 `a784675` Remove unnecessary executables from gitian release (laanwj) + +### Wallet +- #7715 `19866c1` Fix calculation of balances and available coins. (morcos) + +### Miscellaneous +- #7617 `f04f4fd` Fix markdown syntax and line terminate LogPrint (MarcoFalke) +- #7747 `4d035bc` added depends cross compile info (accraze) +- #7741 `a0cea89` Mark p2p alert system as deprecated (btcdrak) +- #7780 `c5f94f6` Disable bad-chain alert (btcdrak) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- accraze +- Alex Morcos +- BtcDrak +- Jonas Schnelli +- Luke Dashjr +- MarcoFalke +- Mark Friedenbach +- NicolasDorier +- Pieter Wuille +- Suhas Daftuar +- Wladimir J. van der Laan + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). + diff --git a/doc/release-notes/release-notes-0.13.0.md b/doc/release-notes/release-notes-0.13.0.md new file mode 100644 index 0000000000..5dd3f5a651 --- /dev/null +++ b/doc/release-notes/release-notes-0.13.0.md @@ -0,0 +1,863 @@ +Bitcoin Core version 0.13.0 is now available from: + + <https://bitcoin.org/bin/bitcoin-core-0.13.0/> + +This is a new major version release, including new features, various bugfixes +and performance improvements, as well as updated translations. + +Please report bugs using the issue tracker at github: + + <https://github.com/bitcoin/bitcoin/issues> + +To receive security and update notifications, please subscribe to: + + <https://bitcoincore.org/en/list/announcements/join/> + +Compatibility +============== + +Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support), +an OS initially released in 2001. This means that not even critical security +updates will be released anymore. Without security updates, using a bitcoin +wallet on a XP machine is irresponsible at least. + +In addition to that, with 0.12.x there have been varied reports of Bitcoin Core +randomly crashing on Windows XP. It is [not clear](https://github.com/bitcoin/bitcoin/issues/7681#issuecomment-217439891) +what the source of these crashes is, but it is likely that upstream +libraries such as Qt are no longer being tested on XP. + +We do not have time nor resources to provide support for an OS that is +end-of-life. From 0.13.0 on, Windows XP is no longer supported. Users are +suggested to upgrade to a newer verion of Windows, or install an alternative OS +that is supported. + +No attempt is made to prevent installing or running the software on Windows XP, +you can still do so at your own risk, but do not expect it to work: do not +report issues about Windows XP to the issue tracker. + +Notable changes +=============== + +Database cache memory increased +-------------------------------- + +As a result of growth of the UTXO set, performance with the prior default +database cache of 100 MiB has suffered. +For this reason the default was changed to 300 MiB in this release. + +For nodes on low-memory systems, the database cache can be changed back to +100 MiB (or to another value) by either: + +- Adding `dbcache=100` in bitcoin.conf +- Changing it in the GUI under `Options → Size of database cache` + +Note that the database cache setting has the most performance impact +during initial sync of a node, and when catching up after downtime. + + +bitcoin-cli: arguments privacy +------------------------------ + +The RPC command line client gained a new argument, `-stdin` +to read extra arguments from standard input, one per line until EOF/Ctrl-D. +For example: + + $ src/bitcoin-cli -stdin walletpassphrase + mysecretcode + 120 + ..... press Ctrl-D here to end input + $ + +It is recommended to use this for sensitive information such as wallet +passphrases, as command-line arguments can usually be read from the process +table by any user on the system. + + +C++11 and Python 3 +------------------ + +Various code modernizations have been done. The Bitcoin Core code base has +started using C++11. This means that a C++11-capable compiler is now needed for +building. Effectively this means GCC 4.7 or higher, or Clang 3.3 or higher. + +When cross-compiling for a target that doesn't have C++11 libraries, configure with +`./configure --enable-glibc-back-compat ... LDFLAGS=-static-libstdc++`. + +For running the functional tests in `qa/rpc-tests`, Python3.4 or higher is now +required. + + +Linux ARM builds +---------------- + +Due to popular request, Linux ARM builds have been added to the uploaded +executables. + +The following extra files can be found in the download directory or torrent: + +- `bitcoin-${VERSION}-arm-linux-gnueabihf.tar.gz`: Linux binaries for the most + common 32-bit ARM architecture. +- `bitcoin-${VERSION}-aarch64-linux-gnu.tar.gz`: Linux binaries for the most + common 64-bit ARM architecture. + +ARM builds are still experimental. If you have problems on a certain device or +Linux distribution combination please report them on the bug tracker, it may be +possible to resolve them. + +Note that Android is not considered ARM Linux in this context. The executables +are not expected to work out of the box on Android. + + +Compact Block support (BIP 152) +------------------------------- + +Support for block relay using the Compact Blocks protocol has been implemented +in PR 8068. + +The primary goal is reducing the bandwidth spikes at relay time, though in many +cases it also reduces propagation delay. It is automatically enabled between +compatible peers. +[BIP 152](https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki) + +As a side-effect, ordinary non-mining nodes will download and upload blocks +faster if those blocks were produced by miners using similar transaction +filtering policies. This means that a miner who produces a block with many +transactions discouraged by your node will be relayed slower than one with +only transactions already in your memory pool. The overall effect of such +relay differences on the network may result in blocks which include widely- +discouraged transactions losing a stale block race, and therefore miners may +wish to configure their node to take common relay policies into consideration. + + +Hierarchical Deterministic Key Generation +----------------------------------------- +Newly created wallets will use hierarchical deterministic key generation +according to BIP32 (keypath m/0'/0'/k'). +Existing wallets will still use traditional key generation. + +Backups of HD wallets, regardless of when they have been created, can +therefore be used to re-generate all possible private keys, even the +ones which haven't already been generated during the time of the backup. +**Attention:** Encrypting the wallet will create a new seed which requires +a new backup! + +Wallet dumps (created using the `dumpwallet` RPC) will contain the deterministic +seed. This is expected to allow future versions to import the seed and all +associated funds, but this is not yet implemented. + +HD key generation for new wallets can be disabled by `-usehd=0`. Keep in +mind that this flag only has affect on newly created wallets. +You can't disable HD key generation once you have created a HD wallet. + +There is no distinction between internal (change) and external keys. + +HD wallets are incompatible with older versions of Bitcoin Core. + +[Pull request](https://github.com/bitcoin/bitcoin/pull/8035/files), [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) + + +Segregated Witness +------------------ + +The code preparations for Segregated Witness ("segwit"), as described in [BIP +141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki), [BIP +143](https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki), [BIP +144](https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki), and [BIP +145](https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki) are +finished and included in this release. However, BIP 141 does not yet specify +activation parameters on mainnet, and so this release does not support segwit +use on mainnet. Testnet use is supported, and after BIP 141 is updated with +proposed parameters, a future release of Bitcoin Core is expected that +implements those parameters for mainnet. + +Furthermore, because segwit activation is not yet specified for mainnet, +version 0.13.0 will behave similarly as other pre-segwit releases even after a +future activation of BIP 141 on the network. Upgrading from 0.13.0 will be +required in order to utilize segwit-related features on mainnet (such as signal +BIP 141 activation, mine segwit blocks, fully validate segwit blocks, relay +segwit blocks to other segwit nodes, and use segwit transactions in the +wallet, etc). + + +Mining transaction selection ("Child Pays For Parent") +------------------------------------------------------ + +The mining transaction selection algorithm has been replaced with an algorithm +that selects transactions based on their feerate inclusive of unconfirmed +ancestor transactions. This means that a low-fee transaction can become more +likely to be selected if a high-fee transaction that spends its outputs is +relayed. + +With this change, the `-blockminsize` command line option has been removed. + +The command line option `-blockmaxsize` remains an option to specify the +maximum number of serialized bytes in a generated block. In addition, the new +command line option `-blockmaxweight` has been added, which specifies the +maximum "block weight" of a generated block, as defined by [BIP 141 (Segregated +Witness)] (https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki). + +In preparation for Segregated Witness, the mining algorithm has been modified +to optimize transaction selection for a given block weight, rather than a given +number of serialized bytes in a block. In this release, transaction selection +is unaffected by this distinction (as BIP 141 activation is not supported on +mainnet in this release, see above), but in future releases and after BIP 141 +activation, these calculations would be expected to differ. + +For optimal runtime performance, miners using this release should specify +`-blockmaxweight` on the command line, and not specify `-blockmaxsize`. +Additionally (or only) specifying `-blockmaxsize`, or relying on default +settings for both, may result in performance degradation, as the logic to +support `-blockmaxsize` performs additional computation to ensure that +constraint is met. (Note that for mainnet, in this release, the equivalent +parameter for `-blockmaxweight` would be four times the desired +`-blockmaxsize`. See [BIP 141] +(https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki) for additional +details.) + +In the future, the `-blockmaxsize` option may be removed, as block creation is +no longer optimized for this metric. Feedback is requested on whether to +deprecate or keep this command line option in future releases. + + +Reindexing changes +------------------ + +In earlier versions, reindexing did validation while reading through the block +files on disk. These two have now been split up, so that all blocks are known +before validation starts. This was necessary to make certain optimizations that +are available during normal synchronizations also available during reindexing. + +The two phases are distinct in the Bitcoin-Qt GUI. During the first one, +"Reindexing blocks on disk" is shown. During the second (slower) one, +"Processing blocks on disk" is shown. + +It is possible to only redo validation now, without rebuilding the block index, +using the command line option `-reindex-chainstate` (in addition to +`-reindex` which does both). This new option is useful when the blocks on disk +are assumed to be fine, but the chainstate is still corrupted. It is also +useful for benchmarks. + + +Removal of internal miner +-------------------------- + +As CPU mining has been useless for a long time, the internal miner has been +removed in this release, and replaced with a simpler implementation for the +test framework. + +The overall result of this is that `setgenerate` RPC call has been removed, as +well as the `-gen` and `-genproclimit` command-line options. + +For testing, the `generate` call can still be used to mine a block, and a new +RPC call `generatetoaddress` has been added to mine to a specific address. This +works with wallet disabled. + + +New bytespersigop implementation +-------------------------------- + +The former implementation of the bytespersigop filter accidentally broke bare +multisig (which is meant to be controlled by the `permitbaremultisig` option), +since the consensus protocol always counts these older transaction forms as 20 +sigops for backwards compatibility. Simply fixing this bug by counting more +accurately would have reintroduced a vulnerability. It has therefore been +replaced with a new implementation that rather than filter such transactions, +instead treats them (for fee purposes only) as if they were in fact the size +of a transaction actually using all 20 sigops. + + +Low-level P2P changes +---------------------- + +- The optional new p2p message "feefilter" is implemented and the protocol + version is bumped to 70013. Upon receiving a feefilter message from a peer, + a node will not send invs for any transactions which do not meet the filter + feerate. [BIP 133](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki) + +- The P2P alert system has been removed in PR #7692 and the `alert` P2P message + is no longer supported. + +- The transaction relay mechanism used to relay one quarter of all transactions + instantly, while queueing up the rest and sending them out in batch. As + this resulted in chains of dependent transactions being reordered, it + systematically hurt transaction relay. The relay code was redesigned in PRs + \#7840 and #8082, and now always batches transactions announcements while also + sorting them according to dependency order. This significantly reduces orphan + transactions. To compensate for the removal of instant relay, the frequency of + batch sending was doubled for outgoing peers. + +- Since PR #7840 the BIP35 `mempool` command is also subject to batch processing. + Also the `mempool` message is no longer handled for non-whitelisted peers when + `NODE_BLOOM` is disabled through `-peerbloomfilters=0`. + +- The maximum size of orphan transactions that are kept in memory until their + ancestors arrive has been raised in PR #8179 from 5000 to 99999 bytes. They + are now also removed from memory when they are included in a block, conflict + with a block, and time out after 20 minutes. + +- We respond at most once to a getaddr request during the lifetime of a + connection since PR #7856. + +- Connections to peers who have recently been the first one to give us a valid + new block or transaction are protected from disconnections since PR #8084. + + +Low-level RPC changes +---------------------- + +- RPC calls have been added to output detailed statistics for individual mempool + entries, as well as to calculate the in-mempool ancestors or descendants of a + transaction: see `getmempoolentry`, `getmempoolancestors`, `getmempooldescendants`. + +- `gettxoutsetinfo` UTXO hash (`hash_serialized`) has changed. There was a divergence between + 32-bit and 64-bit platforms, and the txids were missing in the hashed data. This has been + fixed, but this means that the output will be different than from previous versions. + +- Full UTF-8 support in the RPC API. Non-ASCII characters in, for example, + wallet labels have always been malformed because they weren't taken into account + properly in JSON RPC processing. This is no longer the case. This also affects + the GUI debug console. + +- Asm script outputs replacements for OP_NOP2 and OP_NOP3 + + - OP_NOP2 has been renamed to OP_CHECKLOCKTIMEVERIFY by [BIP +65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) + + - OP_NOP3 has been renamed to OP_CHECKSEQUENCEVERIFY by [BIP +112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki) + + - The following outputs are affected by this change: + + - RPC `getrawtransaction` (in verbose mode) + - RPC `decoderawtransaction` + - RPC `decodescript` + - REST `/rest/tx/` (JSON format) + - REST `/rest/block/` (JSON format when including extended tx details) + - `bitcoin-tx -json` + +- The sorting of the output of the `getrawmempool` output has changed. + +- New RPC commands: `generatetoaddress`, `importprunedfunds`, `removeprunedfunds`, `signmessagewithprivkey`, + `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry`, + `createwitnessaddress`, `addwitnessaddress`. + +- Removed RPC commands: `setgenerate`, `getgenerate`. + +- New options were added to `fundrawtransaction`: `includeWatching`, `changeAddress`, `changePosition` and `feeRate`. + + +Low-level ZMQ changes +---------------------- + +- Each ZMQ notification now contains an up-counting sequence number that allows + listeners to detect lost notifications. + The sequence number is always the last element in a multi-part ZMQ notification and + therefore backward compatible. Each message type has its own counter. + PR [#7762](https://github.com/bitcoin/bitcoin/pull/7762). + + +0.13.0 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### RPC and other APIs + +- #7156 `9ee02cf` Remove cs_main lock from `createrawtransaction` (laanwj) +- #7326 `2cd004b` Fix typo, wrong information in gettxout help text (paveljanik) +- #7222 `82429d0` Indicate which transactions are signaling opt-in RBF (sdaftuar) +- #7480 `b49a623` Changed getnetworkhps value to double to avoid overflow (instagibbs) +- #7550 `8b958ab` Input-from-stdin mode for bitcoin-cli (laanwj) +- #7670 `c9a1265` Use cached block hash in blockToJSON() (rat4) +- #7726 `9af69fa` Correct importaddress help reference to importpubkey (CypherGrue) +- #7766 `16555b6` Register calls where they are defined (laanwj) +- #7797 `e662a76` Fix generatetoaddress failing to parse address (mruddy) +- #7774 `916b15a` Add versionHex in getblock and getblockheader JSON results (mruddy) +- #7863 `72c54e3` Getblockchaininfo: make bip9_softforks an object, not an array (rustyrussell) +- #7842 `d97101e` Do not print minping time in getpeerinfo when no ping received yet (paveljanik) +- #7518 `be14ca5` Add multiple options to fundrawtransaction (promag) +- #7756 `9e47fce` Add cursor to iterate over utxo set, use this in `gettxoutsetinfo` (laanwj) +- #7848 `88616d2` Divergence between 32- and 64-bit when hashing >4GB affects `gettxoutsetinfo` (laanwj) +- #7827 `4205ad7` Speed up `getchaintips` (mrbandrews) +- #7762 `a1eb344` Append a message sequence number to every ZMQ notification (jonasschnelli) +- #7688 `46880ed` List solvability in listunspent output and improve help (sipa) +- #7926 `5725807` Push back `getaddednodeinfo` dead value (instagibbs) +- #7953 `0630353` Create `signmessagewithprivkey` rpc (achow101) +- #8049 `c028c7b` Expose information on whether transaction relay is enabled in `getnetworkinfo` (laanwj) +- #7967 `8c1e49b` Add feerate option to `fundrawtransaction` (jonasschnelli) +- #8118 `9b6a48c` Reduce unnecessary hashing in `signrawtransaction` (jonasnick) +- #7957 `79004d4` Add support for transaction sequence number (jonasschnelli) +- #8153 `75ec320` `fundrawtransaction` feeRate: Use BTC/kB (MarcoFalke) +- #7292 `7ce9ac5` Expose ancestor/descendant information over RPC (sdaftuar) +- #8171 `62fcf27` Fix createrawtx sequence number unsigned int parsing (jonasschnelli) +- #7892 `9c3d0fa` Add full UTF-8 support to RPC (laanwj) +- #8317 `304eff3` Don't use floating point in rpcwallet (MarcoFalke) +- #8258 `5a06ebb` Hide softfork in `getblockchaininfo` if timeout is 0 (jl2012) +- #8244 `1922e5a` Remove unnecessary LOCK(cs_main) in getrawmempool (dcousens) + +### Block and transaction handling + +- #7056 `6a07208` Save last db read (morcos) +- #6842 `0192806` Limitfreerelay edge case bugfix (ptschip) +- #7084 `11d74f6` Replace maxFeeRate of 10000*minRelayTxFee with maxTxFee in mempool (MarcoFalke) +- #7539 `9f33dba` Add tags to mempool's mapTx indices (sdaftuar) +- #7592 `26a2a72` Re-remove ERROR logging for mempool rejects (laanwj) +- #7187 `14d6324` Keep reorgs fast for SequenceLocks checks (morcos) +- #7594 `01f4267` Mempool: Add tracking of ancestor packages (sdaftuar) +- #7904 `fc9e334` Txdb: Fix assert crash in new UTXO set cursor (laanwj) +- #7927 `f9c2ac7` Minor changes to dbwrapper to simplify support for other databases (laanwj) +- #7933 `e26b620` Fix OOM when deserializing UTXO entries with invalid length (sipa) +- #8020 `5e374f7` Use SipHash-2-4 for various non-cryptographic hashes (sipa) +- #8076 `d720980` VerifyDB: don't check blocks that have been pruned (sdaftuar) +- #8080 `862fd24` Do not use mempool for GETDATA for tx accepted after the last mempool req (gmaxwell) +- #7997 `a82f033` Replace mapNextTx with slimmer setSpends (kazcw) +- #8220 `1f86d64` Stop trimming when mapTx is empty (sipa) +- #8273 `396f9d6` Bump `-dbcache` default to 300MiB (laanwj) +- #7225 `eb33179` Eliminate unnecessary call to CheckBlock (sdaftuar) +- #7907 `006cdf6` Optimize and Cleanup CScript::FindAndDelete (pstratem) +- #7917 `239d419` Optimize reindex (sipa) +- #7763 `3081fb9` Put hex-encoded version in UpdateTip (sipa) +- #8149 `d612837` Testnet-only segregated witness (sipa) +- #8305 `3730393` Improve handling of unconnecting headers (sdaftuar) +- #8363 `fca1a41` Rename "block cost" to "block weight" (sdaftuar) +- #8381 `f84ee3d` Make witness v0 outputs non-standard (jl2012) +- #8364 `3f65ba2` Treat high-sigop transactions as larger rather than rejecting them (sipa) + +### P2P protocol and network code + +- #6589 `dc0305d` Log bytes recv/sent per command (jonasschnelli) +- #7164 `3b43cad` Do not download transactions during initial blockchain sync (ptschip) +- #7458 `898fedf` peers.dat, banlist.dat recreated when missing (kirkalx) +- #7637 `3da5d1b` Fix memleak in TorController (laanwj, jonasschnelli) +- #7553 `9f14e5a` Remove vfReachable and modify IsReachable to only use vfLimited (pstratem) +- #7708 `9426632` De-neuter NODE_BLOOM (pstratem) +- #7692 `29b2be6` Remove P2P alert system (btcdrak) +- #7542 `c946a15` Implement "feefilter" P2P message (morcos) +- #7573 `352fd57` Add `-maxtimeadjustment` command line option (mruddy) +- #7570 `232592a` Add IPv6 Link-Local Address Support (mruddy) +- #7874 `e6a4d48` Improve AlreadyHave (morcos) +- #7856 `64e71b3` Only send one GetAddr response per connection (gmaxwell) +- #7868 `7daa3ad` Split DNS resolving functionality out of net structures (theuni) +- #7919 `7617682` Fix headers announcements edge case (sdaftuar) +- #7514 `d9594bf` Fix IsInitialBlockDownload for testnet (jmacwhyte) +- #7959 `03cf6e8` fix race that could fail to persist a ban (kazcw) +- #7840 `3b9a0bf` Several performance and privacy improvements to inv/mempool handling (sipa) +- #8011 `65aecda` Don't run ThreadMessageHandler at lowered priority (kazcw) +- #7696 `5c3f8dd` Fix de-serialization bug where AddrMan is left corrupted (EthanHeilman) +- #7932 `ed749bd` CAddrMan::Deserialize handle corrupt serializations better (pstratem) +- #7906 `83121cc` Prerequisites for p2p encapsulation changes (theuni) +- #8033 `18436d8` Fix Socks5() connect failures to be less noisy and less unnecessarily scary (wtogami) +- #8082 `01d8359` Defer inserting into maprelay until just before relaying (gmaxwell) +- #7960 `6a22373` Only use AddInventoryKnown for transactions (sdaftuar) +- #8078 `2156fa2` Disable the mempool P2P command when bloom filters disabled (petertodd) +- #8065 `67c91f8` Addrman offline attempts (gmaxwell) +- #7703 `761cddb` Tor: Change auth order to only use password auth if -torpassword (laanwj) +- #8083 `cd0c513` Add support for dnsseeds with option to filter by servicebits (jonasschnelli) +- #8173 `4286f43` Use SipHash for node eviction (sipa) +- #8154 `1445835` Drop vAddrToSend after sending big addr message (kazcw) +- #7749 `be9711e` Enforce expected outbound services (sipa) +- #8208 `0a64777` Do not set extra flags for unfiltered DNS seed results (sipa) +- #8084 `e4bb4a8` Add recently accepted blocks and txn to AttemptToEvictConnection (gmaxwell) +- #8113 `3f89a53` Rework addnode behaviour (sipa) +- #8179 `94ab58b` Evict orphans which are included or precluded by accepted blocks (gmaxwell) +- #8068 `e9d76a1` Compact Blocks (TheBlueMatt) +- #8204 `0833894` Update petertodd's testnet seed (petertodd) +- #8247 `5cd35d3` Mark my dnsseed as supporting filtering (sipa) +- #8275 `042c323` Remove bad chain alert partition check (btcdrak) +- #8271 `1bc9c80` Do not send witnesses in cmpctblock (sipa) +- #8312 `ca40ef6` Fix mempool DoS vulnerability from malleated transactions (sdaftuar) +- #7180 `16ccb74` Account for `sendheaders` `verack` messages (laanwj) +- #8102 `425278d` Bugfix: use global ::fRelayTxes instead of CNode in version send (sipa) +- #8408 `b7e2011` Prevent fingerprinting, disk-DoS with compact blocks (sdaftuar) + +### Build system + +- #7302 `41f1a3e` C++11 build/runtime fixes (theuni) +- #7322 `fd9356b` c++11: add scoped enum fallbacks to CPPFLAGS rather than defining them locally (theuni) +- #7441 `a6771fc` Use Debian 8.3 in gitian build guide (fanquake) +- #7349 `152a821` Build against system UniValue when available (luke-jr) +- #7520 `621940e` LibreSSL doesn't define OPENSSL_VERSION, use LIBRESSL_VERSION_TEXT instead (paveljanik) +- #7528 `9b9bfce` autogen.sh: warn about needing autoconf if autoreconf is not found (knocte) +- #7504 `19324cf` Crystal clean make clean (paveljanik) +- #7619 `18b3f1b` Add missing sudo entry in gitian VM setup (btcdrak) +- #7616 `639ec58` [depends] Delete unused patches (MarcoFalke) +- #7658 `c15eb28` Add curl to Gitian setup instructions (btcdrak) +- #7710 `909b72b` [Depends] Bump miniupnpc and config.guess+sub (fanquake) +- #7723 `5131005` build: python 3 compatibility (laanwj) +- #7477 `28ad4d9` Fix quoting of copyright holders in configure.ac (domob1812) +- #7711 `a67bc5e` [build-aux] Update Boost & check macros to latest serials (fanquake) +- #7788 `4dc1b3a` Use relative paths instead of absolute paths in protoc calls (paveljanik) +- #7809 `bbd210d` depends: some base fixes/changes (theuni) +- #7603 `73fc922` Build System: Use PACKAGE_TARNAME in NSIS script (JeremyRand) +- #7905 `187186b` test: move accounting_tests and rpc_wallet_tests to wallet/test (laanwj) +- #7911 `351abf9` leveldb: integrate leveldb into our buildsystem (theuni) +- #7944 `a407807` Re-instate TARGET_OS=linux in configure.ac. Removed by 351abf9e035 (randy-waterhouse) +- #7920 `c3e3cfb` Switch Travis to Trusty (theuni) +- #7954 `08b37c5` build: quiet annoying warnings without adding new ones (theuni) +- #7165 `06162f1` build: Enable C++11 in build, require C++11 compiler (laanwj) +- #7982 `559fbae` build: No need to check for leveldb atomics (theuni) +- #8002 `f9b4582` [depends] Add -stdlib=libc++ to darwin CXX flags (fanquake) +- #7993 `6a034ed` [depends] Bump Freetype, ccache, ZeroMQ, miniupnpc, expat (fanquake) +- #8167 `19ea173` Ship debug tarballs/zips with debug symbols (theuni) +- #8175 `f0299d8` Add --disable-bench to config flags for windows (laanwj) +- #7283 `fd9881a` [gitian] Default reference_datetime to commit author date (MarcoFalke) +- #8181 `9201ce8` Get rid of `CLIENT_DATE` (laanwj) +- #8133 `fde0ac4` Finish up out-of-tree changes (theuni) +- #8188 `65a9d7d` Add armhf/aarch64 gitian builds (theuni) +- #8194 `cca1c8c` [gitian] set correct PATH for wrappers (MarcoFalke) +- #8198 `5201614` Sync ax_pthread with upstream draft4 (fanquake) +- #8210 `12a541e` [Qt] Bump to Qt5.6.1 (jonasschnelli) +- #8285 `da50997` windows: Add testnet link to installer (laanwj) +- #8304 `0cca2fe` [travis] Update SDK_URL (MarcoFalke) +- #8310 `6ae20df` Require boost for bench (theuni) +- #8315 `2e51590` Don't require sudo for Linux (theuni) +- #8314 `67caef6` Fix pkg-config issues for 0.13 (theuni) +- #8373 `1fe7f40` Fix OSX non-deterministic dmg (theuni) +- #8358 `cfd1280` Gbuild: Set memory explicitly (default is too low) (MarcoFalke) + +### GUI + +- #7154 `00b4b8d` Add InMempool() info to transaction details (jonasschnelli) +- #7068 `5f3c670` [RPC-Tests] add simple way to run rpc test over QT clients (jonasschnelli) +- #7218 `a1c185b` Fix misleading translation (MarcoFalke) +- #7214 `be9a9a3` qt5: Use the fixed font the system recommends (MarcoFalke) +- #7256 `08ab906` Add note to coin control dialog QT5 workaround (fanquake) +- #7255 `e289807` Replace some instances of formatWithUnit with formatHtmlWithUnit (fanquake) +- #7317 `3b57e9c` Fix RPCTimerInterface ordering issue (jonasschnelli) +- #7327 `c079d79` Transaction View: LastMonth calculation fixed (crowning-) +- #7334 `e1060c5` coincontrol workaround is still needed in qt5.4 (fixed in qt5.5) (MarcoFalke) +- #7383 `ae2db67` Rename "amount" to "requested amount" in receive coins table (jonasschnelli) +- #7396 `cdcbc59` Add option to increase/decrease font size in the console window (jonasschnelli) +- #7437 `9645218` Disable tab navigation for peers tables (Kefkius) +- #7604 `354b03d` build: Remove spurious dollar sign. Fixes #7189 (dooglus) +- #7605 `7f001bd` Remove openssl info from init/log and from Qt debug window (jonasschnelli) +- #7628 `87d6562` Add 'copy full transaction details' option (ericshawlinux) +- #7613 `3798e5d` Add autocomplete to bitcoin-qt's console window (GamerSg) +- #7668 `b24266c` Fix history deletion bug after font size change (achow101) +- #7680 `41d2dfa` Remove reflection from `about` icon (laanwj) +- #7686 `f034bce` Remove 0-fee from send dialog (MarcoFalke) +- #7506 `b88e0b0` Use CCoinControl selection in CWallet::FundTransaction (promag) +- #7732 `0b98dd7` Debug window: replace "Build date" with "Datadir" (jonasschnelli) +- #7761 `60db51d` remove trailing output-index from transaction-id (jonasschnelli) +- #7772 `6383268` Clear the input line after activating autocomplete (paveljanik) +- #7925 `f604bf6` Fix out-of-tree GUI builds (laanwj) +- #7939 `574ddc6` Make it possible to show details for multiple transactions (laanwj) +- #8012 `b33824b` Delay user confirmation of send (Tyler-Hardin) +- #8006 `7c8558d` Add option to disable the system tray icon (Tyler-Hardin) +- #8046 `169d379` Fix Cmd-Q / Menu Quit shutdown on OSX (jonasschnelli) +- #8042 `6929711` Don't allow to open the debug window during splashscreen & verification state (jonasschnelli) +- #8014 `77b49ac` Sort transactions by date (Tyler-Hardin) +- #8073 `eb2f6f7` askpassphrasedialog: Clear pass fields on accept (rat4) +- #8129 `ee1533e` Fix RPC console auto completer (UdjinM6) +- #7636 `fb0ac48` Add bitcoin address label to request payment QR code (makevoid) +- #8231 `760a6c7` Fix a bug where the SplashScreen will not be hidden during startup (jonasschnelli) +- #8256 `af2421c` BUG: bitcoin-qt crash (fsb4000) +- #8257 `ff03c50` Do not ask a UI question from bitcoind (sipa) +- #8288 `91abb77` Network-specific example address (laanwj) +- #7707 `a914968` UI support for abandoned transactions (jonasschnelli) +- #8207 `f7a403b` Add a link to the Bitcoin-Core repository and website to the About Dialog (MarcoFalke) +- #8281 `6a87eb0` Remove client name from debug window (laanwj) +- #8407 `45eba4b` Add dbcache migration path (jonasschnelli) + +### Wallet + +- #7262 `fc08994` Reduce inefficiency of GetAccountAddress() (dooglus) +- #7537 `78e81b0` Warn on unexpected EOF while salvaging wallet (laanwj) +- #7521 `3368895` Don't resend wallet txs that aren't in our own mempool (morcos) +- #7576 `86a1ec5` Move wallet help string creation to CWallet (jonasschnelli) +- #7577 `5b3b5a7` Move "load wallet phase" to CWallet (jonasschnelli) +- #7608 `0735c0c` Move hardcoded file name out of log messages (MarcoFalke) +- #7649 `4900641` Prevent multiple calls to CWallet::AvailableCoins (promag) +- #7646 `e5c3511` Fix lockunspent help message (promag) +- #7558 `b35a591` Add import/removeprunedfunds rpc call (instagibbs) +- #6215 `48c5adf` add bip32 pub key serialization (jonasschnelli) +- #7913 `bafd075` Fix for incorrect locking in GetPubKey() (keystore.cpp) (yurizhykin) +- #8036 `41138f9` init: Move berkeleydb version reporting to wallet (laanwj) +- #8028 `373b50d` Fix insanity of CWalletDB::WriteTx and CWalletTx::WriteToDisk (pstratem) +- #8061 `f6b7df3` Improve Wallet encapsulation (pstratem) +- #7891 `950be19` Always require OS randomness when generating secret keys (sipa) +- #7689 `b89ef13` Replace OpenSSL AES with ctaes-based version (sipa) +- #7825 `f972b04` Prevent multiple calls to ExtractDestination (pedrobranco) +- #8137 `243ac0c` Improve CWallet API with new AccountMove function (pstratem) +- #8142 `52c3f34` Improve CWallet API with new GetAccountPubkey function (pstratem) +- #8035 `b67a472` Add simplest BIP32/deterministic key generation implementation (jonasschnelli) +- #7687 `a6ddb19` Stop treating importaddress'ed scripts as change (sipa) +- #8298 `aef3811` wallet: Revert input selection post-pruning (laanwj) +- #8324 `bc94b87` Keep HD seed during salvagewallet (jonasschnelli) +- #8323 `238300b` Add HD keypath to CKeyMetadata, report metadata in validateaddress (jonasschnelli) +- #8367 `3b38a6a` Ensure <0.13 clients can't open HD wallets (jonasschnelli) +- #8378 `ebea651` Move SetMinVersion for FEATURE_HD to SetHDMasterKey (pstratem) +- #8390 `73adfe3` Correct hdmasterkeyid/masterkeyid name confusion (jonasschnelli) +- #8206 `18b8ee1` Add HD xpriv to dumpwallet (jonasschnelli) +- #8389 `c3c82c4` Create a new HD seed after encrypting the wallet (jonasschnelli) + +### Tests and QA + +- #7320 `d3dfc6d` Test walletpassphrase timeout (MarcoFalke) +- #7208 `47c5ed1` Make max tip age an option instead of chainparam (laanwj) +- #7372 `21376af` Trivial: [qa] wallet: Print maintenance (MarcoFalke) +- #7280 `668906f` [travis] Fail when documentation is outdated (MarcoFalke) +- #7177 `93b0576` [qa] Change default block priority size to 0 (MarcoFalke) +- #7236 `02676c5` Use createrawtx locktime parm in txn_clone (dgenr8) +- #7212 `326ffed` Adds unittests for CAddrMan and CAddrinfo, removes source of non-determinism (EthanHeilman) +- #7490 `d007511` tests: Remove May15 test (laanwj) +- #7531 `18cb2d5` Add bip68-sequence.py to extended rpc tests (btcdrak) +- #7536 `ce5fc02` test: test leading spaces for ParseHex (laanwj) +- #7620 `1b68de3` [travis] Only run check-doc.py once (MarcoFalke) +- #7455 `7f96671` [travis] Exit early when check-doc.py fails (MarcoFalke) +- #7667 `56d2c4e` Move GetTempPath() to testutil (musalbas) +- #7517 `f1ca891` test: script_error checking in script_invalid tests (laanwj) +- #7684 `3d0dfdb` Extend tests (MarcoFalke) +- #7697 `622fe6c` Tests: make prioritise_transaction.py more robust (sdaftuar) +- #7709 `efde86b` Tests: fix missing import in mempool_packages (sdaftuar) +- #7702 `29e1131` Add tests verifychain, lockunspent, getbalance, listsinceblock (MarcoFalke) +- #7720 `3b4324b` rpc-test: Normalize assert() (MarcoFalke) +- #7757 `26794d4` wallet: Wait for reindex to catch up (MarcoFalke) +- #7764 `a65b36c` Don't run pruning.py twice (MarcoFalke) +- #7773 `7c80e72` Fix comments in tests (btcdrak) +- #7489 `e9723cb` tests: Make proxy_test work on travis servers without IPv6 (laanwj) +- #7801 `70ac71b` Remove misleading "errorString syntax" (MarcoFalke) +- #7803 `401c65c` maxblocksinflight: Actually enable test (MarcoFalke) +- #7802 `3bc71e1` httpbasics: Actually test second connection (MarcoFalke) +- #7849 `ab8586e` tests: add varints_bitpatterns test (laanwj) +- #7846 `491171f` Clean up lockorder data of destroyed mutexes (sipa) +- #7853 `6ef5e00` py2: Unfiddle strings into bytes explicitly (MarcoFalke) +- #7878 `53adc83` [test] bctest.py: Revert faa41ee (MarcoFalke) +- #7798 `cabba24` [travis] Print the commit which was evaluated (MarcoFalke) +- #7833 `b1bf511` tests: Check Content-Type header returned from RPC server (laanwj) +- #7851 `fa9d86f` pull-tester: Don't mute zmq ImportError (MarcoFalke) +- #7822 `0e6fd5e` Add listunspent() test for spendable/unspendable UTXO (jpdffonseca) +- #7912 `59ad568` Tests: Fix deserialization of reject messages (sdaftuar) +- #7941 `0ea3941` Fixing comment in script_test.json test case (Christewart) +- #7807 `0ad1041` Fixed miner test values, gave constants for less error-prone values (instagibbs) +- #7980 `88b77c7` Smartfees: Properly use ordered dict (MarcoFalke) +- #7814 `77b637f` Switch to py3 (MarcoFalke) +- #8030 `409a8a1` Revert fatal-ness of missing python-zmq (laanwj) +- #8018 `3e90fe6` Autofind rpc tests --srcdir (jonasschnelli) +- #8016 `5767e80` Fix multithread CScheduler and reenable test (paveljanik) +- #7972 `423ca30` pull-tester: Run rpc test in parallel (MarcoFalke) +- #8039 `69b3a6d` Bench: Add crypto hash benchmarks (laanwj) +- #8041 `5b736dd` Fix bip9-softforks blockstore issue (MarcoFalke) +- #7994 `1f01443` Add op csv tests to script_tests.json (Christewart) +- #8038 `e2bf830` Various minor fixes (MarcoFalke) +- #8072 `1b87e5b` Travis: 'make check' in parallel and verbose (MarcoFalke) +- #8056 `8844ef1` Remove hardcoded "4 nodes" from test_framework (MarcoFalke) +- #8047 `37f9a1f` Test_framework: Set wait-timeout for bitcoind procs (MarcoFalke) +- #8095 `6700cc9` Test framework: only cleanup on successful test runs (sdaftuar) +- #8098 `06bd4f6` Test_framework: Append portseed to tmpdir (MarcoFalke) +- #8104 `6ff2c8d` Add timeout to sync_blocks() and sync_mempools() (sdaftuar) +- #8111 `61b8684` Benchmark SipHash (sipa) +- #8107 `52b803e` Bench: Added base58 encoding/decoding benchmarks (yurizhykin) +- #8115 `0026e0e` Avoid integer division in the benchmark inner-most loop (gmaxwell) +- #8090 `a2df115` Adding P2SH(p2pkh) script test case (Christewart) +- #7992 `ec45cc5` Extend #7956 with one more test (TheBlueMatt) +- #8139 `ae5575b` Fix interrupted HTTP RPC connection workaround for Python 3.5+ (sipa) +- #8164 `0f24eaf` [Bitcoin-Tx] fix missing test fixtures, fix 32bit atoi issue (jonasschnelli) +- #8166 `0b5279f` Src/test: Do not shadow local variables (paveljanik) +- #8141 `44c1b1c` Continuing port of java comparison tool (mrbandrews) +- #8201 `36b7400` fundrawtransaction: Fix race, assert amounts (MarcoFalke) +- #8214 `ed2cd59` Mininode: fail on send_message instead of silent return (MarcoFalke) +- #8215 `a072d1a` Don't use floating point in wallet tests (MarcoFalke) +- #8066 `65c2058` Test_framework: Use different rpc_auth_pair for each node (MarcoFalke) +- #8216 `0d41d70` Assert 'changePosition out of bounds' (MarcoFalke) +- #8222 `961893f` Enable mempool consistency checks in unit tests (sipa) +- #7751 `84370d5` test_framework: python3.4 authproxy compat (laanwj) +- #7744 `d8e862a` test_framework: detect failure of bitcoind startup (laanwj) +- #8280 `115735d` Increase sync_blocks() timeouts in pruning.py (MarcoFalke) +- #8340 `af9b7a9` Solve trivial merge conflict in p2p-segwit.py (MarcoFalke) +- #8067 `3e4cf8f` Travis: use slim generic image, and some fixups (theuni) +- #7951 `5c7df70` Test_framework: Properly print exception (MarcoFalke) +- #8070 `7771aa5` Remove non-determinism which is breaking net_tests #8069 (EthanHeilman) +- #8309 `bb2646a` Add wallet-hd test (MarcoFalke) +- #8444 `cd0910b` Fix p2p-feefilter.py for changed tx relay behavior (sdaftuar) + +### Mining + +- #7507 `11c7699` Remove internal miner (Leviathn) +- #7663 `c87f51e` Make the generate RPC call function for non-regtest (sipa) +- #7671 `e2ebd25` Add generatetoaddress RPC to mine to an address (achow101) +- #7935 `66ed450` Versionbits: GBT support (luke-jr) +- #7600 `66db2d6` Select transactions using feerate-with-ancestors (sdaftuar) +- #8295 `f5660d3` Mining-related fixups for 0.13.0 (sdaftuar) +- #7796 `536b75e` Add support for negative fee rates, fixes `prioritizetransaction` (MarcoFalke) +- #8362 `86edc20` Scale legacy sigop count in CreateNewBlock (sdaftuar) +- #8489 `8b0eee6` Bugfix: Use pre-BIP141 sigops until segwit activates (GBT) (luke-jr) + +### Documentation and miscellaneous + +- #7423 `69e2a40` Add example for building with constrained resources (jarret) +- #8254 `c2c69ed` Add OSX ZMQ requirement to QA readme (fanquake) +- #8203 `377d131` Clarify documentation for running a tor node (nathaniel-mahieu) +- #7428 `4b12266` Add example for listing ./configure flags (nathaniel-mahieu) +- #7847 `3eae681` Add arch linux build example (mruddy) +- #7968 `ff69aaf` Fedora build requirements (wtogami) +- #8013 `fbedc09` Fedora build requirements, add gcc-c++ and fix typo (wtogami) +- #8009 `fbd8478` Fixed invalid example paths in gitian-building.md (JeremyRand) +- #8240 `63fbdbc` Mention Windows XP end of support in release notes (laanwj) +- #8303 `5077d2c` Update bips.md for CSV softfork (fanquake) +- #7789 `e0b3e19` Add note about using the Qt official binary installer (paveljanik) +- #7791 `e30a5b0` Change Precise to Trusty in gitian-building.md (JeremyRand) +- #7838 `8bb5d3d` Update gitian build guide to debian 8.4.0 (fanquake) +- #7855 `b778e59` Replace precise with trusty (MarcoFalke) +- #7975 `fc23fee` Update bitcoin-core GitHub links (MarcoFalke) +- #8034 `e3a8207` Add basic git squash workflow (fanquake) +- #7813 `214ec0b` Update port in tor.md (MarcoFalke) +- #8193 `37c9830` Use Debian 8.5 in the gitian-build guide (fanquake) +- #8261 `3685e0c` Clarify help for `getblockchaininfo` (paveljanik) +- #7185 `ea0f5a2` Note that reviewers should mention the id of the commits they reviewed (pstratem) +- #7290 `c851d8d` [init] Add missing help for args (MarcoFalke) +- #7281 `f9fd4c2` Improve CheckInputs() comment about sig verification (petertodd) +- #7417 `1e06bab` Minor improvements to the release process (PRabahy) +- #7444 `4cdbd42` Improve block validity/ConnectBlock() comments (petertodd) +- #7527 `db2e1c0` Fix and cleanup listreceivedbyX documentation (instagibbs) +- #7541 `b6e00af` Clarify description of blockindex (pinheadmz) +- #7590 `f06af57` Improving wording related to Boost library requirements [updated] (jonathancross) +- #7635 `0fa88ef` Add dependency info to test docs (elliotolds) +- #7609 `3ba07bd` RPM spec file project (AliceWonderMiscreations) +- #7850 `229a17c` Removed call to `TryCreateDirectory` from `GetDefaultDataDir` in `src/util.cpp` (alexreg) +- #7888 `ec870e1` Prevector: fix 2 bugs in currently unreached code paths (kazcw) +- #7922 `90653bc` CBase58Data::SetString: cleanse the full vector (kazcw) +- #7881 `c4e8390` Update release process (laanwj) +- #7952 `a9c8b74` Log invalid block hash to make debugging easier (paveljanik) +- #7974 `8206835` More comments on the design of AttemptToEvictConnection (gmaxwell) +- #7795 `47a7cfb` UpdateTip: log only one line at most per block (laanwj) +- #8110 `e7e25ea` Add benchmarking notes (fanquake) +- #8121 `58f0c92` Update implemented BIPs list (fanquake) +- #8029 `58725ba` Simplify OS X build notes (fanquake) +- #8143 `d46b8b5` comment nit: miners don't vote (instagibbs) +- #8136 `22e0b35` Log/report in 10% steps during VerifyDB (jonasschnelli) +- #8168 `d366185` util: Add ParseUInt32 and ParseUInt64 (laanwj) +- #8178 `f7b1bfc` Add git and github tips and tricks to developer notes (sipa) +- #8177 `67db011` developer notes: updates for C++11 (kazcw) +- #8229 `8ccdac1` [Doc] Update OS X build notes for 10.11 SDK (fanquake) +- #8233 `9f1807a` Mention Linux ARM executables in release process and notes (laanwj) +- #7540 `ff46dd4` Rename OP_NOP3 to OP_CHECKSEQUENCEVERIFY (btcdrak) +- #8289 `26316ff` bash-completion: Adapt for 0.12 and 0.13 (roques) +- #7453 `3dc3149` Missing patches from 0.12 (MarcoFalke) +- #7113 `54a550b` Switch to a more efficient rolling Bloom filter (sipa) +- #7257 `de9e5ea` Combine common error strings for different options so translations can be shared and reused (luke-jr) +- #7304 `b8f485c` [contrib] Add clang-format-diff.py (MarcoFalke) +- #7378 `e6f97ef` devtools: replace github-merge with python version (laanwj) +- #7395 `0893705` devtools: show pull and commit information in github-merge (laanwj) +- #7402 `6a5932b` devtools: github-merge get toplevel dir without extra whitespace (achow101) +- #7425 `20a408c` devtools: Fix utf-8 support in messages for github-merge (laanwj) +- #7632 `409f843` Delete outdated test-patches reference (Lewuathe) +- #7662 `386f438` remove unused NOBLKS_VERSION_{START,END} constants (rat4) +- #7737 `aa0d2b2` devtools: make github-merge.py use py3 (laanwj) +- #7781 `55db5f0` devtools: Auto-set branch to merge to in github-merge (laanwj) +- #7934 `f17032f` Improve rolling bloom filter performance and benchmark (sipa) +- #8004 `2efe38b` signal handling: fReopenDebugLog and fRequestShutdown should be type sig_atomic_t (catilac) +- #7713 `f6598df` Fixes for verify-commits script (petertodd) +- #8412 `8360d5b` libconsensus: Expose a flag for BIP112 (jtimon) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- 21E14 +- accraze +- Adam Brown +- Alexander Regueiro +- Alex Morcos +- Alfie John +- Alice Wonder +- AlSzacrel +- Andrew Chow +- Andrés G. Aragoneses +- Bob McElrath +- BtcDrak +- calebogden +- Cédric Félizard +- Chirag Davé +- Chris Moore +- Chris Stewart +- Christian von Roques +- Chris Wheeler +- Cory Fields +- crowning- +- Daniel Cousens +- Daniel Kraft +- Denis Lukianov +- Elias Rohrer +- Elliot Olds +- Eric Shaw +- error10 +- Ethan Heilman +- face +- fanquake +- Francesco 'makevoid' Canessa +- fsb4000 +- Gavin Andresen +- gladoscc +- Gregory Maxwell +- Gregory Sanders +- instagibbs +- James O'Beirne +- Jannes Faber +- Jarret Dyrbye +- Jeremy Rand +- jloughry +- jmacwhyte +- Joao Fonseca +- Johnson Lau +- Jonas Nick +- Jonas Schnelli +- Jonathan Cross +- João Barbosa +- Jorge Timón +- Kaz Wesley +- Kefkius +- kirkalx +- Krzysztof Jurewicz +- Leviathn +- lewuathe +- Luke Dashjr +- Luv Khemani +- Marcel Krüger +- Marco Falke +- Mark Friedenbach +- Matt +- Matt Bogosian +- Matt Corallo +- Matthew English +- Matthew Zipkin +- mb300sd +- Mitchell Cash +- mrbandrews +- mruddy +- Murch +- Mustafa +- Nathaniel Mahieu +- Nicolas Dorier +- Patrick Strateman +- Paul Rabahy +- paveljanik +- Pavel Janík +- Pavel Vasin +- Pedro Branco +- Peter Todd +- Philip Kaufmann +- Pieter Wuille +- Prayag Verma +- ptschip +- Puru +- randy-waterhouse +- R E Broadley +- Rusty Russell +- Suhas Daftuar +- Suriyaa Kudo +- TheLazieR Yip +- Thomas Kerin +- Tom Harding +- Tyler Hardin +- UdjinM6 +- Warren Togami +- Will Binns +- Wladimir J. van der Laan +- Yuri Zhykin + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). diff --git a/doc/release-process.md b/doc/release-process.md index 41c1ac8556..394b159b31 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -137,9 +137,10 @@ Build output expected: ### Verify other gitian builders signatures to your own. (Optional) -Add other gitian builders keys to your gpg keyring +Add other gitian builders keys to your gpg keyring, and/or refresh keys. gpg --import bitcoin/contrib/gitian-keys/*.pgp + gpg --refresh-keys Verify the signatures diff --git a/doc/translation_process.md b/doc/translation_process.md index d8a85292e8..a443a16fe2 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -94,7 +94,7 @@ When new plurals are added to the source file, it's important to do the followin 7. Save the source file ### Translating a new language -To create a new language template, you will need to edit the languages manifest file `src/qt/bitcoin.qrc` and add a new entry. Below is an example of the English language entry. +To create a new language template, you will need to edit the languages manifest file `src/qt/bitcoin_locale.qrc` and add a new entry. Below is an example of the English language entry. ```xml <qresource prefix="/translations"> diff --git a/qa/README.md b/qa/README.md index 723660c6c8..225207cc1c 100644 --- a/qa/README.md +++ b/qa/README.md @@ -41,8 +41,8 @@ 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 `-parallel=n` (default n=4). +By default, tests will be run in parallel. To specify how many jobs to run, +append `-parallel=n` (default n=4). If you want to create a basic coverage report for the rpc test suite, append `--coverage`. diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index daaa7782f9..771f6c7a0f 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -92,18 +92,19 @@ if not (ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1): if ENABLE_ZMQ: try: import zmq - except ImportError as e: - print("WARNING: \"import zmq\" failed. Set ENABLE_ZMQ=0 or " \ - "to run zmq tests, see dependency info in /qa/README.md.") - ENABLE_ZMQ=0 + 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 -#Tests testScripts = [ # longest test should go first, to favor running tests in parallel 'p2p-fullblocktest.py', 'walletbackup.py', 'bip68-112-113-p2p.py', 'wallet.py', + 'wallet-accounts.py', 'wallet-hd.py', 'wallet-dump.py', 'listtransactions.py', diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py index eb3c11b4d8..0dee8ad4ec 100755 --- a/qa/rpc-tests/importprunedfunds.py +++ b/qa/rpc-tests/importprunedfunds.py @@ -20,14 +20,10 @@ class ImportPrunedFundsTest(BitcoinTestFramework): self.is_network_split=False self.sync_all() - def run_test (self): - import time - begintime = int(time.time()) - + def run_test(self): print("Mining blocks...") self.nodes[0].generate(101) - # sync self.sync_all() # address @@ -72,7 +68,6 @@ class ImportPrunedFundsTest(BitcoinTestFramework): rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex'] proof2 = self.nodes[0].gettxoutproof([txnid2]) - txnid3 = self.nodes[0].sendtoaddress(address3, 0.025) self.nodes[0].generate(1) rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex'] @@ -82,28 +77,27 @@ class ImportPrunedFundsTest(BitcoinTestFramework): #Import with no affiliated address try: - result1 = self.nodes[1].importprunedfunds(rawtxn1, proof1, "") + self.nodes[1].importprunedfunds(rawtxn1, proof1) except JSONRPCException as e: assert('No addresses' in e.error['message']) else: assert(False) - balance1 = self.nodes[1].getbalance("", 0, True) assert_equal(balance1, Decimal(0)) #Import with affiliated address with no rescan - self.nodes[1].importaddress(address2, "", False) - result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2, "") - balance2 = Decimal(self.nodes[1].getbalance("", 0, True)) + self.nodes[1].importaddress(address2, "add2", False) + result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2) + balance2 = self.nodes[1].getbalance("add2", 0, True) assert_equal(balance2, Decimal('0.05')) #Import with private key with no rescan - self.nodes[1].importprivkey(address3_privkey, "", False) - result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3, "") - balance3 = Decimal(self.nodes[1].getbalance("", 0, False)) + self.nodes[1].importprivkey(address3_privkey, "add3", False) + result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3) + balance3 = self.nodes[1].getbalance("add3", 0, False) assert_equal(balance3, Decimal('0.025')) - balance3 = Decimal(self.nodes[1].getbalance("", 0, True)) + balance3 = self.nodes[1].getbalance("*", 0, True) assert_equal(balance3, Decimal('0.075')) #Addresses Test - after import @@ -118,7 +112,6 @@ class ImportPrunedFundsTest(BitcoinTestFramework): assert_equal(address_info['ismine'], True) #Remove transactions - try: self.nodes[1].removeprunedfunds(txnid1) except JSONRPCException as e: @@ -126,18 +119,16 @@ class ImportPrunedFundsTest(BitcoinTestFramework): else: assert(False) - - balance1 = Decimal(self.nodes[1].getbalance("", 0, True)) + balance1 = self.nodes[1].getbalance("*", 0, True) assert_equal(balance1, Decimal('0.075')) - self.nodes[1].removeprunedfunds(txnid2) - balance2 = Decimal(self.nodes[1].getbalance("", 0, True)) + balance2 = self.nodes[1].getbalance("*", 0, True) assert_equal(balance2, Decimal('0.025')) self.nodes[1].removeprunedfunds(txnid3) - balance3 = Decimal(self.nodes[1].getbalance("", 0, True)) + balance3 = self.nodes[1].getbalance("*", 0, True) assert_equal(balance3, Decimal('0.0')) if __name__ == '__main__': - ImportPrunedFundsTest ().main () + ImportPrunedFundsTest().main() diff --git a/qa/rpc-tests/p2p-segwit.py b/qa/rpc-tests/p2p-segwit.py index eb857ed983..ca784644d8 100755 --- a/qa/rpc-tests/p2p-segwit.py +++ b/qa/rpc-tests/p2p-segwit.py @@ -964,8 +964,24 @@ class SegWitTest(BitcoinTestFramework): tx3 = CTransaction() tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b"")) - tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, CScript([OP_TRUE]))) tx3.wit.vtxinwit.append(CTxInWitness()) + + # Add too-large for IsStandard witness and check that it does not enter reject filter + p2sh_program = CScript([OP_TRUE]) + p2sh_pubkey = hash160(p2sh_program) + witness_program2 = CScript([b'a'*400000]) + tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL]))) + tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program2] + tx3.rehash() + + # Node will not be blinded to the transaction + self.std_node.announce_tx_and_wait_for_getdata(tx3) + self.std_node.test_transaction_acceptance(tx3, True, False, b'tx-size') + self.std_node.announce_tx_and_wait_for_getdata(tx3) + self.std_node.test_transaction_acceptance(tx3, True, False, b'tx-size') + + # Remove witness stuffing, instead add extra witness push on stack + tx3.vout[0] = CTxOut(tx2.vout[0].nValue-1000, CScript([OP_TRUE])) tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), witness_program ] tx3.rehash() diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py index c9c2eaf7f3..b769cd71f2 100755 --- a/qa/rpc-tests/rest.py +++ b/qa/rpc-tests/rest.py @@ -179,14 +179,14 @@ class RESTTest (BitcoinTestFramework): #do some invalid requests json_request = '{"checkmempool' response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'json', json_request, True) - assert_equal(response.status, 500) #must be a 500 because we send a invalid json request + assert_equal(response.status, 400) #must be a 400 because we send a invalid json request json_request = '{"checkmempool' response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', json_request, True) - assert_equal(response.status, 500) #must be a 500 because we send a invalid bin request + assert_equal(response.status, 400) #must be a 400 because we send a invalid bin request response = http_post_call(url.hostname, url.port, '/rest/getutxos/checkmempool'+self.FORMAT_SEPARATOR+'bin', '', True) - assert_equal(response.status, 500) #must be a 500 because we send a invalid bin request + assert_equal(response.status, 400) #must be a 400 because we send a invalid bin request #test limits json_request = '/checkmempool/' @@ -194,14 +194,14 @@ class RESTTest (BitcoinTestFramework): json_request += txid+'-'+str(n)+'/' json_request = json_request.rstrip("/") response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True) - assert_equal(response.status, 500) #must be a 500 because we exceeding the limits + assert_equal(response.status, 400) #must be a 400 because we exceeding the limits json_request = '/checkmempool/' for x in range(0, 15): json_request += txid+'-'+str(n)+'/' json_request = json_request.rstrip("/") response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True) - assert_equal(response.status, 200) #must be a 500 because we exceeding the limits + assert_equal(response.status, 200) #must be a 200 because we are within the limits self.nodes[0].generate(1) #generate block to not affect upcoming tests self.sync_all() diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 190fa7f661..eee77f1a10 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -125,12 +125,16 @@ def sync_blocks(rpc_connections, wait=1, timeout=60): """ Wait until everybody has the same tip """ + maxheight = 0 while timeout > 0: - tips = [ x.getbestblockhash() for x in rpc_connections ] + tips = [ x.waitforblockheight(maxheight, int(wait * 1000)) for x in rpc_connections ] + heights = [ x["height"] for x in tips ] if tips == [ tips[0] ]*len(tips): return True - time.sleep(wait) + if heights == [ heights[0] ]*len(heights): #heights are the same but hashes are not + raise AssertionError("Block sync failed") timeout -= wait + maxheight = max(heights) raise AssertionError("Block sync failed") def sync_mempools(rpc_connections, wait=1, timeout=60): diff --git a/qa/rpc-tests/wallet-accounts.py b/qa/rpc-tests/wallet-accounts.py new file mode 100755 index 0000000000..c51181e4f8 --- /dev/null +++ b/qa/rpc-tests/wallet-accounts.py @@ -0,0 +1,94 @@ +#!/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. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + start_nodes, + start_node, + assert_equal, + connect_nodes_bi, +) + + +class WalletAccountsTest(BitcoinTestFramework): + + def __init__(self): + super().__init__() + self.setup_clean_chain = True + self.num_nodes = 1 + self.node_args = [[]] + + def setup_network(self): + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.node_args) + self.is_network_split = False + + def run_test (self): + node = self.nodes[0] + # Check that there's no UTXO on any of the nodes + assert_equal(len(node.listunspent()), 0) + + node.generate(101) + + assert_equal(node.getbalance(), 50) + + accounts = ["a","b","c","d","e"] + amount_to_send = 1.0 + account_addresses = dict() + for account in accounts: + address = node.getaccountaddress(account) + account_addresses[account] = address + + node.getnewaddress(account) + assert_equal(node.getaccount(address), account) + assert(address in node.getaddressesbyaccount(account)) + + node.sendfrom("", address, amount_to_send) + + node.generate(1) + + for i in range(len(accounts)): + from_account = accounts[i] + to_account = accounts[(i+1)%len(accounts)] + to_address = account_addresses[to_account] + node.sendfrom(from_account, to_address, amount_to_send) + + node.generate(1) + + for account in accounts: + address = node.getaccountaddress(account) + assert(address != account_addresses[account]) + assert_equal(node.getreceivedbyaccount(account), 2) + node.move(account, "", node.getbalance(account)) + + node.generate(101) + + expected_account_balances = {"": 5200} + for account in accounts: + expected_account_balances[account] = 0 + + assert_equal(node.listaccounts(), expected_account_balances) + + assert_equal(node.getbalance(""), 5200) + + for account in accounts: + address = node.getaccountaddress("") + node.setaccount(address, account) + assert(address in node.getaddressesbyaccount(account)) + assert(address not in node.getaddressesbyaccount("")) + + for account in accounts: + addresses = [] + for x in range(10): + addresses.append(node.getnewaddress()) + multisig_address = node.addmultisigaddress(5, addresses, account) + node.sendfrom("", multisig_address, 50) + + node.generate(101) + + for account in accounts: + assert_equal(node.getbalance(account), 50) + +if __name__ == '__main__': + WalletAccountsTest().main () diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 27e7694748..0748d1a39d 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -97,8 +97,7 @@ BITCOIN_TESTS += \ wallet/test/wallet_test_fixture.h \ wallet/test/accounting_tests.cpp \ wallet/test/wallet_tests.cpp \ - wallet/test/crypto_tests.cpp \ - wallet/test/rpc_wallet_tests.cpp + wallet/test/crypto_tests.cpp endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 8e8ac47455..cb863bda19 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -395,10 +395,8 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) if (!registers.count("privatekeys")) throw runtime_error("privatekeys register variable must be set."); - bool fGivenKeys = false; CBasicKeyStore tempKeystore; UniValue keysObj = registers["privatekeys"]; - fGivenKeys = true; for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) { if (!keysObj[kidx].isStr()) @@ -454,7 +452,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) // if redeemScript given and private keys given, // add redeemScript to the tempKeystore so it can be signed: - if (fGivenKeys && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) && + if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) && prevOut.exists("redeemScript")) { UniValue v = prevOut["redeemScript"]; vector<unsigned char> rsData(ParseHexUV(v, "redeemScript")); @@ -517,7 +515,7 @@ public: static void MutateTx(CMutableTransaction& tx, const string& command, const string& commandVal) { - boost::scoped_ptr<Secp256k1Init> ecc; + std::unique_ptr<Secp256k1Init> ecc; if (command == "nversion") MutateTxVersion(tx, commandVal); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 28bc374acc..322298d1b3 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -40,8 +40,6 @@ * Use the buttons <code>Namespaces</code>, <code>Classes</code> or <code>Files</code> at the top of the page to start navigating the code. */ -static bool fDaemon; - void WaitForShutdown(boost::thread_group* threadGroup) { bool fShutdown = ShutdownRequested(); @@ -130,8 +128,7 @@ bool AppInit(int argc, char* argv[]) exit(1); } #ifndef WIN32 - fDaemon = GetBoolArg("-daemon", false); - if (fDaemon) + if (GetBoolArg("-daemon", false)) { fprintf(stdout, "Bitcoin server starting\n"); diff --git a/src/blockencodings.h b/src/blockencodings.h index b980e9e286..349fcbd50f 100644 --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -53,11 +53,11 @@ public: } uint16_t offset = 0; - for (size_t i = 0; i < indexes.size(); i++) { - if (uint64_t(indexes[i]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max()) + for (size_t j = 0; j < indexes.size(); j++) { + if (uint64_t(indexes[j]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max()) throw std::ios_base::failure("indexes overflowed 16 bits"); - indexes[i] = indexes[i] + offset; - offset = indexes[i] + 1; + indexes[j] = indexes[j] + offset; + offset = indexes[j] + 1; } } else { for (size_t i = 0; i < indexes.size(); i++) { diff --git a/src/chain.h b/src/chain.h index 76a774c123..6588e8f57d 100644 --- a/src/chain.h +++ b/src/chain.h @@ -137,15 +137,15 @@ enum BlockStatus: uint32_t { BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS | BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS, - BLOCK_HAVE_DATA = 8, //! full block available in blk*.dat - BLOCK_HAVE_UNDO = 16, //! undo data available in rev*.dat + BLOCK_HAVE_DATA = 8, //!< full block available in blk*.dat + BLOCK_HAVE_UNDO = 16, //!< undo data available in rev*.dat BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO, - BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed - BLOCK_FAILED_CHILD = 64, //! descends from failed block + BLOCK_FAILED_VALID = 32, //!< stage after last reached validness failed + BLOCK_FAILED_CHILD = 64, //!< descends from failed block BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD, - BLOCK_OPT_WITNESS = 128, //! block data in blk*.data was received with a witness-enforcing client + BLOCK_OPT_WITNESS = 128, //!< block data in blk*.data was received with a witness-enforcing client }; /** The block chain is a tree shaped structure starting with the diff --git a/src/chainparams.cpp b/src/chainparams.cpp index ea6e3aada2..e6be1b5d5b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -118,7 +118,7 @@ public: vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); // Luke Dashjr vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com")); // Christian Decker vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); // Jeff Garzik - vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch")); // Jonas Schnelli + vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0); base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5); diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 000b197270..3e24294a64 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -22,9 +22,9 @@ static const unsigned char REJECT_CHECKPOINT = 0x43; class CValidationState { private: enum mode_state { - MODE_VALID, //! everything ok - MODE_INVALID, //! network rule violation (DoS value may be set) - MODE_ERROR, //! run-time error + MODE_VALID, //!< everything ok + MODE_INVALID, //!< network rule violation (DoS value may be set) + MODE_ERROR, //!< run-time error } mode; int nDoS; std::string strRejectReason; diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 09c68fbe55..4fa06135d2 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -117,7 +117,7 @@ std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const bool CDBWrapper::IsEmpty() { - boost::scoped_ptr<CDBIterator> it(NewIterator()); + std::unique_ptr<CDBIterator> it(NewIterator()); it->SeekToFirst(); return !(it->Valid()); } diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 04d3386e9a..6a6c5276cc 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -45,7 +45,7 @@ private: class HTTPRPCTimerInterface : public RPCTimerInterface { public: - HTTPRPCTimerInterface(struct event_base* base) : base(base) + HTTPRPCTimerInterface(struct event_base* _base) : base(_base) { } const char* Name() diff --git a/src/httpserver.cpp b/src/httpserver.cpp index f921305fcc..b296b28503 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -42,8 +42,8 @@ static const size_t MAX_HEADERS_SIZE = 8192; class HTTPWorkItem : public HTTPClosure { public: - HTTPWorkItem(std::unique_ptr<HTTPRequest> req, const std::string &path, const HTTPRequestHandler& func): - req(std::move(req)), path(path), func(func) + HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func): + req(std::move(_req)), path(_path), func(_func) { } void operator()() @@ -92,8 +92,8 @@ private: }; public: - WorkQueue(size_t maxDepth) : running(true), - maxDepth(maxDepth), + WorkQueue(size_t _maxDepth) : running(true), + maxDepth(_maxDepth), numThreads(0) { } @@ -158,8 +158,8 @@ public: struct HTTPPathHandler { HTTPPathHandler() {} - HTTPPathHandler(std::string prefix, bool exactMatch, HTTPRequestHandler handler): - prefix(prefix), exactMatch(exactMatch), handler(handler) + HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler): + prefix(_prefix), exactMatch(_exactMatch), handler(_handler) { } std::string prefix; @@ -522,8 +522,8 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data) delete self; } -HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void(void)>& handler): - deleteWhenTriggered(deleteWhenTriggered), handler(handler) +HTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function<void(void)>& _handler): + deleteWhenTriggered(_deleteWhenTriggered), handler(_handler) { ev = event_new(base, -1, 0, httpevent_callback_fn, this); assert(ev); @@ -539,7 +539,7 @@ void HTTPEvent::trigger(struct timeval* tv) else evtimer_add(ev, tv); // trigger after timeval passed } -HTTPRequest::HTTPRequest(struct evhttp_request* req) : req(req), +HTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req), replySent(false) { } diff --git a/src/init.cpp b/src/init.cpp index ce5f4b3a88..64e161b9b2 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -162,7 +162,7 @@ public: static CCoinsViewDB *pcoinsdbview = NULL; static CCoinsViewErrorCatcher *pcoinscatcher = NULL; -static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle; +static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; void Interrupt(boost::thread_group& threadGroup) { @@ -280,9 +280,15 @@ bool static Bind(const CService &addr, unsigned int flags) { } return true; } +void OnRPCStarted() +{ + uiInterface.NotifyBlockTip.connect(&RPCNotifyBlockChange); +} void OnRPCStopped() { + uiInterface.NotifyBlockTip.disconnect(&RPCNotifyBlockChange); + RPCNotifyBlockChange(false, nullptr); cvBlockChange.notify_all(); LogPrint("rpc", "RPC stopped.\n"); } @@ -380,7 +386,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") + " " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway")); strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY)); - strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY)); + strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY)); strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET)); #ifdef ENABLE_WALLET @@ -666,6 +672,7 @@ bool InitSanityCheck(void) bool AppInitServers(boost::thread_group& threadGroup) { + RPCServer::OnStarted(&OnRPCStarted); RPCServer::OnStopped(&OnRPCStopped); RPCServer::OnPreCommand(&OnRPCPreCommand); if (!InitHTTPServer()) @@ -1183,8 +1190,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); fRelayTxes = !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); - bool fBound = false; if (fListen) { + bool fBound = false; if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) { BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) { CService addrBind; @@ -1357,6 +1364,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) { LOCK(cs_main); CBlockIndex* tip = chainActive.Tip(); + RPCNotifyBlockChange(true, tip); if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { strLoadError = _("The block database contains a block which appears to be from the future. " "This may be due to your computer's date and time being set incorrectly. " @@ -1494,12 +1502,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) //// debug print LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("nBestHeight = %d\n", chainActive.Height()); -#ifdef ENABLE_WALLET - LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0); - LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0); - LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0); -#endif - if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) StartTorControl(threadGroup, scheduler); @@ -1512,9 +1514,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #ifdef ENABLE_WALLET if (pwalletMain) { - // Add wallet transactions that aren't already in a block to mapTransactions - pwalletMain->ReacceptWalletTransactions(); - // Run a thread to flush wallet periodically threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile))); } diff --git a/src/main.cpp b/src/main.cpp index 27ab677eb1..2c98de070a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -196,7 +196,7 @@ namespace { * * Memory used: 1.3 MB */ - boost::scoped_ptr<CRollingBloomFilter> recentRejects; + std::unique_ptr<CRollingBloomFilter> recentRejects; uint256 hashRecentRejectsChainTip; /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ @@ -532,7 +532,7 @@ CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) { /** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has * at most count entries. */ -void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller) { +void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) { if (count == 0) return; @@ -589,6 +589,10 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl // We consider the chain that this peer is on invalid. return; } + if (!State(nodeid)->fHaveWitness && IsWitnessEnabled(pindex->pprev, consensusParams)) { + // We wouldn't download this block or its descendants from this peer. + return; + } if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) { if (pindex->nChainTx) state->pindexLastCommonBlock = pindex; @@ -1492,13 +1496,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true)) { + PrecomputedTransactionData txdata(tx); + if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata)) { // SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we // need to turn both off, and compare against just turning off CLEANSTACK // to see if the failure is specifically due to witness validation. - if (CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true) && - !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true)) { - // Only the witness is wrong, so the transaction itself may be fine. + if (tx.wit.IsNull() && CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) && + !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata)) { + // Only the witness is missing, so the transaction itself may be fine. state.SetCorruptionPossible(); } return false; @@ -1513,7 +1518,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // There is a similar check in CreateNewBlock() to prevent creating // invalid blocks, however allowing such transactions into the mempool // can be exploited as a DoS attack. - if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) + if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata)) { return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); @@ -1910,7 +1915,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight) bool CScriptCheck::operator()() { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; const CScriptWitness *witness = (nIn < ptxTo->wit.vtxinwit.size()) ? &ptxTo->wit.vtxinwit[nIn].scriptWitness : NULL; - if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore), &error)) { + if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) { return false; } return true; @@ -1969,7 +1974,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins } }// namespace Consensus -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks) +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) { if (!tx.IsCoinBase()) { @@ -1996,7 +2001,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi assert(coins); // Verify signature - CScriptCheck check(*coins, tx, i, flags, cacheStore); + CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata); if (pvChecks) { pvChecks->push_back(CScriptCheck()); check.swap(pvChecks->back()); @@ -2009,7 +2014,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // avoid splitting the network between upgraded and // non-upgraded nodes. CScriptCheck check2(*coins, tx, i, - flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore); + flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata); if (check2()) return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); } @@ -2405,6 +2410,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin std::vector<std::pair<uint256, CDiskTxPos> > vPos; vPos.reserve(block.vtx.size()); blockundo.vtxundo.reserve(block.vtx.size() - 1); + std::vector<PrecomputedTransactionData> txdata; + txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = block.vtx[i]; @@ -2451,13 +2458,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock(): too many sigops"), REJECT_INVALID, "bad-blk-sigops"); + txdata.emplace_back(tx); if (!tx.IsCoinBase()) { nFees += view.GetValueIn(tx)-tx.GetValueOut(); std::vector<CScriptCheck> vChecks; bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ - if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL)) + if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : NULL)) return error("ConnectBlock(): CheckInputs on %s failed with %s", tx.GetHash().ToString(), FormatStateMessage(state)); control.Add(vChecks); @@ -4633,6 +4641,7 @@ std::string GetWarnings(const std::string& strFor) string strStatusBar; string strRPC; string strGUI; + const string uiAlertSeperator = "<hr />"; if (!CLIENT_VERSION_IS_RELEASE) { strStatusBar = "This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"; @@ -4645,18 +4654,19 @@ std::string GetWarnings(const std::string& strFor) // Misc warnings like out of disk space and clock is wrong if (strMiscWarning != "") { - strStatusBar = strGUI = strMiscWarning; + strStatusBar = strMiscWarning; + strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + strMiscWarning; } if (fLargeWorkForkFound) { strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."; - strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); + strGUI += strGUI.empty() ? "" : uiAlertSeperator + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); } else if (fLargeWorkInvalidChainFound) { strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."; - strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); + strGUI += strGUI.empty() ? "" : uiAlertSeperator + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); } if (strFor == "gui") @@ -4779,10 +4789,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam pfrom->PushMessage(NetMsgType::BLOCK, block); else if (inv.type == MSG_FILTERED_BLOCK) { - LOCK(pfrom->cs_filter); - if (pfrom->pfilter) + bool send = false; + CMerkleBlock merkleBlock; { - CMerkleBlock merkleBlock(block, *pfrom->pfilter); + LOCK(pfrom->cs_filter); + if (pfrom->pfilter) { + send = true; + merkleBlock = CMerkleBlock(block, *pfrom->pfilter); + } + } + if (send) { pfrom->PushMessage(NetMsgType::MERKLEBLOCK, merkleBlock); // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see // This avoids hurting performance by pointlessly requiring a round-trip @@ -4903,6 +4919,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (strCommand == NetMsgType::VERSION) { + // Feeler connections exist only to verify if address is online. + if (pfrom->fFeeler) { + assert(pfrom->fInbound == false); + pfrom->fDisconnect = true; + } + // Each connection can only send one version message if (pfrom->nVersion != 0) { @@ -5005,11 +5027,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CAddress addr = GetLocalAddress(&pfrom->addr); if (addr.IsRoutable()) { - LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString()); + LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString()); pfrom->PushAddress(addr); } else if (IsPeerAddrLocalGood(pfrom)) { addr.SetIP(pfrom->addrLocal); - LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString()); + LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString()); pfrom->PushAddress(addr); } } @@ -5021,12 +5043,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->fGetAddr = true; } addrman.Good(pfrom->addr); - } else { - if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom) - { - addrman.Add(addrFrom, addrFrom); - addrman.Good(addrFrom); - } } pfrom->fSuccessfullyConnected = true; @@ -5387,7 +5403,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end vector<CBlock> vHeaders; int nLimit = MAX_HEADERS_RESULTS; - LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id); + LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom->id); for (; pindex; pindex = chainActive.Next(pindex)) { vHeaders.push_back(pindex->GetBlockHeader()); @@ -5477,7 +5493,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (!fMissingInputs2) { int nDos = 0; - if (stateDummy.IsInvalid(nDos) && nDos > 0 && (!state.CorruptionPossible() || State(fromPeer)->fHaveWitness)) + if (stateDummy.IsInvalid(nDos) && nDos > 0) { // Punish peer that gave us an invalid orphan tx Misbehaving(fromPeer, nDos); @@ -5488,7 +5504,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Probably non-standard or insufficient fee/priority LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); vEraseQueue.push_back(orphanHash); - if (!stateDummy.CorruptionPossible()) { + if (orphanTx.wit.IsNull() && !stateDummy.CorruptionPossible()) { + // Do not use rejection cache for witness transactions or + // witness-stripped transactions, as they can have been malleated. + // See https://github.com/bitcoin/bitcoin/issues/8279 for details. assert(recentRejects); recentRejects->insert(orphanHash); } @@ -5526,7 +5545,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("mempool", "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString()); } } else { - if (!state.CorruptionPossible()) { + if (tx.wit.IsNull() && !state.CorruptionPossible()) { + // Do not use rejection cache for witness transactions or + // witness-stripped transactions, as they can have been malleated. + // See https://github.com/bitcoin/bitcoin/issues/8279 for details. assert(recentRejects); recentRejects->insert(tx.GetHash()); } @@ -5558,9 +5580,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); - if (nDoS > 0 && (!state.CorruptionPossible() || State(pfrom->id)->fHaveWitness)) { - // When a non-witness-supporting peer gives us a transaction that would - // be accepted if witness validation was off, we can't blame them for it. + if (nDoS > 0) { Misbehaving(pfrom->GetId(), nDoS); } } @@ -6044,8 +6064,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CBloomFilter filter; vRecv >> filter; - LOCK(pfrom->cs_filter); - if (!filter.IsWithinSizeConstraints()) { // There is no excuse for sending a too-large filter @@ -6054,11 +6072,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } else { + LOCK(pfrom->cs_filter); delete pfrom->pfilter; pfrom->pfilter = new CBloomFilter(filter); pfrom->pfilter->UpdateEmptyFull(); + pfrom->fRelayTxes = true; } - pfrom->fRelayTxes = true; } @@ -6069,20 +6088,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Nodes must NEVER send a data item > 520 bytes (the max size for a script data object, // and thus, the maximum size any matched object can have) in a filteradd message - if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) - { - LOCK(cs_main); - Misbehaving(pfrom->GetId(), 100); + bool bad = false; + if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) { + bad = true; } else { LOCK(pfrom->cs_filter); - if (pfrom->pfilter) + if (pfrom->pfilter) { pfrom->pfilter->insert(vData); - else - { - LOCK(cs_main); - Misbehaving(pfrom->GetId(), 100); + } else { + bad = true; } } + if (bad) { + LOCK(cs_main); + Misbehaving(pfrom->GetId(), 100); + } } @@ -6705,15 +6725,13 @@ bool SendMessages(CNode* pto) if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { vector<CBlockIndex*> vToDownload; NodeId staller = -1; - FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); + FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams); BOOST_FOREACH(CBlockIndex *pindex, vToDownload) { - if (State(pto->GetId())->fHaveWitness || !IsWitnessEnabled(pindex->pprev, consensusParams)) { - uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams); - vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash())); - MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex); - LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), - pindex->nHeight, pto->id); - } + uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams); + vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash())); + MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex); + LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), + pindex->nHeight, pto->id); } if (state.nBlocksInFlight == 0 && staller != -1) { if (State(staller)->nStallingSince == 0) { diff --git a/src/main.h b/src/main.h index e9106fccf7..18d674612f 100644 --- a/src/main.h +++ b/src/main.h @@ -39,6 +39,7 @@ class CTxMemPool; class CValidationInterface; class CValidationState; +struct PrecomputedTransactionData; struct CNodeStateStats; struct LockPoints; @@ -191,7 +192,7 @@ extern uint64_t nPruneTarget; /** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */ static const unsigned int MIN_BLOCKS_TO_KEEP = 288; -static const signed int DEFAULT_CHECKBLOCKS = MIN_BLOCKS_TO_KEEP; +static const signed int DEFAULT_CHECKBLOCKS = 6; static const unsigned int DEFAULT_CHECKLEVEL = 3; // Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat) @@ -347,7 +348,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i * instead of being performed inline. */ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, - unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL); + unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = NULL); /** Apply the effects of this transaction on the UTXO set represented by view */ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight); @@ -421,12 +422,13 @@ private: unsigned int nFlags; bool cacheStore; ScriptError error; + PrecomputedTransactionData *txdata; public: CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} - CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) : + CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) : scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue), - ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { } + ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { } bool operator()(); @@ -438,6 +440,7 @@ public: std::swap(nFlags, check.nFlags); std::swap(cacheStore, check.cacheStore); std::swap(error, check.error); + std::swap(txdata, check.txdata); } ScriptError GetScriptError() const { return error; } diff --git a/src/net.cpp b/src/net.cpp index 39c8d12e20..c5b080f794 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -43,6 +43,9 @@ // Dump addresses to peers.dat and banlist.dat every 15 minutes (900s) #define DUMP_ADDRESSES_INTERVAL 900 +// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization. +#define FEELER_SLEEP_WINDOW 1 + #if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 #endif @@ -61,12 +64,13 @@ namespace { const int MAX_OUTBOUND_CONNECTIONS = 8; + const int MAX_FEELER_CONNECTIONS = 1; struct ListenSocket { SOCKET socket; bool whitelisted; - ListenSocket(SOCKET socket, bool whitelisted) : socket(socket), whitelisted(whitelisted) {} + ListenSocket(SOCKET _socket, bool _whitelisted) : socket(_socket), whitelisted(_whitelisted) {} }; } @@ -217,7 +221,7 @@ void AdvertiseLocal(CNode *pnode) } if (addrLocal.IsRoutable()) { - LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); + LogPrint("net", "AdvertiseLocal: advertising address %s\n", addrLocal.ToString()); pnode->PushAddress(addrLocal); } } @@ -1017,7 +1021,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) { SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); CAddress addr; int nInbound = 0; - int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS; + int nMaxInbound = nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); + assert(nMaxInbound > 0); if (hSocket != INVALID_SOCKET) if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) @@ -1613,6 +1618,9 @@ void ThreadOpenConnections() // Initiate network connections int64_t nStart = GetTime(); + + // Minimum time before next feeler connection (in microseconds). + int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL); while (true) { ProcessOneShot(); @@ -1652,13 +1660,36 @@ void ThreadOpenConnections() } } } + assert(nOutbound <= (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS)); - int64_t nANow = GetAdjustedTime(); + // Feeler Connections + // + // Design goals: + // * Increase the number of connectable addresses in the tried table. + // + // Method: + // * Choose a random address from new and attempt to connect to it if we can connect + // successfully it is added to tried. + // * Start attempting feeler connections only after node finishes making outbound + // connections. + // * Only make a feeler connection once every few minutes. + // + bool fFeeler = false; + if (nOutbound >= MAX_OUTBOUND_CONNECTIONS) { + int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds). + if (nTime > nNextFeeler) { + nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL); + fFeeler = true; + } else { + continue; + } + } + int64_t nANow = GetAdjustedTime(); int nTries = 0; while (true) { - CAddrInfo addr = addrman.Select(); + CAddrInfo addr = addrman.Select(fFeeler); // if we selected an invalid address, restart if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr)) @@ -1694,8 +1725,17 @@ void ThreadOpenConnections() break; } - if (addrConnect.IsValid()) - OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant); + if (addrConnect.IsValid()) { + + if (fFeeler) { + // Add small amount of random noise before connection to avoid synchronization. + int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000); + MilliSleep(randsleep); + LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString()); + } + + OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, NULL, false, fFeeler); + } } } @@ -1777,7 +1817,7 @@ void ThreadOpenAddedConnections() } // if successful, this moves the passed grant to the constructed node -bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot) +bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler) { // // Initiate outbound network connection @@ -1801,6 +1841,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem pnode->fNetworkNode = true; if (fOneShot) pnode->fOneShot = true; + if (fFeeler) + pnode->fFeeler = true; return true; } @@ -2062,7 +2104,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler) if (semOutbound == NULL) { // initialize semaphore - int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); + int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections); semOutbound = new CSemaphore(nMaxOutbound); } @@ -2107,7 +2149,7 @@ bool StopNode() LogPrintf("StopNode()\n"); MapPort(false); if (semOutbound) - for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++) + for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++) semOutbound->post(); if (fAddressesInitialized) @@ -2448,6 +2490,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa fWhitelisted = false; fOneShot = false; fClient = false; // set by version message + fFeeler = false; fInbound = fInboundIn; fNetworkNode = false; fSuccessfullyConnected = false; @@ -41,6 +41,8 @@ namespace boost { static const int PING_INTERVAL = 2 * 60; /** Time after which to disconnect, after waiting for a ping response (or inactivity). */ static const int TIMEOUT_INTERVAL = 20 * 60; +/** Run the feeler connection loop once every 2 minutes or 120 seconds. **/ +static const int FEELER_INTERVAL = 120; /** The maximum number of entries in an 'inv' protocol message */ static const unsigned int MAX_INV_SZ = 50000; /** The maximum number of new addresses to accumulate before announcing. */ @@ -89,7 +91,7 @@ CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); CNode* FindNode(const CService& ip); CNode* FindNode(const NodeId id); //TODO: Remove this -bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false); +bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false); void MapPort(bool fUseUPnP); unsigned short GetListenPort(); bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); @@ -350,6 +352,7 @@ public: // the network or wire types and the cleaned string used when displayed or logged. std::string strSubVer, cleanSubVer; bool fWhitelisted; // This peer can bypass DoS banning. + bool fFeeler; // If true this node is being used as a short lived feeler. bool fOneShot; bool fClient; bool fInbound; @@ -509,21 +512,21 @@ public: - void AddAddressKnown(const CAddress& addr) + void AddAddressKnown(const CAddress& _addr) { - addrKnown.insert(addr.GetKey()); + addrKnown.insert(_addr.GetKey()); } - void PushAddress(const CAddress& addr) + void PushAddress(const CAddress& _addr) { // Known checking here is only to save space from duplicates. // SendMessages will filter it again for knowns that were added // after addresses were pushed. - if (addr.IsValid() && !addrKnown.contains(addr.GetKey())) { + if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) { if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) { - vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr; + vAddrToSend[insecure_rand() % vAddrToSend.size()] = _addr; } else { - vAddrToSend.push_back(addr); + vAddrToSend.push_back(_addr); } } } diff --git a/src/netaddress.cpp b/src/netaddress.cpp index 7000ce3f0a..db5cc3bc20 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -197,8 +197,8 @@ bool CNetAddr::IsValid() const return false; // unspecified IPv6 address (::/128) - unsigned char ipNone[16] = {}; - if (memcmp(ip, ipNone, 16) == 0) + unsigned char ipNone6[16] = {}; + if (memcmp(ip, ipNone6, 16) == 0) return false; // documentation IPv6 address diff --git a/src/netbase.cpp b/src/netbase.cpp index 4f243ec6f5..7d7f1b6788 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -631,8 +631,8 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest SplitHostPort(std::string(pszDest), port, strDest); - proxyType nameProxy; - GetNameProxy(nameProxy); + proxyType proxy; + GetNameProxy(proxy); std::vector<CService> addrResolved; if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy(), 256)) { @@ -646,7 +646,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest if (!HaveNameProxy()) return false; - return ConnectThroughProxy(nameProxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed); + return ConnectThroughProxy(proxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed); } bool LookupSubNet(const char* pszName, CSubNet& ret) diff --git a/src/netbase.h b/src/netbase.h index bb12019a82..eb39d16578 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -29,7 +29,7 @@ class proxyType { public: proxyType(): randomize_credentials(false) {} - proxyType(const CService &proxy, bool randomize_credentials=false): proxy(proxy), randomize_credentials(randomize_credentials) {} + proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {} bool IsValid() const { return proxy.IsValid(); } diff --git a/src/protocol.h b/src/protocol.h index 015215b2a6..9b474ec79c 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -267,6 +267,9 @@ enum ServiceFlags : uint64_t { // Indicates that a node can be asked for blocks and transactions including // witness data. NODE_WITNESS = (1 << 3), + // NODE_XTHIN means the node supports Xtreme Thinblocks + // If this is turned off then the node will not service nor make xthin requests + NODE_XTHIN = (1 << 4), // Bits 24-31 are reserved for temporary experiments. Just pick a bit that // isn't getting used, or one not being used much, and notify the diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 837f8ba6c1..f53242100c 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -76,7 +76,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this); QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this); QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this); - QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this); QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this); QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); @@ -85,7 +84,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(clipboardFee())); connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(clipboardAfterFee())); connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(clipboardBytes())); - connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(clipboardPriority())); connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(clipboardLowOutput())); connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(clipboardChange())); @@ -94,7 +92,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget ui->labelCoinControlFee->addAction(clipboardFeeAction); ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction); ui->labelCoinControlBytes->addAction(clipboardBytesAction); - ui->labelCoinControlPriority->addAction(clipboardPriorityAction); ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction); ui->labelCoinControlChange->addAction(clipboardChangeAction); @@ -124,16 +121,14 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString()); ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84); - ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100); - ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170); - ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 290); - ui->treeWidget->setColumnWidth(COLUMN_DATE, 110); - ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100); - ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100); + ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 110); + ui->treeWidget->setColumnWidth(COLUMN_LABEL, 190); + ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 320); + ui->treeWidget->setColumnWidth(COLUMN_DATE, 130); + ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 110); ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it - ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but don't show it ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but don't show it // default view is sorted by amount desc @@ -325,12 +320,6 @@ void CoinControlDialog::clipboardBytes() GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, "")); } -// copy label "Priority" to clipboard -void CoinControlDialog::clipboardPriority() -{ - GUIUtil::setClipboard(ui->labelCoinControlPriority->text()); -} - // copy label "Dust" to clipboard void CoinControlDialog::clipboardLowOutput() { @@ -419,25 +408,6 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column) #endif } -// return human readable label for priority number -QString CoinControlDialog::getPriorityLabel(double dPriority, double mempoolEstimatePriority) -{ - double dPriorityMedium = mempoolEstimatePriority; - - if (dPriorityMedium <= 0) - dPriorityMedium = AllowFreeThreshold(); // not enough data, back to hard-coded - - if (dPriority / 1000000 > dPriorityMedium) return tr("highest"); - else if (dPriority / 100000 > dPriorityMedium) return tr("higher"); - else if (dPriority / 10000 > dPriorityMedium) return tr("high"); - else if (dPriority / 1000 > dPriorityMedium) return tr("medium-high"); - else if (dPriority > dPriorityMedium) return tr("medium"); - else if (dPriority * 10 > dPriorityMedium) return tr("low-medium"); - else if (dPriority * 100 > dPriorityMedium) return tr("low"); - else if (dPriority * 1000 > dPriorityMedium) return tr("lower"); - else return tr("lowest"); -} - // shows count of locked unspent outputs void CoinControlDialog::updateLabelLocked() { @@ -473,7 +443,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) } } - QString sPriorityLabel = tr("none"); CAmount nAmount = 0; CAmount nPayFee = 0; CAmount nAfterFee = 0; @@ -551,11 +520,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) nBytes += nQuantity; // account for the witness byte that holds the number of stack items for each input. } - // Priority - double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget); - dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority) - sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority); - // in the subtract fee from amount case, we can tell if zero change already and subtract the bytes, so that fee calculation afterwards is accurate if (CoinControlDialog::fSubtractFeeFromAmount) if (nAmount - nPayAmount == 0) @@ -568,6 +532,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // Allow free? (require at least hard-coded threshold and default to that if no estimate) + double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget); + dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority) double dPriorityNeeded = std::max(mempoolEstimatePriority, AllowFreeThreshold()); fAllowFree = (dPriority >= dPriorityNeeded); @@ -617,7 +583,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) QLabel *l3 = dialog->findChild<QLabel *>("labelCoinControlFee"); QLabel *l4 = dialog->findChild<QLabel *>("labelCoinControlAfterFee"); QLabel *l5 = dialog->findChild<QLabel *>("labelCoinControlBytes"); - QLabel *l6 = dialog->findChild<QLabel *>("labelCoinControlPriority"); QLabel *l7 = dialog->findChild<QLabel *>("labelCoinControlLowOutput"); QLabel *l8 = dialog->findChild<QLabel *>("labelCoinControlChange"); @@ -633,7 +598,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes - l6->setText(sPriorityLabel); // Priority l7->setText(fDust ? tr("yes") : tr("no")); // Dust l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change if (nPayFee > 0 && (coinControl->nMinimumTotalFee < nPayFee)) @@ -644,21 +608,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) l8->setText(ASYMP_UTF8 + l8->text()); } - // turn labels "red" - l5->setStyleSheet((nBytes >= MAX_FREE_TRANSACTION_CREATE_SIZE) ? "color:red;" : "");// Bytes >= 1000 - l6->setStyleSheet((dPriority > 0 && !fAllowFree) ? "color:red;" : ""); // Priority < "medium" - l7->setStyleSheet((fDust) ? "color:red;" : ""); // Dust = "yes" + // turn label red when dust + l7->setStyleSheet((fDust) ? "color:red;" : ""); // tool tips - QString toolTip1 = tr("This label turns red if the transaction size is greater than 1000 bytes.") + "<br /><br />"; - toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))) + "<br /><br />"; - toolTip1 += tr("Can vary +/- 1 byte per input."); - - QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />"; - toolTip2 += tr("This label turns red if the priority is smaller than \"medium\".") + "<br /><br />"; - toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))); - - QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold."); + QString toolTipDust = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold."); // how many satoshis the estimated fee can vary per byte we guess wrong double dFeeVary; @@ -671,14 +625,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) l3->setToolTip(toolTip4); l4->setToolTip(toolTip4); - l5->setToolTip(toolTip1); - l6->setToolTip(toolTip2); - l7->setToolTip(toolTip3); + l7->setToolTip(toolTipDust); l8->setToolTip(toolTip4); dialog->findChild<QLabel *>("labelCoinControlFeeText") ->setToolTip(l3->toolTip()); dialog->findChild<QLabel *>("labelCoinControlAfterFeeText") ->setToolTip(l4->toolTip()); dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip()); - dialog->findChild<QLabel *>("labelCoinControlPriorityText") ->setToolTip(l6->toolTip()); dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip()); dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setToolTip(l8->toolTip()); @@ -702,7 +653,6 @@ void CoinControlDialog::updateView() QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); - double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget); std::map<QString, std::vector<COutput> > mapCoins; model->listCoins(mapCoins); @@ -731,11 +681,8 @@ void CoinControlDialog::updateView() } CAmount nSum = 0; - double dPrioritySum = 0; int nChildren = 0; - int nInputSum = 0; BOOST_FOREACH(const COutput& out, coins.second) { - int nInputSize = 0; nSum += out.tx->vout[out.i].nValue; nChildren++; @@ -755,11 +702,6 @@ void CoinControlDialog::updateView() // if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs if (!treeMode || (!(sAddress == sWalletAddress))) itemOutput->setText(COLUMN_ADDRESS, sAddress); - - CPubKey pubkey; - CKeyID *keyid = boost::get<CKeyID>(&outputAddress); - if (keyid && model->getPubKey(*keyid, pubkey) && !pubkey.IsCompressed()) - nInputSize = 29; // 29 = 180 - 151 (public key is 180 bytes, priority free area is 151 bytes) } // label @@ -788,13 +730,6 @@ void CoinControlDialog::updateView() // confirmations itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " ")); - // priority - double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10 - itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority)); - itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " ")); - dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1); - nInputSum += nInputSize; - // transaction hash uint256 txhash = out.tx->GetHash(); itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(txhash.GetHex())); @@ -819,12 +754,9 @@ void CoinControlDialog::updateView() // amount if (treeMode) { - dPrioritySum = dPrioritySum / (nInputSum + 78); itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")"); itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " ")); - itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum, mempoolEstimatePriority)); - itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " ")); } } diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 1a467eb2ff..7d73421e3a 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -40,7 +40,6 @@ public: // static because also called from sendcoinsdialog static void updateLabels(WalletModel*, QDialog*); - static QString getPriorityLabel(double dPriority, double mempoolEstimatePriority); static QList<CAmount> payAmounts; static CCoinControl *coinControl; @@ -72,11 +71,9 @@ private: COLUMN_ADDRESS, COLUMN_DATE, COLUMN_CONFIRMATIONS, - COLUMN_PRIORITY, COLUMN_TXHASH, COLUMN_VOUT_INDEX, COLUMN_AMOUNT_INT64, - COLUMN_PRIORITY_INT64, COLUMN_DATE_INT64 }; @@ -87,8 +84,6 @@ private: { if (column == COLUMN_AMOUNT_INT64) return COLUMN_AMOUNT; - else if (column == COLUMN_PRIORITY_INT64) - return COLUMN_PRIORITY; else if (column == COLUMN_DATE_INT64) return COLUMN_DATE; } @@ -96,8 +91,6 @@ private: { if (column == COLUMN_AMOUNT) return COLUMN_AMOUNT_INT64; - else if (column == COLUMN_PRIORITY) - return COLUMN_PRIORITY_INT64; else if (column == COLUMN_DATE) return COLUMN_DATE_INT64; } @@ -118,7 +111,6 @@ private Q_SLOTS: void clipboardFee(); void clipboardAfterFee(); void clipboardBytes(); - void clipboardPriority(); void clipboardLowOutput(); void clipboardChange(); void radioTreeMode(bool); diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui index c1fef6b9b1..1ea00eb5c3 100644 --- a/src/qt/forms/coincontroldialog.ui +++ b/src/qt/forms/coincontroldialog.ui @@ -140,7 +140,10 @@ </widget> </item> <item row="1" column="0"> - <widget class="QLabel" name="labelCoinControlPriorityText"> + <widget class="QLabel" name="labelCoinControlLowOutputText"> + <property name="enabled"> + <bool>false</bool> + </property> <property name="font"> <font> <weight>75</weight> @@ -148,12 +151,15 @@ </font> </property> <property name="text"> - <string>Priority:</string> + <string>Dust:</string> </property> </widget> </item> <item row="1" column="1"> - <widget class="QLabel" name="labelCoinControlPriority"> + <widget class="QLabel" name="labelCoinControlLowOutput"> + <property name="enabled"> + <bool>false</bool> + </property> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> </property> @@ -161,7 +167,7 @@ <enum>Qt::ActionsContextMenu</enum> </property> <property name="text"> - <string notr="true">medium</string> + <string notr="true">no</string> </property> <property name="textInteractionFlags"> <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> @@ -213,41 +219,6 @@ </property> </widget> </item> - <item row="1" column="0"> - <widget class="QLabel" name="labelCoinControlLowOutputText"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string>Dust:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLabel" name="labelCoinControlLowOutput"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::ActionsContextMenu</enum> - </property> - <property name="text"> - <string notr="true">no</string> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> </layout> </item> <item> @@ -431,7 +402,7 @@ <bool>false</bool> </property> <property name="columnCount"> - <number>12</number> + <number>10</number> </property> <attribute name="headerShowSortIndicator" stdset="0"> <bool>true</bool> @@ -474,16 +445,6 @@ </column> <column> <property name="text"> - <string>Priority</string> - </property> - </column> - <column> - <property name="text"> - <string/> - </property> - </column> - <column> - <property name="text"> <string/> </property> </column> diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 12d6a62c08..06e09074d1 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -332,7 +332,7 @@ </widget> </item> <item row="1" column="0"> - <widget class="QLabel" name="labelCoinControlPriorityText"> + <widget class="QLabel" name="labelCoinControlLowOutputText"> <property name="font"> <font> <weight>75</weight> @@ -340,12 +340,12 @@ </font> </property> <property name="text"> - <string>Priority:</string> + <string>Dust:</string> </property> </widget> </item> <item row="1" column="1"> - <widget class="QLabel" name="labelCoinControlPriority"> + <widget class="QLabel" name="labelCoinControlLowOutput"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> </property> @@ -353,7 +353,7 @@ <enum>Qt::ActionsContextMenu</enum> </property> <property name="text"> - <string notr="true">medium</string> + <string notr="true">no</string> </property> <property name="textInteractionFlags"> <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> @@ -411,36 +411,7 @@ </property> </widget> </item> - <item row="1" column="0"> - <widget class="QLabel" name="labelCoinControlLowOutputText"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string>Dust:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLabel" name="labelCoinControlLowOutput"> - <property name="cursor"> - <cursorShape>IBeamCursor</cursorShape> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::ActionsContextMenu</enum> - </property> - <property name="text"> - <string notr="true">no</string> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - </layout> + </layout> </item> <item> <layout class="QFormLayout" name="formLayoutCoinControl4"> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 947a4c6821..c00f5e8591 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -930,6 +930,9 @@ QString formatServicesStr(quint64 mask) case NODE_WITNESS: strList.append("WITNESS"); break; + case NODE_XTHIN: + strList.append("XTHIN"); + break; default: strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check)); } diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 6a5740e21d..1a241ae0f0 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -178,7 +178,7 @@ bool Intro::pickDataDirectory() /* 2) Allow QSettings to override default dir */ dataDir = settings.value("strDataDir", dataDir).toString(); - if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR)) + if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || GetBoolArg("-resetguisettings", false)) { /* If current default data directory does not exist, let the user choose one */ Intro intro; @@ -204,6 +204,7 @@ bool Intro::pickDataDirectory() } settings.setValue("strDataDir", dataDir); + settings.setValue("fReset", false); } /* Only override -datadir if different from the default, to make it possible to * override -datadir in the bitcoin.conf file in the default data directory diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index d33ab68277..f82e153b67 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -17,6 +17,7 @@ #include "net.h" #include "netbase.h" #include "txdb.h" // for -dbcache defaults +#include "intro.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" @@ -99,6 +100,9 @@ void OptionsModel::Init(bool resetSettings) if (!SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString())) addOverriddenOption("-par"); + if (!settings.contains("strDataDir")) + settings.setValue("strDataDir", Intro::getDefaultDataDirectory()); + // Wallet #ifdef ENABLE_WALLET if (!settings.contains("bSpendZeroConfChange")) @@ -151,9 +155,19 @@ void OptionsModel::Reset() { QSettings settings; + // Save the strDataDir setting + QString dataDir = Intro::getDefaultDataDirectory(); + dataDir = settings.value("strDataDir", dataDir).toString(); + // Remove all entries from our QSettings object settings.clear(); + // Set strDataDir + settings.setValue("strDataDir", dataDir); + + // Set that this was reset + settings.setValue("fReset", true); + // default setting for OptionsModel::StartAtStartup - disabled if (GUIUtil::GetStartOnSystemStartup()) GUIUtil::SetStartOnSystemStartup(false); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 6d50be56ec..3e96bb18c3 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -69,7 +69,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this); QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this); QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this); - QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this); QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this); QAction *clipboardChangeAction = new QAction(tr("Copy change"), this); connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity())); @@ -77,7 +76,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardFee())); connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAfterFee())); connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardBytes())); - connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardPriority())); connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardLowOutput())); connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardChange())); ui->labelCoinControlQuantity->addAction(clipboardQuantityAction); @@ -85,7 +83,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa ui->labelCoinControlFee->addAction(clipboardFeeAction); ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction); ui->labelCoinControlBytes->addAction(clipboardBytesAction); - ui->labelCoinControlPriority->addAction(clipboardPriorityAction); ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction); ui->labelCoinControlChange->addAction(clipboardChangeAction); @@ -681,12 +678,6 @@ void SendCoinsDialog::coinControlClipboardBytes() GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, "")); } -// Coin Control: copy label "Priority" to clipboard -void SendCoinsDialog::coinControlClipboardPriority() -{ - GUIUtil::setClipboard(ui->labelCoinControlPriority->text()); -} - // Coin Control: copy label "Dust" to clipboard void SendCoinsDialog::coinControlClipboardLowOutput() { diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index be4f2ee44b..83dac0bd11 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -88,7 +88,6 @@ private Q_SLOTS: void coinControlClipboardFee(); void coinControlClipboardAfterFee(); void coinControlClipboardBytes(); - void coinControlClipboardPriority(); void coinControlClipboardLowOutput(); void coinControlClipboardChange(); void setMinimumFee(); diff --git a/src/rest.cpp b/src/rest.cpp index 2dff8d7dad..c815592124 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -420,7 +420,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) // throw exception in case of a empty request std::string strRequestMutable = req->ReadBody(); if (strRequestMutable.length() == 0 && uriParts.size() == 0) - return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request"); + return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request"); bool fInputParsed = false; bool fCheckMemPool = false; @@ -444,7 +444,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) std::string strOutput = uriParts[i].substr(uriParts[i].find("-")+1); if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid)) - return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error"); + return RESTERR(req, HTTP_BAD_REQUEST, "Parse error"); txid.SetHex(strTxid); vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput)); @@ -453,7 +453,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) if (vOutPoints.size() > 0) fInputParsed = true; else - return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request"); + return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request"); } switch (rf) { @@ -469,7 +469,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) if (strRequestMutable.size() > 0) { if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA - return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Combination of URI scheme inputs and raw post data is not allowed"); + return RESTERR(req, HTTP_BAD_REQUEST, "Combination of URI scheme inputs and raw post data is not allowed"); CDataStream oss(SER_NETWORK, PROTOCOL_VERSION); oss << strRequestMutable; @@ -478,14 +478,14 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) } } catch (const std::ios_base::failure& e) { // abort in case of unreadable binary data - return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error"); + return RESTERR(req, HTTP_BAD_REQUEST, "Parse error"); } break; } case RF_JSON: { if (!fInputParsed) - return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request"); + return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request"); break; } default: { @@ -495,7 +495,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) // limit max outpoints if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS) - return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size())); + return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size())); // check spentness and form a bitmap (as well as a JSON capable human-readable string representation) vector<unsigned char> bitmap; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index e3c32d905a..dc7e4721bb 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -26,8 +26,20 @@ #include <boost/thread/thread.hpp> // boost::thread::interrupt +#include <mutex> +#include <condition_variable> using namespace std; +struct CUpdatedBlock +{ + uint256 hash; + int height; +}; + +static std::mutex cs_blockchange; +static std::condition_variable cond_blockchange; +static CUpdatedBlock latestblock; + extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); @@ -168,6 +180,138 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp) return chainActive.Tip()->GetBlockHash().GetHex(); } +void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex) +{ + if(pindex) { + std::lock_guard<std::mutex> lock(cs_blockchange); + latestblock.hash = pindex->GetBlockHash(); + latestblock.height = pindex->nHeight; + } + cond_blockchange.notify_all(); +} + +UniValue waitfornewblock(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "waitfornewblock\n" + "\nWaits for a specific new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n" + "\nArguments:\n" + "1. timeout (milliseconds) (int, optional, default=false)\n" + "\nResult::\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + "\nExamples\n" + + HelpExampleCli("waitfornewblock", "1000") + + HelpExampleRpc("waitfornewblock", "1000") + ); + int timeout = 0; + if (params.size() > 0) + timeout = params[0].get_int(); + + CUpdatedBlock block; + { + std::unique_lock<std::mutex> lock(cs_blockchange); + block = latestblock; + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); + else + cond_blockchange.wait(lock, [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); + block = latestblock; + } + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + +UniValue waitforblock(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "waitforblock\n" + "\nWaits for a specific new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n" + "\nArguments:\n" + "1. blockhash to wait for (string)\n" + "2. timeout (milliseconds) (int, optional, default=false)\n" + "\nResult::\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + "\nExamples\n" + + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + ); + int timeout = 0; + + uint256 hash = uint256S(params[0].get_str()); + + if (params.size() > 1) + timeout = params[1].get_int(); + + CUpdatedBlock block; + { + std::unique_lock<std::mutex> lock(cs_blockchange); + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();}); + else + cond_blockchange.wait(lock, [&hash]{return latestblock.hash == hash || !IsRPCRunning(); }); + block = latestblock; + } + + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + +UniValue waitforblockheight(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "waitforblock\n" + "\nWaits for (at least) block height and returns the height and hash\n" + "\nof the current tip.\n" + "\nReturns the current block on timeout or exit.\n" + "\nArguments:\n" + "1. block height to wait for (int)\n" + "2. timeout (milliseconds) (int, optional, default=false)\n" + "\nResult::\n" + "{ (json object)\n" + " \"hash\" : { (string) The blockhash\n" + " \"height\" : { (int) Block height\n" + "}\n" + "\nExamples\n" + + HelpExampleCli("waitforblockheight", "\"100\", 1000") + + HelpExampleRpc("waitforblockheight", "\"100\", 1000") + ); + int timeout = 0; + + int height = params[0].get_int(); + + if (params.size() > 1) + timeout = params[1].get_int(); + + CUpdatedBlock block; + { + std::unique_lock<std::mutex> lock(cs_blockchange); + if(timeout) + cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();}); + else + cond_blockchange.wait(lock, [&height]{return latestblock.height >= height || !IsRPCRunning(); }); + block = latestblock; + } + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("hash", block.hash.GetHex())); + ret.push_back(Pair("height", block.height)); + return ret; +} + UniValue getdifficulty(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -632,7 +776,7 @@ struct CCoinsStats //! Calculate statistics about the unspent transaction output set static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats) { - boost::scoped_ptr<CCoinsViewCursor> pcursor(view->Cursor()); + std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor()); CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); stats.hashBlock = pcursor->GetBestBlock(); @@ -1203,10 +1347,13 @@ static const CRPCCommand commands[] = /* Not shown in help */ { "hidden", "invalidateblock", &invalidateblock, true }, { "hidden", "reconsiderblock", &reconsiderblock, true }, + { "hidden", "waitfornewblock", &waitfornewblock, true }, + { "hidden", "waitforblock", &waitforblock, true }, + { "hidden", "waitforblockheight", &waitforblockheight, true }, }; -void RegisterBlockchainRPCCommands(CRPCTable &tableRPC) +void RegisterBlockchainRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index d0675fdb49..c14d9d6747 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -26,7 +26,6 @@ static const CRPCConvertParam vRPCConvertParams[] = { { "stop", 0 }, { "setmocktime", 0 }, - { "getaddednodeinfo", 0 }, { "generate", 0 }, { "generate", 1 }, { "generatetoaddress", 0 }, @@ -47,6 +46,12 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getbalance", 1 }, { "getbalance", 2 }, { "getblockhash", 0 }, + { "waitforblockheight", 0 }, + { "waitforblockheight", 1 }, + { "waitforblock", 1 }, + { "waitforblock", 2 }, + { "waitfornewblock", 0 }, + { "waitfornewblock", 1 }, { "move", 2 }, { "move", 3 }, { "sendfrom", 2 }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index a26340f3e4..14183c8e82 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -919,8 +919,8 @@ static const CRPCCommand commands[] = { "util", "estimatesmartpriority", &estimatesmartpriority, true }, }; -void RegisterMiningRPCCommands(CRPCTable &tableRPC) +void RegisterMiningRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index a8c5bcd177..e96feaa864 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -498,8 +498,8 @@ static const CRPCCommand commands[] = { "hidden", "setmocktime", &setmocktime, true }, }; -void RegisterMiscRPCCommands(CRPCTable &tableRPC) +void RegisterMiscRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 4ce122648b..840bfd5a24 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -269,14 +269,13 @@ UniValue disconnectnode(const UniValue& params, bool fHelp) UniValue getaddednodeinfo(const UniValue& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() > 1) throw runtime_error( - "getaddednodeinfo dummy ( \"node\" )\n" + "getaddednodeinfo ( \"node\" )\n" "\nReturns information about the given added node, or all added nodes\n" "(note that onetry addnodes are not listed here)\n" "\nArguments:\n" - "1. dummy (boolean, required) Kept for historical purposes but ignored\n" - "2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n" + "1. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n" "\nResult:\n" "[\n" " {\n" @@ -299,10 +298,10 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo(); - if (params.size() == 2) { + if (params.size() == 1) { bool found = false; for (const AddedNodeInfo& info : vInfo) { - if (info.strAddedNode == params[1].get_str()) { + if (info.strAddedNode == params[0].get_str()) { vInfo.assign(1, info); found = true; break; @@ -590,8 +589,8 @@ static const CRPCCommand commands[] = { "network", "clearbanned", &clearbanned, true }, }; -void RegisterNetRPCCommands(CRPCTable &tableRPC) +void RegisterNetRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index 55d0aac68b..988e0fc5fa 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -38,18 +38,18 @@ enum RPCErrorCode RPC_PARSE_ERROR = -32700, //! General application defined errors - RPC_MISC_ERROR = -1, //! std::exception thrown in command handling - RPC_FORBIDDEN_BY_SAFE_MODE = -2, //! Server is in safe mode, and command is not allowed in safe mode - RPC_TYPE_ERROR = -3, //! Unexpected type was passed as parameter - RPC_INVALID_ADDRESS_OR_KEY = -5, //! Invalid address or key - RPC_OUT_OF_MEMORY = -7, //! Ran out of memory during operation - RPC_INVALID_PARAMETER = -8, //! Invalid, missing or duplicate parameter - RPC_DATABASE_ERROR = -20, //! Database error - RPC_DESERIALIZATION_ERROR = -22, //! Error parsing or validating structure in raw format - RPC_VERIFY_ERROR = -25, //! General error during transaction or block submission - RPC_VERIFY_REJECTED = -26, //! Transaction or block was rejected by network rules - RPC_VERIFY_ALREADY_IN_CHAIN = -27, //! Transaction already in chain - RPC_IN_WARMUP = -28, //! Client still warming up + RPC_MISC_ERROR = -1, //!< std::exception thrown in command handling + RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode + RPC_TYPE_ERROR = -3, //!< Unexpected type was passed as parameter + RPC_INVALID_ADDRESS_OR_KEY = -5, //!< Invalid address or key + RPC_OUT_OF_MEMORY = -7, //!< Ran out of memory during operation + RPC_INVALID_PARAMETER = -8, //!< Invalid, missing or duplicate parameter + RPC_DATABASE_ERROR = -20, //!< Database error + RPC_DESERIALIZATION_ERROR = -22, //!< Error parsing or validating structure in raw format + RPC_VERIFY_ERROR = -25, //!< General error during transaction or block submission + RPC_VERIFY_REJECTED = -26, //!< Transaction or block was rejected by network rules + RPC_VERIFY_ALREADY_IN_CHAIN = -27, //!< Transaction already in chain + RPC_IN_WARMUP = -28, //!< Client still warming up //! Aliases for backward compatibility RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR, @@ -57,23 +57,23 @@ enum RPCErrorCode RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN, //! P2P client errors - RPC_CLIENT_NOT_CONNECTED = -9, //! Bitcoin is not connected - RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks - RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added - RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before - RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes - RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet + RPC_CLIENT_NOT_CONNECTED = -9, //!< Bitcoin is not connected + RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //!< Still downloading initial blocks + RPC_CLIENT_NODE_ALREADY_ADDED = -23, //!< Node is already added + RPC_CLIENT_NODE_NOT_ADDED = -24, //!< Node has not been added before + RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes + RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet //! Wallet errors - RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.) - RPC_WALLET_INSUFFICIENT_FUNDS = -6, //! Not enough funds in wallet or account - RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //! Invalid account name - RPC_WALLET_KEYPOOL_RAN_OUT = -12, //! Keypool ran out, call keypoolrefill first - RPC_WALLET_UNLOCK_NEEDED = -13, //! Enter the wallet passphrase with walletpassphrase first - RPC_WALLET_PASSPHRASE_INCORRECT = -14, //! The wallet passphrase entered was incorrect - RPC_WALLET_WRONG_ENC_STATE = -15, //! Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.) - RPC_WALLET_ENCRYPTION_FAILED = -16, //! Failed to encrypt the wallet - RPC_WALLET_ALREADY_UNLOCKED = -17, //! Wallet is already unlocked + RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.) + RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account + RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //!< Invalid account name + RPC_WALLET_KEYPOOL_RAN_OUT = -12, //!< Keypool ran out, call keypoolrefill first + RPC_WALLET_UNLOCK_NEEDED = -13, //!< Enter the wallet passphrase with walletpassphrase first + RPC_WALLET_PASSPHRASE_INCORRECT = -14, //!< The wallet passphrase entered was incorrect + RPC_WALLET_WRONG_ENC_STATE = -15, //!< Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.) + RPC_WALLET_ENCRYPTION_FAILED = -16, //!< Failed to encrypt the wallet + RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked }; std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 3270cd384f..9461a7280c 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -910,8 +910,8 @@ static const CRPCCommand commands[] = { "blockchain", "verifytxoutproof", &verifytxoutproof, true }, }; -void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC) +void RegisterRawTransactionRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/rpc/register.h b/src/rpc/register.h index 01aa58a25d..49aee2365f 100644 --- a/src/rpc/register.h +++ b/src/rpc/register.h @@ -20,13 +20,13 @@ void RegisterMiningRPCCommands(CRPCTable &tableRPC); /** Register raw transaction RPC commands */ void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC); -static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC) +static inline void RegisterAllCoreRPCCommands(CRPCTable &t) { - RegisterBlockchainRPCCommands(tableRPC); - RegisterNetRPCCommands(tableRPC); - RegisterMiscRPCCommands(tableRPC); - RegisterMiningRPCCommands(tableRPC); - RegisterRawTransactionRPCCommands(tableRPC); + RegisterBlockchainRPCCommands(t); + RegisterNetRPCCommands(t); + RegisterMiscRPCCommands(t); + RegisterMiningRPCCommands(t); + RegisterRawTransactionRPCCommands(t); } #endif diff --git a/src/rpc/server.h b/src/rpc/server.h index b5ccc153d0..4e0aa2c6d6 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -194,5 +194,6 @@ bool StartRPC(); void InterruptRPC(); void StopRPC(); std::string JSONRPCExecBatch(const UniValue& vReq); +void RPCNotifyBlockChange(bool ibd, const CBlockIndex *); #endif // BITCOIN_RPCSERVER_H diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index 62fd9031f8..b629f4278b 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -84,8 +84,8 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP // Regardless of the verification result, the tx did not error. set_error(err, bitcoinconsensus_ERR_OK); - - return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount), NULL); + PrecomputedTransactionData txdata(tx); + return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), NULL); } catch (const std::exception&) { return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing } diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index bc027e9f0c..47ea261e31 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1108,9 +1108,40 @@ public: } }; +uint256 GetPrevoutHash(const CTransaction& txTo) { + CHashWriter ss(SER_GETHASH, 0); + for (unsigned int n = 0; n < txTo.vin.size(); n++) { + ss << txTo.vin[n].prevout; + } + return ss.GetHash(); +} + +uint256 GetSequenceHash(const CTransaction& txTo) { + CHashWriter ss(SER_GETHASH, 0); + for (unsigned int n = 0; n < txTo.vin.size(); n++) { + ss << txTo.vin[n].nSequence; + } + return ss.GetHash(); +} + +uint256 GetOutputsHash(const CTransaction& txTo) { + CHashWriter ss(SER_GETHASH, 0); + for (unsigned int n = 0; n < txTo.vout.size(); n++) { + ss << txTo.vout[n]; + } + return ss.GetHash(); +} + } // anon namespace -uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion) +PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) +{ + hashPrevouts = GetPrevoutHash(txTo); + hashSequence = GetSequenceHash(txTo); + hashOutputs = GetOutputsHash(txTo); +} + +uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) { if (sigversion == SIGVERSION_WITNESS_V0) { uint256 hashPrevouts; @@ -1118,27 +1149,16 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig uint256 hashOutputs; if (!(nHashType & SIGHASH_ANYONECANPAY)) { - CHashWriter ss(SER_GETHASH, 0); - for (unsigned int n = 0; n < txTo.vin.size(); n++) { - ss << txTo.vin[n].prevout; - } - hashPrevouts = ss.GetHash(); // TODO: cache this value for all signatures in a transaction + hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo); } if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - CHashWriter ss(SER_GETHASH, 0); - for (unsigned int n = 0; n < txTo.vin.size(); n++) { - ss << txTo.vin[n].nSequence; - } - hashSequence = ss.GetHash(); // TODO: cache this value for all signatures in a transaction + hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo); } + if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - CHashWriter ss(SER_GETHASH, 0); - for (unsigned int n = 0; n < txTo.vout.size(); n++) { - ss << txTo.vout[n]; - } - hashOutputs = ss.GetHash(); // TODO: cache this value for all signatures in a transaction + hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo); } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { CHashWriter ss(SER_GETHASH, 0); ss << txTo.vout[nIn]; @@ -1209,7 +1229,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn int nHashType = vchSig.back(); vchSig.pop_back(); - uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion); + uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata); if (!VerifySignature(vchSig, pubkey, sighash)) return false; diff --git a/src/script/interpreter.h b/src/script/interpreter.h index bd2f211663..e5d7865cd3 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -98,13 +98,20 @@ enum bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror); +struct PrecomputedTransactionData +{ + uint256 hashPrevouts, hashSequence, hashOutputs; + + PrecomputedTransactionData(const CTransaction& tx); +}; + enum SigVersion { SIGVERSION_BASE = 0, SIGVERSION_WITNESS_V0 = 1, }; -uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion); +uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL); class BaseSignatureChecker { @@ -133,12 +140,14 @@ private: const CTransaction* txTo; unsigned int nIn; const CAmount amount; + const PrecomputedTransactionData* txdata; protected: virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; public: - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn) {} + TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {} + TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const; bool CheckLockTime(const CScriptNum& nLockTime) const; bool CheckSequence(const CScriptNum& nSequence) const; diff --git a/src/script/sigcache.h b/src/script/sigcache.h index 050bf8cc42..44551ec2bc 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -22,7 +22,7 @@ private: bool store; public: - CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn) : TransactionSignatureChecker(txToIn, nInIn, amount), store(storeIn) {} + CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {} bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; }; diff --git a/src/script/sign.h b/src/script/sign.h index 6404b4523e..f9aa6fca27 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -51,7 +51,7 @@ public: MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {} }; -/** A signature creator that just produces 72-byte empty signatyres. */ +/** A signature creator that just produces 72-byte empty signatures. */ class DummySignatureCreator : public BaseSignatureCreator { public: DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {} diff --git a/src/serialize.h b/src/serialize.h index 378ed39074..04ab9aa2e7 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -322,8 +322,8 @@ uint64_t ReadCompactSize(Stream& is) * 0: [0x00] 256: [0x81 0x00] * 1: [0x01] 16383: [0xFE 0x7F] * 127: [0x7F] 16384: [0xFF 0x00] - * 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F] - * 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F] + * 128: [0x80 0x00] 16511: [0xFF 0x7F] + * 255: [0x80 0x7F] 65535: [0x82 0xFE 0x7F] * 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] */ diff --git a/src/sync.h b/src/sync.h index 0c58fb6b4e..7733910749 100644 --- a/src/sync.h +++ b/src/sync.h @@ -171,7 +171,10 @@ public: typedef CMutexLock<CCriticalSection> CCriticalBlock; -#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__) +#define PASTE(x, y) x ## y +#define PASTE2(x, y) PASTE(x, y) + +#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) #define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__) #define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true) diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp index 53ab7e95ee..b19d2faea0 100644 --- a/src/test/arith_uint256_tests.cpp +++ b/src/test/arith_uint256_tests.cpp @@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality BOOST_CHECK( (R1L & arith_uint256("0xffffffffffffffff")) == arith_uint256(R1LLow64)); BOOST_CHECK(ZeroL == arith_uint256(0)); BOOST_CHECK(OneL == arith_uint256(1)); - BOOST_CHECK(arith_uint256("0xffffffffffffffff") = arith_uint256(0xffffffffffffffffULL)); + BOOST_CHECK(arith_uint256("0xffffffffffffffff") == arith_uint256(0xffffffffffffffffULL)); // Assignment (from base_uint) arith_uint256 tmpL = ~ZeroL; BOOST_CHECK(tmpL == ~ZeroL); diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 01eb2aee9e..ac3ab4c83f 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -121,7 +121,6 @@ public: BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) { UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); - std::vector<unsigned char> result; CBitcoinSecret secret; CBitcoinAddress addr; SelectParams(CBaseChainParams::MAIN); @@ -179,7 +178,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) { UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); - std::vector<unsigned char> result; for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; @@ -247,7 +245,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) BOOST_AUTO_TEST_CASE(base58_keys_invalid) { UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases - std::vector<unsigned char> result; CBitcoinSecret secret; CBitcoinAddress addr; diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 3884bf3fe3..d2392cfb22 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -283,7 +283,6 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) std::vector<CTransaction> vtx_missing; BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString()); - bool mutated; BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString()); BOOST_CHECK(!mutated); } diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index a0bdcf4afb..d4d825d199 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) uint256 in2 = GetRandHash(); BOOST_CHECK(dbw.Write(key2, in2)); - boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator()); + std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator()); // Be sure to seek past the obfuscation key (if it exists) it->Seek(key); @@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(iterator_ordering) BOOST_CHECK(dbw.Write(key, value)); } - boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator()); + std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator()); for (int c=0; c<2; ++c) { int seek_start; if (c == 0) @@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering) } } - boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator()); + std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator()); for (int c=0; c<2; ++c) { int seek_start; if (c == 0) diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 6511e6ffa2..267d1b55e1 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -150,4 +150,26 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted) BOOST_CHECK(addrman2.size() == 0); } +BOOST_AUTO_TEST_CASE(cnode_simple_test) +{ + SOCKET hSocket = INVALID_SOCKET; + + in_addr ipv4Addr; + ipv4Addr.s_addr = 0xa0b0c001; + + CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK); + std::string pszDest = ""; + bool fInboundIn = false; + + // Test that fFeeler is false by default. + CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn); + BOOST_CHECK(pnode1->fInbound == false); + BOOST_CHECK(pnode1->fFeeler == false); + + fInboundIn = true; + CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn); + BOOST_CHECK(pnode2->fInbound == true); + BOOST_CHECK(pnode2->fFeeler == false); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 74ffe0cc74..e9c8691745 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -122,7 +122,6 @@ BOOST_AUTO_TEST_CASE(pmt_malleability) std::vector<bool> vMatch = boost::assign::list_of(false)(false)(false)(false)(false)(false)(false)(false)(false)(true)(true)(false); CPartialMerkleTree tree(vTxid, vMatch); - std::vector<uint256> vTxid2; std::vector<unsigned int> vIndex; BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull()); } diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp index d1407c1da9..b8c45ca564 100644 --- a/src/test/prevector_tests.cpp +++ b/src/test/prevector_tests.cpp @@ -26,57 +26,70 @@ class prevector_tester { pretype pre_vector_alt; typedef typename pretype::size_type Size; + bool passed = true; + uint32_t insecure_rand_Rz_cache; + uint32_t insecure_rand_Rw_cache; + + template <typename A, typename B> + void local_check_equal(A a, B b) + { + local_check(a == b); + } + void local_check(bool b) + { + passed &= b; + } void test() { const pretype& const_pre_vector = pre_vector; - BOOST_CHECK_EQUAL(real_vector.size(), pre_vector.size()); - BOOST_CHECK_EQUAL(real_vector.empty(), pre_vector.empty()); + local_check_equal(real_vector.size(), pre_vector.size()); + local_check_equal(real_vector.empty(), pre_vector.empty()); for (Size s = 0; s < real_vector.size(); s++) { - BOOST_CHECK(real_vector[s] == pre_vector[s]); - BOOST_CHECK(&(pre_vector[s]) == &(pre_vector.begin()[s])); - BOOST_CHECK(&(pre_vector[s]) == &*(pre_vector.begin() + s)); - BOOST_CHECK(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size())); + local_check(real_vector[s] == pre_vector[s]); + local_check(&(pre_vector[s]) == &(pre_vector.begin()[s])); + local_check(&(pre_vector[s]) == &*(pre_vector.begin() + s)); + local_check(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size())); } - // BOOST_CHECK(realtype(pre_vector) == real_vector); - BOOST_CHECK(pretype(real_vector.begin(), real_vector.end()) == pre_vector); - BOOST_CHECK(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector); + // local_check(realtype(pre_vector) == real_vector); + local_check(pretype(real_vector.begin(), real_vector.end()) == pre_vector); + local_check(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector); size_t pos = 0; BOOST_FOREACH(const T& v, pre_vector) { - BOOST_CHECK(v == real_vector[pos++]); + local_check(v == real_vector[pos++]); } BOOST_REVERSE_FOREACH(const T& v, pre_vector) { - BOOST_CHECK(v == real_vector[--pos]); + local_check(v == real_vector[--pos]); } BOOST_FOREACH(const T& v, const_pre_vector) { - BOOST_CHECK(v == real_vector[pos++]); + local_check(v == real_vector[pos++]); } BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) { - BOOST_CHECK(v == real_vector[--pos]); + local_check(v == real_vector[--pos]); } CDataStream ss1(SER_DISK, 0); CDataStream ss2(SER_DISK, 0); ss1 << real_vector; ss2 << pre_vector; - BOOST_CHECK_EQUAL(ss1.size(), ss2.size()); + local_check_equal(ss1.size(), ss2.size()); for (Size s = 0; s < ss1.size(); s++) { - BOOST_CHECK_EQUAL(ss1[s], ss2[s]); + local_check_equal(ss1[s], ss2[s]); } } public: void resize(Size s) { real_vector.resize(s); - BOOST_CHECK_EQUAL(real_vector.size(), s); + local_check_equal(real_vector.size(), s); pre_vector.resize(s); - BOOST_CHECK_EQUAL(pre_vector.size(), s); + local_check_equal(pre_vector.size(), s); test(); } void reserve(Size s) { real_vector.reserve(s); - BOOST_CHECK(real_vector.capacity() >= s); + local_check(real_vector.capacity() >= s); pre_vector.reserve(s); - BOOST_CHECK(pre_vector.capacity() >= s); + local_check(pre_vector.capacity() >= s); test(); } @@ -157,6 +170,17 @@ public: pre_vector.swap(pre_vector_alt); test(); } + ~prevector_tester() { + BOOST_CHECK_MESSAGE(passed, "insecure_rand_Rz: " + << insecure_rand_Rz_cache + << ", insecure_rand_Rw: " + << insecure_rand_Rw_cache); + } + prevector_tester() { + seed_insecure_rand(); + insecure_rand_Rz_cache = insecure_rand_Rz; + insecure_rand_Rw_cache = insecure_rand_Rw; + } }; BOOST_AUTO_TEST_CASE(PrevectorTestInt) diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index bbda6a48f4..a15915aad2 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -18,18 +18,6 @@ using namespace std; -UniValue -createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL) -{ - UniValue result(UniValue::VARR); - result.push_back(nRequired); - UniValue addresses(UniValue::VARR); - if (address1) addresses.push_back(address1); - if (address2) addresses.push_back(address2); - result.push_back(addresses); - return result; -} - UniValue CallRPC(string args) { vector<string> vArgs; diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 5224b57ca4..1a01593a8e 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -107,18 +107,20 @@ BOOST_AUTO_TEST_CASE(sign) } // All of the above should be OK, and the txTos have valid signatures // Check to make sure signature verification fails if we use the wrong ScriptSig: - for (int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { + PrecomputedTransactionData txdata(txTo[i]); for (int j = 0; j < 8; j++) { CScript sigSave = txTo[i].vin[0].scriptSig; txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; - bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)(); + bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)(); if (i == j) BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); else BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j)); txTo[i].vin[0].scriptSig = sigSave; } + } } BOOST_AUTO_TEST_CASE(norecurse) diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index fd4f174b40..b5af400bc5 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -7,6 +7,7 @@ #include "test/test_bitcoin.h" #include "clientversion.h" +#include "checkqueue.h" #include "consensus/validation.h" #include "core_io.h" #include "key.h" @@ -153,6 +154,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); BOOST_CHECK(state.IsValid()); + PrecomputedTransactionData txdata(tx); for (unsigned int i = 0; i < tx.vin.size(); i++) { if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout)) @@ -168,7 +170,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL; BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], - witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err), + witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err), strTest); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } @@ -237,6 +239,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) CValidationState state; fValid = CheckTransaction(tx, state) && state.IsValid(); + PrecomputedTransactionData txdata(tx); for (unsigned int i = 0; i < tx.vin.size() && fValid; i++) { if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout)) @@ -252,7 +255,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) } const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL; fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], - witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err); + witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err); } BOOST_CHECK_MESSAGE(!fValid, strTest); BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err)); @@ -419,6 +422,86 @@ void ReplaceRedeemScript(CScript& script, const CScript& redeemScript) script = PushAll(stack); } +BOOST_AUTO_TEST_CASE(test_big_witness_transaction) { + CMutableTransaction mtx; + mtx.nVersion = 1; + + CKey key; + key.MakeNewKey(false); + CBasicKeyStore keystore; + keystore.AddKeyPubKey(key, key.GetPubKey()); + CKeyID hash = key.GetPubKey().GetID(); + CScript scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(hash.begin(), hash.end()); + + vector<int> sigHashes; + sigHashes.push_back(SIGHASH_NONE | SIGHASH_ANYONECANPAY); + sigHashes.push_back(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY); + sigHashes.push_back(SIGHASH_ALL | SIGHASH_ANYONECANPAY); + sigHashes.push_back(SIGHASH_NONE); + sigHashes.push_back(SIGHASH_SINGLE); + sigHashes.push_back(SIGHASH_ALL); + + // create a big transaction of 4500 inputs signed by the same key + for(uint32_t ij = 0; ij < 4500; ij++) { + uint32_t i = mtx.vin.size(); + uint256 prevId; + prevId.SetHex("0000000000000000000000000000000000000000000000000000000000000100"); + COutPoint outpoint(prevId, i); + + mtx.vin.resize(mtx.vin.size() + 1); + mtx.vin[i].prevout = outpoint; + mtx.vin[i].scriptSig = CScript(); + + mtx.vout.resize(mtx.vout.size() + 1); + mtx.vout[i].nValue = 1000; + mtx.vout[i].scriptPubKey = CScript() << OP_1; + } + + // sign all inputs + for(uint32_t i = 0; i < mtx.vin.size(); i++) { + bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size())); + assert(hashSigned); + } + + CTransaction tx; + CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION); + WithOrVersion(&ssout, 0) << mtx; + WithOrVersion(&ssout, 0) >> tx; + + // check all inputs concurrently, with the cache + PrecomputedTransactionData txdata(tx); + boost::thread_group threadGroup; + CCheckQueue<CScriptCheck> scriptcheckqueue(128); + CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue); + + for (int i=0; i<20; i++) + threadGroup.create_thread(boost::bind(&CCheckQueue<CScriptCheck>::Thread, boost::ref(scriptcheckqueue))); + + CCoins coins; + coins.nVersion = 1; + coins.fCoinBase = false; + for(uint32_t i = 0; i < mtx.vin.size(); i++) { + CTxOut txout; + txout.nValue = 1000; + txout.scriptPubKey = scriptPubKey; + coins.vout.push_back(txout); + } + + for(uint32_t i = 0; i < mtx.vin.size(); i++) { + std::vector<CScriptCheck> vChecks; + CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata); + vChecks.push_back(CScriptCheck()); + check.swap(vChecks.back()); + control.Add(vChecks); + } + + bool controlCheck = control.Wait(); + assert(controlCheck); + + threadGroup.interrupt_all(); + threadGroup.join_all(); +} + BOOST_AUTO_TEST_CASE(test_witness) { CBasicKeyStore keystore, keystore2; diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index e467a4171d..efd4498747 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -243,11 +243,7 @@ BOOST_AUTO_TEST_CASE(util_IsHex) BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) { - int i; - int count=0; - seed_insecure_rand(true); - for (int mod=2;mod<11;mod++) { int mask = 1; @@ -256,10 +252,9 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) //mask is 2^ceil(log2(mod))-1 while(mask<mod-1)mask=(mask<<1)+1; - count = 0; + int count = 0; //How often does it get a zero from the uniform range [0,mod)? - for (i=0;i<10000;i++) - { + for (int i = 0; i < 10000; i++) { uint32_t rval; do{ rval=insecure_rand()&mask; diff --git a/src/txdb.cpp b/src/txdb.cpp index 078c29def3..4f11c7b951 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -173,7 +173,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex) { - boost::scoped_ptr<CDBIterator> pcursor(NewIterator()); + std::unique_ptr<CDBIterator> pcursor(NewIterator()); pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256())); diff --git a/src/txdb.h b/src/txdb.h index 5b98d2792c..adb3f66327 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -92,7 +92,7 @@ public: private: CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256 &hashBlockIn): CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {} - boost::scoped_ptr<CDBIterator> pcursor; + std::unique_ptr<CDBIterator> pcursor; std::pair<char, uint256> keyTmp; friend class CCoinsViewDB; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index b631c48484..0a00d757a2 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -576,7 +576,6 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed) { // Remove transactions which depend on inputs of tx, recursively - list<CTransaction> result; LOCK(cs); BOOST_FOREACH(const CTxIn &txin, tx.vin) { auto it = mapNextTx.find(txin.prevout); diff --git a/src/util.cpp b/src/util.cpp index 9a9209c621..c7d147a11e 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -107,7 +107,6 @@ map<string, vector<string> > mapMultiArgs; bool fDebug = false; bool fPrintToConsole = false; bool fPrintToDebugLog = true; -bool fDaemon = false; bool fServer = false; string strMiscWarning; bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; @@ -801,11 +800,10 @@ int GetNumCores() std::string CopyrightHolders(const std::string& strPrefix) { - std::string strCopyrightHolders = strPrefix + _(COPYRIGHT_HOLDERS); - if (strCopyrightHolders.find("%s") != strCopyrightHolders.npos) { - strCopyrightHolders = strprintf(strCopyrightHolders, _(COPYRIGHT_HOLDERS_SUBSTITUTION)); - } - if (strCopyrightHolders.find("Bitcoin Core developers") == strCopyrightHolders.npos) { + std::string strCopyrightHolders = strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION)); + + // Check for untranslated substitution to make sure Bitcoin Core copyright is not removed by accident + if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Bitcoin Core") == std::string::npos) { strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers"; } return strCopyrightHolders; diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index cfd007ca1c..a809c9ad64 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -43,7 +43,7 @@ void CDBEnv::EnvShutdown() if (ret != 0) LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret)); if (!fMockDb) - DbEnv(0).remove(strPath.c_str(), 0); + DbEnv((u_int32_t)0).remove(strPath.c_str(), 0); } void CDBEnv::Reset() @@ -387,11 +387,11 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) while (fSuccess) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); - if (ret == DB_NOTFOUND) { + int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue); + if (ret1 == DB_NOTFOUND) { pcursor->close(); break; - } else if (ret != 0) { + } else if (ret1 != 0) { pcursor->close(); fSuccess = false; break; diff --git a/src/wallet/db.h b/src/wallet/db.h index 01b8c71a04..a0f673ecfc 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -228,19 +228,17 @@ protected: return pcursor; } - int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT) + int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false) { // Read at cursor Dbt datKey; - if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) { + unsigned int fFlags = DB_NEXT; + if (setRange) { datKey.set_data(&ssKey[0]); datKey.set_size(ssKey.size()); + fFlags = DB_SET_RANGE; } Dbt datValue; - if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) { - datValue.set_data(&ssValue[0]); - datValue.set_size(ssValue.size()); - } datKey.set_flags(DB_DBT_MALLOC); datValue.set_flags(DB_DBT_MALLOC); int ret = pcursor->get(&datKey, &datValue, fFlags); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index fe8b53ceb0..42ebdb9b9b 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -257,14 +257,13 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp) if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - if (fHelp || params.size() < 2 || params.size() > 3) + if (fHelp || params.size() != 2) throw runtime_error( "importprunedfunds\n" "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n" "\nArguments:\n" "1. \"rawtransaction\" (string, required) A raw transaction in hex funding an already-existing address in wallet\n" "2. \"txoutproof\" (string, required) The hex output from gettxoutproof that contains the transaction\n" - "3. \"label\" (string, optional) An optional label\n" ); CTransaction tx; @@ -277,10 +276,6 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp) CMerkleBlock merkleBlock; ssMB >> merkleBlock; - string strLabel = ""; - if (params.size() == 3) - strLabel = params[2].get_str(); - //Search partial merkle tree in proof for our transaction and index in valid block vector<uint256> vMatch; vector<unsigned int> vIndex; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index aa0a9374c1..0ba6706baf 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1176,10 +1176,10 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) if (fByAccounts) { - tallyitem& item = mapAccountTally[strAccount]; - item.nAmount += nAmount; - item.nConf = min(item.nConf, nConf); - item.fIsWatchonly = fIsWatchonly; + tallyitem& _item = mapAccountTally[strAccount]; + _item.nAmount += nAmount; + _item.nConf = min(_item.nConf, nConf); + _item.fIsWatchonly = fIsWatchonly; } else { @@ -1195,9 +1195,9 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) UniValue transactions(UniValue::VARR); if (it != mapTally.end()) { - BOOST_FOREACH(const uint256& item, (*it).second.txids) + BOOST_FOREACH(const uint256& _item, (*it).second.txids) { - transactions.push_back(item.GetHex()); + transactions.push_back(_item.GetHex()); } } obj.push_back(Pair("txids", transactions)); @@ -2617,8 +2617,8 @@ static const CRPCCommand commands[] = { "wallet", "removeprunedfunds", &removeprunedfunds, true }, }; -void RegisterWalletRPCCommands(CRPCTable &tableRPC) +void RegisterWalletRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h index a5de7e2de1..3a68ccf1b2 100644 --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -7,6 +7,6 @@ class CRPCTable; -void RegisterWalletRPCCommands(CRPCTable &tableRPC); +void RegisterWalletRPCCommands(CRPCTable &t); #endif //BITCOIN_WALLET_RPCWALLET_H diff --git a/src/wallet/test/rpc_wallet_tests.cpp b/src/wallet/test/rpc_wallet_tests.cpp deleted file mode 100644 index 4e7d177f51..0000000000 --- a/src/wallet/test/rpc_wallet_tests.cpp +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (c) 2013-2015 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 "rpc/server.h" -#include "rpc/client.h" - -#include "base58.h" -#include "main.h" -#include "wallet/wallet.h" - -#include "wallet/test/wallet_test_fixture.h" - -#include <boost/algorithm/string.hpp> -#include <boost/test/unit_test.hpp> - -#include <univalue.h> - -using namespace std; - -extern UniValue createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL); -extern UniValue CallRPC(string args); - -extern CWallet* pwalletMain; - -BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, WalletTestingSetup) - -BOOST_AUTO_TEST_CASE(rpc_addmultisig) -{ - rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor; - - // old, 65-byte-long: - const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8"; - // new, compressed: - const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4"; - - UniValue v; - CBitcoinAddress address; - BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false)); - address.SetString(v.get_str()); - BOOST_CHECK(address.IsValid() && address.IsScript()); - - BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false)); - address.SetString(v.get_str()); - BOOST_CHECK(address.IsValid() && address.IsScript()); - - BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false)); - address.SetString(v.get_str()); - BOOST_CHECK(address.IsValid() && address.IsScript()); - - BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error); - BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error); - BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error); - - BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error); - BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error); - - string short1(address1Hex, address1Hex + sizeof(address1Hex) - 2); // last byte missing - BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error); - - string short2(address1Hex + 1, address1Hex + sizeof(address1Hex)); // first byte missing - BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error); -} - -BOOST_AUTO_TEST_CASE(rpc_wallet) -{ - // Test RPC calls for various wallet statistics - UniValue r; - CPubKey demoPubkey; - CBitcoinAddress demoAddress; - UniValue retValue; - string strAccount = "walletDemoAccount"; - CBitcoinAddress setaccountDemoAddress; - { - LOCK(pwalletMain->cs_wallet); - - demoPubkey = pwalletMain->GenerateNewKey(); - demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID())); - string strPurpose = "receive"; - BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */ - CWalletDB walletdb(pwalletMain->strWalletFile); - CAccount account; - account.vchPubKey = demoPubkey; - pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose); - walletdb.WriteAccount(strAccount, account); - }); - - CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey(); - setaccountDemoAddress = CBitcoinAddress(CTxDestination(setaccountDemoPubkey.GetID())); - } - /********************************* - * setaccount - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("setaccount " + setaccountDemoAddress.ToString() + " nullaccount")); - /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ is not owned by the test wallet. */ - BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount"), runtime_error); - BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error); - /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */ - BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error); - - - /********************************* - * getbalance - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("getbalance")); - BOOST_CHECK_NO_THROW(CallRPC("getbalance " + demoAddress.ToString())); - - /********************************* - * listunspent - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("listunspent")); - BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error); - BOOST_CHECK_NO_THROW(r = CallRPC("listunspent 0 1 []")); - BOOST_CHECK(r.get_array().empty()); - - /********************************* - * listreceivedbyaddress - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress")); - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0")); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true")); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error); - - /********************************* - * listreceivedbyaccount - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount")); - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0")); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true")); - BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error); - - /********************************* - * listsinceblock - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("listsinceblock")); - - /********************************* - * listtransactions - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("listtransactions")); - BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString())); - BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " 20")); - BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " 20 0")); - BOOST_CHECK_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " not_int"), runtime_error); - - /********************************* - * listlockunspent - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("listlockunspent")); - - /********************************* - * listaccounts - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("listaccounts")); - - /********************************* - * listaddressgroupings - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("listaddressgroupings")); - - /********************************* - * getrawchangeaddress - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress")); - - /********************************* - * getnewaddress - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("getnewaddress")); - BOOST_CHECK_NO_THROW(CallRPC("getnewaddress getnewaddress_demoaccount")); - - /********************************* - * getaccountaddress - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\"")); - BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account - BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount)); - BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get()); - - /********************************* - * getaccount - *********************************/ - BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString())); - - /********************************* - * signmessage + verifymessage - *********************************/ - BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage")); - BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error); - /* Should throw error because this address is not loaded in the wallet */ - BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error); - - /* missing arguments */ - BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString()), runtime_error); - BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str()), runtime_error); - /* Illegal address */ - BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error); - /* wrong address */ - BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false); - /* Correct address and signature but wrong message */ - BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false); - /* Correct address, message and signature*/ - BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true); - - /********************************* - * getaddressesbyaccount - *********************************/ - BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error); - BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount)); - UniValue arr = retValue.get_array(); - BOOST_CHECK(arr.size() > 0); - BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get()); - - /********************************* - * fundrawtransaction - *********************************/ - BOOST_CHECK_THROW(CallRPC("fundrawtransaction 28z"), runtime_error); - BOOST_CHECK_THROW(CallRPC("fundrawtransaction 01000000000180969800000000001976a91450ce0a4b0ee0ddeb633da85199728b940ac3fe9488ac00000000"), runtime_error); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index c6c5058984..acf980c784 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) // run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) // they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change empty_wallet(); - for (int i = 0; i < 20; i++) + for (int j = 0; j < 20; j++) add_coin(50000 * COIN); BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); @@ -296,7 +296,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2)); int fails = 0; - for (int i = 0; i < RANDOM_REPEATS; i++) + for (int j = 0; j < RANDOM_REPEATS; j++) { // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time // run the test RANDOM_REPEATS times and only complain if all of them fail @@ -317,7 +317,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) add_coin(25 * CENT); fails = 0; - for (int i = 0; i < RANDOM_REPEATS; i++) + for (int j = 0; j < RANDOM_REPEATS; j++) { // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time // run the test RANDOM_REPEATS times and only complain if all of them fail diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 2d413fb9f9..10aca2e499 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2461,7 +2461,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) AddToWallet(wtxNew); // Notify that old coins are spent - set<CWalletTx*> setCoins; BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) { CWalletTx &coin = mapWallet[txin.prevout.hash]; @@ -3416,7 +3415,17 @@ bool CWallet::InitLoadWallet() } walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); + { + LOCK(walletInstance->cs_wallet); + LogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize()); + LogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size()); + LogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size()); + } + // Add wallet transactions that aren't already in a block to mapTransactions + walletInstance->ReacceptWalletTransactions(); + pwalletMain = walletInstance; + return true; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 30f092e9a8..c06513650c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -582,6 +582,8 @@ private: CHDChain hdChain; bool fFileBacked; + + std::set<int64_t> setKeyPool; public: /* * Main wallet lock. @@ -594,7 +596,18 @@ public: std::string strWalletFile; - std::set<int64_t> setKeyPool; + void LoadKeyPool(int nIndex, const CKeyPool &keypool) + { + setKeyPool.insert(nIndex); + + // If no metadata exists yet, create a default with the pool key's + // creation time. Note that this may be overwritten by actually + // stored metadata for that key later, which is fine. + CKeyID keyid = keypool.vchPubKey.GetID(); + if (mapKeyMetadata.count(keyid) == 0) + mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); + } + std::map<CKeyID, CKeyMetadata> mapKeyMetadata; typedef std::map<unsigned int, CMasterKey> MasterKeyMap; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f824492cb6..80bfe8255d 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -18,7 +18,6 @@ #include <boost/version.hpp> #include <boost/filesystem.hpp> #include <boost/foreach.hpp> -#include <boost/scoped_ptr.hpp> #include <boost/thread.hpp> using namespace std; @@ -216,16 +215,16 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin Dbc* pcursor = GetCursor(); if (!pcursor) throw runtime_error(std::string(__func__) + ": cannot create DB cursor"); - unsigned int fFlags = DB_SET_RANGE; + bool setRange = true; while (true) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); - if (fFlags == DB_SET_RANGE) + if (setRange) ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0))); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); - fFlags = DB_NEXT; + int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange); + setRange = false; if (ret == DB_NOTFOUND) break; else if (ret != 0) @@ -556,14 +555,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssKey >> nIndex; CKeyPool keypool; ssValue >> keypool; - pwallet->setKeyPool.insert(nIndex); - - // If no metadata exists yet, create a default with the pool key's - // creation time. Note that this may be overwritten by actually - // stored metadata for that key later, which is fine. - CKeyID keyid = keypool.vchPubKey.GetID(); - if (pwallet->mapKeyMetadata.count(keyid) == 0) - pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); + + pwallet->LoadKeyPool(nIndex, keypool); } else if (strType == "version") { @@ -893,8 +886,8 @@ void ThreadFlushWalletDB(const string& strFile) if (nRefCount == 0) { boost::this_thread::interruption_point(); - map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile); - if (mi != bitdb.mapFileUseCount.end()) + map<string, int>::iterator _mi = bitdb.mapFileUseCount.find(strFile); + if (_mi != bitdb.mapFileUseCount.end()) { LogPrint("db", "Flushing %s\n", strFile); nLastFlushed = nWalletDBUpdated; @@ -904,7 +897,7 @@ void ThreadFlushWalletDB(const string& strFile) bitdb.CloseDb(strFile); bitdb.CheckpointLSN(strFile); - bitdb.mapFileUseCount.erase(mi++); + bitdb.mapFileUseCount.erase(_mi++); LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); } } @@ -947,7 +940,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe } LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size()); - boost::scoped_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0)); + std::unique_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0)); int ret = pdbCopy->open(NULL, // Txn pointer filename.c_str(), // Filename "main", // Logical db name diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h index 22f02a3d0d..751ded3957 100644 --- a/src/zmq/zmqpublishnotifier.h +++ b/src/zmq/zmqpublishnotifier.h @@ -12,7 +12,7 @@ class CBlockIndex; class CZMQAbstractPublishNotifier : public CZMQAbstractNotifier { private: - uint32_t nSequence; //! upcounting per message sequence number + uint32_t nSequence; //!< upcounting per message sequence number public: |