aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rwxr-xr-xautogen.sh3
-rw-r--r--configure.ac2
-rw-r--r--contrib/debian/control1
-rw-r--r--contrib/gitian-descriptors/gitian-osx-bitcoin.yml1
-rw-r--r--doc/build-osx.md4
-rw-r--r--doc/gitian-building.md35
-rw-r--r--doc/release-notes.md20
-rw-r--r--doc/release-process.md32
-rw-r--r--src/Makefile.am20
-rw-r--r--src/Makefile.qt.include3
-rw-r--r--src/Makefile.qttest.include3
-rw-r--r--src/Makefile.test.include5
-rw-r--r--src/core.cpp2
-rw-r--r--src/core.h9
-rw-r--r--src/init.cpp33
-rw-r--r--src/key.cpp130
-rw-r--r--src/main.cpp33
-rw-r--r--src/main.h12
-rw-r--r--src/miner.cpp2
-rw-r--r--src/qt/bitcoin.cpp2
-rw-r--r--src/qt/bitcoingui.cpp78
-rw-r--r--src/qt/bitcoingui.h37
-rw-r--r--src/qt/bitcoinunits.cpp10
-rw-r--r--src/qt/bitcoinunits.h2
-rw-r--r--src/qt/coincontroldialog.cpp60
-rw-r--r--src/qt/coincontroldialog.h3
-rw-r--r--src/qt/guiutil.cpp3
-rw-r--r--src/qt/optionsdialog.cpp9
-rw-r--r--src/qt/optionsmodel.cpp17
-rw-r--r--src/qt/optionsmodel.h2
-rw-r--r--src/qt/paymentserver.cpp4
-rw-r--r--src/qt/recentrequeststablemodel.cpp27
-rw-r--r--src/qt/recentrequeststablemodel.h6
-rw-r--r--src/qt/transactiontablemodel.cpp11
-rw-r--r--src/qt/transactiontablemodel.h2
-rw-r--r--src/qt/transactionview.cpp2
-rw-r--r--src/rpcmisc.cpp2
-rw-r--r--src/rpcnet.cpp2
-rw-r--r--src/rpcserver.cpp2
-rw-r--r--src/secp256k1/.empty0
-rw-r--r--src/txmempool.cpp35
-rw-r--r--src/txmempool.h4
-rw-r--r--src/wallet.cpp51
-rw-r--r--src/wallet.h6
45 files changed, 565 insertions, 163 deletions
diff --git a/Makefile.am b/Makefile.am
index 719af42ac7..3a6a6b6d88 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,6 +35,7 @@ COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \
dist-hook:
-$(MAKE) -C $(top_distdir)/src/leveldb clean
+ -$(MAKE) -C $(top_distdir)/src/secp256k1 distclean
-$(GIT) archive --format=tar HEAD -- src/version.cpp | $(AMTAR) -C $(top_distdir) -xf -
distcheck-hook:
diff --git a/autogen.sh b/autogen.sh
index 5b883a6a4c..50b85bcba0 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -2,4 +2,7 @@
set -e
srcdir="$(dirname $0)"
cd "$srcdir"
+if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then
+ export LIBTOOLIZE="${GLIBTOOLIZE}"
+fi
autoreconf --install --force
diff --git a/configure.ac b/configure.ac
index 811ef1dd80..2a4636e360 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,6 +9,7 @@ define(_COPYRIGHT_YEAR, 2014)
AC_INIT([Bitcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@bitcoin.org],[bitcoin])
AC_CONFIG_AUX_DIR([src/build-aux])
AC_CONFIG_MACRO_DIR([src/m4])
+LT_INIT([disable-shared])
AC_CANONICAL_HOST
AH_TOP([#ifndef BITCOIN_CONFIG_H])
AH_TOP([#define BITCOIN_CONFIG_H])
@@ -679,6 +680,7 @@ AM_CONDITIONAL([USE_LCOV],[test x$use_lcov == xyes])
AM_CONDITIONAL([USE_COMPARISON_TOOL],[test x$use_comparison_tool != xno])
AM_CONDITIONAL([USE_COMPARISON_TOOL_REORG_TESTS],[test x$use_comparison_tool_reorg_test != xno])
AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes])
+AM_CONDITIONAL([USE_LIBSECP256K1],[test x$use_libsecp256k1 = xyes])
AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version])
AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version])
diff --git a/contrib/debian/control b/contrib/debian/control
index 9e006a7070..a04e88d4e1 100644
--- a/contrib/debian/control
+++ b/contrib/debian/control
@@ -6,6 +6,7 @@ Uploaders: Micah Anderson <micah@debian.org>
Build-Depends: debhelper,
devscripts,
automake,
+ libtool,
bash-completion,
libboost-system-dev (>> 1.35) | libboost-system1.35-dev,
libdb4.8++-dev,
diff --git a/contrib/gitian-descriptors/gitian-osx-bitcoin.yml b/contrib/gitian-descriptors/gitian-osx-bitcoin.yml
index 44b5de9be3..bc3d561c35 100644
--- a/contrib/gitian-descriptors/gitian-osx-bitcoin.yml
+++ b/contrib/gitian-descriptors/gitian-osx-bitcoin.yml
@@ -11,6 +11,7 @@ packages:
- "bsdmainutils"
- "pkg-config"
- "p7zip-full"
+- "libtool"
reference_datetime: "2013-06-01 00:00:00"
remotes:
diff --git a/doc/build-osx.md b/doc/build-osx.md
index 1e38326d86..bc42723b12 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -41,7 +41,7 @@ Instructions: MacPorts
### Install dependencies
- sudo port install boost db48@+no_java openssl miniupnpc autoconf pkgconfig automake
+ sudo port install boost db48@+no_java openssl miniupnpc autoconf pkgconfig automake libtool
Optional: install Qt4
@@ -69,7 +69,7 @@ Instructions: Homebrew
#### Install dependencies using Homebrew
- brew install autoconf automake berkeley-db4 boost miniupnpc openssl pkg-config protobuf qt
+ brew install autoconf automake libtool berkeley-db4 boost miniupnpc openssl pkg-config protobuf qt
Note: After you have installed the dependencies, you should check that the Homebrew installed version of OpenSSL is the one available for compilation. You can check this by typing
diff --git a/doc/gitian-building.md b/doc/gitian-building.md
index 378a45eda5..b356a5d88d 100644
--- a/doc/gitian-building.md
+++ b/doc/gitian-building.md
@@ -4,8 +4,8 @@ Gitian building
*Setup instructions for a gitian build of Bitcoin using a Debian VM or physical system.*
Gitian is the deterministic build process that is used to build the Bitcoin
-Core executables [1]. It provides a way to be reasonably sure that the
-executables are really built from source on github. It also makes sure that
+Core executables. It provides a way to be reasonably sure that the
+executables are really built from source on GitHub. It also makes sure that
the same, tested dependencies are used and statically built into the executable.
Multiple developers build the source code by following a specific descriptor
@@ -17,9 +17,6 @@ More independent gitian builders are needed, which is why I wrote this
guide. It is preferred to follow these steps yourself instead of using someone else's
VM image to avoid 'contaminating' the build.
-[1] For all platforms except for MacOSX, at this point. Work for deterministic
-builds for Mac is under way here: https://github.com/theuni/osx-cross-depends .
-
Table of Contents
------------------
@@ -38,7 +35,7 @@ Preparing the Gitian builder host
---------------------------------
The first step is to prepare the host environment that will be used to perform the Gitian builds.
-In this guide it is explained how to set up the environment, and how to get the builds started.
+This guide explains how to set up the environment, and how to start the builds.
Debian Linux was chosen as the host distribution because it has a lightweight install (in contrast to Ubuntu) and is readily available.
Any kind of virtualization can be used, for example:
@@ -134,7 +131,7 @@ and proceed, just press `Enter`. To select a different button, press `Tab`.
![](gitian-building/debian_install_5_configure_the_network.png)
-- Choose a root password and enter it twice (and remember it for later)
+- Choose a root password and enter it twice (remember it for later)
![](gitian-building/debian_install_6a_set_up_root_password.png)
@@ -143,7 +140,7 @@ and proceed, just press `Enter`. To select a different button, press `Tab`.
![](gitian-building/debian_install_7_set_up_user_fullname.png)
![](gitian-building/debian_install_8_set_up_username.png)
-- Choose a user password and enter it twice (and remember it for later)
+- Choose a user password and enter it twice (remember it for later)
![](gitian-building/debian_install_9_user_password.png)
@@ -236,7 +233,7 @@ adduser debian sudo
When you get a colorful screen with a question about the 'LXC directory', just
go with the default (`/var/lib/lxc`).
-Then set up LXC and the rest with the following is a complex jumble of settings and workarounds:
+Then set up LXC and the rest with the following, which is a complex jumble of settings and workarounds:
```bash
# the version of lxc-start in Debian 7.4 needs to run as root, so make sure
@@ -280,7 +277,7 @@ cd ..
**Note**: When sudo asks for a password, enter the password for the user *debian* not for *root*.
-Clone the git repositories for bitcoin and gitian and then checkout the bitcoin version that you are willing to build.
+Clone the git repositories for bitcoin and gitian and then checkout the bitcoin version that you want to build.
```bash
git clone https://github.com/devrandom/gitian-builder.git
@@ -319,10 +316,10 @@ you will find a list of `wget` commands that can be executed to get the dependen
I needed to add `--no-check-certificate` to the OpenSSL wget line to make it work.
Likely this is because the ca-certificates in Debian 7.4 is fairly old. This does not create a
-security issue as the gitian descriptors check integrity of the input archives and refuse to work
+security issue as the gitian descriptors check the integrity of the input archives and refuse to work
if any one is corrupted.
-After downloading the archives, execute the `gbuild` commends to build the dependencies.
+After downloading the archives, execute the `gbuild` commands to build the dependencies.
This can take a long time, but only has to be done when the dependencies change, for example
to upgrade the used version.
@@ -339,7 +336,7 @@ tail -f var/build.log
Building Bitcoin
----------------
-To build Bitcoin (for Linux and/or Windows) just follow the steps under 'perform
+To build Bitcoin (for Linux, OSX and Windows) just follow the steps under 'perform
gitian builds' in [doc/release-process.md](release-process.md) in the bitcoin repository.
Output from `gbuild` will look something like
@@ -372,7 +369,7 @@ can be inspected in `var/install.log` and `var/build.log`.
Building an alternative repository
-----------------------------------
-If you want to do a test build of a pull on github it can be useful to point
+If you want to do a test build of a pull on GitHub it can be useful to point
the gitian builder at an alternative repository, using the same descriptors
and inputs.
@@ -382,13 +379,14 @@ URL=https://github.com/laanwj/bitcoin.git
COMMIT=2014_03_windows_unicode_path
./bin/gbuild --commit bitcoin=${COMMIT} --url bitcoin=${URL} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
./bin/gbuild --commit bitcoin=${COMMIT} --url bitcoin=${URL} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+./bin/gbuild --commit bitcoin=${COMMIT} --url bitcoin=${URL} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
```
Signing externally
-------------------
-If you want to do the PGP signing on another device that's possible too; just define `SIGNER` as mentioned
-and follow the steps in the build process as normally.
+If you want to do the PGP signing on another device that's also possible; just define `SIGNER` as mentioned
+and follow the steps in the build process as normal.
gpg: skipped "laanwj": secret key not available
@@ -396,8 +394,9 @@ When you execute `gsign` you will get an error from GPG, which can be ignored. C
in `gitian.sigs` to your signing machine and do
```bash
- gpg --detach-sign ${VERSION}/${SIGNER}/bitcoin-build.assert
+ gpg --detach-sign ${VERSION}-linux/${SIGNER}/bitcoin-build.assert
gpg --detach-sign ${VERSION}-win/${SIGNER}/bitcoin-build.assert
+ gpg --detach-sign ${VERSION}-osx/${SIGNER}/bitcoin-build.assert
```
This will create the `.sig` files that can be committed together with the `.assert` files to assert your
@@ -407,5 +406,5 @@ Uploading signatures
---------------------
After building and signing you can push your signatures (both the `.assert` and `.assert.sig` files) to the
-[bitcoin/gitian.sigs](https://github.com/bitcoin/gitian.sigs/) repository, or if not possible create a pull
+[bitcoin/gitian.sigs](https://github.com/bitcoin/gitian.sigs/) repository, or if that's not possible create a pull
request. You can also mail the files to me (laanwj@gmail.com) and I'll commit them.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 3a4079e437..66059800b6 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,6 +1,26 @@
(note: this is a temporary file, to be added-to by anybody, and moved to
release-notes at release time)
+Transaction fee changes
+=======================
+
+This release automatically estimates how high a transaction fee (or how
+high a priority) transactions require to be confirmed quickly. The default
+settings will create transactions that confirm quickly; see the new
+'txconfirmtarget' setting to control the tradeoff between fees and
+confirmation times.
+
+Prior releases used hard-coded fees (and priorities), and would
+sometimes create transactions that took a very long time to confirm.
+
+
+New Command Line Options
+========================
+
+-txconfirmtarget=n : create transactions that have enough fees (or priority)
+so they are likely to confirm within n blocks (default: 1). This setting
+is over-ridden by the -paytxfee option.
+
New RPC methods
===============
diff --git a/doc/release-process.md b/doc/release-process.md
index d12b41772e..c588381411 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -23,7 +23,7 @@ Release Process
* * *
-##perform gitian builds
+###perform gitian builds
From a directory containing the bitcoin source, gitian-builder and gitian.sigs
@@ -33,16 +33,21 @@ Release Process
git checkout v${VERSION}
popd
pushd ./gitian-builder
- mkdir -p inputs; cd inputs/
- Register and download the Apple SDK (see OSX Readme for details)
- visit https://developer.apple.com/downloads/download.action?path=Developer_Tools/xcode_4.6.3/xcode4630916281a.dmg
+###fetch and build inputs: (first time, or when dependency versions change)
- Using a Mac, create a tarball for the 10.7 SDK
- tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.7.sdk.tar.gz MacOSX10.7.sdk
+ mkdir -p inputs; cd inputs/
- Fetch and build inputs: (first time, or when dependency versions change)
+ Register and download the Apple SDK: (see OSX Readme for details)
+
+ https://developer.apple.com/downloads/download.action?path=Developer_Tools/xcode_4.6.3/xcode4630916281a.dmg
+
+ Using a Mac, create a tarball for the 10.7 SDK and copy it to the inputs directory:
+
+ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.7.sdk.tar.gz MacOSX10.7.sdk
+ Download remaining inputs, and build everything:
+
wget 'http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.9.tar.gz' -O miniupnpc-1.9.tar.gz
wget 'https://www.openssl.org/source/openssl-1.0.1h.tar.gz'
wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
@@ -87,10 +92,10 @@ Release Process
The expected SHA256 hashes of the intermediate inputs are:
- 46710f673467e367738d8806e45b4cb5931aaeea61f4b6b55a68eea56d5006c5 bitcoin-deps-linux32-gitian-r6.zip
- f03be39fb26670243d3a659e64d18e19d03dec5c11e9912011107768390b5268 bitcoin-deps-linux64-gitian-r6.zip
f29b7d9577417333fb56e023c2977f5726a7c297f320b175a4108cf7cd4c2d29 boost-linux32-1.55.0-gitian-r1.zip
88232451c4104f7eb16e469ac6474fd1231bd485687253f7b2bdf46c0781d535 boost-linux64-1.55.0-gitian-r1.zip
+ 46710f673467e367738d8806e45b4cb5931aaeea61f4b6b55a68eea56d5006c5 bitcoin-deps-linux32-gitian-r6.zip
+ f03be39fb26670243d3a659e64d18e19d03dec5c11e9912011107768390b5268 bitcoin-deps-linux64-gitian-r6.zip
57e57dbdadc818cd270e7e00500a5e1085b3bcbdef69a885f0fb7573a8d987e1 qt-linux32-4.6.4-gitian-r1.tar.gz
60eb4b9c5779580b7d66529efa5b2836ba1a70edde2a0f3f696d647906a826be qt-linux64-4.6.4-gitian-r1.tar.gz
60dc2d3b61e9c7d5dbe2f90d5955772ad748a47918ff2d8b74e8db9b1b91c909 boost-win32-1.55.0-gitian-r6.zip
@@ -106,10 +111,10 @@ Release Process
ec95abef1df2b096a970359787c01d8c45e2a4475b7ae34e12c022634fbdba8a osx-depends-qt-5.2.1-r4.tar.gz
- Build bitcoind and bitcoin-qt on Linux32, Linux64, and Win32:
+ Build Bitcoin Core for Linux, Windows, and OS X:
./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
- ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ ./bin/gsign --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
pushd build/out
zip -r bitcoin-${VERSION}-linux-gitian.zip *
mv bitcoin-${VERSION}-linux-gitian.zip ../../../
@@ -132,7 +137,7 @@ Release Process
1. linux 32-bit and 64-bit binaries + source (bitcoin-${VERSION}-linux-gitian.zip)
2. windows 32-bit and 64-bit binaries + installer + source (bitcoin-${VERSION}-win-gitian.zip)
3. OSX installer (Bitcoin-Qt.dmg)
- 4. Gitian signatures (in gitian.sigs/${VERSION}[-win|-osx]/(your gitian key)/
+ 4. Gitian signatures (in gitian.sigs/${VERSION}-<linux|win|osx>/(your gitian key)/
repackage gitian builds for release as stand-alone zip/tar/installer exe
@@ -172,8 +177,9 @@ repackage gitian builds for release as stand-alone zip/tar/installer exe
Commit your signature to gitian.sigs:
pushd gitian.sigs
- git add ${VERSION}/${SIGNER}
+ git add ${VERSION}-linux/${SIGNER}
git add ${VERSION}-win/${SIGNER}
+ git add ${VERSION}-osx/${SIGNER}
git commit -a
git push # Assuming you can push to the gitian.sigs tree
popd
diff --git a/src/Makefile.am b/src/Makefile.am
index 9c7b294d35..e2a62c9699 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,10 @@
AM_CPPFLAGS = $(INCLUDES)
AM_LDFLAGS = $(PTHREAD_CFLAGS)
+if USE_LIBSECP256K1
+secp256k1/libsecp256k1.la: $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
+ @$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
+endif
if EMBEDDED_LEVELDB
LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include
@@ -20,6 +24,10 @@ endif
BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS)
+if USE_LIBSECP256K1
+BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
+endif
+
LIBBITCOIN_SERVER=libbitcoin_server.a
LIBBITCOIN_WALLET=libbitcoin_wallet.a
LIBBITCOIN_COMMON=libbitcoin_common.a
@@ -220,6 +228,11 @@ bitcoind_LDADD = \
$(LIBBITCOIN_CRYPTO) \
$(LIBLEVELDB) \
$(LIBMEMENV)
+
+if USE_LIBSECP256K1
+ bitcoind_LDADD += secp256k1/libsecp256k1.la
+endif
+
if ENABLE_WALLET
bitcoind_LDADD += libbitcoin_wallet.a
endif
@@ -242,6 +255,10 @@ bitcoin_cli_LDADD = \
$(BOOST_LIBS)
bitcoin_cli_SOURCES = \
bitcoin-cli.cpp
+
+if USE_LIBSECP256K1
+ bitcoin_cli_LDADD += secp256k1/libsecp256k1.la
+endif
bitcoin_cli_CPPFLAGS = $(BITCOIN_INCLUDES)
#
@@ -253,10 +270,11 @@ CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno
DISTCLEANFILES = obj/build.h
-EXTRA_DIST = leveldb
+EXTRA_DIST = leveldb secp256k1
clean-local:
-$(MAKE) -C leveldb clean
+ -$(MAKE) -C secp256k1 clean
rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno
-rm -f config.h
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 9df0779ba3..4563bb3565 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -357,6 +357,9 @@ qt_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
+if USE_LIBSECP256K1
+ qt_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la
+endif
qt_bitcoin_qt_LDFLAGS = $(QT_LDFLAGS)
#locale/foo.ts -> locale/foo.qm
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index a509f23755..7e10ce5a96 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -33,6 +33,9 @@ endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBLEVELDB) \
$(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
+if USE_LIBSECP256K1
+ qt_test_test_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la
+endif
qt_test_test_bitcoin_qt_LDFLAGS = $(QT_LDFLAGS)
CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 8685452c7b..12b90adca3 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -69,6 +69,11 @@ test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_CO
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
endif
+
+if USE_LIBSECP256K1
+ test_test_bitcoin_LDADD += secp256k1/libsecp256k1.la
+endif
+
test_test_bitcoin_LDADD += $(BDB_LIBS)
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
diff --git a/src/core.cpp b/src/core.cpp
index ca28624529..47f3b2a015 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -80,7 +80,7 @@ CFeeRate::CFeeRate(int64_t nFeePaid, size_t nSize)
nSatoshisPerK = 0;
}
-int64_t CFeeRate::GetFee(size_t nSize)
+int64_t CFeeRate::GetFee(size_t nSize) const
{
return nSatoshisPerK*nSize / 1000;
}
diff --git a/src/core.h b/src/core.h
index 8606831575..0387336c98 100644
--- a/src/core.h
+++ b/src/core.h
@@ -125,13 +125,14 @@ public:
CFeeRate(int64_t nFeePaid, size_t nSize);
CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
- int64_t GetFee(size_t size); // unit returned is satoshis
- int64_t GetFeePerK() { return GetFee(1000); } // satoshis-per-1000-bytes
+ int64_t GetFee(size_t size) const; // unit returned is satoshis
+ int64_t GetFeePerK() const { return GetFee(1000); } // satoshis-per-1000-bytes
friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
-
+ friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }
+ friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
std::string ToString() const;
IMPLEMENT_SERIALIZE( READWRITE(nSatoshisPerK); )
@@ -216,8 +217,6 @@ private:
void UpdateHash() const;
public:
- static CFeeRate minTxFee;
- static CFeeRate minRelayTxFee;
static const int CURRENT_VERSION=1;
// The local variables are made const to prevent unintended modification
diff --git a/src/init.cpp b/src/init.cpp
index 6c0898c036..fb1c144751 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -253,14 +253,16 @@ std::string HelpMessage(HelpMessageMode mode)
#ifdef ENABLE_WALLET
strUsage += "\n" + _("Wallet options:") + "\n";
strUsage += " -disablewallet " + _("Do not load the wallet and disable wallet RPC calls") + "\n";
+ strUsage += " -mintxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"), FormatMoney(CWallet::minTxFee.GetFeePerK())) + "\n";
strUsage += " -paytxfee=<amt> " + strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())) + "\n";
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + " " + _("on startup") + "\n";
+ strUsage += " -respendnotify=<cmd> " + _("Execute command when a network tx respends wallet tx input (%s=respend TxID, %t=wallet TxID)") + "\n";
strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup") + "\n";
strUsage += " -spendzeroconfchange " + _("Spend unconfirmed change when sending transactions (default: 1)") + "\n";
+ strUsage += " -txconfirmtarget=<n> " + _("If paytxfee is not set, include enough fee so transactions are confirmed on average within n blocks (default: 1)") + "\n";
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + " " + _("on startup") + "\n";
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + " " + _("(default: wallet.dat)") + "\n";
strUsage += " -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n";
- strUsage += " -respendnotify=<cmd> " + _("Execute command when a network tx respends wallet tx input (%s=respend TxID, %t=wallet TxID)") + "\n";
strUsage += " -zapwallettxes=<mode> " + _("Delete all wallet transactions and only recover those part of the blockchain through -rescan on startup") + "\n";
strUsage += " " + _("(default: 1, 1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)") + "\n";
#endif
@@ -294,8 +296,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -limitfreerelay=<n> " + _("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default:15)") + "\n";
strUsage += " -maxsigcachesize=<n> " + _("Limit size of signature cache to <n> entries (default: 50000)") + "\n";
}
- strUsage += " -mintxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"), FormatMoney(CTransaction::minTxFee.GetFeePerK())) + "\n";
- strUsage += " -minrelaytxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(CTransaction::minRelayTxFee.GetFeePerK())) + "\n";
+ strUsage += " -minrelaytxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())) + "\n";
strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n";
if (GetBoolArg("-help-debug", false))
{
@@ -323,7 +324,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -rpcuser=<user> " + _("Username for JSON-RPC connections") + "\n";
strUsage += " -rpcpassword=<pw> " + _("Password for JSON-RPC connections") + "\n";
strUsage += " -rpcport=<port> " + _("Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)") + "\n";
- strUsage += " -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified IP address. This option can be specified multiple times") + "\n";
+ strUsage += " -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times") + "\n";
strUsage += " -rpcthreads=<n> " + _("Set the number of threads to service RPC calls (default: 4)") + "\n";
strUsage += "\n" + _("RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
@@ -609,24 +610,24 @@ bool AppInit2(boost::thread_group& threadGroup)
// a transaction spammer can cheaply fill blocks using
// 1-satoshi-fee transactions. It should be set above the real
// cost to you of processing a transaction.
- if (mapArgs.count("-mintxfee"))
- {
- int64_t n = 0;
- if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0)
- CTransaction::minTxFee = CFeeRate(n);
- else
- return InitError(strprintf(_("Invalid amount for -mintxfee=<amount>: '%s'"), mapArgs["-mintxfee"]));
- }
if (mapArgs.count("-minrelaytxfee"))
{
int64_t n = 0;
if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0)
- CTransaction::minRelayTxFee = CFeeRate(n);
+ ::minRelayTxFee = CFeeRate(n);
else
return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"]));
}
#ifdef ENABLE_WALLET
+ if (mapArgs.count("-mintxfee"))
+ {
+ int64_t n = 0;
+ if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0)
+ CWallet::minTxFee = CFeeRate(n);
+ else
+ return InitError(strprintf(_("Invalid amount for -mintxfee=<amount>: '%s'"), mapArgs["-mintxfee"]));
+ }
if (mapArgs.count("-paytxfee"))
{
int64_t nFeePerK = 0;
@@ -635,7 +636,13 @@ bool AppInit2(boost::thread_group& threadGroup)
if (nFeePerK > nHighTransactionFeeWarning)
InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
payTxFee = CFeeRate(nFeePerK, 1000);
+ if (payTxFee < ::minRelayTxFee)
+ {
+ return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
+ mapArgs["-paytxfee"], ::minRelayTxFee.ToString()));
+ }
}
+ nTxConfirmTarget = GetArg("-txconfirmtarget", 1);
bSpendZeroConfChange = GetArg("-spendzeroconfchange", true);
std::string strWalletFile = GetArg("-wallet", "wallet.dat");
diff --git a/src/key.cpp b/src/key.cpp
index 784085da34..3c4fa77e72 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -5,15 +5,34 @@
#include "key.h"
#include "crypto/sha2.h"
+#include <openssl/rand.h>
+#ifdef USE_SECP256K1
+#include <secp256k1.h>
+#else
#include <openssl/bn.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
-#include <openssl/rand.h>
+#endif
// anonymous namespace with local implementation code (OpenSSL interaction)
namespace {
+#ifdef USE_SECP256K1
+#include <secp256k1.h>
+class CSecp256k1Init {
+public:
+ CSecp256k1Init() {
+ secp256k1_start();
+ }
+ ~CSecp256k1Init() {
+ secp256k1_stop();
+ }
+};
+static CSecp256k1Init instance_of_csecp256k1;
+
+#else
+
// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
@@ -334,6 +353,8 @@ public:
}
};
+#endif
+
int CompareBigEndian(const unsigned char *c1, size_t c1len, const unsigned char *c2, size_t c2len) {
while (c1len > c2len) {
if (*c1)
@@ -398,10 +419,15 @@ void CKey::MakeNewKey(bool fCompressedIn) {
}
bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
+#ifdef USE_SECP256K1
+ if (!secp256k1_ecdsa_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size()))
+ return false;
+#else
CECKey key;
if (!key.SetPrivKey(privkey))
return false;
key.GetSecretBytes(vch);
+#endif
fCompressed = fCompressedIn;
fValid = true;
return true;
@@ -409,99 +435,167 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
CPrivKey CKey::GetPrivKey() const {
assert(fValid);
+ CPrivKey privkey;
+#ifdef USE_SECP256K1
+ privkey.resize(279);
+ int privkeylen = 279;
+ int ret = secp256k1_ecdsa_privkey_export(begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed);
+ assert(ret);
+ privkey.resize(privkeylen);
+#else
CECKey key;
key.SetSecretBytes(vch);
- CPrivKey privkey;
key.GetPrivKey(privkey, fCompressed);
+#endif
return privkey;
}
CPubKey CKey::GetPubKey() const {
assert(fValid);
+ CPubKey pubkey;
+#ifdef USE_SECP256K1
+ int clen = 65;
+ int ret = secp256k1_ecdsa_pubkey_create((unsigned char*)pubkey.begin(), &clen, begin(), fCompressed);
+ assert(ret);
+ assert(pubkey.IsValid());
+ assert((int)pubkey.size() == clen);
+#else
CECKey key;
key.SetSecretBytes(vch);
- CPubKey pubkey;
key.GetPubKey(pubkey, fCompressed);
+#endif
return pubkey;
}
bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
if (!fValid)
return false;
+#ifdef USE_SECP256K1
+ vchSig.resize(72);
+ int nSigLen = 72;
+ CKey nonce;
+ do {
+ nonce.MakeNewKey(true);
+ if (secp256k1_ecdsa_sign((const unsigned char*)&hash, 32, (unsigned char*)&vchSig[0], &nSigLen, begin(), nonce.begin()))
+ break;
+ } while(true);
+ vchSig.resize(nSigLen);
+ return true;
+#else
CECKey key;
key.SetSecretBytes(vch);
return key.Sign(hash, vchSig);
+#endif
}
bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const {
if (!fValid)
return false;
- CECKey key;
- key.SetSecretBytes(vch);
vchSig.resize(65);
int rec = -1;
+#ifdef USE_SECP256K1
+ CKey nonce;
+ do {
+ nonce.MakeNewKey(true);
+ if (secp256k1_ecdsa_sign_compact((const unsigned char*)&hash, 32, &vchSig[1], begin(), nonce.begin(), &rec))
+ break;
+ } while(true);
+#else
+ CECKey key;
+ key.SetSecretBytes(vch);
if (!key.SignCompact(hash, &vchSig[1], rec))
return false;
+#endif
assert(rec != -1);
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
return true;
}
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
+#ifdef USE_SECP256K1
+ if (!secp256k1_ecdsa_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size()))
+ return false;
+#else
CECKey key;
if (!key.SetPrivKey(privkey, fSkipCheck))
return false;
-
key.GetSecretBytes(vch);
+#endif
fCompressed = vchPubKey.IsCompressed();
fValid = true;
-
+
if (fSkipCheck)
return true;
-
+
if (GetPubKey() != vchPubKey)
return false;
-
+
return true;
}
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
if (!IsValid())
return false;
+#ifdef USE_SECP256K1
+ if (secp256k1_ecdsa_verify((const unsigned char*)&hash, 32, &vchSig[0], vchSig.size(), begin(), size()) != 1)
+ return false;
+#else
CECKey key;
if (!key.SetPubKey(*this))
return false;
if (!key.Verify(hash, vchSig))
return false;
+#endif
return true;
}
bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
if (vchSig.size() != 65)
return false;
+ int recid = (vchSig[0] - 27) & 3;
+ bool fComp = (vchSig[0] - 27) & 4;
+#ifdef USE_SECP256K1
+ int pubkeylen = 65;
+ if (!secp256k1_ecdsa_recover_compact((const unsigned char*)&hash, 32, &vchSig[1], (unsigned char*)begin(), &pubkeylen, fComp, recid))
+ return false;
+ assert((int)size() == pubkeylen);
+#else
CECKey key;
- if (!key.Recover(hash, &vchSig[1], (vchSig[0] - 27) & ~4))
+ if (!key.Recover(hash, &vchSig[1], recid))
return false;
- key.GetPubKey(*this, (vchSig[0] - 27) & 4);
+ key.GetPubKey(*this, fComp);
+#endif
return true;
}
bool CPubKey::IsFullyValid() const {
if (!IsValid())
return false;
+#ifdef USE_SECP256K1
+ if (!secp256k1_ecdsa_pubkey_verify(begin(), size()))
+ return false;
+#else
CECKey key;
if (!key.SetPubKey(*this))
return false;
+#endif
return true;
}
bool CPubKey::Decompress() {
if (!IsValid())
return false;
+#ifdef USE_SECP256K1
+ int clen = size();
+ int ret = secp256k1_ecdsa_pubkey_decompress((unsigned char*)begin(), &clen);
+ assert(ret);
+ assert(clen == (int)size());
+#else
CECKey key;
if (!key.SetPubKey(*this))
return false;
key.GetPubKey(*this, false);
+#endif
return true;
}
@@ -531,7 +625,12 @@ bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild
BIP32Hash(cc, nChild, 0, begin(), out);
}
memcpy(ccChild, out+32, 32);
+#ifdef USE_SECP256K1
+ memcpy((unsigned char*)keyChild.begin(), begin(), 32);
+ bool ret = secp256k1_ecdsa_privkey_tweak_add((unsigned char*)keyChild.begin(), out);
+#else
bool ret = CECKey::TweakSecret((unsigned char*)keyChild.begin(), begin(), out);
+#endif
UnlockObject(out);
keyChild.fCompressed = true;
keyChild.fValid = ret;
@@ -545,10 +644,15 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned i
unsigned char out[64];
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
memcpy(ccChild, out+32, 32);
+#ifdef USE_SECP256K1
+ pubkeyChild = *this;
+ bool ret = secp256k1_ecdsa_pubkey_tweak_add((unsigned char*)pubkeyChild.begin(), pubkeyChild.size(), out);
+#else
CECKey key;
bool ret = key.SetPubKey(*this);
ret &= key.TweakPublic(out);
key.GetPubKey(pubkeyChild, true);
+#endif
return ret;
}
@@ -629,6 +733,9 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const {
}
bool ECC_InitSanityCheck() {
+#ifdef USE_SECP256K1
+ return true;
+#else
EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if(pkey == NULL)
return false;
@@ -636,6 +743,7 @@ bool ECC_InitSanityCheck() {
// TODO Is there more EC functionality that could be missing?
return true;
+#endif
}
diff --git a/src/main.cpp b/src/main.cpp
index 7baf33c39f..862775a711 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -38,8 +38,6 @@ using namespace boost;
CCriticalSection cs_main;
-CTxMemPool mempool;
-
map<uint256, CBlockIndex*> mapBlockIndex;
CChain chainActive;
int64_t nTimeBestReceived = 0;
@@ -50,10 +48,10 @@ bool fBenchmark = false;
bool fTxIndex = false;
unsigned int nCoinCacheSize = 5000;
-/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */
-CFeeRate CTransaction::minTxFee = CFeeRate(10000); // Override with -mintxfee
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
-CFeeRate CTransaction::minRelayTxFee = CFeeRate(1000);
+CFeeRate minRelayTxFee = CFeeRate(1000);
+
+CTxMemPool mempool(::minRelayTxFee);
struct COrphanBlock {
uint256 hashBlock;
@@ -608,7 +606,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
}
if (whichType == TX_NULL_DATA)
nDataOut++;
- else if (txout.IsDust(CTransaction::minRelayTxFee)) {
+ else if (txout.IsDust(::minRelayTxFee)) {
reason = "dust";
return false;
}
@@ -849,7 +847,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return true;
}
-int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, enum GetMinFee_mode mode)
+int64_t GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree)
{
{
LOCK(mempool.cs);
@@ -861,10 +859,7 @@ int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree,
return 0;
}
- // Base fee is either minTxFee or minRelayTxFee
- CFeeRate baseFeeRate = (mode == GMF_RELAY) ? tx.minRelayTxFee : tx.minTxFee;
-
- int64_t nMinFee = baseFeeRate.GetFee(nBytes);
+ int64_t nMinFee = ::minRelayTxFee.GetFee(nBytes);
if (fAllowFree)
{
@@ -872,9 +867,7 @@ int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree,
// * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
// to be considered to fall into this category. We don't want to encourage sending
// multiple transactions instead of one big transaction to avoid fees.
- // * If we are creating a transaction we allow transactions up to 1,000 bytes
- // to be considered safe and assume they can likely make it into this section.
- if (nBytes < (mode == GMF_SEND ? 1000 : (DEFAULT_BLOCK_PRIORITY_SIZE - 1000)))
+ if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))
nMinFee = 0;
}
@@ -1037,7 +1030,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
unsigned int nSize = entry.GetTxSize();
// Don't accept it if it can't get into a block
- int64_t txMinFee = GetMinFee(tx, nSize, true, GMF_RELAY);
+ int64_t txMinFee = GetMinRelayFee(tx, nSize, true);
if (fLimitFree && nFees < txMinFee)
return state.DoS(0, error("AcceptToMemoryPool : not enough fees %s, %d < %d",
hash.ToString(), nFees, txMinFee),
@@ -1046,7 +1039,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Continuously rate-limit free (really, very-low-fee)transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
- if (fLimitFree && nFees < CTransaction::minRelayTxFee.GetFee(nSize))
+ if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize))
{
static double dFreeCount;
static int64_t nLastFreeTime;
@@ -1059,10 +1052,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
}
- if (fRejectInsaneFee && nFees > CTransaction::minRelayTxFee.GetFee(nSize) * 10000)
+ if (fRejectInsaneFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
return error("AcceptToMemoryPool: : insane fees %s, %d > %d",
hash.ToString(),
- nFees, CTransaction::minRelayTxFee.GetFee(nSize) * 10000);
+ nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
@@ -1132,10 +1125,10 @@ int CMerkleTx::GetBlocksToMaturity() const
}
-bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree)
+bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL);
+ return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectInsaneFee);
}
diff --git a/src/main.h b/src/main.h
index 26450bb721..33b00a7b50 100644
--- a/src/main.h
+++ b/src/main.h
@@ -93,6 +93,7 @@ extern bool fBenchmark;
extern int nScriptCheckThreads;
extern bool fTxIndex;
extern unsigned int nCoinCacheSize;
+extern CFeeRate minRelayTxFee;
// Minimum disk space required - used in CheckDiskSpace()
static const uint64_t nMinDiskSpace = 52428800;
@@ -245,14 +246,7 @@ struct CDiskTxPos : public CDiskBlockPos
};
-
-enum GetMinFee_mode
-{
- GMF_RELAY,
- GMF_SEND,
-};
-
-int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree, enum GetMinFee_mode mode);
+int64_t GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
//
// Check transaction inputs, and make sure any
@@ -459,7 +453,7 @@ public:
int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
int GetBlocksToMaturity() const;
- bool AcceptToMemoryPool(bool fLimitFree=true);
+ bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectInsaneFee=true);
};
diff --git a/src/miner.cpp b/src/miner.cpp
index 69e53756e0..17918a1280 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -236,7 +236,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
double dPriorityDelta = 0;
int64_t nFeeDelta = 0;
mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
- if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < CTransaction::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
+ if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
continue;
// Prioritise by fee once past the priority size or we run out of high-priority
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 569facb499..7c4af25edf 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -134,7 +134,7 @@ void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
{
Q_UNUSED(context);
const char *category = (type == QtDebugMsg) ? "qt" : NULL;
- LogPrint(category, "GUI: %s\n", QString::toStdString(msg));
+ LogPrint(category, "GUI: %s\n", msg.toStdString());
}
#endif
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 30f5ec8939..f2fb8c877e 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -28,6 +28,7 @@
#include <iostream>
+#include <QAction>
#include <QApplication>
#include <QDateTime>
#include <QDesktopWidget>
@@ -39,6 +40,7 @@
#include <QMenuBar>
#include <QMessageBox>
#include <QMimeData>
+#include <QPoint>
#include <QProgressBar>
#include <QProgressDialog>
#include <QSettings>
@@ -49,6 +51,8 @@
#include <QToolBar>
#include <QVBoxLayout>
+
+
#if QT_VERSION < 0x050000
#include <QUrl>
#include <QTextDocument>
@@ -156,10 +160,13 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
frameBlocksLayout->setContentsMargins(3,0,3,0);
frameBlocksLayout->setSpacing(3);
+ unitDisplayControl = new UnitDisplayStatusBarControl();
labelEncryptionIcon = new QLabel();
labelConnectionsIcon = new QLabel();
labelBlocksIcon = new QLabel();
frameBlocksLayout->addStretch();
+ frameBlocksLayout->addWidget(unitDisplayControl);
+ frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelEncryptionIcon);
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelConnectionsIcon);
@@ -420,6 +427,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
walletFrame->setClientModel(clientModel);
}
#endif
+
+ this->unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
}
}
@@ -1000,3 +1009,72 @@ void BitcoinGUI::unsubscribeFromCoreSignals()
// Disconnect signals from client
uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
}
+
+UnitDisplayStatusBarControl::UnitDisplayStatusBarControl():QLabel()
+{
+ optionsModel = 0;
+ createContextMenu();
+ setStyleSheet("font:11pt; color: #333333");
+ setToolTip(tr("Unit to show amounts in. Click to select another unit."));
+}
+
+/** So that it responds to left-button clicks */
+void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event)
+{
+ onDisplayUnitsClicked(event->pos());
+}
+
+/** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
+void UnitDisplayStatusBarControl::createContextMenu()
+{
+ menu = new QMenu();
+ foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
+ {
+ QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this);
+ menuAction->setData(QVariant(u));
+ menu->addAction(menuAction);
+ }
+ connect(menu,SIGNAL(triggered(QAction*)),this,SLOT(onMenuSelection(QAction*)));
+
+ // what happens on right click.
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(this,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(onDisplayUnitsClicked(const QPoint&)));
+}
+
+/** Lets the control know about the Options Model (and its signals) */
+void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *optionsModel)
+{
+ if (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)));
+
+ // initialize the display units label with the current value in the model.
+ updateDisplayUnit(optionsModel->getDisplayUnit());
+ }
+}
+
+/** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
+void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits)
+{
+ setText(BitcoinUnits::name(newUnits));
+}
+
+/** Shows context menu with Display Unit options by the mouse coordinates */
+void UnitDisplayStatusBarControl::onDisplayUnitsClicked(const QPoint& point)
+{
+ QPoint globalPos = mapToGlobal(point);
+ menu->exec(globalPos);
+}
+
+/** Tells underlying optionsModel to update its current display unit. */
+void UnitDisplayStatusBarControl::onMenuSelection(QAction* action)
+{
+ if (action)
+ {
+ optionsModel->setDisplayUnit(action->data());
+ }
+}
+
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index e7a842df99..705e629a69 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -9,12 +9,16 @@
#include "config/bitcoin-config.h"
#endif
+#include <QLabel>
#include <QMainWindow>
#include <QMap>
+#include <QMenu>
+#include <QPoint>
#include <QSystemTrayIcon>
class ClientModel;
class Notificator;
+class OptionsModel;
class RPCConsole;
class SendCoinsRecipient;
class WalletFrame;
@@ -22,9 +26,13 @@ class WalletModel;
class CWallet;
+class UnitDisplayStatusBarControl;
+
QT_BEGIN_NAMESPACE
class QAction;
class QLabel;
+class QMenu;
+class QPoint;
class QProgressBar;
class QProgressDialog;
QT_END_NAMESPACE
@@ -69,6 +77,7 @@ private:
ClientModel *clientModel;
WalletFrame *walletFrame;
+ UnitDisplayStatusBarControl *unitDisplayControl;
QLabel *labelEncryptionIcon;
QLabel *labelConnectionsIcon;
QLabel *labelBlocksIcon;
@@ -198,4 +207,32 @@ private slots:
void showProgress(const QString &title, int nProgress);
};
+class UnitDisplayStatusBarControl : public QLabel
+{
+ Q_OBJECT
+
+public:
+ explicit UnitDisplayStatusBarControl();
+ /** Lets the control know about the Options Model (and its signals) */
+ void setOptionsModel(OptionsModel *optionsModel);
+
+protected:
+ /** So that it responds to left-button clicks */
+ void mousePressEvent(QMouseEvent *event);
+
+private:
+ OptionsModel *optionsModel;
+ QMenu* menu;
+ /** Shows context menu with Display Unit options by the mouse coordinates */
+ void onDisplayUnitsClicked(const QPoint& point);
+ /** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
+ void createContextMenu();
+
+private slots:
+ /** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
+ void updateDisplayUnit(int newUnits);
+ /** Tells underlying optionsModel to update its current display unit. */
+ void onMenuSelection(QAction* action);
+};
+
#endif // BITCOINGUI_H
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 2fed443cf2..4ba6aba551 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -169,6 +169,16 @@ bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out)
return ok;
}
+QString BitcoinUnits::getAmountColumnTitle(int unit)
+{
+ QString amountTitle = QObject::tr("Amount");
+ if (BitcoinUnits::valid(unit))
+ {
+ amountTitle += " ("+BitcoinUnits::name(unit) + ")";
+ }
+ return amountTitle;
+}
+
int BitcoinUnits::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index 46517fc07b..451b52ee21 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -54,6 +54,8 @@ public:
static QString formatWithUnit(int unit, qint64 amount, bool plussign=false);
//! Parse string to coin amount
static bool parse(int unit, const QString &value, qint64 *val_out);
+ //! Gets title for amount column including current display unit if optionsModel reference available */
+ static QString getAmountColumnTitle(int unit);
///@}
//! @name AbstractListModel implementation
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index c6a6150392..e0a524a55e 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -16,6 +16,8 @@
#include "main.h"
#include "wallet.h"
+#include <boost/assign/list_of.hpp> // for 'map_list_of()'
+
#include <QApplication>
#include <QCheckBox>
#include <QCursor>
@@ -400,23 +402,24 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
}
// return human readable label for priority number
-QString CoinControlDialog::getPriorityLabel(double dPriority)
+QString CoinControlDialog::getPriorityLabel(const CTxMemPool& pool, double dPriority)
{
- if (AllowFree(dPriority)) // at least medium
+ // confirmations -> textual description
+ typedef std::map<unsigned int, QString> PriorityDescription;
+ const static PriorityDescription priorityDescriptions = boost::assign::map_list_of
+ (1, tr("highest"))(2, tr("higher"))(3, tr("high"))
+ (5, tr("medium-high"))(6, tr("medium"))
+ (10, tr("low-medium"))(15, tr("low"))
+ (20, tr("lower"));
+
+ BOOST_FOREACH(const PriorityDescription::value_type& i, priorityDescriptions)
{
- if (AllowFree(dPriority / 1000000)) return tr("highest");
- else if (AllowFree(dPriority / 100000)) return tr("higher");
- else if (AllowFree(dPriority / 10000)) return tr("high");
- else if (AllowFree(dPriority / 1000)) return tr("medium-high");
- else return tr("medium");
- }
- else
- {
- if (AllowFree(dPriority * 10)) return tr("low-medium");
- else if (AllowFree(dPriority * 100)) return tr("low");
- else if (AllowFree(dPriority * 1000)) return tr("lower");
- else return tr("lowest");
+ double p = mempool.estimatePriority(i.first);
+ if (p > 0 && dPriority >= p) return i.second;
}
+ // Note: if mempool hasn't accumulated enough history (estimatePriority
+ // returns -1) we're conservative and classify as "lowest"
+ return tr("lowest");
}
// shows count of locked unspent outputs
@@ -449,7 +452,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
{
CTxOut txout(amount, (CScript)vector<unsigned char>(24, 0));
txDummy.vout.push_back(txout);
- if (txout.IsDust(CTransaction::minRelayTxFee))
+ if (txout.IsDust(::minRelayTxFee))
fDust = true;
}
}
@@ -518,15 +521,20 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// Priority
dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
- sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority);
+ sPriorityLabel = CoinControlDialog::getPriorityLabel(mempool, dPriority);
// Fee
int64_t nFee = payTxFee.GetFee(max((unsigned int)1000, nBytes));
// Min Fee
- int64_t nMinFee = GetMinFee(txDummy, nBytes, AllowFree(dPriority), GMF_SEND);
+ nPayFee = CWallet::GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
+
+ double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
+ if (dPriorityNeeded <= 0) // Not enough mempool history: never send free
+ dPriorityNeeded = std::numeric_limits<double>::max();
- nPayFee = max(nFee, nMinFee);
+ if (nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE && dPriority >= dPriorityNeeded)
+ nPayFee = 0;
if (nPayAmount > 0)
{
@@ -536,7 +544,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (nChange > 0 && nChange < CENT)
{
CTxOut txout(nChange, (CScript)vector<unsigned char>(24, 0));
- if (txout.IsDust(CTransaction::minRelayTxFee))
+ if (txout.IsDust(::minRelayTxFee))
{
nPayFee += nChange;
nChange = 0;
@@ -591,23 +599,23 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
}
// turn labels "red"
- l5->setStyleSheet((nBytes >= 1000) ? "color:red;" : ""); // Bytes >= 1000
+ l5->setStyleSheet((nBytes >= MAX_FREE_TRANSACTION_CREATE_SIZE) ? "color:red;" : "");// Bytes >= 1000
l6->setStyleSheet((dPriority > 0 && !AllowFree(dPriority)) ? "color:red;" : ""); // Priority < "medium"
l7->setStyleSheet((fDust) ? "color:red;" : ""); // Dust = "yes"
// tool tips
QString toolTip1 = tr("This label turns red, if the transaction size is greater than 1000 bytes.") + "<br /><br />";
- toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minTxFee.GetFeePerK())) + "<br /><br />";
+ toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::minTxFee.GetFeePerK())) + "<br /><br />";
toolTip1 += tr("Can vary +/- 1 byte per input.");
QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />";
toolTip2 += tr("This label turns red, if the priority is smaller than \"medium\".") + "<br /><br />";
- toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minTxFee.GetFeePerK()));
+ toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::minTxFee.GetFeePerK()));
- QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minRelayTxFee.GetFee(546)));
+ QString toolTip3 = tr("This label turns red, if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, ::minRelayTxFee.GetFee(546)));
// how many satoshis the estimated fee can vary per byte we guess wrong
- double dFeeVary = (double)std::max(CTransaction::minTxFee.GetFeePerK(), payTxFee.GetFeePerK()) / 1000;
+ double dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), payTxFee.GetFeePerK()) / 1000;
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
l3->setToolTip(toolTip4);
@@ -732,7 +740,7 @@ void CoinControlDialog::updateView()
// priority
double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10
- itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority));
+ itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(mempool, dPriority));
itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " "));
dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
nInputSum += nInputSize;
@@ -765,7 +773,7 @@ void CoinControlDialog::updateView()
itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
- itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum));
+ itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(mempool, dPrioritySum));
itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " "));
}
}
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 465e2a009d..4f7422642f 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -19,6 +19,7 @@ namespace Ui {
}
class WalletModel;
class CCoinControl;
+class CTxMemPool;
class CoinControlDialog : public QDialog
{
@@ -32,7 +33,7 @@ public:
// static because also called from sendcoinsdialog
static void updateLabels(WalletModel*, QDialog*);
- static QString getPriorityLabel(double);
+ static QString getPriorityLabel(const CTxMemPool& pool, double);
static QList<qint64> payAmounts;
static CCoinControl *coinControl;
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 81b9054252..60a131df7e 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -11,6 +11,7 @@
#include "core.h"
#include "init.h"
+#include "main.h"
#include "protocol.h"
#include "util.h"
@@ -212,7 +213,7 @@ bool isDust(const QString& address, qint64 amount)
CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
CScript script; script.SetDestination(dest);
CTxOut txOut(amount, script);
- return txOut.IsDust(CTransaction::minRelayTxFee);
+ return txOut.IsDust(::minRelayTxFee);
}
QString HtmlEscape(const QString& str, bool fMultiLine)
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 12d54dff64..9502dba904 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -14,7 +14,10 @@
#include "monitoreddatamapper.h"
#include "optionsmodel.h"
-#include "main.h" // for CTransaction::minTxFee and MAX_SCRIPTCHECK_THREADS
+#include "main.h" // for MAX_SCRIPTCHECK_THREADS
+#ifdef ENABLE_WALLET
+#include "wallet.h" // for CWallet::minTxFee
+#endif
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults
@@ -101,7 +104,9 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
#endif
ui->unit->setModel(new BitcoinUnits(this));
- ui->transactionFee->setSingleStep(CTransaction::minTxFee.GetFeePerK());
+#ifdef ENABLE_WALLET
+ ui->transactionFee->setSingleStep(CWallet::minTxFee.GetFeePerK());
+#endif
/* Widget-to-option mapper */
mapper = new MonitoredDataMapper(this);
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 6d985abaf8..09553a2587 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -308,9 +308,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
break;
#endif
case DisplayUnit:
- nDisplayUnit = value.toInt();
- settings.setValue("nDisplayUnit", nDisplayUnit);
- emit displayUnitChanged(nDisplayUnit);
+ setDisplayUnit(value);
break;
case DisplayAddresses:
bDisplayAddresses = value.toBool();
@@ -356,11 +354,24 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
break;
}
}
+
emit dataChanged(index, index);
return successful;
}
+/** Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal */
+void OptionsModel::setDisplayUnit(const QVariant &value)
+{
+ if (!value.isNull())
+ {
+ QSettings settings;
+ nDisplayUnit = value.toInt();
+ settings.setValue("nDisplayUnit", nDisplayUnit);
+ emit displayUnitChanged(nDisplayUnit);
+ }
+}
+
bool OptionsModel::getProxySettings(QNetworkProxy& proxy) const
{
// Directly query current base proxy, because
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 2596682d07..89c2ec7453 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -52,6 +52,8 @@ public:
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
+ /** Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal */
+ void setDisplayUnit(const QVariant &value);
/* Explicit getters */
bool getMinimizeToTray() { return fMinimizeToTray; }
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 2049d65073..53db2c5cd9 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -195,7 +195,7 @@ bool PaymentServer::ipcParseCommandLine(int argc, char* argv[])
savedPaymentRequests.append(arg);
SendCoinsRecipient r;
- if (GUIUtil::parseBitcoinURI(arg, &r))
+ if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty())
{
CBitcoinAddress address(r.address.toStdString());
@@ -551,7 +551,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
// Extract and check amounts
CTxOut txOut(sendingTo.second, sendingTo.first);
- if (txOut.IsDust(CTransaction::minRelayTxFee)) {
+ if (txOut.IsDust(::minRelayTxFee)) {
emit message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
.arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
CClientUIInterface::MSG_ERROR);
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 844d62518c..b5a998f9f5 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -21,7 +21,9 @@ RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel
addNewRequest(request);
/* These columns must match the indices in the ColumnIndex enumeration */
- columns << tr("Date") << tr("Label") << tr("Message") << tr("Amount");
+ columns << tr("Date") << tr("Label") << tr("Message") << getAmountTitle();
+
+ connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
}
RecentRequestsTableModel::~RecentRequestsTableModel()
@@ -101,6 +103,24 @@ QVariant RecentRequestsTableModel::headerData(int section, Qt::Orientation orien
return QVariant();
}
+/** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
+void RecentRequestsTableModel::updateAmountColumnTitle()
+{
+ columns[Amount] = getAmountTitle();
+ emit headerDataChanged(Qt::Horizontal,Amount,Amount);
+}
+
+/** Gets title for amount column including current display unit if optionsModel reference available. */
+QString RecentRequestsTableModel::getAmountTitle()
+{
+ QString amountTitle = tr("Amount");
+ if (this->walletModel->getOptionsModel() != NULL)
+ {
+ amountTitle += " ("+BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")";
+ }
+ return amountTitle;
+}
+
QModelIndex RecentRequestsTableModel::index(int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(parent);
@@ -185,6 +205,11 @@ void RecentRequestsTableModel::sort(int column, Qt::SortOrder order)
emit dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex()));
}
+void RecentRequestsTableModel::updateDisplayUnit()
+{
+ updateAmountColumnTitle();
+}
+
bool RecentRequestEntryLessThan::operator()(RecentRequestEntry &left, RecentRequestEntry &right) const
{
RecentRequestEntry *pLeft = &left;
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index d4cc5078aa..4f0b241259 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -91,12 +91,18 @@ public:
public slots:
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+ void updateDisplayUnit();
private:
WalletModel *walletModel;
QStringList columns;
QList<RecentRequestEntry> list;
int64_t nReceiveRequestsMaxId;
+
+ /** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
+ void updateAmountColumnTitle();
+ /** Gets title for amount column including current display unit if optionsModel reference available. */
+ QString getAmountTitle();
};
#endif
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index a935752246..6c1a6c3579 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -235,8 +235,7 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
walletModel(parent),
priv(new TransactionTablePriv(wallet, this))
{
- columns << QString() << tr("Date") << tr("Type") << tr("Address") << tr("Amount");
-
+ columns << QString() << tr("Date") << tr("Type") << tr("Address") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
priv->refreshWallet();
connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
@@ -247,6 +246,13 @@ TransactionTableModel::~TransactionTableModel()
delete priv;
}
+/** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
+void TransactionTableModel::updateAmountColumnTitle()
+{
+ columns[Amount] = BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
+ emit headerDataChanged(Qt::Horizontal,Amount,Amount);
+}
+
void TransactionTableModel::updateTransaction(const QString &hash, int status)
{
uint256 updated;
@@ -632,5 +638,6 @@ QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex
void TransactionTableModel::updateDisplayUnit()
{
// emit dataChanged to update Amount column with the current unit
+ updateAmountColumnTitle();
emit dataChanged(index(0, Amount), index(priv->size()-1, Amount));
}
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index 333e6bc6ed..e8b6ed065d 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -87,6 +87,8 @@ public slots:
void updateTransaction(const QString &hash, int status);
void updateConfirmations();
void updateDisplayUnit();
+ /** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
+ void updateAmountColumnTitle();
friend class TransactionTablePriv;
};
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index d4d29416ca..d6d210a561 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -309,7 +309,7 @@ void TransactionView::exportClicked()
writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole);
- writer.addColumn(tr("Amount"), 0, TransactionTableModel::FormattedAmountRole);
+ writer.addColumn(BitcoinUnits::getAmountColumnTitle(model->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole);
writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole);
if(!writer.write()) {
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index 5b470516a1..9ed6b52513 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -84,7 +84,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
#endif
- obj.push_back(Pair("relayfee", ValueFromAmount(CTransaction::minRelayTxFee.GetFeePerK())));
+ obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj;
}
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 2d7abb2d58..cd3bd59f8f 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -372,7 +372,7 @@ Value getnetworkinfo(const Array& params, bool fHelp)
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
- obj.push_back(Pair("relayfee", ValueFromAmount(CTransaction::minRelayTxFee.GetFeePerK())));
+ obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
Array localAddresses;
{
LOCK(cs_mapLocalHost);
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index f47b3385da..5c4d307497 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -512,7 +512,7 @@ void StartRPCThreads()
if(!subnet.IsValid())
{
uiInterface.ThreadSafeMessageBox(
- strprintf("Invalid -rpcallowip subnet specification: %s", strAllow),
+ strprintf("Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).", strAllow),
"", CClientUIInterface::MSG_ERROR);
StartShutdown();
return;
diff --git a/src/secp256k1/.empty b/src/secp256k1/.empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/secp256k1/.empty
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 97a426dd35..a852de5da8 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -80,13 +80,13 @@ public:
// Used as belt-and-suspenders check when reading to detect
// file corruption
- bool AreSane(const std::vector<CFeeRate>& vecFee)
+ bool AreSane(const std::vector<CFeeRate>& vecFee, const CFeeRate& minRelayFee)
{
BOOST_FOREACH(CFeeRate fee, vecFee)
{
if (fee < CFeeRate(0))
return false;
- if (fee.GetFee(1000) > CTransaction::minRelayTxFee.GetFee(1000) * 10000)
+ if (fee.GetFeePerK() > minRelayFee.GetFeePerK() * 10000)
return false;
}
return true;
@@ -109,10 +109,10 @@ public:
fileout << vecPriority;
}
- void Read(CAutoFile& filein) {
+ void Read(CAutoFile& filein, const CFeeRate& minRelayFee) {
std::vector<CFeeRate> vecFee;
filein >> vecFee;
- if (AreSane(vecFee))
+ if (AreSane(vecFee, minRelayFee))
feeSamples.insert(feeSamples.end(), vecFee.begin(), vecFee.end());
else
throw runtime_error("Corrupt fee value in estimates file.");
@@ -141,7 +141,7 @@ private:
// nBlocksAgo is 0 based, i.e. transactions that confirmed in the highest seen block are
// nBlocksAgo == 0, transactions in the block before that are nBlocksAgo == 1 etc.
- void seenTxConfirm(CFeeRate feeRate, double dPriority, int nBlocksAgo)
+ void seenTxConfirm(const CFeeRate& feeRate, const CFeeRate& minRelayFee, double dPriority, int nBlocksAgo)
{
// Last entry records "everything else".
int nBlocksTruncated = min(nBlocksAgo, (int) history.size() - 1);
@@ -149,7 +149,7 @@ private:
// We need to guess why the transaction was included in a block-- either
// because it is high-priority or because it has sufficient fees.
- bool sufficientFee = (feeRate > CTransaction::minRelayTxFee);
+ bool sufficientFee = (feeRate > minRelayFee);
bool sufficientPriority = AllowFree(dPriority);
const char* assignedTo = "unassigned";
if (sufficientFee && !sufficientPriority)
@@ -177,7 +177,7 @@ public:
history.resize(nEntries);
}
- void seenBlock(const std::vector<CTxMemPoolEntry>& entries, int nBlockHeight)
+ void seenBlock(const std::vector<CTxMemPoolEntry>& entries, int nBlockHeight, const CFeeRate minRelayFee)
{
if (nBlockHeight <= nBestSeenHeight)
{
@@ -222,7 +222,7 @@ public:
// Fees are stored and reported as BTC-per-kb:
CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());
double dPriority = entry->GetPriority(entry->GetHeight()); // Want priority when it went IN
- seenTxConfirm(feeRate, dPriority, i);
+ seenTxConfirm(feeRate, minRelayFee, dPriority, i);
}
}
for (size_t i = 0; i < history.size(); i++) {
@@ -251,8 +251,13 @@ public:
std::sort(sortedFeeSamples.begin(), sortedFeeSamples.end(),
std::greater<CFeeRate>());
}
- if (sortedFeeSamples.size() == 0)
+ if (sortedFeeSamples.size() < 11)
+ {
+ // Eleven is Gavin's Favorite Number
+ // ... but we also take a maximum of 10 samples per block so eleven means
+ // we're getting samples from at least two different blocks
return CFeeRate(0);
+ }
int nBucketSize = history.at(nBlocksToConfirm).FeeSamples();
@@ -281,7 +286,7 @@ public:
std::sort(sortedPrioritySamples.begin(), sortedPrioritySamples.end(),
std::greater<double>());
}
- if (sortedPrioritySamples.size() == 0)
+ if (sortedPrioritySamples.size() < 11)
return -1.0;
int nBucketSize = history.at(nBlocksToConfirm).PrioritySamples();
@@ -308,7 +313,7 @@ public:
}
}
- void Read(CAutoFile& filein)
+ void Read(CAutoFile& filein, const CFeeRate& minRelayFee)
{
filein >> nBestSeenHeight;
size_t numEntries;
@@ -317,14 +322,14 @@ public:
for (size_t i = 0; i < numEntries; i++)
{
CBlockAverage entry;
- entry.Read(filein);
+ entry.Read(filein, minRelayFee);
history.push_back(entry);
}
}
};
-CTxMemPool::CTxMemPool()
+CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) : minRelayFee(_minRelayFee)
{
// Sanity checks off by default for performance, because otherwise
// accepting transactions becomes O(N^2) where N is the number
@@ -440,7 +445,7 @@ void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned i
if (mapTx.count(hash))
entries.push_back(mapTx[hash]);
}
- minerPolicyEstimator->seenBlock(entries, nBlockHeight);
+ minerPolicyEstimator->seenBlock(entries, nBlockHeight, minRelayFee);
BOOST_FOREACH(const CTransaction& tx, vtx)
{
std::list<CTransaction> dummy;
@@ -555,7 +560,7 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
return error("CTxMemPool::ReadFeeEstimates() : up-version (%d) fee estimate file", nVersionRequired);
LOCK(cs);
- minerPolicyEstimator->Read(filein);
+ minerPolicyEstimator->Read(filein, minRelayFee);
}
catch (std::exception &e) {
LogPrintf("CTxMemPool::ReadFeeEstimates() : unable to read policy estimator data (non-fatal)");
diff --git a/src/txmempool.h b/src/txmempool.h
index f7dbb126a0..41b2c52f39 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -67,13 +67,15 @@ private:
unsigned int nTransactionsUpdated;
CMinerPolicyEstimator* minerPolicyEstimator;
+ CFeeRate minRelayFee; // Passed to constructor to avoid dependency on main
+
public:
mutable CCriticalSection cs;
std::map<uint256, CTxMemPoolEntry> mapTx;
std::map<COutPoint, CInPoint> mapNextTx;
std::map<uint256, std::pair<double, int64_t> > mapDeltas;
- CTxMemPool();
+ CTxMemPool(const CFeeRate& _minRelayFee);
~CTxMemPool();
/*
diff --git a/src/wallet.cpp b/src/wallet.cpp
index daca7ac04b..318a1388d2 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -18,8 +18,12 @@ using namespace std;
// Settings
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
+unsigned int nTxConfirmTarget = 1;
bool bSpendZeroConfChange = true;
+/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */
+CFeeRate CWallet::minTxFee = CFeeRate(10000); // Override with -mintxfee
+
//////////////////////////////////////////////////////////////////////////////
//
// mapWallet
@@ -1273,6 +1277,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
return false;
}
+ wtxNew.fTimeReceivedIsTxTime = true;
wtxNew.BindWallet(this);
CMutableTransaction txNew;
@@ -1292,7 +1297,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
{
CTxOut txout(s.second, s.first);
- if (txout.IsDust(CTransaction::minRelayTxFee))
+ if (txout.IsDust(::minRelayTxFee))
{
strFailReason = _("Transaction amount too small");
return false;
@@ -1353,7 +1358,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
// Never create dust outputs; if we would, just
// add the dust to the fee.
- if (newTxOut.IsDust(CTransaction::minRelayTxFee))
+ if (newTxOut.IsDust(::minRelayTxFee))
{
nFeeRet += nChange;
reservekey.ReturnKey();
@@ -1393,19 +1398,31 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
}
dPriority = wtxNew.ComputePriority(dPriority, nBytes);
- // Check that enough fee is included
- int64_t nPayFee = payTxFee.GetFee(nBytes);
- bool fAllowFree = AllowFree(dPriority);
- int64_t nMinFee = GetMinFee(wtxNew, nBytes, fAllowFree, GMF_SEND);
- if (nFeeRet < max(nPayFee, nMinFee))
+ int64_t nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
+
+ if (nFeeRet >= nFeeNeeded)
+ break; // Done, enough fee included.
+
+ // Too big to send for free? Include more fee and try again:
+ if (nBytes > MAX_FREE_TRANSACTION_CREATE_SIZE)
{
- nFeeRet = max(nPayFee, nMinFee);
+ nFeeRet = nFeeNeeded;
continue;
}
- wtxNew.fTimeReceivedIsTxTime = true;
+ // Not enough fee: enough priority?
+ double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
+ // Not enough mempool history to estimate: use hard-coded AllowFree.
+ if (dPriorityNeeded <= 0 && AllowFree(dPriority))
+ break;
+
+ // Small enough, and priority high enough, to send for free
+ if (dPriority >= dPriorityNeeded)
+ break;
- break;
+ // Include more fee and try again.
+ nFeeRet = nFeeNeeded;
+ continue;
}
}
}
@@ -1513,6 +1530,20 @@ string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nV
return SendMoney(scriptPubKey, nValue, wtxNew);
}
+int64_t CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
+{
+ // payTxFee is user-set "I want to pay this much"
+ int64_t nFeeNeeded = payTxFee.GetFee(nTxBytes);
+ // User didn't set: use -txconfirmtarget to estimate...
+ if (nFeeNeeded == 0)
+ nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes);
+ // ... unless we don't have enough mempool data, in which case fall
+ // back to a hard-coded fee
+ if (nFeeNeeded == 0)
+ nFeeNeeded = minTxFee.GetFee(nTxBytes);
+ return nFeeNeeded;
+}
+
diff --git a/src/wallet.h b/src/wallet.h
index 1c2512d678..a5162bb838 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -25,12 +25,15 @@
// Settings
extern CFeeRate payTxFee;
+extern unsigned int nTxConfirmTarget;
extern bool bSpendZeroConfChange;
// -paytxfee default
static const int64_t DEFAULT_TRANSACTION_FEE = 0;
// -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB
static const int nHighTransactionFeeWarning = 0.01 * COIN;
+// Largest (in bytes) free transaction we're willing to create
+static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
class CAccountingEntry;
class CCoinControl;
@@ -265,6 +268,9 @@ public:
std::string SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew);
std::string SendMoneyToDestination(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew);
+ static CFeeRate minTxFee;
+ static int64_t GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool);
+
bool NewKeyPool();
bool TopUpKeyPool(unsigned int kpSize = 0);
void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool);