diff options
131 files changed, 1871 insertions, 1007 deletions
diff --git a/.travis.yml b/.travis.yml index 0b38fd45fe..d201cea732 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ env: # No wallet - HOST=x86_64-unknown-linux-gnu PACKAGES="python3" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" # Cross-Mac - - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy" + - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy" before_install: - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 62ebc7917a..fd1a912c4f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,6 +87,15 @@ before it will be merged. The basic squashing workflow is shown below. # save and quit git push -f # (force push to GitHub) +If you have problems with squashing (or other workflows with `git`), you can +alternatively enable "Allow edits from maintainers" in the right GitHub +sidebar and ask for help in the pull request. + +Please refrain from creating several pull requests for the same change. +Use the pull request that is already open (or was created earlier) to amend +changes. This preserves the discussion and review that happened earlier for +the respective change set. + The length of time required for peer review is unpredictable and will vary from pull request to pull request. @@ -198,3 +207,11 @@ Release Policy -------------- The project leader is the release manager for each Bitcoin Core release. + +Copyright +--------- + +By contributing to this repository, you agree to license your work under the +MIT license unless specified otherwise in `contrib/debian/copyright` or at +the top of the file itself. Any work contributed where you are not the original +author must contain its license header with the original author(s) and source. diff --git a/configure.ac b/configure.ac index 25b828f18c..97f44f269b 100644 --- a/configure.ac +++ b/configure.ac @@ -482,6 +482,7 @@ if test x$use_hardening != xno; then AX_CHECK_LINK_FLAG([[-Wl,--dynamicbase]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--dynamicbase"]) AX_CHECK_LINK_FLAG([[-Wl,--nxcompat]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--nxcompat"]) + AX_CHECK_LINK_FLAG([[-Wl,--high-entropy-va]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--high-entropy-va"]) AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"]) AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"]) diff --git a/contrib/README.md b/contrib/README.md index 3e3c83da5f..ab5f57587e 100644 --- a/contrib/README.md +++ b/contrib/README.md @@ -1,11 +1,3 @@ -Wallet Tools ---------------------- - -### [SpendFrom](/contrib/spendfrom) ### - -Use the raw transactions API to send coins received on a particular -address (or addresses). - Repository Tools --------------------- diff --git a/contrib/debian/bitcoin-qt.manpages b/contrib/debian/bitcoin-qt.manpages new file mode 100644 index 0000000000..9a3cc31c09 --- /dev/null +++ b/contrib/debian/bitcoin-qt.manpages @@ -0,0 +1 @@ +doc/man/bitcoin-qt.1 diff --git a/contrib/debian/bitcoin-tx.manpages b/contrib/debian/bitcoin-tx.manpages new file mode 100644 index 0000000000..861d49d070 --- /dev/null +++ b/contrib/debian/bitcoin-tx.manpages @@ -0,0 +1 @@ +doc/man/bitcoin-tx.1 diff --git a/contrib/debian/bitcoind.manpages b/contrib/debian/bitcoind.manpages index 6d3e683855..bab644ece1 100644 --- a/contrib/debian/bitcoind.manpages +++ b/contrib/debian/bitcoind.manpages @@ -1,3 +1,2 @@ -debian/manpages/bitcoind.1 -debian/manpages/bitcoin.conf.5 -debian/manpages/bitcoin-cli.1 +doc/man/bitcoind.1 +doc/man/bitcoin-cli.1 diff --git a/contrib/debian/copyright b/contrib/debian/copyright index cc4606ca88..5cac6e533c 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -15,10 +15,6 @@ Copyright: 2010-2011, Jonas Smedegaard <dr@jones.dk> 2011, Matt Corallo <matt@bluematt.me> License: GPL-2+ -Files: debian/manpages/* -Copyright: Micah Anderson <micah@debian.org> -License: GPL-3+ - Files: src/qt/res/icons/add.png src/qt/res/icons/address-book.png src/qt/res/icons/chevron.png diff --git a/contrib/debian/manpages/bitcoin-cli.1 b/contrib/debian/manpages/bitcoin-cli.1 deleted file mode 100644 index 16c338dd3e..0000000000 --- a/contrib/debian/manpages/bitcoin-cli.1 +++ /dev/null @@ -1,21 +0,0 @@ -.TH BITCOIN-CLI "1" "February 2016" "bitcoin-cli 0.12" -.SH NAME -bitcoin-cli \- a remote procedure call client for Bitcoin Core. -.SH SYNOPSIS -bitcoin-cli [options] <command> [params] \- Send command to Bitcoin Core. -.TP -bitcoin-cli [options] help \- Asks Bitcoin Core for a list of supported commands. -.SH DESCRIPTION -This manual page documents the bitcoin-cli program. bitcoin-cli is an RPC client used to send commands to Bitcoin Core. - -.SH OPTIONS -.TP -\fB\-?\fR -Show possible options. - -.SH "SEE ALSO" -\fBbitcoind\fP, \fBbitcoin.conf\fP -.SH AUTHOR -This manual page was written by Ciemon Dunville <ciemon@gmail.com>. Permission is granted to copy, distribute and/or modify this document under the terms of the MIT License. - -The complete text of the MIT License can be found on the web at \fIhttp://opensource.org/licenses/MIT\fP. diff --git a/contrib/debian/manpages/bitcoin-qt.1 b/contrib/debian/manpages/bitcoin-qt.1 deleted file mode 100644 index 685a282080..0000000000 --- a/contrib/debian/manpages/bitcoin-qt.1 +++ /dev/null @@ -1,13 +0,0 @@ -.TH BITCOIN-QT "1" "February 2016" "bitcoin-qt 0.12" -.SH NAME -bitcoin-qt \- peer-to-peer network based digital currency -.SH DESCRIPTION -.SS "Usage:" -.IP -bitcoin\-qt [command\-line options] -.SH OPTIONS -.TP -\-? -List options. -.SH "SEE ALSO" -bitcoind(1) diff --git a/contrib/debian/manpages/bitcoin.conf.5 b/contrib/debian/manpages/bitcoin.conf.5 deleted file mode 100644 index 839dc26c1a..0000000000 --- a/contrib/debian/manpages/bitcoin.conf.5 +++ /dev/null @@ -1,19 +0,0 @@ -.TH BITCOIN.CONF "5" "February 2016" "bitcoin.conf 0.12" -.SH NAME -bitcoin.conf \- bitcoin configuration file -.SH SYNOPSIS -All command-line options (except for '\-conf') may be specified in a configuration file, and all configuration file options may also be specified on the command line. Command-line options override values set in the configuration file. -.TP -The configuration file is a list of 'setting=value' pairs, one per line, with optional comments starting with the '#' character. Please refer to bitcoind(1) for a up to date list of valid options. -.TP -The configuration file is not automatically created; you can create it using your favorite plain-text editor. By default, bitcoind(1) will look for a file named bitcoin.conf(5) in the bitcoin data directory, but both the data directory and the configuration file path may be changed using the '\-datadir' and '\-conf' command-line arguments. -.SH LOCATION -bitcoin.conf should be located in $HOME/.bitcoin - -.SH "SEE ALSO" -bitcoind(1) -.SH AUTHOR -This manual page was written by Micah Anderson <micah@debian.org> for the Debian system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. - -On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. - diff --git a/contrib/debian/manpages/bitcoind.1 b/contrib/debian/manpages/bitcoind.1 deleted file mode 100644 index 5c3e52f441..0000000000 --- a/contrib/debian/manpages/bitcoind.1 +++ /dev/null @@ -1,30 +0,0 @@ -.TH BITCOIND "1" "February 2016" "bitcoind 0.12" -.SH NAME -bitcoind \- peer-to-peer network based digital currency -.SH SYNOPSIS -bitcoin [options] <command> [params] -.TP -bitcoin [options] help <command> \- Get help for a command -.SH DESCRIPTION -This manual page documents the bitcoind program. Bitcoin is an experimental new digital currency that enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate with no central authority: managing transactions and issuing money are carried out collectively by the network. Bitcoin Core is the name of open source software which enables the use of this currency. - -.SH OPTIONS -.TP -\-? -List of possible options. -.SH COMMANDS -.TP -\fBhelp\fR -List commands. - -.TP -\fBhelp 'command'\fR -Get help for a command. - -.SH "SEE ALSO" -bitcoin.conf(5) -.SH AUTHOR -This manual page was written by Micah Anderson <micah@debian.org> for the Debian system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 or any later version published by the Free Software Foundation. - -On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. - diff --git a/contrib/debian/rules b/contrib/debian/rules index 52b357cf01..3896d2caa3 100755 --- a/contrib/debian/rules +++ b/contrib/debian/rules @@ -5,9 +5,6 @@ #build/bitcoind:: # $(if $(filter nocheck,$(DEB_BUILD_OPTIONS)),,src/test_bitcoin) -DEB_INSTALL_EXAMPLES_bitcoind += debian/examples/* -DEB_INSTALL_MANPAGES_bitcoind += debian/manpages/* - %: dh --with bash-completion $@ diff --git a/contrib/devtools/git-subtree-check.sh b/contrib/devtools/git-subtree-check.sh index 1cb82fe682..2384d66cad 100755 --- a/contrib/devtools/git-subtree-check.sh +++ b/contrib/devtools/git-subtree-check.sh @@ -1,4 +1,7 @@ #!/bin/sh +# Copyright (c) 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. DIR="$1" COMMIT="$2" diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py index 799e0cc7d0..b7b8dc0082 100755 --- a/contrib/devtools/optimize-pngs.py +++ b/contrib/devtools/optimize-pngs.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (c) 2014-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. ''' Run this script every time you change one of the png files. Using pngcrush, it will optimize the png files, remove various color profiles, remove ancillary chunks (alla) and text chunks (text). #pngcrush -brute -ow -rem gAMA -rem cHRM -rem iCCP -rem sRGB -rem alla -rem text diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index c61d652641..c90541e271 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (c) 2015-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. ''' Perform basic ELF security checks on a series of executables. Exit status will be 0 if successful, and the program will be silent. @@ -12,6 +15,7 @@ import os READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump') +NONFATAL = {'HIGH_ENTROPY_VA'} # checks which are non-fatal for now but only generate a warning def check_ELF_PIE(executable): ''' @@ -114,26 +118,50 @@ def check_ELF_Canary(executable): def get_PE_dll_characteristics(executable): ''' - Get PE DllCharacteristics bits + Get PE DllCharacteristics bits. + Returns a tuple (arch,bits) where arch is 'i386:x86-64' or 'i386' + and bits is the DllCharacteristics value. ''' p = subprocess.Popen([OBJDUMP_CMD, '-x', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) (stdout, stderr) = p.communicate() if p.returncode: raise IOError('Error opening file') + arch = '' + bits = 0 for line in stdout.split('\n'): tokens = line.split() + if len(tokens)>=2 and tokens[0] == 'architecture:': + arch = tokens[1].rstrip(',') if len(tokens)>=2 and tokens[0] == 'DllCharacteristics': - return int(tokens[1],16) - return 0 + bits = int(tokens[1],16) + return (arch,bits) +IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020 +IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040 +IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100 -def check_PE_PIE(executable): +def check_PE_DYNAMIC_BASE(executable): '''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)''' - return bool(get_PE_dll_characteristics(executable) & 0x40) + (arch,bits) = get_PE_dll_characteristics(executable) + reqbits = IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE + return (bits & reqbits) == reqbits + +# On 64 bit, must support high-entropy 64-bit address space layout randomization in addition to DYNAMIC_BASE +# to have secure ASLR. +def check_PE_HIGH_ENTROPY_VA(executable): + '''PIE: DllCharacteristics bit 0x20 signifies high-entropy ASLR''' + (arch,bits) = get_PE_dll_characteristics(executable) + if arch == 'i386:x86-64': + reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA + else: # Unnecessary on 32-bit + assert(arch == 'i386') + reqbits = 0 + return (bits & reqbits) == reqbits def check_PE_NX(executable): '''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)''' - return bool(get_PE_dll_characteristics(executable) & 0x100) + (arch,bits) = get_PE_dll_characteristics(executable) + return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT CHECKS = { 'ELF': [ @@ -143,7 +171,8 @@ CHECKS = { ('Canary', check_ELF_Canary) ], 'PE': [ - ('PIE', check_PE_PIE), + ('DYNAMIC_BASE', check_PE_DYNAMIC_BASE), + ('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA), ('NX', check_PE_NX) ] } @@ -168,12 +197,18 @@ if __name__ == '__main__': continue failed = [] + warning = [] for (name, func) in CHECKS[etype]: if not func(filename): - failed.append(name) + if name in NONFATAL: + warning.append(name) + else: + failed.append(name) if failed: print('%s: failed %s' % (filename, ' '.join(failed))) retval = 1 + if warning: + print('%s: warning %s' % (filename, ' '.join(warning))) except IOError: print('%s: cannot open' % filename) retval = 1 diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index 324b7bcd85..c0f120392e 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -1,4 +1,7 @@ #!/usr/bin/env python2 +# Copyright (c) 2015-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. ''' Test script for security-check.py ''' diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh index ee47d138f3..53c24e3a87 100755 --- a/contrib/gitian-build.sh +++ b/contrib/gitian-build.sh @@ -1,3 +1,7 @@ +# 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. + # What to do sign=false verify=false diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh index 781fe315ed..91674a92e6 100755 --- a/contrib/macdeploy/detached-sig-apply.sh +++ b/contrib/macdeploy/detached-sig-apply.sh @@ -1,4 +1,8 @@ #!/bin/sh +# Copyright (c) 2014-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. + set -e UNSIGNED="$1" diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh index 89a2da32f7..5022ea88bc 100755 --- a/contrib/macdeploy/detached-sig-create.sh +++ b/contrib/macdeploy/detached-sig-create.sh @@ -1,4 +1,8 @@ #!/bin/sh +# Copyright (c) 2014-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. + set -e ROOTDIR=dist diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh index 46d2d825d4..ff9fbd58df 100755 --- a/contrib/macdeploy/extract-osx-sdk.sh +++ b/contrib/macdeploy/extract-osx-sdk.sh @@ -1,4 +1,8 @@ #!/bin/bash +# 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. + set -e INPUTFILE="Xcode_7.3.1.dmg" diff --git a/contrib/qos/tc.sh b/contrib/qos/tc.sh index f620604212..aaf5e1fa11 100644 --- a/contrib/qos/tc.sh +++ b/contrib/qos/tc.sh @@ -1,3 +1,7 @@ +# Copyright (c) 2013 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + #network interface on which to limit traffic IF="eth0" #limit of the network interface in question diff --git a/contrib/qt_translations.py b/contrib/qt_translations.py deleted file mode 100755 index fd8a8b7129..0000000000 --- a/contrib/qt_translations.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python - -# Helpful little script that spits out a comma-separated list of -# language codes for Qt icons that should be included -# in binary bitcoin distributions - -import glob -import os -import re -import sys - -if len(sys.argv) != 3: - sys.exit("Usage: %s $QTDIR/translations $BITCOINDIR/src/qt/locale"%sys.argv[0]) - -d1 = sys.argv[1] -d2 = sys.argv[2] - -l1 = set([ re.search(r'qt_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d1, 'qt_*.qm')) ]) -l2 = set([ re.search(r'bitcoin_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d2, 'bitcoin_*.qm')) ]) - -print ",".join(sorted(l1.intersection(l2))) - diff --git a/contrib/rpm/bitcoin.spec b/contrib/rpm/bitcoin.spec index 38ae038180..516f42334e 100644 --- a/contrib/rpm/bitcoin.spec +++ b/contrib/rpm/bitcoin.spec @@ -27,10 +27,9 @@ Source1: http://download.oracle.com/berkeley-db/db-%{bdbv}.NC.tar.gz Source10: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/examples/bitcoin.conf #man pages -Source20: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoind.1 -Source21: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin-cli.1 -Source22: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin-qt.1 -Source23: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/debian/manpages/bitcoin.conf.5 +Source20: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/doc/man/bitcoind.1 +Source21: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/doc/man/bitcoin-cli.1 +Source22: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/doc/man/bitcoin-qt.1 #selinux Source30: https://raw.githubusercontent.com/bitcoin/bitcoin/v%{version}/contrib/rpm/bitcoin.te @@ -306,7 +305,6 @@ install -p %{SOURCE21} %{buildroot}%{_mandir}/man1/bitcoin-cli.1 %if %{_buildqt} install -p %{SOURCE22} %{buildroot}%{_mandir}/man1/bitcoin-qt.1 %endif -install -D -p %{SOURCE23} %{buildroot}%{_mandir}/man5/bitcoin.conf.5 # nuke these, we do extensive testing of binaries in %%check before packaging rm -f %{buildroot}%{_bindir}/test_* @@ -415,7 +413,6 @@ rm -rf %{buildroot} %config(noreplace) %attr(0600,root,root) %{_sysconfdir}/sysconfig/bitcoin %attr(0644,root,root) %{_datadir}/selinux/*/*.pp %attr(0644,root,root) %{_mandir}/man1/bitcoind.1* -%attr(0644,root,root) %{_mandir}/man5/bitcoin.conf.5* %files utils %defattr(-,root,root,-) @@ -425,7 +422,6 @@ rm -rf %{buildroot} %attr(0755,root,root) %{_bindir}/bitcoin-tx %attr(0755,root,root) %{_bindir}/bench_bitcoin %attr(0644,root,root) %{_mandir}/man1/bitcoin-cli.1* -%attr(0644,root,root) %{_mandir}/man5/bitcoin.conf.5* diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index 4072405ef5..041f224f40 100755 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# 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. # # Generate seeds.txt from Pieter's DNS seeder # diff --git a/contrib/spendfrom/README.md b/contrib/spendfrom/README.md deleted file mode 100644 index c0a9c9ccf9..0000000000 --- a/contrib/spendfrom/README.md +++ /dev/null @@ -1,35 +0,0 @@ -### SpendFrom ### - -Use the raw transactions API to send coins received on a particular -address (or addresses). - -### Usage: ### -Depends on [jsonrpc](http://json-rpc.org/). - - spendfrom.py --from=FROMADDRESS1[,FROMADDRESS2] --to=TOADDRESS --amount=amount \ - --fee=fee --datadir=/path/to/.bitcoin --testnet --dry_run - -With no arguments, outputs a list of amounts associated with addresses. - -With arguments, sends coins received by the `FROMADDRESS` addresses to the `TOADDRESS`. - -### Notes ### - -- You may explicitly specify how much fee to pay (a fee more than 1% of the amount -will fail, though, to prevent bitcoin-losing accidents). Spendfrom may fail if -it thinks the transaction would never be confirmed (if the amount being sent is -too small, or if the transaction is too many bytes for the fee). - -- If a change output needs to be created, the change will be sent to the last -`FROMADDRESS` (if you specify just one `FROMADDRESS`, change will go back to it). - -- If `--datadir` is not specified, the default datadir is used. - -- The `--dry_run` option will just create and sign the transaction and print -the transaction data (as hexadecimal), instead of broadcasting it. - -- If the transaction is created and broadcast successfully, a transaction id -is printed. - -- If this was a tool for end-users and not programmers, it would have much friendlier -error-handling. diff --git a/contrib/spendfrom/setup.py b/contrib/spendfrom/setup.py deleted file mode 100644 index 01b9768a5b..0000000000 --- a/contrib/spendfrom/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -from distutils.core import setup -setup(name='btcspendfrom', - version='1.0', - description='Command-line utility for bitcoin "coin control"', - author='Gavin Andresen', - author_email='gavin@bitcoinfoundation.org', - requires=['jsonrpc'], - scripts=['spendfrom.py'], - ) diff --git a/contrib/spendfrom/spendfrom.py b/contrib/spendfrom/spendfrom.py deleted file mode 100755 index 72ee0425eb..0000000000 --- a/contrib/spendfrom/spendfrom.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/env python -# -# Use the raw transactions API to spend bitcoins received on particular addresses, -# and send any change back to that same address. -# -# Example usage: -# spendfrom.py # Lists available funds -# spendfrom.py --from=ADDRESS --to=ADDRESS --amount=11.00 -# -# Assumes it will talk to a bitcoind or Bitcoin-Qt running -# on localhost. -# -# Depends on jsonrpc -# - -from decimal import * -import getpass -import math -import os -import os.path -import platform -import sys -import time -from jsonrpc import ServiceProxy, json - -BASE_FEE=Decimal("0.001") - -def check_json_precision(): - """Make sure json library being used does not lose precision converting BTC values""" - n = Decimal("20000000.00000003") - satoshis = int(json.loads(json.dumps(float(n)))*1.0e8) - if satoshis != 2000000000000003: - raise RuntimeError("JSON encode/decode loses precision") - -def determine_db_dir(): - """Return the default location of the bitcoin data directory""" - if platform.system() == "Darwin": - return os.path.expanduser("~/Library/Application Support/Bitcoin/") - elif platform.system() == "Windows": - return os.path.join(os.environ['APPDATA'], "Bitcoin") - return os.path.expanduser("~/.bitcoin") - -def read_bitcoin_config(dbdir): - """Read the bitcoin.conf file from dbdir, returns dictionary of settings""" - from ConfigParser import SafeConfigParser - - class FakeSecHead(object): - def __init__(self, fp): - self.fp = fp - self.sechead = '[all]\n' - def readline(self): - if self.sechead: - try: return self.sechead - finally: self.sechead = None - else: - s = self.fp.readline() - if s.find('#') != -1: - s = s[0:s.find('#')].strip() +"\n" - return s - - config_parser = SafeConfigParser() - config_parser.readfp(FakeSecHead(open(os.path.join(dbdir, "bitcoin.conf")))) - return dict(config_parser.items("all")) - -def connect_JSON(config): - """Connect to a bitcoin JSON-RPC server""" - testnet = config.get('testnet', '0') - testnet = (int(testnet) > 0) # 0/1 in config file, convert to True/False - if not 'rpcport' in config: - config['rpcport'] = 18332 if testnet else 8332 - connect = "http://%s:%s@127.0.0.1:%s"%(config['rpcuser'], config['rpcpassword'], config['rpcport']) - try: - result = ServiceProxy(connect) - # ServiceProxy is lazy-connect, so send an RPC command mostly to catch connection errors, - # but also make sure the bitcoind we're talking to is/isn't testnet: - if result.getmininginfo()['testnet'] != testnet: - sys.stderr.write("RPC server at "+connect+" testnet setting mismatch\n") - sys.exit(1) - return result - except: - sys.stderr.write("Error connecting to RPC server at "+connect+"\n") - sys.exit(1) - -def unlock_wallet(bitcoind): - info = bitcoind.getinfo() - if 'unlocked_until' not in info: - return True # wallet is not encrypted - t = int(info['unlocked_until']) - if t <= time.time(): - try: - passphrase = getpass.getpass("Wallet is locked; enter passphrase: ") - bitcoind.walletpassphrase(passphrase, 5) - except: - sys.stderr.write("Wrong passphrase\n") - - info = bitcoind.getinfo() - return int(info['unlocked_until']) > time.time() - -def list_available(bitcoind): - address_summary = dict() - - address_to_account = dict() - for info in bitcoind.listreceivedbyaddress(0): - address_to_account[info["address"]] = info["account"] - - unspent = bitcoind.listunspent(0) - for output in unspent: - # listunspent doesn't give addresses, so: - rawtx = bitcoind.getrawtransaction(output['txid'], 1) - vout = rawtx["vout"][output['vout']] - pk = vout["scriptPubKey"] - - # This code only deals with ordinary pay-to-bitcoin-address - # or pay-to-script-hash outputs right now; anything exotic is ignored. - if pk["type"] != "pubkeyhash" and pk["type"] != "scripthash": - continue - - address = pk["addresses"][0] - if address in address_summary: - address_summary[address]["total"] += vout["value"] - address_summary[address]["outputs"].append(output) - else: - address_summary[address] = { - "total" : vout["value"], - "outputs" : [output], - "account" : address_to_account.get(address, "") - } - - return address_summary - -def select_coins(needed, inputs): - # Feel free to improve this, this is good enough for my simple needs: - outputs = [] - have = Decimal("0.0") - n = 0 - while have < needed and n < len(inputs): - outputs.append({ "txid":inputs[n]["txid"], "vout":inputs[n]["vout"]}) - have += inputs[n]["amount"] - n += 1 - return (outputs, have-needed) - -def create_tx(bitcoind, fromaddresses, toaddress, amount, fee): - all_coins = list_available(bitcoind) - - total_available = Decimal("0.0") - needed = amount+fee - potential_inputs = [] - for addr in fromaddresses: - if addr not in all_coins: - continue - potential_inputs.extend(all_coins[addr]["outputs"]) - total_available += all_coins[addr]["total"] - - if total_available < needed: - sys.stderr.write("Error, only %f BTC available, need %f\n"%(total_available, needed)); - sys.exit(1) - - # - # Note: - # Python's json/jsonrpc modules have inconsistent support for Decimal numbers. - # Instead of wrestling with getting json.dumps() (used by jsonrpc) to encode - # Decimals, I'm casting amounts to float before sending them to bitcoind. - # - outputs = { toaddress : float(amount) } - (inputs, change_amount) = select_coins(needed, potential_inputs) - if change_amount > BASE_FEE: # don't bother with zero or tiny change - change_address = fromaddresses[-1] - if change_address in outputs: - outputs[change_address] += float(change_amount) - else: - outputs[change_address] = float(change_amount) - - rawtx = bitcoind.createrawtransaction(inputs, outputs) - signed_rawtx = bitcoind.signrawtransaction(rawtx) - if not signed_rawtx["complete"]: - sys.stderr.write("signrawtransaction failed\n") - sys.exit(1) - txdata = signed_rawtx["hex"] - - return txdata - -def compute_amount_in(bitcoind, txinfo): - result = Decimal("0.0") - for vin in txinfo['vin']: - in_info = bitcoind.getrawtransaction(vin['txid'], 1) - vout = in_info['vout'][vin['vout']] - result = result + vout['value'] - return result - -def compute_amount_out(txinfo): - result = Decimal("0.0") - for vout in txinfo['vout']: - result = result + vout['value'] - return result - -def sanity_test_fee(bitcoind, txdata_hex, max_fee): - class FeeError(RuntimeError): - pass - try: - txinfo = bitcoind.decoderawtransaction(txdata_hex) - total_in = compute_amount_in(bitcoind, txinfo) - total_out = compute_amount_out(txinfo) - if total_in-total_out > max_fee: - raise FeeError("Rejecting transaction, unreasonable fee of "+str(total_in-total_out)) - - tx_size = len(txdata_hex)/2 - kb = tx_size/1000 # integer division rounds down - if kb > 1 and fee < BASE_FEE: - raise FeeError("Rejecting no-fee transaction, larger than 1000 bytes") - if total_in < 0.01 and fee < BASE_FEE: - raise FeeError("Rejecting no-fee, tiny-amount transaction") - # Exercise for the reader: compute transaction priority, and - # warn if this is a very-low-priority transaction - - except FeeError as err: - sys.stderr.write((str(err)+"\n")) - sys.exit(1) - -def main(): - import optparse - - parser = optparse.OptionParser(usage="%prog [options]") - parser.add_option("--from", dest="fromaddresses", default=None, - help="addresses to get bitcoins from") - parser.add_option("--to", dest="to", default=None, - help="address to get send bitcoins to") - parser.add_option("--amount", dest="amount", default=None, - help="amount to send") - parser.add_option("--fee", dest="fee", default="0.0", - help="fee to include") - parser.add_option("--datadir", dest="datadir", default=determine_db_dir(), - help="location of bitcoin.conf file with RPC username/password (default: %default)") - parser.add_option("--testnet", dest="testnet", default=False, action="store_true", - help="Use the test network") - parser.add_option("--dry_run", dest="dry_run", default=False, action="store_true", - help="Don't broadcast the transaction, just create and print the transaction data") - - (options, args) = parser.parse_args() - - check_json_precision() - config = read_bitcoin_config(options.datadir) - if options.testnet: config['testnet'] = True - bitcoind = connect_JSON(config) - - if options.amount is None: - address_summary = list_available(bitcoind) - for address,info in address_summary.iteritems(): - n_transactions = len(info['outputs']) - if n_transactions > 1: - print("%s %.8f %s (%d transactions)"%(address, info['total'], info['account'], n_transactions)) - else: - print("%s %.8f %s"%(address, info['total'], info['account'])) - else: - fee = Decimal(options.fee) - amount = Decimal(options.amount) - while unlock_wallet(bitcoind) == False: - pass # Keep asking for passphrase until they get it right - txdata = create_tx(bitcoind, options.fromaddresses.split(","), options.to, amount, fee) - sanity_test_fee(bitcoind, txdata, amount*Decimal("0.01")) - if options.dry_run: - print(txdata) - else: - txid = bitcoind.sendrawtransaction(txdata) - print(txid) - -if __name__ == '__main__': - main() diff --git a/contrib/testgen/base58.py b/contrib/testgen/base58.py index b716495145..72b288b2dc 100644 --- a/contrib/testgen/base58.py +++ b/contrib/testgen/base58.py @@ -1,3 +1,6 @@ +# Copyright (c) 2012 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' Bitcoin base58 encoding and decoding. diff --git a/contrib/testgen/gen_base58_test_vectors.py b/contrib/testgen/gen_base58_test_vectors.py index 1813436953..8518774db3 100755 --- a/contrib/testgen/gen_base58_test_vectors.py +++ b/contrib/testgen/gen_base58_test_vectors.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (c) 2012 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' Generate valid and invalid base58 address and private key test vectors. diff --git a/contrib/tidy_datadir.sh b/contrib/tidy_datadir.sh index 5d6d826444..8960f8811d 100755 --- a/contrib/tidy_datadir.sh +++ b/contrib/tidy_datadir.sh @@ -1,4 +1,7 @@ #!/bin/bash +# Copyright (c) 2013 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. if [ -d "$1" ]; then cd "$1" diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh index 375d711725..09ff237544 100755 --- a/contrib/verify-commits/gpg.sh +++ b/contrib/verify-commits/gpg.sh @@ -1,4 +1,8 @@ #!/bin/sh +# Copyright (c) 2014-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + INPUT=$(cat /dev/stdin) VALID=false REVSIG=false diff --git a/contrib/verify-commits/pre-push-hook.sh b/contrib/verify-commits/pre-push-hook.sh index c57222818a..c21febb9e9 100755 --- a/contrib/verify-commits/pre-push-hook.sh +++ b/contrib/verify-commits/pre-push-hook.sh @@ -1,4 +1,8 @@ #!/bin/bash +# Copyright (c) 2014-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. + if ! [[ "$2" =~ ^(git@)?(www.)?github.com(:|/)bitcoin/bitcoin(.git)?$ ]]; then exit 0 fi diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh index 5219331e2e..cfe4f11a0b 100755 --- a/contrib/verify-commits/verify-commits.sh +++ b/contrib/verify-commits/verify-commits.sh @@ -1,4 +1,8 @@ #!/bin/sh +# Copyright (c) 2014-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + # Not technically POSIX-compliant due to use of "local", but almost every # shell anyone uses today supports it, so its probably fine diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh index e22b911743..e20770c96a 100755 --- a/contrib/verifybinaries/verify.sh +++ b/contrib/verifybinaries/verify.sh @@ -1,4 +1,7 @@ #!/bin/bash +# 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. ### This script attempts to download the signature file SHA256SUMS.asc from bitcoin.org ### It first checks if the signature passes, and then downloads the files specified in diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py index 6268123dd8..3dea5e3c14 100755 --- a/contrib/zmq/zmq_sub.py +++ b/contrib/zmq/zmq_sub.py @@ -1,4 +1,7 @@ #!/usr/bin/env python2 +# Copyright (c) 2014-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. import array import binascii diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk index bd29275638..81a660e83a 100644 --- a/depends/packages/expat.mk +++ b/depends/packages/expat.mk @@ -1,8 +1,8 @@ package=expat -$(package)_version=2.1.1 +$(package)_version=2.2.0 $(package)_download_path=https://downloads.sourceforge.net/project/expat/expat/$($(package)_version) $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=aff584e5a2f759dcfc6d48671e9529f6afe1e30b0cd6a4cec200cbe3f793de67 +$(package)_sha256_hash=d9e50ff2d19b3538bd2127902a89987474e1a4db8e43a66a4d1a712ab9a504ff define $(package)_set_vars $(package)_config_opts=--disable-static diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk index 2cf553ed96..fb97e0b9ec 100644 --- a/depends/packages/fontconfig.mk +++ b/depends/packages/fontconfig.mk @@ -1,8 +1,8 @@ package=fontconfig -$(package)_version=2.11.1 +$(package)_version=2.12.1 $(package)_download_path=http://www.freedesktop.org/software/fontconfig/release/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=dc62447533bca844463a3c3fd4083b57c90f18a70506e7a9f4936b5a1e516a99 +$(package)_sha256_hash=b449a3e10c47e1d1c7a6ec6e2016cca73d3bd68fbbd4f0ae5cc6b573f7d6c7f3 $(package)_dependencies=freetype expat define $(package)_set_vars diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk index 9216e17598..a3a58604e5 100644 --- a/depends/packages/native_ccache.mk +++ b/depends/packages/native_ccache.mk @@ -1,8 +1,8 @@ package=native_ccache -$(package)_version=3.2.5 -$(package)_download_path=http://samba.org/ftp/ccache +$(package)_version=3.3.1 +$(package)_download_path=https://samba.org/ftp/ccache $(package)_file_name=ccache-$($(package)_version).tar.bz2 -$(package)_sha256_hash=7a553809e90faf9de3a23ee9c5b5f786cfd4836bf502744bedb824a24bee1097 +$(package)_sha256_hash=cb6e4bafbb19ba0a2ec43386b123a5f92a20e1e3384c071d5d13e0cb3c84bf73 define $(package)_set_vars $(package)_config_opts= diff --git a/doc/build-osx.md b/doc/build-osx.md index c9eb4225ab..bc90a30562 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -16,7 +16,7 @@ Then install [Homebrew](http://brew.sh). Dependencies ---------------------- - brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf --c++11 qt5 libevent + brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config homebrew/versions/protobuf260 --c++11 qt5 libevent NOTE: Building with Qt4 is still supported, however, could result in a broken UI. Building with Qt5 is recommended. diff --git a/doc/build-windows.md b/doc/build-windows.md index 129774491b..ec5f26c88b 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -27,6 +27,7 @@ To build executables for Windows 32-bit: cd depends make HOST=i686-w64-mingw32 -j4 cd .. + ./autogen.sh # not required when building from tarball ./configure --prefix=`pwd`/depends/i686-w64-mingw32 make @@ -35,6 +36,7 @@ To build executables for Windows 64-bit: cd depends make HOST=x86_64-w64-mingw32 -j4 cd .. + ./autogen.sh # not required when building from tarball ./configure --prefix=`pwd`/depends/x86_64-w64-mingw32 make diff --git a/doc/gitian-building.md b/doc/gitian-building.md index 938f92ff12..4914d90df4 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -95,14 +95,14 @@ After creating the VM, we need to configure it. - Click `Ok` twice to save. -Get the [Debian 8.x net installer](http://cdimage.debian.org/debian-cd/8.5.0/amd64/iso-cd/debian-8.5.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). -This DVD image can be validated using a SHA256 hashing tool, for example on +Get the [Debian 8.x net installer](http://cdimage.debian.org/mirror/cdimage/archive/8.5.0/amd64/iso-cd/debian-8.5.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). +This DVD image can be [validated](https://www.debian.org/CD/verify) using a SHA256 hashing tool, for example on Unixy OSes by entering the following in a terminal: echo "ad4e8c27c561ad8248d5ebc1d36eb172f884057bfeb2c22ead823f59fa8c3dff debian-8.5.0-amd64-netinst.iso" | sha256sum -c # (must return OK) -Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded iso. +Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded ISO. ![](gitian-building/select_startup_disk.png) @@ -336,8 +336,8 @@ There will be a lot of warnings printed during the build of the image. These can Getting and building the inputs -------------------------------- -Follow the instructions in [doc/release-process.md](release-process.md#fetch-and-build-inputs-first-time-or-when-dependency-versions-change) -in the bitcoin repository under 'Fetch and build inputs' to install sources which require +Follow the instructions in [doc/release-process.md](release-process.md#fetch-and-create-inputs-first-time-or-when-dependency-versions-change) +in the bitcoin repository under 'Fetch and create inputs' to install sources which require manual intervention. Also optionally follow the next step: 'Seed the Gitian sources cache and offline git repositories' which will fetch the remaining files required for building offline. diff --git a/doc/release-process.md b/doc/release-process.md index 394b159b31..04d9473c20 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -5,6 +5,8 @@ Before every release candidate: * Update translations (ping wumpus on IRC) see [translation_process.md](https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md#synchronising-translations). +* Update manpages, see [gen-manpages.sh](https://github.com/bitcoin/bitcoin/blob/master/contrib/devtools/README.md#gen-manpagessh). + Before every minor and major release: * Update [bips.md](bips.md) to account for changes since the last release. diff --git a/doc/translation_process.md b/doc/translation_process.md index a443a16fe2..9e9ced2457 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -6,7 +6,7 @@ The Bitcoin-Core project has been designed to support multiple localisations. Th ### Helping to translate (using Transifex) Transifex is setup to monitor the Github repo for updates, and when code containing new translations is found, Transifex will process any changes. It may take several hours after a pull-request has been merged, to appear in the Transifex web interface. -Multiple language support is critical in assisting Bitcoin’s global adoption, and growth. One of Bitcoin’s greatest strengths is cross-boarder money transfers, any help making that easier is greatly appreciated. +Multiple language support is critical in assisting Bitcoin’s global adoption, and growth. One of Bitcoin’s greatest strengths is cross-border money transfers, any help making that easier is greatly appreciated. See the [Transifex Bitcoin project](https://www.transifex.com/projects/p/bitcoin/) to assist in translations. You should also join the translation mailing list for announcements - see details below. diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 771f6c7a0f..4a953385e0 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -143,6 +143,7 @@ testScripts = [ 'importprunedfunds.py', 'signmessages.py', 'p2p-compactblocks.py', + 'nulldummy.py', ] if ENABLE_ZMQ: testScripts.append('zmq_test.py') @@ -215,8 +216,8 @@ def runtests(): time_sum += duration print('\n' + BOLD[1] + name + BOLD[0] + ":") - print(stdout) - print('stderr:\n' if not stderr == '' else '', stderr) + print('' if passed else stdout + '\n', end='') + print('' if stderr == '' else 'stderr:\n' + stderr + '\n', end='') results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration) print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration)) results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0] @@ -251,21 +252,27 @@ class RPCTestHandler: self.num_running += 1 t = self.test_list.pop(0) port_seed = ["--portseed=%s" % len(self.test_list)] + log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16) + log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) self.jobs.append((t, time.time(), subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags + port_seed, universal_newlines=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE))) + stdout=log_stdout, + stderr=log_stderr), + log_stdout, + log_stderr)) if not self.jobs: raise IndexError('pop from empty list') while True: # Return first proc that finishes time.sleep(.5) for j in self.jobs: - (name, time0, proc) = j + (name, time0, proc, log_out, log_err) = j if proc.poll() is not None: - (stdout, stderr) = proc.communicate(timeout=3) + log_out.seek(0), log_err.seek(0) + [stdout, stderr] = [l.read().decode('utf-8') for l in (log_out, log_err)] + log_out.close(), log_err.close() passed = stderr == "" and proc.returncode == 0 self.num_running -= 1 self.jobs.remove(j) diff --git a/qa/rpc-tests/create_cache.py b/qa/rpc-tests/create_cache.py index b6161e0917..1ace6310d0 100755 --- a/qa/rpc-tests/create_cache.py +++ b/qa/rpc-tests/create_cache.py @@ -12,9 +12,15 @@ from test_framework.test_framework import BitcoinTestFramework class CreateCache(BitcoinTestFramework): + def __init__(self): + super().__init__() + + # Test network and test nodes are not required: + self.num_nodes = 0 + self.nodes = [] + def setup_network(self): - # Don't setup any test nodes - self.options.noshutdown = True + pass def run_test(self): pass diff --git a/qa/rpc-tests/nulldummy.py b/qa/rpc-tests/nulldummy.py new file mode 100755 index 0000000000..eaed7a8c78 --- /dev/null +++ b/qa/rpc-tests/nulldummy.py @@ -0,0 +1,148 @@ +#!/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 ComparisonTestFramework +from test_framework.util import * +from test_framework.mininode import CTransaction, NetworkThread +from test_framework.blocktools import create_coinbase, create_block, add_witness_commitment +from test_framework.comptool import TestManager +from test_framework.script import CScript +from io import BytesIO +import time + +NULLDUMMY_ERROR = "64: non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)" + +def trueDummy(tx): + scriptSig = CScript(tx.vin[0].scriptSig) + newscript = [] + for i in scriptSig: + if (len(newscript) == 0): + assert(len(i) == 0) + newscript.append(b'\x51') + else: + newscript.append(i) + tx.vin[0].scriptSig = CScript(newscript) + tx.rehash() + +''' +This test is meant to exercise NULLDUMMY softfork. +Connect to a single node. +Generate 2 blocks (save the coinbases for later). +Generate 427 more blocks. +[Policy/Consensus] Check that NULLDUMMY compliant transactions are accepted in the 430th block. +[Policy] Check that non-NULLDUMMY transactions are rejected before activation. +[Consensus] Check that the new NULLDUMMY rules are not enforced on the 431st block. +[Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block. +''' + +class NULLDUMMYTest(ComparisonTestFramework): + + def __init__(self): + super().__init__() + self.num_nodes = 1 + + def setup_network(self): + # Must set the blockversion for this test + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, + extra_args=[['-debug', '-whitelist=127.0.0.1', '-walletprematurewitness']]) + + def run_test(self): + self.address = self.nodes[0].getnewaddress() + self.ms_address = self.nodes[0].addmultisigaddress(1,[self.address]) + self.wit_address = self.nodes[0].addwitnessaddress(self.address) + self.wit_ms_address = self.nodes[0].addwitnessaddress(self.ms_address) + + test = TestManager(self, self.options.tmpdir) + test.add_all_connections(self.nodes) + NetworkThread().start() # Start up network handling in another thread + self.coinbase_blocks = self.nodes[0].generate(2) # Block 2 + coinbase_txid = [] + for i in self.coinbase_blocks: + coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0]) + self.nodes[0].generate(427) # Block 429 + self.lastblockhash = self.nodes[0].getbestblockhash() + self.tip = int("0x" + self.lastblockhash, 0) + self.lastblockheight = 429 + self.lastblocktime = int(time.time()) + 429 + + print ("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]") + test1txs = [self.create_transaction(self.nodes[0], coinbase_txid[0], self.ms_address, 49)] + txid1 = self.tx_submit(self.nodes[0], test1txs[0]) + test1txs.append(self.create_transaction(self.nodes[0], txid1, self.ms_address, 48)) + txid2 = self.tx_submit(self.nodes[0], test1txs[1]) + test1txs.append(self.create_transaction(self.nodes[0], coinbase_txid[1], self.wit_ms_address, 49)) + txid3 = self.tx_submit(self.nodes[0], test1txs[2]) + self.block_submit(self.nodes[0], test1txs, False, True) + + print ("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation") + test2tx = self.create_transaction(self.nodes[0], txid2, self.ms_address, 48) + trueDummy(test2tx) + txid4 = self.tx_submit(self.nodes[0], test2tx, NULLDUMMY_ERROR) + + print ("Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]") + self.block_submit(self.nodes[0], [test2tx], False, True) + + print ("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation") + test4tx = self.create_transaction(self.nodes[0], txid4, self.address, 47) + test6txs=[CTransaction(test4tx)] + trueDummy(test4tx) + self.tx_submit(self.nodes[0], test4tx, NULLDUMMY_ERROR) + self.block_submit(self.nodes[0], [test4tx]) + + print ("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation") + test5tx = self.create_transaction(self.nodes[0], txid3, self.wit_address, 48) + test6txs.append(CTransaction(test5tx)) + test5tx.wit.vtxinwit[0].scriptWitness.stack[0] = b'\x01' + self.tx_submit(self.nodes[0], test5tx, NULLDUMMY_ERROR) + self.block_submit(self.nodes[0], [test5tx], True) + + print ("Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]") + for i in test6txs: + self.tx_submit(self.nodes[0], i) + self.block_submit(self.nodes[0], test6txs, True, True) + + + def create_transaction(self, node, txid, to_address, amount): + inputs = [{ "txid" : txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + signresult = node.signrawtransaction(rawtx) + tx = CTransaction() + f = BytesIO(hex_str_to_bytes(signresult['hex'])) + tx.deserialize(f) + return tx + + + def tx_submit(self, node, tx, msg = ""): + tx.rehash() + try: + node.sendrawtransaction(bytes_to_hex_str(tx.serialize_with_witness()), True) + except JSONRPCException as exp: + assert_equal(exp.error["message"], msg) + return tx.hash + + + def block_submit(self, node, txs, witness = False, accept = False): + block = create_block(self.tip, create_coinbase(self.lastblockheight + 1), self.lastblocktime + 1) + block.nVersion = 4 + for tx in txs: + tx.rehash() + block.vtx.append(tx) + block.hashMerkleRoot = block.calc_merkle_root() + witness and add_witness_commitment(block) + block.rehash() + block.solve() + node.submitblock(bytes_to_hex_str(block.serialize(True))) + if (accept): + assert_equal(node.getbestblockhash(), block.hash) + self.tip = block.sha256 + self.lastblockhash = block.hash + self.lastblocktime += 1 + self.lastblockheight += 1 + else: + assert_equal(node.getbestblockhash(), self.lastblockhash) + +if __name__ == '__main__': + NULLDUMMYTest().main()
\ No newline at end of file diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index 7fe7ecc16c..bf4fb43add 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -78,6 +78,13 @@ class TestNode(SingleNodeConnCB): headers_message.headers = [CBlockHeader(b) for b in new_blocks] self.send_message(headers_message) + def request_headers_and_sync(self, locator, hashstop=0): + self.clear_block_announcement() + self.get_headers(locator, hashstop) + assert(wait_until(self.received_block_announcement, timeout=30)) + assert(self.received_block_announcement()) + self.clear_block_announcement() + class CompactBlocksTest(BitcoinTestFramework): def __init__(self): @@ -130,7 +137,7 @@ class CompactBlocksTest(BitcoinTestFramework): # Test "sendcmpct": # - No compact block announcements or getdata(MSG_CMPCT_BLOCK) unless # sendcmpct is sent. - # - If sendcmpct is sent with version > 0, the message is ignored. + # - If sendcmpct is sent with version > 1, the message is ignored. # - If sendcmpct is sent with boolean 0, then block announcements are not # made with compact blocks. # - If sendcmpct is then sent with boolean 1, then new block announcements @@ -142,57 +149,66 @@ class CompactBlocksTest(BitcoinTestFramework): def received_sendcmpct(): return (self.test_node.last_sendcmpct is not None) got_message = wait_until(received_sendcmpct, timeout=30) + assert(received_sendcmpct()) assert(got_message) assert_equal(self.test_node.last_sendcmpct.version, 1) tip = int(self.nodes[0].getbestblockhash(), 16) def check_announcement_of_new_block(node, peer, predicate): - self.test_node.clear_block_announcement() + peer.clear_block_announcement() node.generate(1) - got_message = wait_until(peer.received_block_announcement, timeout=30) + got_message = wait_until(lambda: peer.block_announced, timeout=30) + assert(peer.block_announced) assert(got_message) with mininode_lock: - assert(predicate) + assert(predicate(peer)) # We shouldn't get any block announcements via cmpctblock yet. - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None) # Try one more time, this time after requesting headers. - self.test_node.clear_block_announcement() - self.test_node.get_headers(locator=[tip], hashstop=0) - wait_until(self.test_node.received_block_announcement, timeout=30) - self.test_node.clear_block_announcement() + self.test_node.request_headers_and_sync(locator=[tip]) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None and p.last_inv is not None) - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None and self.test_node.last_inv is not None) + # Test a few ways of using sendcmpct that should NOT + # result in compact block announcements. + # Before each test, sync the headers chain. + self.test_node.request_headers_and_sync(locator=[tip]) # Now try a SENDCMPCT message with too-high version sendcmpct = msg_sendcmpct() sendcmpct.version = 2 - self.test_node.send_message(sendcmpct) + self.test_node.send_and_ping(sendcmpct) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None) - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None) + # Headers sync before next test. + self.test_node.request_headers_and_sync(locator=[tip]) # Now try a SENDCMPCT message with valid version, but announce=False - self.test_node.send_message(msg_sendcmpct()) - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None) + self.test_node.send_and_ping(msg_sendcmpct()) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None) + + # Headers sync before next test. + self.test_node.request_headers_and_sync(locator=[tip]) # Finally, try a SENDCMPCT message with announce=True sendcmpct.version = 1 sendcmpct.announce = True - self.test_node.send_message(sendcmpct) - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is not None) + self.test_node.send_and_ping(sendcmpct) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is not None) - # Try one more time - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is not None) + # Try one more time (no headers sync should be needed!) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is not None) # Try one more time, after turning on sendheaders - self.test_node.send_message(msg_sendheaders()) - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is not None) + self.test_node.send_and_ping(msg_sendheaders()) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is not None) # Now turn off announcements sendcmpct.announce = False - check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None and self.test_node.last_headers is not None) + self.test_node.send_and_ping(sendcmpct) + check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None and p.last_headers is not None) # This test actually causes bitcoind to (reasonably!) disconnect us, so do this last. def test_invalid_cmpctblock_message(self): diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/qa/rpc-tests/p2p-versionbits-warning.py index 962cafef0b..00dbbc02cf 100755 --- a/qa/rpc-tests/p2p-versionbits-warning.py +++ b/qa/rpc-tests/p2p-versionbits-warning.py @@ -6,6 +6,7 @@ from test_framework.mininode import * from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * +import re import time from test_framework.blocktools import create_block, create_coinbase @@ -21,6 +22,10 @@ VB_THRESHOLD = 108 # versionbits activation threshold for regtest VB_TOP_BITS = 0x20000000 VB_UNKNOWN_BIT = 27 # Choose a bit unassigned to any deployment +WARN_UNKNOWN_RULES_MINED = "Unknown block versions being mined! It's possible unknown rules are in effect" +WARN_UNKNOWN_RULES_ACTIVE = "unknown new rules activated (versionbit {})".format(VB_UNKNOWN_BIT) +VB_PATTERN = re.compile("^Warning.*versionbit") + # TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending # p2p messages to a node, generating the messages in the main testing logic. class TestNode(NodeConnCB): @@ -65,16 +70,12 @@ class VersionBitsWarningTest(BitcoinTestFramework): self.num_nodes = 1 def setup_network(self): - self.nodes = [] self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") # Open and close to create zero-length file - with open(self.alert_filename, 'w') as f: + with open(self.alert_filename, 'w') as _: pass - self.node_options = ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""] - self.nodes.append(start_node(0, self.options.tmpdir, self.node_options)) - - import re - self.vb_pattern = re.compile("^Warning.*versionbit") + self.extra_args = [["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]] + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) # Send numblocks blocks via peer with nVersionToUse set. def send_blocks_with_version(self, peer, numblocks, nVersionToUse): @@ -83,7 +84,7 @@ class VersionBitsWarningTest(BitcoinTestFramework): block_time = self.nodes[0].getblockheader(tip)["time"]+1 tip = int(tip, 16) - for i in range(numblocks): + for _ in range(numblocks): block = create_block(tip, create_coinbase(height+1), block_time) block.nVersion = nVersionToUse block.solve() @@ -96,7 +97,7 @@ class VersionBitsWarningTest(BitcoinTestFramework): def test_versionbits_in_alert_file(self): with open(self.alert_filename, 'r') as f: alert_text = f.read() - assert(self.vb_pattern.match(alert_text)) + assert(VB_PATTERN.match(alert_text)) def run_test(self): # Setup the p2p connection and start up the network thread. @@ -122,8 +123,10 @@ class VersionBitsWarningTest(BitcoinTestFramework): # Fill rest of period with regular version blocks self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD + 1) # Check that we're not getting any versionbit-related errors in - # getinfo() - assert(not self.vb_pattern.match(self.nodes[0].getinfo()["errors"])) + # get*info() + assert(not VB_PATTERN.match(self.nodes[0].getinfo()["errors"])) + assert(not VB_PATTERN.match(self.nodes[0].getmininginfo()["errors"])) + assert(not VB_PATTERN.match(self.nodes[0].getnetworkinfo()["warnings"])) # 3. Now build one period of blocks with >= VB_THRESHOLD blocks signaling # some unknown bit @@ -132,8 +135,10 @@ class VersionBitsWarningTest(BitcoinTestFramework): # Might not get a versionbits-related alert yet, as we should # have gotten a different alert due to more than 51/100 blocks # being of unexpected version. - # Check that getinfo() shows some kind of error. - assert(len(self.nodes[0].getinfo()["errors"]) != 0) + # Check that get*info() shows some kind of error. + assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getinfo()["errors"]) + assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getmininginfo()["errors"]) + assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getnetworkinfo()["warnings"]) # Mine a period worth of expected blocks so the generic block-version warning # is cleared, and restart the node. This should move the versionbit state @@ -142,20 +147,21 @@ class VersionBitsWarningTest(BitcoinTestFramework): stop_node(self.nodes[0], 0) wait_bitcoinds() # Empty out the alert file - with open(self.alert_filename, 'w') as f: + with open(self.alert_filename, 'w') as _: pass - self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]) + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) # Connecting one block should be enough to generate an error. self.nodes[0].generate(1) - assert(len(self.nodes[0].getinfo()["errors"]) != 0) + assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getinfo()["errors"]) + assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getmininginfo()["errors"]) + assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getnetworkinfo()["warnings"]) stop_node(self.nodes[0], 0) wait_bitcoinds() self.test_versionbits_in_alert_file() # Test framework expects the node to still be running... - self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]) - + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) if __name__ == '__main__': VersionBitsWarningTest().main() diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py index 3ac32140ba..085024e268 100755 --- a/qa/rpc-tests/rpcbind_test.py +++ b/qa/rpc-tests/rpcbind_test.py @@ -44,7 +44,7 @@ class RPCBindTest(BitcoinTestFramework): def run_allowip_test(self, allow_ips, rpchost, rpcport): ''' - Start a node with rpcwallow IP, and request getinfo + Start a node with rpcallow IP, and request getnetworkinfo at a non-localhost IP. ''' base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] @@ -52,7 +52,7 @@ class RPCBindTest(BitcoinTestFramework): try: # connect to node through non-loopback interface node = get_rpc_proxy(rpc_url(0, "%s:%d" % (rpchost, rpcport)), 0) - node.getinfo() + node.getnetworkinfo() finally: node = None # make sure connection will be garbage collected and closed stop_nodes(self.nodes) diff --git a/qa/rpc-tests/test_framework/blockstore.py b/qa/rpc-tests/test_framework/blockstore.py index 6120dd574b..1e2bbb277a 100644 --- a/qa/rpc-tests/test_framework/blockstore.py +++ b/qa/rpc-tests/test_framework/blockstore.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 +# Copyright (c) 2015-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. # BlockStore: a helper class that keeps a map of blocks and implements # helper functions for responding to getheaders and getdata, # and for constructing a getheaders message diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 5d96e7a6e5..3420be1a2e 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -18,9 +18,10 @@ class WalletTest (BitcoinTestFramework): super().__init__() self.setup_clean_chain = True self.num_nodes = 4 + self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] def setup_network(self, split=False): - self.nodes = start_nodes(3, self.options.tmpdir) + self.nodes = start_nodes(3, self.options.tmpdir, self.extra_args[:3]) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) @@ -154,7 +155,7 @@ class WalletTest (BitcoinTestFramework): txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) sync_mempools(self.nodes) - self.nodes.append(start_node(3, self.options.tmpdir)) + self.nodes.append(start_node(3, self.options.tmpdir, self.extra_args[3])) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py index b991d5c761..e12cb10a50 100755 --- a/qa/rpc-tests/walletbackup.py +++ b/qa/rpc-tests/walletbackup.py @@ -45,12 +45,12 @@ class WalletBackupTest(BitcoinTestFramework): super().__init__() self.setup_clean_chain = True self.num_nodes = 4 + # nodes 1, 2,3 are spenders, let's give them a keypool=100 + self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []] # This mirrors how the network was setup in the bash test def setup_network(self, split=False): - # nodes 1, 2,3 are spenders, let's give them a keypool=100 - extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []] - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) connect_nodes(self.nodes[0], 3) connect_nodes(self.nodes[1], 3) connect_nodes(self.nodes[2], 3) @@ -79,6 +79,7 @@ class WalletBackupTest(BitcoinTestFramework): # Must sync mempools before mining. sync_mempools(self.nodes) self.nodes[3].generate(1) + sync_blocks(self.nodes) # As above, this mirrors the original bash test. def start_three(self): diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py index 9624abf1fc..92e0df259e 100755 --- a/share/qt/extract_strings_qt.py +++ b/share/qt/extract_strings_qt.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +# Copyright (c) 2012-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. ''' Extract _("...") strings for translation and convert to Qt stringdefs so that they can be picked up by Qt linguist. diff --git a/share/qt/protobuf.pri b/share/qt/protobuf.pri deleted file mode 100644 index 865fe86555..0000000000 --- a/share/qt/protobuf.pri +++ /dev/null @@ -1,35 +0,0 @@ -# Based on: http://code.google.com/p/ostinato/source/browse/protobuf.pri -# -# Qt qmake integration with Google Protocol Buffers compiler protoc -# -# To compile protocol buffers with qt qmake, specify PROTOS variable and -# include this file -# -# Example: -# PROTOS = a.proto b.proto -# include(protobuf.pri) -# -# Set PROTO_PATH if you need to set the protoc --proto_path search path -# Set PROTOC to the path to the protoc compiler if it is not in your $PATH -# - -isEmpty(PROTO_DIR):PROTO_DIR = . -isEmpty(PROTOC):PROTOC = protoc - -PROTOPATHS = -for(p, PROTO_PATH):PROTOPATHS += --proto_path=$${p} - -protobuf_decl.name = protobuf header -protobuf_decl.input = PROTOS -protobuf_decl.output = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.h -protobuf_decl.commands = $${PROTOC} --cpp_out="$${PROTO_DIR}" $${PROTOPATHS} --proto_path=${QMAKE_FILE_IN_PATH} ${QMAKE_FILE_NAME} -protobuf_decl.variable_out = GENERATED_FILES -QMAKE_EXTRA_COMPILERS += protobuf_decl - -protobuf_impl.name = protobuf implementation -protobuf_impl.input = PROTOS -protobuf_impl.output = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.cc -protobuf_impl.depends = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.h -protobuf_impl.commands = $$escape_expand(\\n) -protobuf_impl.variable_out = GENERATED_SOURCES -QMAKE_EXTRA_COMPILERS += protobuf_impl diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 8947aeaca0..ea9be82717 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -96,6 +96,7 @@ QT_FORMS_UI = \ qt/forms/editaddressdialog.ui \ qt/forms/helpmessagedialog.ui \ qt/forms/intro.ui \ + qt/forms/modaloverlay.ui \ qt/forms/openuridialog.ui \ qt/forms/optionsdialog.ui \ qt/forms/overviewpage.ui \ @@ -125,6 +126,7 @@ QT_MOC_CPP = \ qt/moc_intro.cpp \ qt/moc_macdockiconhandler.cpp \ qt/moc_macnotificationhandler.cpp \ + qt/moc_modaloverlay.cpp \ qt/moc_notificator.cpp \ qt/moc_openuridialog.cpp \ qt/moc_optionsdialog.cpp \ @@ -192,6 +194,7 @@ BITCOIN_QT_H = \ qt/intro.h \ qt/macdockiconhandler.h \ qt/macnotificationhandler.h \ + qt/modaloverlay.h \ qt/networkstyle.h \ qt/notificator.h \ qt/openuridialog.h \ @@ -292,6 +295,7 @@ BITCOIN_QT_CPP = \ qt/csvmodelwriter.cpp \ qt/guiutil.cpp \ qt/intro.cpp \ + qt/modaloverlay.cpp \ qt/networkstyle.cpp \ qt/notificator.cpp \ qt/optionsdialog.cpp \ diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 813a343ffa..0a7efb5d5b 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -1,13 +1,16 @@ bin_PROGRAMS += qt/test/test_bitcoin-qt TESTS += qt/test/test_bitcoin-qt -TEST_QT_MOC_CPP = qt/test/moc_uritests.cpp +TEST_QT_MOC_CPP = \ + qt/test/moc_rpcnestedtests.cpp \ + qt/test/moc_uritests.cpp if ENABLE_WALLET TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp endif TEST_QT_H = \ + qt/test/rpcnestedtests.h \ qt/test/uritests.h \ qt/test/paymentrequestdata.h \ qt/test/paymentservertests.h @@ -16,6 +19,7 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) qt_test_test_bitcoin_qt_SOURCES = \ + qt/test/rpcnestedtests.cpp \ qt/test/test_main.cpp \ qt/test/uritests.cpp \ $(TEST_QT_H) diff --git a/src/addrman.cpp b/src/addrman.cpp index cebb1c8e5e..bfb8e94575 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -255,6 +255,11 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP int nId; CAddrInfo* pinfo = Find(addr, &nId); + // Do not set a penality for a source's self-announcement + if (addr == source) { + nTimePenalty = 0; + } + if (pinfo) { // periodically update nTime bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index a04101d3ed..68f5d90f51 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -116,17 +116,42 @@ static bool AppInitRPC(int argc, char* argv[]) /** Reply structure for request_done to fill in */ struct HTTPReply { + HTTPReply(): status(0), error(-1) {} + int status; + int error; std::string body; }; +const char *http_errorstring(int code) +{ + switch(code) { +#if LIBEVENT_VERSION_NUMBER >= 0x02010300 + case EVREQ_HTTP_TIMEOUT: + return "timeout reached"; + case EVREQ_HTTP_EOF: + return "EOF reached"; + case EVREQ_HTTP_INVALID_HEADER: + return "error while reading header, or invalid header"; + case EVREQ_HTTP_BUFFER_ERROR: + return "error encountered while reading or writing"; + case EVREQ_HTTP_REQUEST_CANCEL: + return "request was canceled"; + case EVREQ_HTTP_DATA_TOO_LONG: + return "response body is larger than allowed"; +#endif + default: + return "unknown"; + } +} + static void http_request_done(struct evhttp_request *req, void *ctx) { HTTPReply *reply = static_cast<HTTPReply*>(ctx); if (req == NULL) { - /* If req is NULL, it means an error occurred while connecting, but - * I'm not sure how to find out which one. We also don't really care. + /* If req is NULL, it means an error occurred while connecting: the + * error code will have been passed to http_error_cb. */ reply->status = 0; return; @@ -145,6 +170,14 @@ static void http_request_done(struct evhttp_request *req, void *ctx) } } +#if LIBEVENT_VERSION_NUMBER >= 0x02010300 +static void http_error_cb(enum evhttp_request_error err, void *ctx) +{ + HTTPReply *reply = static_cast<HTTPReply*>(ctx); + reply->error = err; +} +#endif + UniValue CallRPC(const string& strMethod, const UniValue& params) { std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT); @@ -165,6 +198,9 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII if (req == NULL) throw runtime_error("create http request failed"); +#if LIBEVENT_VERSION_NUMBER >= 0x02010300 + evhttp_request_set_error_cb(req, http_error_cb); +#endif // Get credentials std::string strRPCUserColonPass; @@ -204,7 +240,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) event_base_free(base); if (response.status == 0) - throw CConnectionFailed("couldn't connect to server"); + throw CConnectionFailed(strprintf("couldn't connect to server (%d %s)", response.error, http_errorstring(response.error))); else if (response.status == HTTP_UNAUTHORIZED) throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) diff --git a/src/init.cpp b/src/init.cpp index 8d1e330a05..b20675dd9e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -759,10 +759,7 @@ void InitParameterInteraction() if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { if (SoftSetBoolArg("-whitelistrelay", false)) LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__); -#ifdef ENABLE_WALLET - if (SoftSetBoolArg("-walletbroadcast", false)) - LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__); -#endif + // walletbroadcast is disabled in CWallet::ParameterInteraction() } // Forcing relay from whitelisted hosts implies we will accept relays from them in the first place. @@ -821,12 +818,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError("Initializing networking failed"); #ifndef WIN32 - if (GetBoolArg("-sysperms", false)) { -#ifdef ENABLE_WALLET - if (!GetBoolArg("-disablewallet", false)) - return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); -#endif - } else { + if (!GetBoolArg("-sysperms", false)) { umask(077); } @@ -854,15 +846,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // also see: InitParameterInteraction() - // if using block pruning, then disable txindex + // if using block pruning, then disallow txindex if (GetArg("-prune", 0)) { if (GetBoolArg("-txindex", DEFAULT_TXINDEX)) return InitError(_("Prune mode is incompatible with -txindex.")); -#ifdef ENABLE_WALLET - if (GetBoolArg("-rescan", false)) { - return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.")); - } -#endif } // Make sure enough file descriptors are available @@ -948,9 +935,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterAllCoreRPCCommands(tableRPC); #ifdef ENABLE_WALLET - bool fDisableWallet = GetBoolArg("-disablewallet", false); - if (!fDisableWallet) - RegisterWalletRPCCommands(tableRPC); + RegisterWalletRPCCommands(tableRPC); #endif nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); @@ -966,10 +951,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (mapArgs.count("-minrelaytxfee")) { CAmount n = 0; - if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0) - ::minRelayTxFee = CFeeRate(n); - else + if (!ParseMoney(mapArgs["-minrelaytxfee"], n)) return InitError(AmountErrMsg("minrelaytxfee", mapArgs["-minrelaytxfee"])); + // High fee check is done afterward in CWallet::ParameterInteraction() + ::minRelayTxFee = CFeeRate(n); } fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard()); @@ -980,7 +965,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) #ifdef ENABLE_WALLET if (!CWallet::ParameterInteraction()) return false; -#endif // ENABLE_WALLET +#endif fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); @@ -1108,15 +1093,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 5: verify wallet database integrity #ifdef ENABLE_WALLET - if (!fDisableWallet) { - if (!CWallet::Verify()) - return false; - } // (!fDisableWallet) -#endif // ENABLE_WALLET + if (!CWallet::Verify()) + return false; +#endif // ********************************************************* Step 6: network initialization assert(!g_connman); - g_connman = std::unique_ptr<CConnman>(new CConnman()); + g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()))); CConnman& connman = *g_connman; RegisterNodeSignals(GetNodeSignals()); @@ -1249,8 +1232,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterValidationInterface(pzmqNotificationInterface); } #endif + uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set + uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME; + if (mapArgs.count("-maxuploadtarget")) { - connman.SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); + nMaxOutboundLimit = GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024; } // ********************************************************* Step 7: load block chain @@ -1437,17 +1423,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 8: load wallet #ifdef ENABLE_WALLET - if (fDisableWallet) { - pwalletMain = NULL; - LogPrintf("Wallet disabled!\n"); - } else { - CWallet::InitLoadWallet(); - if (!pwalletMain) - return false; - } -#else // ENABLE_WALLET + if (!CWallet::InitLoadWallet()) + return false; +#else LogPrintf("No wallet support compiled in!\n"); -#endif // !ENABLE_WALLET +#endif // ********************************************************* Step 9: data directory maintenance @@ -1533,6 +1513,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); + connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe; + connOptions.nMaxOutboundLimit = nMaxOutboundLimit; + if(!connman.Start(threadGroup, scheduler, strNodeError, connOptions)) return InitError(strNodeError); diff --git a/src/main.cpp b/src/main.cpp index 593897f516..60bda426a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -113,6 +113,8 @@ CScript COINBASE_FLAGS; const string strMessageMagic = "Bitcoin Signed Message:\n"; +static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; // SHA256("main address relay")[0:8] + // Internal stuff namespace { @@ -2062,7 +2064,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin // Open history file to read CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); if (filein.IsNull()) - return error("%s: OpenBlockFile failed", __func__); + return error("%s: OpenUndoFile failed", __func__); // Read block uint256 hashChecksum; @@ -2386,6 +2388,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Start enforcing WITNESS rules using versionbits logic. if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus())) { flags |= SCRIPT_VERIFY_WITNESS; + flags |= SCRIPT_VERIFY_NULLDUMMY; } int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1; @@ -4739,11 +4742,9 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma // Relay to a limited number of other nodes // Use deterministic randomness to send to the same nodes for 24 hours // at a time so the addrKnowns of the chosen nodes prevent repeats - static const uint64_t salt0 = GetRand(std::numeric_limits<uint64_t>::max()); - static const uint64_t salt1 = GetRand(std::numeric_limits<uint64_t>::max()); uint64_t hashAddr = addr.GetHash(); std::multimap<uint64_t, CNode*> mapMix; - const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); + const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60)); auto sortfunc = [&mapMix, &hasher](CNode* pnode) { if (pnode->nVersion >= CADDR_TIME_VERSION) { diff --git a/src/net.cpp b/src/net.cpp index cc9728b853..cce06f2d64 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -63,6 +63,7 @@ const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*"; +static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8] // // Global state variables // @@ -387,7 +388,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo addrman.Attempt(addrConnect, fCountFailure); // Add node - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, pszDest ? pszDest : "", false); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), pszDest ? pszDest : "", false); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); @@ -448,7 +449,7 @@ void CNode::PushVersion() { int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); - CAddress addrMe = GetLocalAddress(&addr, nLocalServices); + CAddress addrMe = CAddress(CService(), nLocalServices); if (fLogIPs) LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), addrYou.ToString(), id); else @@ -1022,7 +1023,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } } - CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, "", true); + CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), "", true); GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->AddRef(); pnode->fWhitelisted = whitelisted; @@ -2023,7 +2024,7 @@ void Discover(boost::thread_group& threadGroup) #endif } -CConnman::CConnman() +CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In) { setBannedIsDirty = false; fAddressesInitialized = false; @@ -2046,9 +2047,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st { nTotalBytesRecv = 0; nTotalBytesSent = 0; - nMaxOutboundLimit = 0; nMaxOutboundTotalBytesSentInCycle = 0; - nMaxOutboundTimeframe = 60*60*24; //1 day nMaxOutboundCycleStartTime = 0; nRelevantServices = connOptions.nRelevantServices; @@ -2060,6 +2059,9 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st nSendBufferMaxSize = connOptions.nSendBufferMaxSize; nReceiveFloodSize = connOptions.nSendBufferMaxSize; + nMaxOutboundLimit = connOptions.nMaxOutboundLimit; + nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe; + SetBestHeight(connOptions.nBestHeight); clientInterface = connOptions.uiInterface; @@ -2108,7 +2110,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (pnodeLocalHost == NULL) { CNetAddr local; LookupHost("127.0.0.1", local, false); - pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices)); + pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0); GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); } @@ -2498,10 +2500,10 @@ void CNode::Fuzz(int nChance) unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } -CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) : +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, const std::string& addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), addr(addrIn), - nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)), + nKeyedNetGroup(nKeyedNetGroupIn), addrKnown(5000, 0.001), filterInventoryKnown(50000, 0.000001) { @@ -2694,12 +2696,14 @@ int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } -/* static */ uint64_t CNode::CalculateKeyedNetGroup(const CAddress& ad) +CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) { - static const uint64_t k0 = GetRand(std::numeric_limits<uint64_t>::max()); - static const uint64_t k1 = GetRand(std::numeric_limits<uint64_t>::max()); + return CSipHasher(nSeed0, nSeed1).Write(id); +} +uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) +{ std::vector<unsigned char> vchNetGroup(ad.GetGroup()); - return CSipHasher(k0, k1).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize(); + return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize(); } @@ -11,6 +11,7 @@ #include "amount.h" #include "bloom.h" #include "compat.h" +#include "hash.h" #include "limitedmap.h" #include "netaddress.h" #include "protocol.h" @@ -72,6 +73,8 @@ static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ; static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; /** The default for -maxuploadtarget. 0 = Unlimited */ static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0; +/** The default timeframe for -maxuploadtarget. 1 day. */ +static const uint64_t MAX_UPLOAD_TIMEFRAME = 60 * 60 * 24; /** Default for blocks only*/ static const bool DEFAULT_BLOCKSONLY = false; @@ -120,8 +123,10 @@ public: CClientUIInterface* uiInterface = nullptr; unsigned int nSendBufferMaxSize = 0; unsigned int nReceiveFloodSize = 0; + uint64_t nMaxOutboundTimeframe = 0; + uint64_t nMaxOutboundLimit = 0; }; - CConnman(); + CConnman(uint64_t seed0, uint64_t seed1); ~CConnman(); bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options options); void Stop(); @@ -294,6 +299,8 @@ public: void SetBestHeight(int height); int GetBestHeight() const; + /** Get a unique deterministic randomizer. */ + CSipHasher GetDeterministicRandomizer(uint64_t id); private: struct ListenSocket { @@ -311,6 +318,8 @@ private: void ThreadSocketHandler(); void ThreadDNSAddressSeed(); + uint64_t CalculateKeyedNetGroup(const CAddress& ad); + CNode* FindNode(const CNetAddr& ip); CNode* FindNode(const CSubNet& subNet); CNode* FindNode(const std::string& addrName); @@ -388,6 +397,9 @@ private: int nMaxFeeler; std::atomic<int> nBestHeight; CClientUIInterface* clientInterface; + + /** SipHasher seeds for deterministic randomness */ + const uint64_t nSeed0, nSeed1; }; extern std::unique_ptr<CConnman> g_connman; void Discover(boost::thread_group& threadGroup); @@ -656,16 +668,16 @@ public: CAmount lastSentFeeFilter; int64_t nextSendTimeFeeFilter; - CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false); + CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, const std::string &addrNameIn = "", bool fInboundIn = false); ~CNode(); private: CNode(const CNode&); void operator=(const CNode&); - static uint64_t CalculateKeyedNetGroup(const CAddress& ad); uint64_t nLocalHostNonce; + // Services offered to this peer ServiceFlags nLocalServices; int nMyStartingHeight; public: diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 2fdc59ea07..4afbe99fd3 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -131,6 +131,11 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const return nTxSize; } +unsigned int CTransaction::GetTotalSize() const +{ + return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); +} + std::string CTransaction::ToString() const { std::string str; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 5689d15bf7..16c2e5c454 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -415,6 +415,13 @@ public: // Compute modified tx size for priority calculation (optionally given tx size) unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const; + + /** + * Get the total transaction size in bytes, including witness data. + * "Total Size" defined in BIP141 and BIP144. + * @return Total transaction size in bytes + */ + unsigned int GetTotalSize() const; bool IsCoinBase() const { diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 135f15ffa8..58cf4dede0 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -21,12 +21,12 @@ #include <QMessageBox> #include <QSortFilterProxyModel> -AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent) : +AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) : QDialog(parent), ui(new Ui::AddressBookPage), model(0), - mode(mode), - tab(tab) + mode(_mode), + tab(_tab) { ui->setupUi(this); @@ -107,14 +107,14 @@ AddressBookPage::~AddressBookPage() delete ui; } -void AddressBookPage::setModel(AddressTableModel *model) +void AddressBookPage::setModel(AddressTableModel *_model) { - this->model = model; - if(!model) + this->model = _model; + if(!_model) return; proxyModel = new QSortFilterProxyModel(this); - proxyModel->setSourceModel(model); + proxyModel->setSourceModel(_model); proxyModel->setDynamicSortFilter(true); proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); @@ -147,7 +147,7 @@ void AddressBookPage::setModel(AddressTableModel *model) this, SLOT(selectionChanged())); // Select row for newly created address - connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int))); + connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int))); selectionChanged(); } diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 71ed3618e4..830c9cdf19 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -31,8 +31,8 @@ struct AddressTableEntry QString address; AddressTableEntry() {} - AddressTableEntry(Type type, const QString &label, const QString &address): - type(type), label(label), address(address) {} + AddressTableEntry(Type _type, const QString &_label, const QString &_address): + type(_type), label(_label), address(_address) {} }; struct AddressTableEntryLessThan @@ -73,8 +73,8 @@ public: QList<AddressTableEntry> cachedAddressTable; AddressTableModel *parent; - AddressTablePriv(CWallet *wallet, AddressTableModel *parent): - wallet(wallet), parent(parent) {} + AddressTablePriv(CWallet *_wallet, AddressTableModel *_parent): + wallet(_wallet), parent(_parent) {} void refreshAddressTable() { @@ -164,8 +164,8 @@ public: } }; -AddressTableModel::AddressTableModel(CWallet *wallet, WalletModel *parent) : - QAbstractTableModel(parent),walletModel(parent),wallet(wallet),priv(0) +AddressTableModel::AddressTableModel(CWallet *_wallet, WalletModel *parent) : + QAbstractTableModel(parent),walletModel(parent),wallet(_wallet),priv(0) { columns << tr("Label") << tr("Address"); priv = new AddressTablePriv(wallet, this); diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index e8aa79679c..129ea1efa4 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -18,10 +18,10 @@ #include <QMessageBox> #include <QPushButton> -AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) : +AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) : QDialog(parent), ui(new Ui::AskPassphraseDialog), - mode(mode), + mode(_mode), model(0), fCapsLock(false) { @@ -81,9 +81,9 @@ AskPassphraseDialog::~AskPassphraseDialog() delete ui; } -void AskPassphraseDialog::setModel(WalletModel *model) +void AskPassphraseDialog::setModel(WalletModel *_model) { - this->model = model; + this->model = _model; } void AskPassphraseDialog::accept() diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 272df3fdae..dd022ee762 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -12,6 +12,7 @@ #include "clientmodel.h" #include "guiconstants.h" #include "guiutil.h" +#include "modaloverlay.h" #include "networkstyle.h" #include "notificator.h" #include "openuridialog.h" @@ -75,8 +76,9 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM = const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; -BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : +BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) : QMainWindow(parent), + enableWallet(false), clientModel(0), walletFrame(0), unitDisplayControl(0), @@ -114,18 +116,16 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n notificator(0), rpcConsole(0), helpMessageDialog(0), + modalOverlay(0), prevBlocks(0), spinnerFrame(0), - platformStyle(platformStyle) + platformStyle(_platformStyle) { GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this); QString windowTitle = tr(PACKAGE_NAME) + " - "; #ifdef ENABLE_WALLET - /* if compiled with wallet support, -disablewallet can still disable the wallet */ - enableWallet = !GetBoolArg("-disablewallet", false); -#else - enableWallet = false; + enableWallet = WalletModel::isWalletEnabled(); #endif // ENABLE_WALLET if(enableWallet) { @@ -148,13 +148,13 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n setUnifiedTitleAndToolBarOnMac(true); #endif - rpcConsole = new RPCConsole(platformStyle, 0); + rpcConsole = new RPCConsole(_platformStyle, 0); helpMessageDialog = new HelpMessageDialog(this, false); #ifdef ENABLE_WALLET if(enableWallet) { /** Create wallet frame and make it the central widget */ - walletFrame = new WalletFrame(platformStyle, this); + walletFrame = new WalletFrame(_platformStyle, this); setCentralWidget(walletFrame); } else #endif // ENABLE_WALLET @@ -241,6 +241,12 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n // Subscribe to notifications from core subscribeToCoreSignals(); + + modalOverlay = new ModalOverlay(this->centralWidget()); +#ifdef ENABLE_WALLET + if(enableWallet) + connect(walletFrame, SIGNAL(requestedSyncWarningInfo()), this, SLOT(showModalOverlay())); +#endif } BitcoinGUI::~BitcoinGUI() @@ -451,38 +457,38 @@ void BitcoinGUI::createToolBars() } } -void BitcoinGUI::setClientModel(ClientModel *clientModel) +void BitcoinGUI::setClientModel(ClientModel *_clientModel) { - this->clientModel = clientModel; - if(clientModel) + this->clientModel = _clientModel; + if(_clientModel) { // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions, // while the client has not yet fully loaded createTrayIconMenu(); // Keep up to date with client - setNumConnections(clientModel->getNumConnections()); - connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); + setNumConnections(_clientModel->getNumConnections()); + connect(_clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); - setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL), false); - connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool))); + setNumBlocks(_clientModel->getNumBlocks(), _clientModel->getLastBlockDate(), _clientModel->getVerificationProgress(NULL), false); + connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool))); // Receive and report messages from client model - connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); + connect(_clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int))); // Show progress dialog - connect(clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int))); + connect(_clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int))); - rpcConsole->setClientModel(clientModel); + rpcConsole->setClientModel(_clientModel); #ifdef ENABLE_WALLET if(walletFrame) { - walletFrame->setClientModel(clientModel); + walletFrame->setClientModel(_clientModel); } #endif // ENABLE_WALLET - unitDisplayControl->setOptionsModel(clientModel->getOptionsModel()); + unitDisplayControl->setOptionsModel(_clientModel->getOptionsModel()); - OptionsModel* optionsModel = clientModel->getOptionsModel(); + OptionsModel* optionsModel = _clientModel->getOptionsModel(); if(optionsModel) { // be aware of the tray icon disable state change reported by the OptionsModel object. @@ -491,6 +497,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) // initialize the disable state of the tray icon with the current value in the model. setTrayIconVisible(optionsModel->getHideTrayIcon()); } + + modalOverlay->setKnownBestHeight(clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(clientModel->getHeaderTipTime())); } else { // Disable possibility to show main window via action toggleHideAction->setEnabled(false); @@ -705,7 +713,17 @@ void BitcoinGUI::setNumConnections(int count) void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header) { - if(!clientModel) + if (modalOverlay) + { + if (header) { + /* use clientmodels getHeaderTipHeight and getHeaderTipTime because the NotifyHeaderTip signal does not fire when updating the best header */ + modalOverlay->setKnownBestHeight(clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(clientModel->getHeaderTipTime())); + } + else { + modalOverlay->tipUpdate(count, blockDate, nVerificationProgress); + } + } + if (!clientModel) return; // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text) @@ -754,7 +772,10 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer #ifdef ENABLE_WALLET if(walletFrame) + { walletFrame->showOutOfSyncWarning(false); + modalOverlay->showHide(true, true); + } #endif // ENABLE_WALLET progressBarLabel->setVisible(false); @@ -762,30 +783,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer } else { - // Represent time from last generated block in human readable text - QString timeBehindText; - const int HOUR_IN_SECONDS = 60*60; - const int DAY_IN_SECONDS = 24*60*60; - const int WEEK_IN_SECONDS = 7*24*60*60; - const int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar - if(secs < 2*DAY_IN_SECONDS) - { - timeBehindText = tr("%n hour(s)","",secs/HOUR_IN_SECONDS); - } - else if(secs < 2*WEEK_IN_SECONDS) - { - timeBehindText = tr("%n day(s)","",secs/DAY_IN_SECONDS); - } - else if(secs < YEAR_IN_SECONDS) - { - timeBehindText = tr("%n week(s)","",secs/WEEK_IN_SECONDS); - } - else - { - qint64 years = secs / YEAR_IN_SECONDS; - qint64 remainder = secs % YEAR_IN_SECONDS; - timeBehindText = tr("%1 and %2").arg(tr("%n year(s)", "", years)).arg(tr("%n week(s)","", remainder/WEEK_IN_SECONDS)); - } + QString timeBehindText = GUIUtil::formateNiceTimeOffset(secs); progressBarLabel->setVisible(true); progressBar->setFormat(tr("%1 behind").arg(timeBehindText)); @@ -805,7 +803,10 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer #ifdef ENABLE_WALLET if(walletFrame) + { walletFrame->showOutOfSyncWarning(true); + modalOverlay->showHide(); + } #endif // ENABLE_WALLET tooltip += QString("<br>"); @@ -1101,6 +1102,12 @@ void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon) } } +void BitcoinGUI::showModalOverlay() +{ + if (modalOverlay) + modalOverlay->showHide(false, true); +} + static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style) { bool modal = (style & CClientUIInterface::MODAL); @@ -1170,17 +1177,17 @@ void UnitDisplayStatusBarControl::createContextMenu() } /** Lets the control know about the Options Model (and its signals) */ -void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *optionsModel) +void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *_optionsModel) { - if (optionsModel) + if (_optionsModel) { - this->optionsModel = optionsModel; + this->optionsModel = _optionsModel; // be aware of a display unit change reported by the OptionsModel object. - connect(optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int))); + connect(_optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int))); // initialize the display units label with the current value in the model. - updateDisplayUnit(optionsModel->getDisplayUnit()); + updateDisplayUnit(_optionsModel->getDisplayUnit()); } } diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 41770929b4..0eaa44b263 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -29,6 +29,7 @@ class UnitDisplayStatusBarControl; class WalletFrame; class WalletModel; class HelpMessageDialog; +class ModalOverlay; class CWallet; @@ -118,6 +119,7 @@ private: Notificator *notificator; RPCConsole *rpcConsole; HelpMessageDialog *helpMessageDialog; + ModalOverlay *modalOverlay; /** Keep track of previous number of blocks, to detect progress */ int prevBlocks; @@ -229,6 +231,8 @@ private Q_SLOTS: /** When hideTrayIcon setting is changed in OptionsModel hide or show the icon accordingly. */ void setTrayIconVisible(bool); + + void showModalOverlay(); }; class UnitDisplayStatusBarControl : public QLabel diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 83c78850e2..6d19b3d122 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -27,9 +27,9 @@ static const int64_t nClientStartupTime = GetTime(); static int64_t nLastHeaderTipUpdateNotification = 0; static int64_t nLastBlockTipUpdateNotification = 0; -ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) : +ClientModel::ClientModel(OptionsModel *_optionsModel, QObject *parent) : QObject(parent), - optionsModel(optionsModel), + optionsModel(_optionsModel), peerTableModel(0), banTableModel(0), pollTimer(0) @@ -70,6 +70,22 @@ int ClientModel::getNumBlocks() const return chainActive.Height(); } +int ClientModel::getHeaderTipHeight() const +{ + LOCK(cs_main); + if (!pindexBestHeader) + return 0; + return pindexBestHeader->nHeight; +} + +int64_t ClientModel::getHeaderTipTime() const +{ + LOCK(cs_main); + if (!pindexBestHeader) + return 0; + return pindexBestHeader->GetBlockTime(); +} + quint64 ClientModel::getTotalBytesRecv() const { if(!g_connman) @@ -240,7 +256,7 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification; // if we are in-sync, update the UI regardless of last update time - if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { + if (fHeader || !initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) { //pass a async signal to the UI thread QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection, Q_ARG(int, pIndex->nHeight), diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 99fd574b9e..3fd8404cbb 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -51,7 +51,8 @@ public: //! Return number of connections, default is in- and outbound (total) int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const; int getNumBlocks() const; - + int getHeaderTipHeight() const; + int64_t getHeaderTipTime() const; //! Return number of transactions in the mempool long getMempoolSize() const; //! Return the dynamic memory usage of the mempool diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index f53242100c..86fd4ebd65 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -35,11 +35,11 @@ QList<CAmount> CoinControlDialog::payAmounts; CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); bool CoinControlDialog::fSubtractFeeFromAmount = false; -CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent) : +CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::CoinControlDialog), model(0), - platformStyle(platformStyle) + platformStyle(_platformStyle) { ui->setupUi(this); @@ -152,15 +152,15 @@ CoinControlDialog::~CoinControlDialog() delete ui; } -void CoinControlDialog::setModel(WalletModel *model) +void CoinControlDialog::setModel(WalletModel *_model) { - this->model = model; + this->model = _model; - if(model && model->getOptionsModel() && model->getAddressTableModel()) + if(_model && _model->getOptionsModel() && _model->getAddressTableModel()) { updateView(); updateLabelLocked(); - CoinControlDialog::updateLabels(model, this); + CoinControlDialog::updateLabels(_model, this); } } diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp index 8a1a49bb06..f424e6cd98 100644 --- a/src/qt/csvmodelwriter.cpp +++ b/src/qt/csvmodelwriter.cpp @@ -8,15 +8,15 @@ #include <QFile> #include <QTextStream> -CSVModelWriter::CSVModelWriter(const QString &filename, QObject *parent) : +CSVModelWriter::CSVModelWriter(const QString &_filename, QObject *parent) : QObject(parent), - filename(filename), model(0) + filename(_filename), model(0) { } -void CSVModelWriter::setModel(const QAbstractItemModel *model) +void CSVModelWriter::setModel(const QAbstractItemModel *_model) { - this->model = model; + this->model = _model; } void CSVModelWriter::addColumn(const QString &title, int column, int role) diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index 5f45031e9e..a9ffe016fd 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -11,11 +11,11 @@ #include <QDataWidgetMapper> #include <QMessageBox> -EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) : +EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) : QDialog(parent), ui(new Ui::EditAddressDialog), mapper(0), - mode(mode), + mode(_mode), model(0) { ui->setupUi(this); @@ -49,13 +49,13 @@ EditAddressDialog::~EditAddressDialog() delete ui; } -void EditAddressDialog::setModel(AddressTableModel *model) +void EditAddressDialog::setModel(AddressTableModel *_model) { - this->model = model; - if(!model) + this->model = _model; + if(!_model) return; - mapper->setModel(model); + mapper->setModel(_model); mapper->addMapping(ui->labelEdit, AddressTableModel::Label); mapper->addMapping(ui->addressEdit, AddressTableModel::Address); } @@ -137,8 +137,8 @@ QString EditAddressDialog::getAddress() const return address; } -void EditAddressDialog::setAddress(const QString &address) +void EditAddressDialog::setAddress(const QString &_address) { - this->address = address; - ui->addressEdit->setText(address); + this->address = _address; + ui->addressEdit->setText(_address); } diff --git a/src/qt/forms/modaloverlay.ui b/src/qt/forms/modaloverlay.ui new file mode 100644 index 0000000000..ccec1b3e1e --- /dev/null +++ b/src/qt/forms/modaloverlay.ui @@ -0,0 +1,373 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ModalOverlay</class> + <widget class="ModalOverlay" name="ModalOverlay"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>640</width> + <height>385</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout" stretch="0"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QWidget" name="bgWidget" native="true"> + <property name="styleSheet"> + <string notr="true">#bgWidget { background: rgba(0,0,0,220); }</string> + </property> + <layout class="QVBoxLayout" name="verticalLayoutMain" stretch="1"> + <property name="leftMargin"> + <number>60</number> + </property> + <property name="topMargin"> + <number>60</number> + </property> + <property name="rightMargin"> + <number>60</number> + </property> + <property name="bottomMargin"> + <number>60</number> + </property> + <item> + <widget class="QWidget" name="contentWidget" native="true"> + <property name="styleSheet"> + <string notr="true">#contentWidget { background: rgba(255,255,255,240); border-radius: 6px; } + +QLabel { color: rgb(40,40,40); }</string> + </property> + <layout class="QVBoxLayout" name="verticalLayoutSub" stretch="1,0,0,0"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>10</number> + </property> + <property name="topMargin"> + <number>10</number> + </property> + <property name="rightMargin"> + <number>10</number> + </property> + <property name="bottomMargin"> + <number>10</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayoutIconText" stretch="0,1"> + <property name="topMargin"> + <number>20</number> + </property> + <item> + <layout class="QVBoxLayout" name="verticalLayoutIcon"> + <property name="leftMargin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="warningIcon"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset> + <normaloff>:/icons/warning</normaloff> + <disabledoff>:/icons/warning</disabledoff>:/icons/warning</iconset> + </property> + <property name="iconSize"> + <size> + <width>48</width> + <height>48</height> + </size> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacerWarningIcon"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayoutInfoText"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="infoText"> + <property name="text"> + <string>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet. This means that recent transactions will not be visible, and the balance will not be up-to-date until this process has completed.</string> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="infoTextStrong"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Spending bitcoins may not be possible during that phase!</string> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacerInTextSpace"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacerAfterText"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::FieldsStayAtSizeHint</enum> + </property> + <property name="horizontalSpacing"> + <number>6</number> + </property> + <property name="verticalSpacing"> + <number>6</number> + </property> + <property name="topMargin"> + <number>10</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="labelAmoutOfBlocksLeft"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Amount of blocks left</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="amountOfBlocksLeft"> + <property name="text"> + <string>unknown...</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="labelLastBlockTime"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Last block time</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="newestBlockDate"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>unknown...</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="labelSyncDone"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Progress</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <layout class="QHBoxLayout" name="horizontalLayoutSync" stretch="0,1"> + <item> + <widget class="QLabel" name="percentageProgress"> + <property name="text"> + <string>~</string> + </property> + </widget> + </item> + <item> + <widget class="QProgressBar" name="progressBar"> + <property name="value"> + <number>24</number> + </property> + </widget> + </item> + </layout> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="labelProgressIncrease"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Progress increase per Hour</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLabel" name="progressIncreasePerH"> + <property name="text"> + <string>calculating...</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="labelEstimatedTimeLeft"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Estimated time left until synced</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QLabel" name="expectedTimeLeft"> + <property name="text"> + <string>calculating...</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayoutButtons"> + <property name="leftMargin"> + <number>10</number> + </property> + <property name="topMargin"> + <number>10</number> + </property> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="closeButton"> + <property name="text"> + <string>Hide</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>ModalOverlay</class> + <extends>QWidget</extends> + <header>modaloverlay.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 6d792d1475..923ed68996 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -61,7 +61,7 @@ <item> <widget class="QPushButton" name="labelWalletStatus"> <property name="enabled"> - <bool>false</bool> + <bool>true</bool> </property> <property name="maximumSize"> <size> @@ -447,7 +447,7 @@ <item> <widget class="QPushButton" name="labelTransactionsStatus"> <property name="enabled"> - <bool>false</bool> + <bool>true</bool> </property> <property name="maximumSize"> <size> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 444e35de8a..0beaddf997 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -462,9 +462,9 @@ void SubstituteFonts(const QString& language) #endif } -ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) : +ToolTipToRichTextFilter::ToolTipToRichTextFilter(int _size_threshold, QObject *parent) : QObject(parent), - size_threshold(size_threshold) + size_threshold(_size_threshold) { } @@ -955,4 +955,40 @@ QString formatTimeOffset(int64_t nTimeOffset) return QString(QObject::tr("%1 s")).arg(QString::number((int)nTimeOffset, 10)); } +QString formateNiceTimeOffset(qint64 secs) +{ + // Represent time from last generated block in human readable text + QString timeBehindText; + const int HOUR_IN_SECONDS = 60*60; + const int DAY_IN_SECONDS = 24*60*60; + const int WEEK_IN_SECONDS = 7*24*60*60; + const int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar + if(secs < 60) + { + timeBehindText = QObject::tr("%n seconds(s)","",secs); + } + else if(secs < 2*HOUR_IN_SECONDS) + { + timeBehindText = QObject::tr("%n minutes(s)","",secs/60); + } + else if(secs < 2*DAY_IN_SECONDS) + { + timeBehindText = QObject::tr("%n hour(s)","",secs/HOUR_IN_SECONDS); + } + else if(secs < 2*WEEK_IN_SECONDS) + { + timeBehindText = QObject::tr("%n day(s)","",secs/DAY_IN_SECONDS); + } + else if(secs < YEAR_IN_SECONDS) + { + timeBehindText = QObject::tr("%n week(s)","",secs/WEEK_IN_SECONDS); + } + else + { + qint64 years = secs / YEAR_IN_SECONDS; + qint64 remainder = secs % YEAR_IN_SECONDS; + timeBehindText = QObject::tr("%1 and %2").arg(QObject::tr("%n year(s)", "", years)).arg(QObject::tr("%n week(s)","", remainder/WEEK_IN_SECONDS)); + } + return timeBehindText; +} } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index d5a658e7c0..e28f68930f 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -200,6 +200,8 @@ namespace GUIUtil /* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */ QString formatTimeOffset(int64_t nTimeOffset); + QString formateNiceTimeOffset(qint64 secs); + #if defined(Q_OS_MAC) && QT_VERSION >= 0x050000 // workaround for Qt OSX Bug: // https://bugreports.qt-project.org/browse/QTBUG-15631 diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 1a241ae0f0..5a336b105e 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -63,9 +63,9 @@ private: #include "intro.moc" -FreespaceChecker::FreespaceChecker(Intro *intro) +FreespaceChecker::FreespaceChecker(Intro *_intro) { - this->intro = intro; + this->intro = _intro; } void FreespaceChecker::check() diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp new file mode 100644 index 0000000000..7951bd784e --- /dev/null +++ b/src/qt/modaloverlay.cpp @@ -0,0 +1,158 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "modaloverlay.h" +#include "ui_modaloverlay.h" + +#include "guiutil.h" + +#include <QResizeEvent> +#include <QPropertyAnimation> + +ModalOverlay::ModalOverlay(QWidget *parent) : +QWidget(parent), +ui(new Ui::ModalOverlay), +bestBlockHeight(0), +layerIsVisible(false), +userClosed(false) +{ + ui->setupUi(this); + connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(closeClicked())); + if (parent) { + parent->installEventFilter(this); + raise(); + } + + blockProcessTime.clear(); + setVisible(false); +} + +ModalOverlay::~ModalOverlay() +{ + delete ui; +} + +bool ModalOverlay::eventFilter(QObject * obj, QEvent * ev) { + if (obj == parent()) { + if (ev->type() == QEvent::Resize) { + QResizeEvent * rev = static_cast<QResizeEvent*>(ev); + resize(rev->size()); + if (!layerIsVisible) + setGeometry(0, height(), width(), height()); + + } + else if (ev->type() == QEvent::ChildAdded) { + raise(); + } + } + return QWidget::eventFilter(obj, ev); +} + +//! Tracks parent widget changes +bool ModalOverlay::event(QEvent* ev) { + if (ev->type() == QEvent::ParentAboutToChange) { + if (parent()) parent()->removeEventFilter(this); + } + else if (ev->type() == QEvent::ParentChange) { + if (parent()) { + parent()->installEventFilter(this); + raise(); + } + } + return QWidget::event(ev); +} + +void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate) +{ + + /* only update the blockheight if the headerschain-tip is not older then 30 days */ + int64_t now = QDateTime::currentDateTime().toTime_t(); + int64_t btime = blockDate.toTime_t(); + if (btime+3600*24*30 > now) + { + if (count > bestBlockHeight) + bestBlockHeight = count; + } +} + +void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress) +{ + QDateTime currentDate = QDateTime::currentDateTime(); + + // keep a vector of samples of verification progress at height + blockProcessTime.push_front(qMakePair(currentDate.currentMSecsSinceEpoch(), nVerificationProgress)); + + // show progress speed if we have more then one sample + if (blockProcessTime.size() >= 2) + { + double progressStart = blockProcessTime[0].second; + double progressDelta = 0; + double progressPerHour = 0; + qint64 timeDelta = 0; + qint64 remainingMSecs = 0; + double remainingProgress = 1.0 - nVerificationProgress; + for (int i = 1; i < blockProcessTime.size(); i++) + { + QPair<qint64, double> sample = blockProcessTime[i]; + + // take first sample after 500 seconds or last available one + if (sample.first < (currentDate.currentMSecsSinceEpoch() - 500*1000) || i == blockProcessTime.size()-1) + { + progressDelta = progressStart-sample.second; + timeDelta = blockProcessTime[0].first - sample.first; + progressPerHour = progressDelta/(double)timeDelta*1000*3600; + remainingMSecs = remainingProgress / progressDelta * timeDelta; + break; + } + } + // show progress increase per hour + ui->progressIncreasePerH->setText(QString::number(progressPerHour*100, 'f', 2)+"%"); + + // show expected remaining time + ui->expectedTimeLeft->setText(GUIUtil::formateNiceTimeOffset(remainingMSecs/1000.0)); + + // keep maximal 5000 samples + static const int MAX_SAMPLES = 5000; + if (blockProcessTime.count() > MAX_SAMPLES) + blockProcessTime.remove(MAX_SAMPLES, blockProcessTime.count()-MAX_SAMPLES); + } + + // show the last block date + ui->newestBlockDate->setText(blockDate.toString()); + + // show the percentage done according to nVerificationProgress + ui->percentageProgress->setText(QString::number(nVerificationProgress*100, 'f', 2)+"%"); + ui->progressBar->setValue(nVerificationProgress*100); + + // show remaining amount of blocks + if (bestBlockHeight > 0) + ui->amountOfBlocksLeft->setText(QString::number(bestBlockHeight-count)); + else + ui->expectedTimeLeft->setText(tr("Unknown. Syncing Headers...")); +} + +void ModalOverlay::showHide(bool hide, bool userRequested) +{ + if ( (layerIsVisible && !hide) || (!layerIsVisible && hide) || (!hide && userClosed && !userRequested)) + return; + + if (!isVisible() && !hide) + setVisible(true); + + setGeometry(0, hide ? 0 : height(), width(), height()); + + QPropertyAnimation* animation = new QPropertyAnimation(this, "pos"); + animation->setDuration(300); + animation->setStartValue(QPoint(0, hide ? 0 : this->height())); + animation->setEndValue(QPoint(0, hide ? this->height() : 0)); + animation->setEasingCurve(QEasingCurve::OutQuad); + animation->start(QAbstractAnimation::DeleteWhenStopped); + layerIsVisible = !hide; +} + +void ModalOverlay::closeClicked() +{ + showHide(true); + userClosed = true; +} diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h new file mode 100644 index 0000000000..670c9e58ab --- /dev/null +++ b/src/qt/modaloverlay.h @@ -0,0 +1,44 @@ +// 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. + +#ifndef BITCOIN_QT_MODALOVERLAY_H +#define BITCOIN_QT_MODALOVERLAY_H + +#include <QDateTime> +#include <QWidget> + +namespace Ui { + class ModalOverlay; +} + +/** Modal overlay to display information about the chain-sync state */ +class ModalOverlay : public QWidget +{ + Q_OBJECT + +public: + explicit ModalOverlay(QWidget *parent); + ~ModalOverlay(); + +public Q_SLOTS: + void tipUpdate(int count, const QDateTime& blockDate, double nVerificationProgress); + void setKnownBestHeight(int count, const QDateTime& blockDate); + + // will show or hide the modal layer + void showHide(bool hide = false, bool userRequested = false); + void closeClicked(); + +protected: + bool eventFilter(QObject * obj, QEvent * ev); + bool event(QEvent* ev); + +private: + Ui::ModalOverlay *ui; + int bestBlockHeight; //best known height (based on the headers) + QVector<QPair<qint64, double> > blockProcessTime; + bool layerIsVisible; + bool userClosed; +}; + +#endif // BITCOIN_QT_MODALOVERLAY_H diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index 5f31f49372..acbfee0868 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -22,9 +22,9 @@ static const struct { static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles); // titleAddText needs to be const char* for tr() -NetworkStyle::NetworkStyle(const QString &appName, const int iconColorHueShift, const int iconColorSaturationReduction, const char *titleAddText): - appName(appName), - titleAddText(qApp->translate("SplashScreen", titleAddText)) +NetworkStyle::NetworkStyle(const QString &_appName, const int iconColorHueShift, const int iconColorSaturationReduction, const char *_titleAddText): + appName(_appName), + titleAddText(qApp->translate("SplashScreen", _titleAddText)) { // load pixmap QPixmap pixmap(":/icons/bitcoin"); diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index a45afde566..8277e20c90 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -33,17 +33,17 @@ const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128; #endif -Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent) : - QObject(parent), - parent(parent), - programName(programName), +Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon, QWidget *_parent) : + QObject(_parent), + parent(_parent), + programName(_programName), mode(None), - trayIcon(trayicon) + trayIcon(_trayIcon) #ifdef USE_DBUS ,interface(0) #endif { - if(trayicon && trayicon->supportsMessages()) + if(_trayIcon && _trayIcon->supportsMessages()) { mode = QSystemTray; } diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index f73bb87064..588059d0c5 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -135,22 +135,22 @@ OptionsDialog::~OptionsDialog() delete ui; } -void OptionsDialog::setModel(OptionsModel *model) +void OptionsDialog::setModel(OptionsModel *_model) { - this->model = model; + this->model = _model; - if(model) + if(_model) { /* check if client restart is needed and show persistent message */ - if (model->isRestartRequired()) + if (_model->isRestartRequired()) showRestartWarning(true); - QString strLabel = model->getOverriddenByCommandLine(); + QString strLabel = _model->getOverriddenByCommandLine(); if (strLabel.isEmpty()) strLabel = tr("none"); ui->overriddenByCommandLineLabel->setText(strLabel); - mapper->setModel(model); + mapper->setModel(_model); setMapper(); mapper->toFirst(); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 6a0404cbf7..7ccdb89c0c 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -25,9 +25,9 @@ class TxViewDelegate : public QAbstractItemDelegate { Q_OBJECT public: - TxViewDelegate(const PlatformStyle *platformStyle): + TxViewDelegate(const PlatformStyle *_platformStyle): QAbstractItemDelegate(), unit(BitcoinUnits::BTC), - platformStyle(platformStyle) + platformStyle(_platformStyle) { } @@ -140,6 +140,8 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) // start with displaying the "out of sync" warnings showOutOfSyncWarning(true); + connect(ui->labelWalletStatus, SIGNAL(clicked()), this, SLOT(handleOutOfSyncWarningClicks())); + connect(ui->labelTransactionsStatus, SIGNAL(clicked()), this, SLOT(handleOutOfSyncWarningClicks())); } void OverviewPage::handleTransactionClicked(const QModelIndex &index) @@ -148,6 +150,11 @@ void OverviewPage::handleTransactionClicked(const QModelIndex &index) Q_EMIT transactionClicked(filter->mapToSource(index)); } +void OverviewPage::handleOutOfSyncWarningClicks() +{ + Q_EMIT outOfSyncWarningClicked(); +} + OverviewPage::~OverviewPage() { delete ui; diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 911443c76a..65cd3341b6 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -42,6 +42,7 @@ public Q_SLOTS: Q_SIGNALS: void transactionClicked(const QModelIndex &index); + void outOfSyncWarningClicked(); private: Ui::OverviewPage *ui; @@ -62,6 +63,7 @@ private Q_SLOTS: void handleTransactionClicked(const QModelIndex &index); void updateAlerts(const QString &warnings); void updateWatchOnlyLabels(bool showWatchOnly); + void handleOutOfSyncWarningClicks(); }; #endif // BITCOIN_QT_OVERVIEWPAGE_H diff --git a/src/qt/paymentrequest.proto b/src/qt/paymentrequest.proto index b2281c4c7b..d2721a34bd 100644 --- a/src/qt/paymentrequest.proto +++ b/src/qt/paymentrequest.proto @@ -6,6 +6,8 @@ // https://en.bitcoin.it/wiki/Payment_Request // +syntax = "proto2"; + package payments; option java_package = "org.bitcoin.protocols.payments"; option java_outer_classname = "Protos"; diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index c80aebb009..9f23e77a13 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -749,9 +749,9 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError> Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR); } -void PaymentServer::setOptionsModel(OptionsModel *optionsModel) +void PaymentServer::setOptionsModel(OptionsModel *_optionsModel) { - this->optionsModel = optionsModel; + this->optionsModel = _optionsModel; } void PaymentServer::handlePaymentACK(const QString& paymentACKMsg) diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp index 11cbc7a47c..e4438cc43d 100644 --- a/src/qt/platformstyle.cpp +++ b/src/qt/platformstyle.cpp @@ -73,11 +73,11 @@ QIcon ColorizeIcon(const QString& filename, const QColor& colorbase) } -PlatformStyle::PlatformStyle(const QString &name, bool imagesOnButtons, bool colorizeIcons, bool useExtraSpacing): - name(name), - imagesOnButtons(imagesOnButtons), - colorizeIcons(colorizeIcons), - useExtraSpacing(useExtraSpacing), +PlatformStyle::PlatformStyle(const QString &_name, bool _imagesOnButtons, bool _colorizeIcons, bool _useExtraSpacing): + name(_name), + imagesOnButtons(_imagesOnButtons), + colorizeIcons(_colorizeIcons), + useExtraSpacing(_useExtraSpacing), singleColor(0,0,0), textColor(0,0,0) { diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp index baa2eb67f7..492b96ff09 100644 --- a/src/qt/qvalidatedlineedit.cpp +++ b/src/qt/qvalidatedlineedit.cpp @@ -15,14 +15,14 @@ QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) : connect(this, SIGNAL(textChanged(QString)), this, SLOT(markValid())); } -void QValidatedLineEdit::setValid(bool valid) +void QValidatedLineEdit::setValid(bool _valid) { - if(valid == this->valid) + if(_valid == this->valid) { return; } - if(valid) + if(_valid) { setStyleSheet(""); } @@ -30,7 +30,7 @@ void QValidatedLineEdit::setValid(bool valid) { setStyleSheet(STYLE_INVALID); } - this->valid = valid; + this->valid = _valid; } void QValidatedLineEdit::focusInEvent(QFocusEvent *evt) diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp index 146f3dd578..2f2478783c 100644 --- a/src/qt/qvaluecombobox.cpp +++ b/src/qt/qvaluecombobox.cpp @@ -20,9 +20,9 @@ void QValueComboBox::setValue(const QVariant &value) setCurrentIndex(findData(value, role)); } -void QValueComboBox::setRole(int role) +void QValueComboBox::setRole(int _role) { - this->role = role; + this->role = _role; } void QValueComboBox::handleSelectionChanged(int idx) diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 0b355837ab..5c6dc97b20 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -22,24 +22,24 @@ #include <QScrollBar> #include <QTextDocument> -ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) : +ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::ReceiveCoinsDialog), model(0), - platformStyle(platformStyle) + platformStyle(_platformStyle) { ui->setupUi(this); - if (!platformStyle->getImagesOnButtons()) { + if (!_platformStyle->getImagesOnButtons()) { ui->clearButton->setIcon(QIcon()); ui->receiveButton->setIcon(QIcon()); ui->showRequestButton->setIcon(QIcon()); ui->removeRequestButton->setIcon(QIcon()); } else { - ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); - ui->receiveButton->setIcon(platformStyle->SingleColorIcon(":/icons/receiving_addresses")); - ui->showRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/edit")); - ui->removeRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); + ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove")); + ui->receiveButton->setIcon(_platformStyle->SingleColorIcon(":/icons/receiving_addresses")); + ui->showRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/edit")); + ui->removeRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove")); } // context menu actions @@ -62,21 +62,21 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidg connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); } -void ReceiveCoinsDialog::setModel(WalletModel *model) +void ReceiveCoinsDialog::setModel(WalletModel *_model) { - this->model = model; + this->model = _model; - if(model && model->getOptionsModel()) + if(_model && _model->getOptionsModel()) { - model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder); - connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + _model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder); + connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); updateDisplayUnit(); QTableView* tableView = ui->recentRequestsView; tableView->verticalHeader()->hide(); tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - tableView->setModel(model->getRecentRequestsTableModel()); + tableView->setModel(_model->getRecentRequestsTableModel()); tableView->setAlternatingRowColors(true); tableView->setSelectionBehavior(QAbstractItemView::SelectRows); tableView->setSelectionMode(QAbstractItemView::ContiguousSelection); diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index b13ea3df70..998c9176d7 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -109,20 +109,20 @@ ReceiveRequestDialog::~ReceiveRequestDialog() delete ui; } -void ReceiveRequestDialog::setModel(OptionsModel *model) +void ReceiveRequestDialog::setModel(OptionsModel *_model) { - this->model = model; + this->model = _model; - if (model) - connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(update())); + if (_model) + connect(_model, SIGNAL(displayUnitChanged(int)), this, SLOT(update())); // update the display unit if necessary update(); } -void ReceiveRequestDialog::setInfo(const SendCoinsRecipient &info) +void ReceiveRequestDialog::setInfo(const SendCoinsRecipient &_info) { - this->info = info; + this->info = _info; update(); } diff --git a/src/qt/res/movies/makespinner.sh b/src/qt/res/movies/makespinner.sh index a4c2fddbbf..d0deb1238c 100755 --- a/src/qt/res/movies/makespinner.sh +++ b/src/qt/res/movies/makespinner.sh @@ -1,3 +1,7 @@ +# Copyright (c) 2014-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. + FRAMEDIR=$(dirname $0) for i in {0..35} do diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index f35f401d06..ace9f1ceaa 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -83,8 +83,8 @@ class QtRPCTimerBase: public QObject, public RPCTimerBase { Q_OBJECT public: - QtRPCTimerBase(boost::function<void(void)>& func, int64_t millis): - func(func) + QtRPCTimerBase(boost::function<void(void)>& _func, int64_t millis): + func(_func) { timer.setSingleShot(true); connect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); @@ -113,9 +113,11 @@ public: #include "rpcconsole.moc" /** - * Split shell command line into a list of arguments. Aims to emulate \c bash and friends. + * Split shell command line into a list of arguments and execute the command(s). + * Aims to emulate \c bash and friends. * - * - Arguments are delimited with whitespace + * - Command nesting is possible with brackets [example: validateaddress(getnewaddress())] + * - Arguments are delimited with whitespace or comma * - Extra whitespace at the beginning and end and between arguments will be ignored * - Text can be "double" or 'single' quoted * - The backslash \c \ is used as escape character @@ -123,11 +125,15 @@ public: * - Within double quotes, only escape \c " and backslashes before a \c " or another backslash * - Within single quotes, no escaping is possible and no special interpretation takes place * - * @param[out] args Parsed arguments will be appended to this list + * @param[out] result stringified Result from the executed command(chain) * @param[in] strCommand Command line to split */ -bool parseCommandLine(std::vector<std::string> &args, const std::string &strCommand) + +bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand) { + std::vector< std::vector<std::string> > stack; + stack.push_back(std::vector<std::string>()); + enum CmdParseState { STATE_EATING_SPACES, @@ -135,95 +141,180 @@ bool parseCommandLine(std::vector<std::string> &args, const std::string &strComm STATE_SINGLEQUOTED, STATE_DOUBLEQUOTED, STATE_ESCAPE_OUTER, - STATE_ESCAPE_DOUBLEQUOTED + STATE_ESCAPE_DOUBLEQUOTED, + STATE_COMMAND_EXECUTED, + STATE_COMMAND_EXECUTED_INNER } state = STATE_EATING_SPACES; std::string curarg; - Q_FOREACH(char ch, strCommand) + UniValue lastResult; + + std::string strCommandTerminated = strCommand; + if (strCommandTerminated.back() != '\n') + strCommandTerminated += "\n"; + for(char ch: strCommandTerminated) { switch(state) { - case STATE_ARGUMENT: // In or after argument - case STATE_EATING_SPACES: // Handle runs of whitespace - switch(ch) + case STATE_COMMAND_EXECUTED_INNER: + case STATE_COMMAND_EXECUTED: { - case '"': state = STATE_DOUBLEQUOTED; break; - case '\'': state = STATE_SINGLEQUOTED; break; - case '\\': state = STATE_ESCAPE_OUTER; break; - case ' ': case '\n': case '\t': - if(state == STATE_ARGUMENT) // Space ends argument + bool breakParsing = true; + switch(ch) { - args.push_back(curarg); - curarg.clear(); + case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break; + default: + if (state == STATE_COMMAND_EXECUTED_INNER) + { + if (ch != ']') + { + // append char to the current argument (which is also used for the query command) + curarg += ch; + break; + } + if (curarg.size()) + { + // if we have a value query, query arrays with index and objects with a string key + UniValue subelement; + if (lastResult.isArray()) + { + for(char argch: curarg) + if (!std::isdigit(argch)) + throw std::runtime_error("Invalid result query"); + subelement = lastResult[atoi(curarg.c_str())]; + } + else if (lastResult.isObject()) + subelement = find_value(lastResult, curarg); + else + throw std::runtime_error("Invalid result query"); //no array or object: abort + lastResult = subelement; + } + + state = STATE_COMMAND_EXECUTED; + break; + } + // don't break parsing when the char is required for the next argument + breakParsing = false; + + // pop the stack and return the result to the current command arguments + stack.pop_back(); + + // don't stringify the json in case of a string to avoid doublequotes + if (lastResult.isStr()) + curarg = lastResult.get_str(); + else + curarg = lastResult.write(2); + + // if we have a non empty result, use it as stack argument otherwise as general result + if (curarg.size()) + { + if (stack.size()) + stack.back().push_back(curarg); + else + strResult = curarg; + } + curarg.clear(); + // assume eating space state + state = STATE_EATING_SPACES; } - state = STATE_EATING_SPACES; - break; - default: curarg += ch; state = STATE_ARGUMENT; + if (breakParsing) + break; } - break; - case STATE_SINGLEQUOTED: // Single-quoted string - switch(ch) + case STATE_ARGUMENT: // In or after argument + case STATE_EATING_SPACES: // Handle runs of whitespace + switch(ch) { - case '\'': state = STATE_ARGUMENT; break; - default: curarg += ch; + case '"': state = STATE_DOUBLEQUOTED; break; + case '\'': state = STATE_SINGLEQUOTED; break; + case '\\': state = STATE_ESCAPE_OUTER; break; + case '(': case ')': case '\n': + if (state == STATE_ARGUMENT) + { + if (ch == '(' && stack.size() && stack.back().size() > 0) + stack.push_back(std::vector<std::string>()); + if (curarg.size()) + { + // don't allow commands after executed commands on baselevel + if (!stack.size()) + throw std::runtime_error("Invalid Syntax"); + stack.back().push_back(curarg); + } + curarg.clear(); + state = STATE_EATING_SPACES; + } + if ((ch == ')' || ch == '\n') && stack.size() > 0) + { + std::string strPrint; + // Convert argument list to JSON objects in method-dependent way, + // and pass it along with the method name to the dispatcher. + lastResult = tableRPC.execute(stack.back()[0], RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()))); + + state = STATE_COMMAND_EXECUTED; + curarg.clear(); + } + break; + case ' ': case ',': case '\t': + if(state == STATE_ARGUMENT) // Space ends argument + { + if (curarg.size()) + stack.back().push_back(curarg); + curarg.clear(); + } + state = STATE_EATING_SPACES; + break; + default: curarg += ch; state = STATE_ARGUMENT; } - break; - case STATE_DOUBLEQUOTED: // Double-quoted string - switch(ch) + break; + case STATE_SINGLEQUOTED: // Single-quoted string + switch(ch) { - case '"': state = STATE_ARGUMENT; break; - case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break; - default: curarg += ch; + case '\'': state = STATE_ARGUMENT; break; + default: curarg += ch; } - break; - case STATE_ESCAPE_OUTER: // '\' outside quotes - curarg += ch; state = STATE_ARGUMENT; - break; - case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text - if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself - curarg += ch; state = STATE_DOUBLEQUOTED; - break; + break; + case STATE_DOUBLEQUOTED: // Double-quoted string + switch(ch) + { + case '"': state = STATE_ARGUMENT; break; + case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break; + default: curarg += ch; + } + break; + case STATE_ESCAPE_OUTER: // '\' outside quotes + curarg += ch; state = STATE_ARGUMENT; + break; + case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text + if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself + curarg += ch; state = STATE_DOUBLEQUOTED; + break; } } switch(state) // final state { - case STATE_EATING_SPACES: - return true; - case STATE_ARGUMENT: - args.push_back(curarg); - return true; - default: // ERROR to end in one of the other states - return false; + case STATE_COMMAND_EXECUTED: + if (lastResult.isStr()) + strResult = lastResult.get_str(); + else + strResult = lastResult.write(2); + case STATE_ARGUMENT: + case STATE_EATING_SPACES: + return true; + default: // ERROR to end in one of the other states + return false; } } void RPCExecutor::request(const QString &command) { - std::vector<std::string> args; - if(!parseCommandLine(args, command.toStdString())) - { - Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); - return; - } - if(args.empty()) - return; // Nothing to do try { - std::string strPrint; - // Convert argument list to JSON objects in method-dependent way, - // and pass it along with the method name to the dispatcher. - UniValue result = tableRPC.execute( - args[0], - RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end()))); - - // Format result reply - if (result.isNull()) - strPrint = ""; - else if (result.isStr()) - strPrint = result.get_str(); - else - strPrint = result.write(2); - - Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); + std::string result; + std::string executableCommand = command.toStdString() + "\n"; + if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand)) + { + Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); + return; + } + Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result)); } catch (UniValue& objError) { @@ -244,13 +335,13 @@ void RPCExecutor::request(const QString &command) } } -RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) : +RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) : QWidget(parent), ui(new Ui::RPCConsole), clientModel(0), historyPtr(0), cachedNodeid(-1), - platformStyle(platformStyle), + platformStyle(_platformStyle), peersTableContextMenu(0), banTableContextMenu(0), consoleFontSize(0) diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 28affa954d..50224a1cc0 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -35,6 +35,8 @@ public: explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent); ~RPCConsole(); + static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand); + void setClientModel(ClientModel *model); enum MessageClass { diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 8433818a64..4b2ba7d624 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -30,25 +30,25 @@ #define SEND_CONFIRM_DELAY 3 -SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) : +SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::SendCoinsDialog), clientModel(0), model(0), fNewRecipientAllowed(true), fFeeMinimized(true), - platformStyle(platformStyle) + platformStyle(_platformStyle) { ui->setupUi(this); - if (!platformStyle->getImagesOnButtons()) { + if (!_platformStyle->getImagesOnButtons()) { ui->addButton->setIcon(QIcon()); ui->clearButton->setIcon(QIcon()); ui->sendButton->setIcon(QIcon()); } else { - ui->addButton->setIcon(platformStyle->SingleColorIcon(":/icons/add")); - ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove")); - ui->sendButton->setIcon(platformStyle->SingleColorIcon(":/icons/send")); + ui->addButton->setIcon(_platformStyle->SingleColorIcon(":/icons/add")); + ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove")); + ui->sendButton->setIcon(_platformStyle->SingleColorIcon(":/icons/send")); } GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this); @@ -116,40 +116,40 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); } -void SendCoinsDialog::setClientModel(ClientModel *clientModel) +void SendCoinsDialog::setClientModel(ClientModel *_clientModel) { - this->clientModel = clientModel; + this->clientModel = _clientModel; - if (clientModel) { - connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel())); + if (_clientModel) { + connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel())); } } -void SendCoinsDialog::setModel(WalletModel *model) +void SendCoinsDialog::setModel(WalletModel *_model) { - this->model = model; + this->model = _model; - if(model && model->getOptionsModel()) + if(_model && _model->getOptionsModel()) { for(int i = 0; i < ui->entries->count(); ++i) { SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget()); if(entry) { - entry->setModel(model); + entry->setModel(_model); } } - setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), - model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); - connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount))); - connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + setBalance(_model->getBalance(), _model->getUnconfirmedBalance(), _model->getImmatureBalance(), + _model->getWatchBalance(), _model->getWatchUnconfirmedBalance(), _model->getWatchImmatureBalance()); + connect(_model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount))); + connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); updateDisplayUnit(); // Coin Control - connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels())); - connect(model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool))); - ui->frameCoinControl->setVisible(model->getOptionsModel()->getCoinControlFeatures()); + connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels())); + connect(_model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool))); + ui->frameCoinControl->setVisible(_model->getOptionsModel()->getCoinControlFeatures()); coinControlUpdateLabels(); // fee section @@ -826,9 +826,9 @@ void SendCoinsDialog::coinControlUpdateLabels() } } -SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int secDelay, +SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int _secDelay, QWidget *parent) : - QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(secDelay) + QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(_secDelay) { setDefaultButton(QMessageBox::Cancel); yesButton = button(QMessageBox::Yes); diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index d063f2c891..7eb1eb7e3a 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -15,11 +15,11 @@ #include <QApplication> #include <QClipboard> -SendCoinsEntry::SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent) : +SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *parent) : QStackedWidget(parent), ui(new Ui::SendCoinsEntry), model(0), - platformStyle(platformStyle) + platformStyle(_platformStyle) { ui->setupUi(this); @@ -79,12 +79,12 @@ void SendCoinsEntry::on_payTo_textChanged(const QString &address) updateLabel(address); } -void SendCoinsEntry::setModel(WalletModel *model) +void SendCoinsEntry::setModel(WalletModel *_model) { - this->model = model; + this->model = _model; - if (model && model->getOptionsModel()) - connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + if (_model && _model->getOptionsModel()) + connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); clear(); } diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 8e2e8a5098..4061909b71 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -20,11 +20,11 @@ #include <QClipboard> -SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *platformStyle, QWidget *parent) : +SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::SignVerifyMessageDialog), model(0), - platformStyle(platformStyle) + platformStyle(_platformStyle) { ui->setupUi(this); @@ -60,9 +60,9 @@ SignVerifyMessageDialog::~SignVerifyMessageDialog() delete ui; } -void SignVerifyMessageDialog::setModel(WalletModel *model) +void SignVerifyMessageDialog::setModel(WalletModel *_model) { - this->model = model; + this->model = _model; } void SignVerifyMessageDialog::setAddress_SM(const QString &address) diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp new file mode 100644 index 0000000000..3dae33bafb --- /dev/null +++ b/src/qt/test/rpcnestedtests.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "rpcnestedtests.h" + +#include "chainparams.h" +#include "consensus/validation.h" +#include "main.h" +#include "rpc/register.h" +#include "rpc/server.h" +#include "rpcconsole.h" +#include "test/testutil.h" +#include "univalue.h" +#include "util.h" + +#include <QDir> + +#include <boost/filesystem.hpp> + +void RPCNestedTests::rpcNestedTests() +{ + UniValue jsonRPCError; + + // do some test setup + // could be moved to a more generic place when we add more tests on QT level + const CChainParams& chainparams = Params(); + RegisterAllCoreRPCCommands(tableRPC); + ClearDatadirCache(); + std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); + QDir dir(QString::fromStdString(path)); + dir.mkpath("."); + mapArgs["-datadir"] = path; + //mempool.setSanityCheck(1.0); + pblocktree = new CBlockTreeDB(1 << 20, true); + pcoinsdbview = new CCoinsViewDB(1 << 23, true); + pcoinsTip = new CCoinsViewCache(pcoinsdbview); + InitBlockIndex(chainparams); + { + CValidationState state; + bool ok = ActivateBestChain(state, chainparams); + QVERIFY(ok); + } + + SetRPCWarmupFinished(); + + std::string result; + std::string result2; + RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]"); //simple result filtering with path + QVERIFY(result=="main"); + + RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())"); //simple 2 level nesting + RPCConsole::RPCExecuteCommandLine(result, "getblock(getblock(getbestblockhash())[hash], true)"); + + RPCConsole::RPCExecuteCommandLine(result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter + + RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo"); + QVERIFY(result.substr(0,1) == "{"); + + RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()"); + QVERIFY(result.substr(0,1) == "{"); + + RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated + QVERIFY(result.substr(0,1) == "{"); + +#if QT_VERSION >= 0x050300 + // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3) + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax + (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments + (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found +#endif + + (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child contaning the quotes in the key + QVERIFY(result == "null"); + + (RPCConsole::RPCExecuteCommandLine(result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed + (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed + QVERIFY(result == result2); + (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parametres is allowed + QVERIFY(result == result2); + + RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]"); + QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"); + + delete pcoinsTip; + delete pcoinsdbview; + delete pblocktree; + + boost::filesystem::remove_all(boost::filesystem::path(path)); +} diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h new file mode 100644 index 0000000000..9ad409019f --- /dev/null +++ b/src/qt/test/rpcnestedtests.h @@ -0,0 +1,25 @@ +// 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. + +#ifndef BITCOIN_QT_TEST_RPC_NESTED_TESTS_H +#define BITCOIN_QT_TEST_RPC_NESTED_TESTS_H + +#include <QObject> +#include <QTest> + +#include "txdb.h" +#include "txmempool.h" + +class RPCNestedTests : public QObject +{ + Q_OBJECT + + private Q_SLOTS: + void rpcNestedTests(); + +private: + CCoinsViewDB *pcoinsdbview; +}; + +#endif // BITCOIN_QT_TEST_RPC_NESTED_TESTS_H diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index db193420bf..dbaab54fb6 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2015 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -6,6 +6,9 @@ #include "config/bitcoin-config.h" #endif +#include "chainparams.h" +#include "key.h" +#include "rpcnestedtests.h" #include "util.h" #include "uritests.h" @@ -27,10 +30,17 @@ Q_IMPORT_PLUGIN(qtwcodecs) Q_IMPORT_PLUGIN(qkrcodecs) #endif +extern void noui_connect(); + // This is all you need to run all the tests int main(int argc, char *argv[]) { + ECC_Start(); SetupEnvironment(); + SetupNetworking(); + SelectParams(CBaseChainParams::MAIN); + noui_connect(); + bool fInvalid = false; // Don't remove this, it's needed to access @@ -48,6 +58,10 @@ int main(int argc, char *argv[]) if (QTest::qExec(&test2) != 0) fInvalid = true; #endif + RPCNestedTests test3; + if (QTest::qExec(&test3) != 0) + fInvalid = true; + ECC_Stop(); return fInvalid; } diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index bae0cbd1c8..65144e7865 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -241,6 +241,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>"; strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxID() + "<br>"; + strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.GetTotalSize()) + " bytes<br>"; strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>"; // Message from normal bitcoin:URI (bitcoin:123...?message=example) diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 9dcb72f55e..e21b89b935 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -66,9 +66,9 @@ void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime invalidateFilter(); } -void TransactionFilterProxy::setAddressPrefix(const QString &addrPrefix) +void TransactionFilterProxy::setAddressPrefix(const QString &_addrPrefix) { - this->addrPrefix = addrPrefix; + this->addrPrefix = _addrPrefix; invalidateFilter(); } @@ -95,9 +95,9 @@ void TransactionFilterProxy::setLimit(int limit) this->limitRows = limit; } -void TransactionFilterProxy::setShowInactive(bool showInactive) +void TransactionFilterProxy::setShowInactive(bool _showInactive) { - this->showInactive = showInactive; + this->showInactive = _showInactive; invalidateFilter(); } diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 8c754c3aad..8eff302aff 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -88,16 +88,16 @@ public: { } - TransactionRecord(uint256 hash, qint64 time): - hash(hash), time(time), type(Other), address(""), debit(0), + TransactionRecord(uint256 _hash, qint64 _time): + hash(_hash), time(_time), type(Other), address(""), debit(0), credit(0), idx(0) { } - TransactionRecord(uint256 hash, qint64 time, - Type type, const std::string &address, - const CAmount& debit, const CAmount& credit): - hash(hash), time(time), type(type), address(address), debit(debit), credit(credit), + TransactionRecord(uint256 _hash, qint64 _time, + Type _type, const std::string &_address, + const CAmount& _debit, const CAmount& _credit): + hash(_hash), time(_time), type(_type), address(_address), debit(_debit), credit(_credit), idx(0) { } diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index b29ecf8348..52261ff04b 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -59,9 +59,9 @@ struct TxLessThan class TransactionTablePriv { public: - TransactionTablePriv(CWallet *wallet, TransactionTableModel *parent) : - wallet(wallet), - parent(parent) + TransactionTablePriv(CWallet *_wallet, TransactionTableModel *_parent) : + wallet(_wallet), + parent(_parent) { } @@ -235,13 +235,13 @@ public: } }; -TransactionTableModel::TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent): +TransactionTableModel::TransactionTableModel(const PlatformStyle *_platformStyle, CWallet* _wallet, WalletModel *parent): QAbstractTableModel(parent), - wallet(wallet), + wallet(_wallet), walletModel(parent), - priv(new TransactionTablePriv(wallet, this)), + priv(new TransactionTablePriv(_wallet, this)), fProcessingQueuedTransactions(false), - platformStyle(platformStyle) + platformStyle(_platformStyle) { columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); priv->refreshWallet(); @@ -714,8 +714,8 @@ struct TransactionNotification { public: TransactionNotification() {} - TransactionNotification(uint256 hash, ChangeType status, bool showTransaction): - hash(hash), status(status), showTransaction(showTransaction) {} + TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction): + hash(_hash), status(_status), showTransaction(_showTransaction) {} void invoke(QObject *ttm) { diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 48cf940502..856b16d2c4 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -184,13 +184,13 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails())); } -void TransactionView::setModel(WalletModel *model) +void TransactionView::setModel(WalletModel *_model) { - this->model = model; - if(model) + this->model = _model; + if(_model) { transactionProxyModel = new TransactionFilterProxy(this); - transactionProxyModel->setSourceModel(model->getTransactionTableModel()); + transactionProxyModel->setSourceModel(_model->getTransactionTableModel()); transactionProxyModel->setDynamicSortFilter(true); transactionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); @@ -214,10 +214,10 @@ void TransactionView::setModel(WalletModel *model) columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH); - if (model->getOptionsModel()) + if (_model->getOptionsModel()) { // Add third party transaction URLs to context menu - QStringList listUrls = model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts); + QStringList listUrls = _model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts); for (int i = 0; i < listUrls.size(); ++i) { QString host = QUrl(listUrls[i].trimmed(), QUrl::StrictMode).host(); @@ -234,10 +234,10 @@ void TransactionView::setModel(WalletModel *model) } // show/hide column Watch-only - updateWatchOnlyColumn(model->haveWatchOnly()); + updateWatchOnlyColumn(_model->haveWatchOnly()); // Watch-only signal - connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool))); + connect(_model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool))); } } diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index e4ca5e1831..69dcc9abb1 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -12,10 +12,10 @@ #include <QHBoxLayout> #include <QLabel> -WalletFrame::WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui) : +WalletFrame::WalletFrame(const PlatformStyle *_platformStyle, BitcoinGUI *_gui) : QFrame(_gui), gui(_gui), - platformStyle(platformStyle) + platformStyle(_platformStyle) { // Leave HBox hook for adding a list view later QHBoxLayout *walletFrameLayout = new QHBoxLayout(this); @@ -33,9 +33,9 @@ WalletFrame::~WalletFrame() { } -void WalletFrame::setClientModel(ClientModel *clientModel) +void WalletFrame::setClientModel(ClientModel *_clientModel) { - this->clientModel = clientModel; + this->clientModel = _clientModel; } bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel) @@ -57,6 +57,8 @@ bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel) // Ensure a walletView is able to show the main window connect(walletView, SIGNAL(showNormalIfMinimized()), gui, SLOT(showNormalIfMinimized())); + connect(walletView, SIGNAL(outOfSyncWarningClicked()), this, SLOT(outOfSyncWarningClicked())); + return true; } @@ -195,3 +197,7 @@ WalletView *WalletFrame::currentWalletView() return qobject_cast<WalletView*>(walletStack->currentWidget()); } +void WalletFrame::outOfSyncWarningClicked() +{ + Q_EMIT requestedSyncWarningInfo(); +} diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 9a5bc273c2..00c2f56363 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -38,6 +38,10 @@ public: void showOutOfSyncWarning(bool fShow); +Q_SIGNALS: + /** Notify that the user has requested more information about the out-of-sync warning */ + void requestedSyncWarningInfo(); + private: QStackedWidget *walletStack; BitcoinGUI *gui; @@ -78,6 +82,8 @@ public Q_SLOTS: void usedSendingAddresses(); /** Show used receiving addresses */ void usedReceivingAddresses(); + /** Pass on signal over requested out-of-sync-warning information */ + void outOfSyncWarningClicked(); }; #endif // BITCOIN_QT_WALLETFRAME_H diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 73851e97fc..c8a2cb37ec 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -27,8 +27,8 @@ #include <boost/foreach.hpp> -WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent) : - QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0), +WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *_wallet, OptionsModel *_optionsModel, QObject *parent) : + QObject(parent), wallet(_wallet), optionsModel(_optionsModel), addressTableModel(0), transactionTableModel(0), recentRequestsTableModel(0), cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0), @@ -531,10 +531,10 @@ WalletModel::UnlockContext WalletModel::requestUnlock() return UnlockContext(this, valid, was_locked); } -WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock): - wallet(wallet), - valid(valid), - relock(relock) +WalletModel::UnlockContext::UnlockContext(WalletModel *_wallet, bool _valid, bool _relock): + wallet(_wallet), + valid(_valid), + relock(_relock) { } @@ -684,6 +684,11 @@ bool WalletModel::abandonTransaction(uint256 hash) const return wallet->AbandonTransaction(hash); } +bool WalletModel::isWalletEnabled() +{ + return !GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET); +} + bool WalletModel::hdEnabled() const { return wallet->IsHDEnabled(); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index a15ecf899b..e233fa690d 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -38,8 +38,8 @@ class SendCoinsRecipient { public: explicit SendCoinsRecipient() : amount(0), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) { } - explicit SendCoinsRecipient(const QString &addr, const QString &label, const CAmount& amount, const QString &message): - address(addr), label(label), amount(amount), message(message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} + explicit SendCoinsRecipient(const QString &addr, const QString &_label, const CAmount& _amount, const QString &_message): + address(addr), label(_label), amount(_amount), message(_message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} // If from an unauthenticated payment request, this is used for storing // the addresses, e.g. address-A<br />address-B<br />address-C. @@ -145,8 +145,8 @@ public: // Return status record for SendCoins, contains error id + information struct SendCoinsReturn { - SendCoinsReturn(StatusCode status = OK): - status(status) {} + SendCoinsReturn(StatusCode _status = OK): + status(_status) {} StatusCode status; }; @@ -203,6 +203,8 @@ public: bool transactionCanBeAbandoned(uint256 hash) const; bool abandonTransaction(uint256 hash) const; + static bool isWalletEnabled(); + bool hdEnabled() const; private: diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index ffadf89cc8..fdec6a1c86 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -7,8 +7,8 @@ #include "policy/policy.h" #include "wallet/wallet.h" -WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &recipients) : - recipients(recipients), +WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) : + recipients(_recipients), walletTransaction(0), keyChange(0), fee(0) diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 495ebfd834..a9518413c2 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -29,11 +29,11 @@ #include <QPushButton> #include <QVBoxLayout> -WalletView::WalletView(const PlatformStyle *platformStyle, QWidget *parent): +WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent): QStackedWidget(parent), clientModel(0), walletModel(0), - platformStyle(platformStyle) + platformStyle(_platformStyle) { // Create tabs overviewPage = new OverviewPage(platformStyle); @@ -66,6 +66,7 @@ WalletView::WalletView(const PlatformStyle *platformStyle, QWidget *parent): // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page connect(overviewPage, SIGNAL(transactionClicked(QModelIndex)), transactionView, SLOT(focusTransaction(QModelIndex))); + connect(overviewPage, SIGNAL(outOfSyncWarningClicked()), this, SLOT(requestedSyncWarningInfo())); // Double-clicking on a transaction on the transaction history page shows details connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails())); @@ -104,47 +105,47 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui) } } -void WalletView::setClientModel(ClientModel *clientModel) +void WalletView::setClientModel(ClientModel *_clientModel) { - this->clientModel = clientModel; + this->clientModel = _clientModel; - overviewPage->setClientModel(clientModel); - sendCoinsPage->setClientModel(clientModel); + overviewPage->setClientModel(_clientModel); + sendCoinsPage->setClientModel(_clientModel); } -void WalletView::setWalletModel(WalletModel *walletModel) +void WalletView::setWalletModel(WalletModel *_walletModel) { - this->walletModel = walletModel; + this->walletModel = _walletModel; // Put transaction list in tabs - transactionView->setModel(walletModel); - overviewPage->setWalletModel(walletModel); - receiveCoinsPage->setModel(walletModel); - sendCoinsPage->setModel(walletModel); - usedReceivingAddressesPage->setModel(walletModel->getAddressTableModel()); - usedSendingAddressesPage->setModel(walletModel->getAddressTableModel()); - - if (walletModel) + transactionView->setModel(_walletModel); + overviewPage->setWalletModel(_walletModel); + receiveCoinsPage->setModel(_walletModel); + sendCoinsPage->setModel(_walletModel); + usedReceivingAddressesPage->setModel(_walletModel->getAddressTableModel()); + usedSendingAddressesPage->setModel(_walletModel->getAddressTableModel()); + + if (_walletModel) { // Receive and pass through messages from wallet model - connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); + connect(_walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int))); // Handle changes in encryption status - connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int))); + connect(_walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int))); updateEncryptionStatus(); // update HD status - Q_EMIT hdEnabledStatusChanged(walletModel->hdEnabled()); + Q_EMIT hdEnabledStatusChanged(_walletModel->hdEnabled()); // Balloon pop-up for new transaction - connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), + connect(_walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(processNewTransaction(QModelIndex,int,int))); // Ask for passphrase if needed - connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); + connect(_walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); // Show progress dialog - connect(walletModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int))); + connect(_walletModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int))); } } @@ -322,3 +323,8 @@ void WalletView::showProgress(const QString &title, int nProgress) else if (progressDialog) progressDialog->setValue(nProgress); } + +void WalletView::requestedSyncWarningInfo() +{ + Q_EMIT outOfSyncWarningClicked(); +} diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 2045605954..aaa6aacbf0 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -110,6 +110,9 @@ public Q_SLOTS: /** Show progress dialog e.g. for rescan */ void showProgress(const QString &title, int nProgress); + /** User has requested more information about the out of sync state */ + void requestedSyncWarningInfo(); + Q_SIGNALS: /** Signal that we want to show the main window */ void showNormalIfMinimized(); @@ -121,6 +124,8 @@ Q_SIGNALS: void hdEnabledStatusChanged(int hdEnabled); /** Notify that a new transaction appeared */ void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label); + /** Notify that the out of sync warning icon has been pressed */ + void outOfSyncWarningClicked(); }; #endif // BITCOIN_QT_WALLETVIEW_H diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 5afcf6353c..f0b7e0a07c 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -44,7 +44,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) if (fHelp || params.size() != 0) throw runtime_error( "getinfo\n" - "Returns an object containing various state info.\n" + "\nDEPRECATED. Returns an object containing various state info.\n" "\nResult:\n" "{\n" " \"version\": xxxxx, (numeric) the server version\n" diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 33f107d84b..97abeb7211 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) { connman->ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, "", true); + CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); // Should get banned @@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning) BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned CAddress addr2(ip(0xa0b0c002), NODE_NONE); - CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, "", true); + CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, "", true); GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2); dummyNode2.nVersion = 1; Misbehaving(dummyNode2.GetId(), 50); @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) connman->ClearBanned(); mapArgs["-banscore"] = "111"; // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, "", true); + CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, "", true); GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); @@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) SetMockTime(nStartTime); // Overrides future calls to GetTime() CAddress addr(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, "", true); + CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, "", true); GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode); dummyNode.nVersion = 1; diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index 5f150e4812..5ccaeb57bb 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -257,8 +257,7 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions) addrman.Good(CAddress(addr, NODE_NONE)); //Test 15: No collision in tried table yet. - BOOST_TEST_MESSAGE(addrman.size()); - BOOST_CHECK(addrman.size() == i); + BOOST_CHECK_EQUAL(addrman.size(), i); } //Test 16: tried table collision! @@ -543,4 +542,4 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) // than 64 buckets. BOOST_CHECK(buckets.size() > 64); } -BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index bc9a98ab04..680708533e 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -164,12 +164,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) bool fInboundIn = false; // Test that fFeeler is false by default. - CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, pszDest, fInboundIn); + CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, pszDest, fInboundIn); BOOST_CHECK(pnode1->fInbound == false); BOOST_CHECK(pnode1->fFeeler == false); fInboundIn = true; - CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, pszDest, fInboundIn); + CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, pszDest, fInboundIn); BOOST_CHECK(pnode2->fInbound == true); BOOST_CHECK(pnode2->fFeeler == false); } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index b1ceef4f64..02843d8525 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -72,7 +72,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); - g_connman = std::unique_ptr<CConnman>(new CConnman()); + g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests. connman = g_connman.get(); RegisterNodeSignals(GetNodeSignals()); } diff --git a/src/ui_interface.cpp b/src/ui_interface.cpp index c778e40a90..74a13e0e05 100644 --- a/src/ui_interface.cpp +++ b/src/ui_interface.cpp @@ -18,6 +18,11 @@ void InitWarning(const std::string& str) uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING); } +std::string AmountHighWarn(const std::string& optname) +{ + return strprintf(_("%s is set very high!"), optname); +} + std::string AmountErrMsg(const char* const optname, const std::string& strValue) { return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue); diff --git a/src/ui_interface.h b/src/ui_interface.h index 7e6557f8e2..177ff238db 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -112,6 +112,8 @@ void InitWarning(const std::string& str); /** Show error message **/ bool InitError(const std::string& str); +std::string AmountHighWarn(const std::string& optname); + std::string AmountErrMsg(const char* const optname, const std::string& strValue); extern CClientUIInterface uiInterface; diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 8428b1c683..e48b905bfb 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -56,7 +56,7 @@ public: bool setNumStr(const std::string& val); bool setInt(uint64_t val); bool setInt(int64_t val); - bool setInt(int val) { return setInt((int64_t)val); } + bool setInt(int val_) { return setInt((int64_t)val_); } bool setFloat(double val); bool setStr(const std::string& val); bool setArray(); @@ -95,28 +95,28 @@ public: bool push_backV(const std::vector<UniValue>& vec); bool pushKV(const std::string& key, const UniValue& val); - bool pushKV(const std::string& key, const std::string& val) { - UniValue tmpVal(VSTR, val); + bool pushKV(const std::string& key, const std::string& val_) { + UniValue tmpVal(VSTR, val_); return pushKV(key, tmpVal); } bool pushKV(const std::string& key, const char *val_) { - std::string val(val_); - return pushKV(key, val); + std::string _val(val_); + return pushKV(key, _val); } - bool pushKV(const std::string& key, int64_t val) { - UniValue tmpVal(val); + bool pushKV(const std::string& key, int64_t val_) { + UniValue tmpVal(val_); return pushKV(key, tmpVal); } - bool pushKV(const std::string& key, uint64_t val) { - UniValue tmpVal(val); + bool pushKV(const std::string& key, uint64_t val_) { + UniValue tmpVal(val_); return pushKV(key, tmpVal); } - bool pushKV(const std::string& key, int val) { - UniValue tmpVal((int64_t)val); + bool pushKV(const std::string& key, int val_) { + UniValue tmpVal((int64_t)val_); return pushKV(key, tmpVal); } - bool pushKV(const std::string& key, double val) { - UniValue tmpVal(val); + bool pushKV(const std::string& key, double val_) { + UniValue tmpVal(val_); return pushKV(key, tmpVal); } bool pushKVs(const UniValue& obj); diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp index 0076d6678e..1f8cee6d29 100644 --- a/src/univalue/lib/univalue.cpp +++ b/src/univalue/lib/univalue.cpp @@ -119,32 +119,29 @@ bool UniValue::setNumStr(const string& val_) return true; } -bool UniValue::setInt(uint64_t val) +bool UniValue::setInt(uint64_t val_) { - string s; ostringstream oss; - oss << val; + oss << val_; return setNumStr(oss.str()); } -bool UniValue::setInt(int64_t val) +bool UniValue::setInt(int64_t val_) { - string s; ostringstream oss; - oss << val; + oss << val_; return setNumStr(oss.str()); } -bool UniValue::setFloat(double val) +bool UniValue::setFloat(double val_) { - string s; ostringstream oss; - oss << std::setprecision(16) << val; + oss << std::setprecision(16) << val_; bool ret = setNumStr(oss.str()); typ = VNUM; @@ -173,12 +170,12 @@ bool UniValue::setObject() return true; } -bool UniValue::push_back(const UniValue& val) +bool UniValue::push_back(const UniValue& val_) { if (typ != VARR) return false; - values.push_back(val); + values.push_back(val_); return true; } @@ -192,13 +189,13 @@ bool UniValue::push_backV(const std::vector<UniValue>& vec) return true; } -bool UniValue::pushKV(const std::string& key, const UniValue& val) +bool UniValue::pushKV(const std::string& key, const UniValue& val_) { if (typ != VOBJ) return false; keys.push_back(key); - values.push_back(val); + values.push_back(val_); return true; } @@ -228,7 +225,7 @@ int UniValue::findKey(const std::string& key) const bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t) { for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin(); - it != t.end(); it++) { + it != t.end(); ++it) { int idx = findKey(it->first); if (idx < 0) return false; diff --git a/src/util.cpp b/src/util.cpp index c7d147a11e..93cc0412b5 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -600,19 +600,19 @@ bool TryCreateDirectory(const boost::filesystem::path& p) return false; } -void FileCommit(FILE *fileout) +void FileCommit(FILE *file) { - fflush(fileout); // harmless if redundantly called + fflush(file); // harmless if redundantly called #ifdef WIN32 - HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fileout)); + HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); FlushFileBuffers(hFile); #else #if defined(__linux__) || defined(__NetBSD__) - fdatasync(fileno(fileout)); + fdatasync(fileno(file)); #elif defined(__APPLE__) && defined(F_FULLFSYNC) - fcntl(fileno(fileout), F_FULLFSYNC, 0); + fcntl(fileno(file), F_FULLFSYNC, 0); #else - fsync(fileno(fileout)); + fsync(fileno(file)); #endif #endif } diff --git a/src/util.h b/src/util.h index 39328b51ef..45b3658557 100644 --- a/src/util.h +++ b/src/util.h @@ -93,7 +93,7 @@ bool error(const char* fmt, const Args&... args) void PrintExceptionContinue(const std::exception *pex, const char* pszThread); void ParseParameters(int argc, const char*const argv[]); -void FileCommit(FILE *fileout); +void FileCommit(FILE *file); bool TruncateFile(FILE *file, unsigned int length); int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 42ebdb9b9b..e80fa7dff8 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -344,8 +344,6 @@ UniValue removeprunedfunds(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet."); } - ThreadFlushWalletDB(pwalletMain->strWalletFile); - return NullUniValue; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 993caad400..3eb7e5d9ba 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2630,6 +2630,9 @@ static const CRPCCommand commands[] = void RegisterWalletRPCCommands(CRPCTable &t) { + if (GetBoolArg("-disablewallet", false)) + return; + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) t.appendCommand(commands[vcidx].name, &commands[vcidx]); } diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp index a6cada46a2..a833be13d0 100644 --- a/src/wallet/test/accounting_tests.cpp +++ b/src/wallet/test/accounting_tests.cpp @@ -3,7 +3,6 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "wallet/wallet.h" -#include "wallet/walletdb.h" #include "wallet/test/wallet_test_fixture.h" @@ -17,13 +16,13 @@ extern CWallet* pwalletMain; BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup) static void -GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results) +GetResults(std::map<CAmount, CAccountingEntry>& results) { std::list<CAccountingEntry> aes; results.clear(); - BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK); - walletdb.ListAccountCreditDebit("", aes); + BOOST_CHECK(pwalletMain->ReorderTransactions() == DB_LOAD_OK); + pwalletMain->ListAccountCreditDebit("", aes); BOOST_FOREACH(CAccountingEntry& ae, aes) { results[ae.nOrderPos] = ae; @@ -32,7 +31,6 @@ GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results) BOOST_AUTO_TEST_CASE(acc_orderupgrade) { - CWalletDB walletdb(pwalletMain->strWalletFile); std::vector<CWalletTx*> vpwtx; CWalletTx wtx; CAccountingEntry ae; @@ -45,7 +43,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333333; ae.strOtherAccount = "b"; ae.strComment = ""; - pwalletMain->AddAccountingEntry(ae, walletdb); + pwalletMain->AddAccountingEntry(ae); wtx.mapValue["comment"] = "z"; pwalletMain->AddToWallet(wtx); @@ -55,9 +53,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333336; ae.strOtherAccount = "c"; - pwalletMain->AddAccountingEntry(ae, walletdb); + pwalletMain->AddAccountingEntry(ae); - GetResults(walletdb, results); + GetResults(results); BOOST_CHECK(pwalletMain->nOrderPosNext == 3); BOOST_CHECK(2 == results.size()); @@ -71,9 +69,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333330; ae.strOtherAccount = "d"; ae.nOrderPos = pwalletMain->IncOrderPosNext(); - pwalletMain->AddAccountingEntry(ae, walletdb); + pwalletMain->AddAccountingEntry(ae); - GetResults(walletdb, results); + GetResults(results); BOOST_CHECK(results.size() == 3); BOOST_CHECK(pwalletMain->nOrderPosNext == 4); @@ -105,7 +103,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) vpwtx[2]->nTimeReceived = (unsigned int)1333333329; vpwtx[2]->nOrderPos = -1; - GetResults(walletdb, results); + GetResults(results); BOOST_CHECK(results.size() == 3); BOOST_CHECK(pwalletMain->nOrderPosNext == 6); @@ -121,9 +119,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) ae.nTime = 1333333334; ae.strOtherAccount = "e"; ae.nOrderPos = -1; - pwalletMain->AddAccountingEntry(ae, walletdb); + pwalletMain->AddAccountingEntry(ae); - GetResults(walletdb, results); + GetResults(results); BOOST_CHECK(results.size() == 4); BOOST_CHECK(pwalletMain->nOrderPosNext == 7); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 4c10ea0edb..50d63182ae 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -414,6 +414,9 @@ void CWallet::Flush(bool shutdown) bool CWallet::Verify() { + if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) + return true; + LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0)); std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); @@ -649,6 +652,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) return true; } +DBErrors CWallet::ReorderTransactions() +{ + CWalletDB walletdb(strWalletFile); + return walletdb.ReorderTransactions(this); +} + int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { AssertLockHeld(cs_wallet); // nOrderPosNext @@ -677,7 +686,7 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun debit.nTime = nNow; debit.strOtherAccount = strTo; debit.strComment = strComment; - AddAccountingEntry(debit, walletdb); + AddAccountingEntry(debit, &walletdb); // Credit CAccountingEntry credit; @@ -687,7 +696,7 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun credit.nTime = nNow; credit.strOtherAccount = strFrom; credit.strComment = strComment; - AddAccountingEntry(credit, walletdb); + AddAccountingEntry(credit, &walletdb); if (!walletdb.TxnCommit()) return false; @@ -2501,9 +2510,21 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon return true; } -bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pwalletdb) +void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) { + CWalletDB walletdb(strWalletFile); + return walletdb.ListAccountCreditDebit(strAccount, entries); +} + +bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry) { - if (!pwalletdb.WriteAccountingEntry_Backend(acentry)) + CWalletDB walletdb(strWalletFile); + + return AddAccountingEntry(acentry, &walletdb); +} + +bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwalletdb) +{ + if (!pwalletdb->WriteAccountingEntry_Backend(acentry)) return false; laccentries.push_back(acentry); @@ -3275,6 +3296,12 @@ std::string CWallet::GetWalletHelpString(bool showDebug) bool CWallet::InitLoadWallet() { + if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { + pwalletMain = NULL; + LogPrintf("Wallet disabled!\n"); + return true; + } + std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); // needed to restore wallet transaction meta data after -zapwallettxes @@ -3446,13 +3473,31 @@ bool CWallet::InitLoadWallet() bool CWallet::ParameterInteraction() { + if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) + return true; + + if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && SoftSetBoolArg("-walletbroadcast", false)) { + LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__); + } + + if (GetBoolArg("-sysperms", false)) + return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); + if (GetArg("-prune", 0) && GetBoolArg("-rescan", false)) + return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.")); + + if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB) + InitWarning(AmountHighWarn("-minrelaytxfee") + " " + + _("The wallet will avoid paying less than the minimum relay fee.")); + if (mapArgs.count("-mintxfee")) { CAmount n = 0; - if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) - CWallet::minTxFee = CFeeRate(n); - else + if (!ParseMoney(mapArgs["-mintxfee"], n)) return InitError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"])); + if (n > HIGH_TX_FEE_PER_KB) + InitWarning(AmountHighWarn("-mintxfee") + " " + + _("This is the minimum transaction fee you pay on every transaction.")); + CWallet::minTxFee = CFeeRate(n); } if (mapArgs.count("-fallbackfee")) { @@ -3460,7 +3505,8 @@ bool CWallet::ParameterInteraction() if (!ParseMoney(mapArgs["-fallbackfee"], nFeePerK)) return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), mapArgs["-fallbackfee"])); if (nFeePerK > HIGH_TX_FEE_PER_KB) - InitWarning(_("-fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available.")); + InitWarning(AmountHighWarn("-fallbackfee") + " " + + _("This is the transaction fee you may pay when fee estimates are not available.")); CWallet::fallbackFee = CFeeRate(nFeePerK); } if (mapArgs.count("-paytxfee")) @@ -3469,7 +3515,9 @@ bool CWallet::ParameterInteraction() if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK)) return InitError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"])); if (nFeePerK > HIGH_TX_FEE_PER_KB) - InitWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction.")); + InitWarning(AmountHighWarn("-paytxfee") + " " + + _("This is the transaction fee you will pay if you send a transaction.")); + payTxFee = CFeeRate(nFeePerK, 1000); if (payTxFee < ::minRelayTxFee) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 61aff6e45a..f6c658928f 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -59,7 +59,7 @@ static const bool DEFAULT_WALLET_RBF = false; //! Largest (in bytes) free transaction we're willing to create static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; static const bool DEFAULT_WALLETBROADCAST = true; - +static const bool DEFAULT_DISABLE_WALLET = false; //! if set, all keys will be derived by using BIP32 static const bool DEFAULT_USE_HD_WALLET = true; @@ -741,6 +741,7 @@ public: * @return next transaction order id */ int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL); + DBErrors ReorderTransactions(); bool AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment = ""); bool GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew = false); @@ -775,7 +776,9 @@ public: std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman); - bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); + void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries); + bool AddAccountingEntry(const CAccountingEntry&); + bool AddAccountingEntry(const CAccountingEntry&, CWalletDB *pwalletdb); static CFeeRate minTxFee; static CFeeRate fallbackFee; |