aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE.md23
-rw-r--r--.gitignore3
-rw-r--r--.travis.yml15
-rw-r--r--CONTRIBUTING.md142
-rw-r--r--Makefile.am24
-rw-r--r--configure.ac50
-rw-r--r--contrib/README.md3
-rw-r--r--contrib/debian/copyright4
-rw-r--r--contrib/devtools/README.md3
-rwxr-xr-xcontrib/devtools/fix-copyright-headers.py77
-rwxr-xr-xcontrib/devtools/security-check.py2
-rwxr-xr-xcontrib/devtools/symbol-check.py2
-rwxr-xr-xcontrib/devtools/test-security-check.py2
-rwxr-xr-xcontrib/devtools/update-translations.py2
-rwxr-xr-xcontrib/gitian-build.sh388
-rwxr-xr-xcontrib/linearize/linearize-data.py2
-rwxr-xr-xcontrib/linearize/linearize-hashes.py2
-rwxr-xr-xcontrib/macdeploy/extract-osx-sdk.sh29
-rwxr-xr-xcontrib/seeds/generate-seeds.py2
-rw-r--r--contrib/verifybinaries/README.md22
-rwxr-xr-xcontrib/verifybinaries/verify.sh19
-rw-r--r--depends/config.site.in3
-rw-r--r--depends/packages/native_comparisontool.mk21
-rw-r--r--depends/packages/packages.mk2
-rw-r--r--depends/packages/qt46.mk66
-rw-r--r--doc/README_osx.md17
-rw-r--r--doc/REST-interface.md2
-rw-r--r--doc/build-openbsd.md46
-rw-r--r--doc/build-unix.md5
-rw-r--r--doc/build-windows.md6
-rw-r--r--doc/developer-notes.md7
-rw-r--r--doc/release-notes.md14
-rw-r--r--doc/release-notes/release-notes-0.12.1.md198
-rw-r--r--doc/release-notes/release-notes-0.13.0.md863
-rw-r--r--doc/release-process.md3
-rw-r--r--qa/README.md4
-rwxr-xr-xqa/pull-tester/rpc-tests.py19
-rwxr-xr-xqa/rpc-tests/abandonconflict.py26
-rwxr-xr-xqa/rpc-tests/importprunedfunds.py37
-rwxr-xr-xqa/rpc-tests/p2p-fullblocktest.py3
-rwxr-xr-xqa/rpc-tests/p2p-mempool.py7
-rwxr-xr-xqa/rpc-tests/p2p-segwit.py7
-rwxr-xr-xqa/rpc-tests/rest.py10
-rwxr-xr-xqa/rpc-tests/rpcbind_test.py6
-rwxr-xr-xqa/rpc-tests/segwit.py9
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py4
-rw-r--r--qa/rpc-tests/test_framework/util.py20
-rwxr-xr-xqa/rpc-tests/wallet-accounts.py94
-rwxr-xr-xshare/qt/extract_strings_qt.py2
-rw-r--r--src/Makefile.qt.include6
-rw-r--r--src/Makefile.test.include3
-rw-r--r--src/bitcoin-tx.cpp6
-rw-r--r--src/blockencodings.cpp2
-rw-r--r--src/blockencodings.h8
-rw-r--r--src/chain.h10
-rw-r--r--src/chainparams.cpp2
-rw-r--r--src/consensus/validation.h6
-rw-r--r--src/dbwrapper.cpp2
-rw-r--r--src/httprpc.cpp2
-rw-r--r--src/httpserver.cpp18
-rw-r--r--src/httpserver.h2
-rw-r--r--src/init.cpp27
-rw-r--r--src/main.cpp72
-rw-r--r--src/main.h13
-rw-r--r--src/net.cpp63
-rw-r--r--src/net.h5
-rw-r--r--src/primitives/transaction.cpp2
-rw-r--r--src/protocol.h3
-rw-r--r--src/qt/bitcoin.cpp3
-rw-r--r--src/qt/bitcoin.qrc2
-rw-r--r--src/qt/bitcoingui.cpp32
-rw-r--r--src/qt/bitcoingui.h9
-rw-r--r--src/qt/coincontroldialog.cpp90
-rw-r--r--src/qt/coincontroldialog.h8
-rw-r--r--src/qt/forms/coincontroldialog.ui61
-rw-r--r--src/qt/forms/sendcoinsdialog.ui39
-rw-r--r--src/qt/guiutil.cpp3
-rw-r--r--src/qt/intro.cpp10
-rw-r--r--src/qt/intro.h5
-rw-r--r--src/qt/optionsmodel.cpp14
-rw-r--r--src/qt/res/icons/hd_disabled.pngbin0 -> 4328 bytes
-rw-r--r--src/qt/res/icons/hd_enabled.pngbin0 -> 1889 bytes
-rw-r--r--src/qt/res/src/hd_disabled.svg26
-rw-r--r--src/qt/res/src/hd_enabled.svg13
-rw-r--r--src/qt/sendcoinsdialog.cpp9
-rw-r--r--src/qt/sendcoinsdialog.h1
-rw-r--r--src/qt/walletmodel.cpp5
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/qt/walletview.cpp6
-rw-r--r--src/qt/walletview.h2
-rw-r--r--src/rest.cpp14
-rw-r--r--src/rpc/blockchain.cpp6
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/rpc/mining.cpp11
-rw-r--r--src/rpc/misc.cpp4
-rw-r--r--src/rpc/net.cpp17
-rw-r--r--src/rpc/protocol.h54
-rw-r--r--src/rpc/rawtransaction.cpp4
-rw-r--r--src/rpc/register.h12
-rw-r--r--src/script/bitcoinconsensus.cpp4
-rw-r--r--src/script/interpreter.cpp54
-rw-r--r--src/script/interpreter.h13
-rw-r--r--src/script/sigcache.h2
-rw-r--r--src/script/sign.h2
-rw-r--r--src/secp256k1/.gitignore19
-rw-r--r--src/secp256k1/.travis.yml19
-rw-r--r--src/secp256k1/Makefile.am72
-rw-r--r--src/secp256k1/README.md2
-rw-r--r--src/secp256k1/build-aux/m4/ax_jni_include_dir.m4140
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m44
-rw-r--r--src/secp256k1/configure.ac146
-rw-r--r--src/secp256k1/libsecp256k1.pc.in2
-rw-r--r--src/secp256k1/sage/group_prover.sage322
-rw-r--r--src/secp256k1/sage/secp256k1.sage306
-rw-r--r--src/secp256k1/sage/weierstrass_prover.sage264
-rw-r--r--src/secp256k1/src/asm/field_10x26_arm.s919
-rw-r--r--src/secp256k1/src/bench_ecdh.c3
-rw-r--r--src/secp256k1/src/bench_internal.c34
-rw-r--r--src/secp256k1/src/bench_verify.c44
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h67
-rw-r--r--src/secp256k1/src/ecmult_impl.h2
-rw-r--r--src/secp256k1/src/field.h8
-rw-r--r--src/secp256k1/src/field_10x26_impl.h12
-rw-r--r--src/secp256k1/src/field_5x52_impl.h1
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h4
-rw-r--r--src/secp256k1/src/field_impl.h36
-rw-r--r--src/secp256k1/src/group.h5
-rw-r--r--src/secp256k1/src/group_impl.h36
-rw-r--r--src/secp256k1/src/hash.h2
-rw-r--r--src/secp256k1/src/hash_impl.h10
-rw-r--r--src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java472
-rw-r--r--src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java247
-rw-r--r--src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java45
-rw-r--r--src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java51
-rw-r--r--src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c412
-rw-r--r--src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h112
-rw-r--r--src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c15
-rw-r--r--src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h22
-rw-r--r--src/secp256k1/src/modules/ecdh/Makefile.am.include2
-rw-r--r--src/secp256k1/src/modules/recovery/Makefile.am.include2
-rw-r--r--src/secp256k1/src/modules/schnorr/Makefile.am.include2
-rw-r--r--src/secp256k1/src/num.h6
-rw-r--r--src/secp256k1/src/num_gmp_impl.h26
-rw-r--r--src/secp256k1/src/scalar_impl.h2
-rw-r--r--src/secp256k1/src/secp256k1.c15
-rw-r--r--src/secp256k1/src/tests.c190
-rw-r--r--src/serialize.h4
-rw-r--r--src/sync.h5
-rw-r--r--src/test/base58_tests.cpp3
-rwxr-xr-xsrc/test/bitcoin-util-test.py2
-rw-r--r--src/test/blockencodings_tests.cpp1
-rw-r--r--src/test/buildenv.py.in2
-rw-r--r--src/test/dbwrapper_tests.cpp6
-rw-r--r--src/test/net_tests.cpp22
-rw-r--r--src/test/pmt_tests.cpp1
-rw-r--r--src/test/rpc_tests.cpp12
-rw-r--r--src/test/script_P2SH_tests.cpp6
-rw-r--r--src/test/transaction_tests.cpp87
-rw-r--r--src/test/util_tests.cpp9
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txdb.h2
-rw-r--r--src/txmempool.cpp1
-rw-r--r--src/util.cpp9
-rw-r--r--src/wallet/db.cpp10
-rw-r--r--src/wallet/db.h10
-rw-r--r--src/wallet/rpcdump.cpp7
-rw-r--r--src/wallet/rpcwallet.cpp16
-rw-r--r--src/wallet/rpcwallet.h2
-rw-r--r--src/wallet/test/rpc_wallet_tests.cpp229
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp4
-rw-r--r--src/wallet/test/wallet_tests.cpp6
-rw-r--r--src/wallet/wallet.cpp64
-rw-r--r--src/wallet/wallet.h18
-rw-r--r--src/wallet/walletdb.cpp31
-rw-r--r--src/zmq/zmqpublishnotifier.h2
175 files changed, 6506 insertions, 1274 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000000..a16cedd7fd
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,23 @@
+<!--- Remove sections that do not apply -->
+### Describe the issue
+
+### Is the issue reproducible?
+#### List steps to reproduce below:
+1.
+2.
+3.
+
+### Expected behavior
+Tell us what should happen
+
+### Actual behavior
+Tell us what happens instead
+
+### Any information in the debug.log file related to this issue?
+
+### Screenshots (if available)
+
+### What binary version was used (official or self compiled)
+
+### Machine specs: CPU, RAM, Disk space & OS (Windows, OS X, Linux)
+
diff --git a/.gitignore b/.gitignore
index ce40019dc3..892b2a3e08 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,10 +103,9 @@ linux-build
win32-build
qa/pull-tester/run-bitcoind-for-test.sh
qa/pull-tester/tests_config.py
-qa/pull-tester/cache/*
qa/pull-tester/test.*/*
qa/tmp
-cache/
+qa/cache/*
share/BitcoindComparisonTool.jar
!src/leveldb*/Makefile
diff --git a/.travis.yml b/.travis.yml
index a6c51753b6..0b38fd45fe 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,5 @@
sudo: required
dist: trusty
-
-#workaround for https://github.com/travis-ci/travis-ci/issues/5227
-addons:
- hostname: bitcoin-tester
-
os: linux
language: generic
cache:
@@ -29,15 +24,15 @@ env:
# ARM
- HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="NO_QT=1" CHECK_DOC=1 GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
# Win32
- - HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-i686 wine1.6 bc openjdk-7-jre-headless" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports"
+ - HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-i686 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports"
# 32-bit + dash
- - HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc python3-zmq openjdk-7-jre-headless" DEP_OPTS="NO_QT=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash"
+ - HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc python3-zmq" DEP_OPTS="NO_QT=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash"
# Win64
- - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine1.6 bc openjdk-7-jre-headless" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports"
+ - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine1.6 bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-reduce-exports"
# bitcoind
- - HOST=x86_64-unknown-linux-gnu PACKAGES="bc python3-zmq openjdk-7-jre-headless" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER"
+ - HOST=x86_64-unknown-linux-gnu PACKAGES="bc python3-zmq" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER"
# No wallet
- - HOST=x86_64-unknown-linux-gnu PACKAGES=" openjdk-7-jre-headless python3" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
+ - 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"
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5c1138b812..62ebc7917a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,15 +1,26 @@
Contributing to Bitcoin Core
============================
-The Bitcoin Core project operates an open contributor model where anyone is welcome to contribute towards development in the form of peer review, testing and patches. This document explains the practical process and guidelines for contributing.
+The Bitcoin Core project operates an open contributor model where anyone is
+welcome to contribute towards development in the form of peer review, testing
+and patches. This document explains the practical process and guidelines for
+contributing.
-Firstly in terms of structure, there is no particular concept of “Core developers” in the sense of privileged people. Open source often naturally revolves around meritocracy where longer term contributors gain more trust from the developer community. However, some hierarchy is necessary for practical purposes. As such there are repository “maintainers” who are responsible for merging pull requests as well as a “lead maintainer” who is responsible for the release cycle, overall merging, moderation and appointment of maintainers.
+Firstly in terms of structure, there is no particular concept of "Core
+developers" in the sense of privileged people. Open source often naturally
+revolves around meritocracy where longer term contributors gain more trust from
+the developer community. However, some hierarchy is necessary for practical
+purposes. As such there are repository "maintainers" who are responsible for
+merging pull requests as well as a "lead maintainer" who is responsible for the
+release cycle, overall merging, moderation and appointment of maintainers.
Contributor Workflow
--------------------
-The codebase is maintained using the “contributor workflow” where everyone without exception contributes patch proposals using “pull requests”. This facilitates social contribution, easy testing and peer review.
+The codebase is maintained using the "contributor workflow" where everyone
+without exception contributes patch proposals using "pull requests". This
+facilitates social contribution, easy testing and peer review.
To contribute a patch, the workflow is as follows:
@@ -17,35 +28,56 @@ To contribute a patch, the workflow is as follows:
- Create topic branch
- Commit patches
-The project coding conventions in the [developer notes](doc/developer-notes.md) must be adhered to.
+The project coding conventions in the [developer notes](doc/developer-notes.md)
+must be adhered to.
-In general [commits should be atomic](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention) and diffs should be easy to read. For this reason do not mix any formatting fixes or code moves with actual code changes.
+In general [commits should be atomic](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention)
+and diffs should be easy to read. For this reason do not mix any formatting
+fixes or code moves with actual code changes.
-Commit messages should be verbose by default consisting of a short subject line (50 chars max), a blank line and detailed explanatory text as separate paragraph(s); unless the title alone is self-explanatory (like "Corrected typo in main.cpp") then a single title line is sufficient. Commit messages should be helpful to people reading your code in the future, so explain the reasoning for your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/).
+Commit messages should be verbose by default consisting of a short subject line
+(50 chars max), a blank line and detailed explanatory text as separate
+paragraph(s); unless the title alone is self-explanatory (like "Corrected typo
+in main.cpp") then a single title line is sufficient. Commit messages should be
+helpful to people reading your code in the future, so explain the reasoning for
+your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/).
-If a particular commit references another issue, please add the reference, for example `refs #1234`, or `fixes #4321`. Using the `fixes` or `closes` keywords will cause the corresponding issue to be closed when the pull request is merged.
+If a particular commit references another issue, please add the reference, for
+example `refs #1234`, or `fixes #4321`. Using the `fixes` or `closes` keywords
+will cause the corresponding issue to be closed when the pull request is merged.
-Please refer to the [Git manual](https://git-scm.com/doc) for more information about Git.
+Please refer to the [Git manual](https://git-scm.com/doc) for more information
+about Git.
- Push changes to your fork
- Create pull request
-The title of the pull request should be prefixed by the component or area that the pull request affects. Examples:
+The title of the pull request should be prefixed by the component or area that
+the pull request affects. Examples:
Consensus: Add new opcode for BIP-XXXX OP_CHECKAWESOMESIG
Net: Automatically create hidden service, listen on Tor
Qt: Add feed bump button
Trivial: Fix typo in main.cpp
-If a pull request is specifically not to be considered for merging (yet) please prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists) in the body of the pull request to indicate tasks are pending.
+If a pull request is specifically not to be considered for merging (yet) please
+prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists)
+in the body of the pull request to indicate tasks are pending.
-The body of the pull request should contain enough description about what the patch does together with any justification/reasoning. You should include references to any discussions (for example other tickets or mailing list discussions).
+The body of the pull request should contain enough description about what the
+patch does together with any justification/reasoning. You should include
+references to any discussions (for example other tickets or mailing list
+discussions).
-At this stage one should expect comments and review from other contributors. You can add more commits to your pull request by committing them locally and pushing to your fork until you have satisfied all feedback.
+At this stage one should expect comments and review from other contributors. You
+can add more commits to your pull request by committing them locally and pushing
+to your fork until you have satisfied all feedback.
Squashing Commits
---------------------------
-If your pull request is accepted for merging, you may be asked by a maintainer to squash and or [rebase](https://git-scm.com/docs/git-rebase) your commits before it will be merged. The basic squashing workflow is shown below.
+If your pull request is accepted for merging, you may be asked by a maintainer
+to squash and or [rebase](https://git-scm.com/docs/git-rebase) your commits
+before it will be merged. The basic squashing workflow is shown below.
git checkout your_branch_name
git rebase -i HEAD~n
@@ -55,67 +87,111 @@ If your pull request is accepted for merging, you may be asked by a maintainer t
# save and quit
git push -f # (force push to GitHub)
-The length of time required for peer review is unpredictable and will vary from pull request to pull request.
+The length of time required for peer review is unpredictable and will vary from
+pull request to pull request.
Pull Request Philosophy
-----------------------
-Patchsets should always be focused. For example, a pull request could add a feature, fix a bug, or refactor code; but not a mixture. Please also avoid super pull requests which attempt to do too much, are overly large, or overly complex as this makes review difficult.
+Patchsets should always be focused. For example, a pull request could add a
+feature, fix a bug, or refactor code; but not a mixture. Please also avoid super
+pull requests which attempt to do too much, are overly large, or overly complex
+as this makes review difficult.
###Features
-When adding a new feature, thought must be given to the long term technical debt and maintenance that feature may require after inclusion. Before proposing a new feature that will require maintenance, please consider if you are willing to maintain it (including bug fixing). If features get orphaned with no maintainer in the future, they may be removed by the Repository Maintainer.
+When adding a new feature, thought must be given to the long term technical debt
+and maintenance that feature may require after inclusion. Before proposing a new
+feature that will require maintenance, please consider if you are willing to
+maintain it (including bug fixing). If features get orphaned with no maintainer
+in the future, they may be removed by the Repository Maintainer.
###Refactoring
-Refactoring is a necessary part of any software project's evolution. The following guidelines cover refactoring pull requests for the project.
+Refactoring is a necessary part of any software project's evolution. The
+following guidelines cover refactoring pull requests for the project.
-There are three categories of refactoring, code only moves, code style fixes, code refactoring. In general refactoring pull requests should not mix these three kinds of activity in order to make refactoring pull requests easy to review and uncontroversial. In all cases, refactoring PRs must not change the behaviour of code within the pull request (bugs must be preserved as is).
+There are three categories of refactoring, code only moves, code style fixes,
+code refactoring. In general refactoring pull requests should not mix these
+three kinds of activity in order to make refactoring pull requests easy to
+review and uncontroversial. In all cases, refactoring PRs must not change the
+behaviour of code within the pull request (bugs must be preserved as is).
-Project maintainers aim for a quick turnaround on refactoring pull requests, so where possible keep them short, uncomplex and easy to verify.
+Project maintainers aim for a quick turnaround on refactoring pull requests, so
+where possible keep them short, uncomplex and easy to verify.
"Decision Making" Process
-------------------------
-The following applies to code changes to the Bitcoin Core project (and related projects such as libsecp256k1), and is not to be confused with overall Bitcoin Network Protocol consensus changes.
+The following applies to code changes to the Bitcoin Core project (and related
+projects such as libsecp256k1), and is not to be confused with overall Bitcoin
+Network Protocol consensus changes.
-Whether a pull request is merged into Bitcoin Core rests with the project merge maintainers and ultimately the project lead.
+Whether a pull request is merged into Bitcoin Core rests with the project merge
+maintainers and ultimately the project lead.
-Maintainers will take into consideration if a patch is in line with the general principles of the project; meets the minimum standards for inclusion; and will judge the general consensus of contributors.
+Maintainers will take into consideration if a patch is in line with the general
+principles of the project; meets the minimum standards for inclusion; and will
+judge the general consensus of contributors.
In general, all pull requests must:
- - have a clear use case, fix a demonstrable bug or serve the greater good of the project (for example refactoring for modularisation);
+ - have a clear use case, fix a demonstrable bug or serve the greater good of
+ the project (for example refactoring for modularisation);
- be well peer reviewed;
- have unit tests and functional tests where appropriate;
- follow code style guidelines;
- not break the existing test suite;
- - where bugs are fixed, where possible, there should be unit tests demonstrating the bug and also proving the fix. This helps prevent regression.
+ - where bugs are fixed, where possible, there should be unit tests
+ demonstrating the bug and also proving the fix. This helps prevent regression.
-Patches that change Bitcoin consensus rules are considerably more involved than normal because they affect the entire ecosystem and so must be preceded by extensive mailing list discussions and have a numbered BIP. While each case will be different, one should be prepared to expend more time and effort than for other kinds of patches because of increased peer review and consensus building requirements.
+Patches that change Bitcoin consensus rules are considerably more involved than
+normal because they affect the entire ecosystem and so must be preceded by
+extensive mailing list discussions and have a numbered BIP. While each case will
+be different, one should be prepared to expend more time and effort than for
+other kinds of patches because of increased peer review and consensus building
+requirements.
###Peer Review
-Anyone may participate in peer review which is expressed by comments in the pull request. Typically reviewers will review the code for obvious errors, as well as test out the patch set and opine on the technical merits of the patch. Project maintainers take into account the peer review when determining if there is consensus to merge a pull request (remember that discussions may have been spread out over github, mailing list and IRC discussions). The following language is used within pull-request comments:
+Anyone may participate in peer review which is expressed by comments in the pull
+request. Typically reviewers will review the code for obvious errors, as well as
+test out the patch set and opine on the technical merits of the patch. Project
+maintainers take into account the peer review when determining if there is
+consensus to merge a pull request (remember that discussions may have been
+spread out over github, mailing list and IRC discussions). The following
+language is used within pull-request comments:
- ACK means "I have tested the code and I agree it should be merged";
- - NACK means "I disagree this should be merged", and must be accompanied by sound technical justification. NACKs without accompanying reasoning may be disregarded;
- - utACK means "I have not tested the code, but I have reviewed it and it looks OK, I agree it can be merged";
+ - NACK means "I disagree this should be merged", and must be accompanied by
+ sound technical justification. NACKs without accompanying reasoning may be disregarded;
+ - utACK means "I have not tested the code, but I have reviewed it and it looks
+ OK, I agree it can be merged";
- Concept ACK means "I agree in the general principle of this pull request";
- Nit refers to trivial, often non-blocking issues.
Reviewers should include the commit hash which they reviewed in their comments.
-Project maintainers reserve the right to weigh the opinions of peer reviewers using common sense judgement and also may weight based on meritocracy: Those that have demonstrated a deeper commitment and understanding towards the project (over time) or have clear domain expertise may naturally have more weight, as one would expect in all walks of life.
-
-Where a patch set affects consensus critical code, the bar will be set much higher in terms of discussion and peer review requirements, keeping in mind that mistakes could be very costly to the wider community. This includes refactoring of consensus critical code.
-
-Where a patch set proposes to change the Bitcoin consensus, it must have been discussed extensively on the mailing list and IRC, be accompanied by a widely discussed BIP and have a generally widely perceived technical consensus of being a worthwhile change based on the judgement of the maintainers.
+Project maintainers reserve the right to weigh the opinions of peer reviewers
+using common sense judgement and also may weight based on meritocracy: Those
+that have demonstrated a deeper commitment and understanding towards the project
+(over time) or have clear domain expertise may naturally have more weight, as
+one would expect in all walks of life.
+
+Where a patch set affects consensus critical code, the bar will be set much
+higher in terms of discussion and peer review requirements, keeping in mind that
+mistakes could be very costly to the wider community. This includes refactoring
+of consensus critical code.
+
+Where a patch set proposes to change the Bitcoin consensus, it must have been
+discussed extensively on the mailing list and IRC, be accompanied by a widely
+discussed BIP and have a generally widely perceived technical consensus of being
+a worthwhile change based on the judgement of the maintainers.
Release Policy
diff --git a/Makefile.am b/Makefile.am
index b10d085066..37c1e98eca 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -47,9 +47,9 @@ OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \
$(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \
$(top_srcdir)/contrib/macdeploy/detached-sig-create.sh
-COVERAGE_INFO = baseline_filtered_combined.info baseline.info block_test.info \
+COVERAGE_INFO = baseline_filtered_combined.info baseline.info \
leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \
- baseline_filtered.info block_test_filtered.info rpc_test.info rpc_test_filtered.info \
+ baseline_filtered.info rpc_test.info rpc_test_filtered.info \
leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info
dist-hook:
@@ -175,16 +175,6 @@ test_bitcoin.info: baseline_filtered_combined.info
test_bitcoin_filtered.info: test_bitcoin.info
$(LCOV) -r $< "/usr/include/*" -o $@
-block_test.info: test_bitcoin_filtered.info
- $(MKDIR_P) qa/tmp
- -@TIMEOUT=15 qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS)
- $(LCOV) -c -d $(abs_builddir)/src --t BitcoinJBlockTest -o $@
- $(LCOV) -z -d $(abs_builddir)/src
- $(LCOV) -z -d $(abs_builddir)/src/leveldb
-
-block_test_filtered.info: block_test.info
- $(LCOV) -r $< "/usr/include/*" -o $@
-
rpc_test.info: test_bitcoin_filtered.info
-@TIMEOUT=15 python qa/pull-tester/rpc-tests.py $(EXTENDED_RPC_TESTS)
$(LCOV) -c -d $(abs_builddir)/src --t rpc-tests -o $@
@@ -197,8 +187,8 @@ rpc_test_filtered.info: rpc_test.info
test_bitcoin_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info
$(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@
-total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info block_test_filtered.info rpc_test_filtered.info
- $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a block_test_filtered.info -a rpc_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
+total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info rpc_test_filtered.info
+ $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a rpc_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info
$(GENHTML) -s $< -o $(@D)
@@ -212,12 +202,6 @@ cov: test_bitcoin.coverage/.dirstamp total.coverage/.dirstamp
endif
-if USE_COMPARISON_TOOL
-check-local:
- $(MKDIR_P) qa/tmp
- @qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS) 2>&1
-endif
-
dist_noinst_SCRIPTS = autogen.sh
EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc-tests $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS)
diff --git a/configure.ac b/configure.ac
index c4b60398be..add8d21781 100644
--- a/configure.ac
+++ b/configure.ac
@@ -66,8 +66,8 @@ AC_PATH_TOOL(RANLIB, ranlib)
AC_PATH_TOOL(STRIP, strip)
AC_PATH_TOOL(GCOV, gcov)
AC_PATH_PROG(LCOV, lcov)
-AC_PATH_PROG(JAVA, java)
-AC_PATH_PROGS([PYTHON], [python3 python2.7 python2 python])
+dnl Python 3.x is supported from 3.4 on (see https://github.com/bitcoin/bitcoin/issues/7893)
+AC_PATH_PROGS([PYTHON], [python3.6 python3.5 python3.4 python3 python2.7 python2 python])
AC_PATH_PROG(GENHTML, genhtml)
AC_PATH_PROG([GIT], [git])
AC_PATH_PROG(CCACHE,ccache)
@@ -113,16 +113,6 @@ AC_ARG_ENABLE(bench,
[use_bench=$enableval],
[use_bench=yes])
-AC_ARG_WITH([comparison-tool],
- AS_HELP_STRING([--with-comparison-tool],[path to java comparison tool (requires --enable-tests)]),
- [use_comparison_tool=$withval],
- [use_comparison_tool=no])
-
-AC_ARG_ENABLE([comparison-tool-reorg-tests],
- AS_HELP_STRING([--enable-comparison-tool-reorg-tests],[enable expensive reorg tests in the comparison tool (default no)]),
- [use_comparison_tool_reorg_tests=$enableval],
- [use_comparison_tool_reorg_tests=no])
-
AC_ARG_ENABLE([extended-rpc-tests],
AS_HELP_STRING([--enable-extended-rpc-tests],[enable expensive RPC tests when using lcov (default no)]),
[use_extended_rpc_tests=$enableval],
@@ -366,8 +356,15 @@ case $host in
TARGET_OS=linux
LEVELDB_TARGET_FLAGS="-DOS_LINUX"
;;
+ *freebsd*)
+ LEVELDB_TARGET_FLAGS="-DOS_FREEBSD"
+ ;;
+ *openbsd*)
+ LEVELDB_TARGET_FLAGS="-DOS_OPENBSD"
+ ;;
*)
OTHER_OS=`echo ${host_os} | awk '{print toupper($0)}'`
+ AC_MSG_WARN([Guessing LevelDB OS as OS_${OTHER_OS}, please check whether this is correct, if not add an entry to configure.ac.])
LEVELDB_TARGET_FLAGS="-DOS_${OTHER_OS}"
;;
esac
@@ -382,19 +379,6 @@ if test x$use_pkgconfig = xyes; then
])
fi
-if test x$use_comparison_tool != xno; then
- AC_SUBST(JAVA_COMPARISON_TOOL, $use_comparison_tool)
-fi
-
-if test x$use_comparison_tool_reorg_tests != xno; then
- if test x$use_comparison_tool = x; then
- AC_MSG_ERROR("comparison tool reorg tests but comparison tool was not specified")
- fi
- AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 1)
-else
- AC_SUBST(COMPARISON_TOOL_REORG_TESTS, 0)
-fi
-
if test x$use_extended_rpc_tests != xno; then
AC_SUBST(EXTENDED_RPC_TESTS, -extended)
fi
@@ -406,18 +390,12 @@ if test x$use_lcov = xyes; then
if test x$GCOV = x; then
AC_MSG_ERROR("lcov testing requested but gcov not found")
fi
- if test x$JAVA = x; then
- AC_MSG_ERROR("lcov testing requested but java not found")
- fi
if test x$PYTHON = x; then
AC_MSG_ERROR("lcov testing requested but python not found")
fi
if test x$GENHTML = x; then
AC_MSG_ERROR("lcov testing requested but genhtml not found")
fi
- if test x$use_comparison_tool = x; then
- AC_MSG_ERROR("lcov testing requested but comparison tool was not specified")
- fi
LCOV="$LCOV --gcov-tool=$GCOV"
AX_CHECK_COMPILE_FLAG([--coverage],[CXXFLAGS="$CXXFLAGS --coverage"],
[AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")])
@@ -880,14 +858,6 @@ AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$need_bundled_univalue = xyes])
AC_SUBST(UNIVALUE_CFLAGS)
AC_SUBST(UNIVALUE_LIBS)
-CXXFLAGS_TEMP="$CXXFLAGS"
-LIBS_TEMP="$LIBS"
-CXXFLAGS="$CXXFLAGS $SSL_CFLAGS $CRYPTO_CFLAGS"
-LIBS="$LIBS $SSL_LIBS $CRYPTO_LIBS"
-AC_CHECK_HEADER([openssl/ec.h],, AC_MSG_ERROR(OpenSSL ec header missing),)
-CXXFLAGS="$CXXFLAGS_TEMP"
-LIBS="$LIBS_TEMP"
-
BITCOIN_QT_PATH_PROGS([PROTOC], [protoc],$protoc_bin_path)
AC_MSG_CHECKING([whether to build bitcoind])
@@ -1036,8 +1006,6 @@ AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes])
AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes])
AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes])
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([HARDEN],[test x$use_hardening = xyes])
diff --git a/contrib/README.md b/contrib/README.md
index a23b197cc6..3e3c83da5f 100644
--- a/contrib/README.md
+++ b/contrib/README.md
@@ -45,6 +45,9 @@ Scripts and notes for Mac builds.
### [RPM](/contrib/rpm) ###
RPM spec file for building bitcoin-core on RPM based distributions
+### [Gitian-build](/contrib/gitian-build.sh) ###
+Script for running full gitian builds.
+
Test and Verify Tools
---------------------
diff --git a/contrib/debian/copyright b/contrib/debian/copyright
index c039a7bae5..cc4606ca88 100644
--- a/contrib/debian/copyright
+++ b/contrib/debian/copyright
@@ -59,6 +59,10 @@ Files: src/qt/res/icons/tx_mined.png
src/qt/res/src/mine.svg
src/qt/res/icons/fontbigger.png
src/qt/res/icons/fontsmaller.png
+ src/qt/res/icons/hd_disabled.png
+ src/qt/res/src/hd_disabled.svg
+ src/qt/res/icons/hd_enabled.png
+ src/qt/res/src/hd_enabled.svg
Copyright: Jonas Schnelli
License: Expat
Comment:
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
index bb8b9246b8..af5c000b03 100644
--- a/contrib/devtools/README.md
+++ b/contrib/devtools/README.md
@@ -51,8 +51,9 @@ maintained:
* for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master)
* for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork)
* for `src/univalue`: https://github.com/bitcoin-core/univalue.git (branch master)
+* for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master)
-Usage: `git-subtree-check.sh DIR COMMIT`
+Usage: `git-subtree-check.sh DIR (COMMIT)`
`COMMIT` may be omitted, in which case `HEAD` is used.
diff --git a/contrib/devtools/fix-copyright-headers.py b/contrib/devtools/fix-copyright-headers.py
index b6414a551f..54836bd83f 100755
--- a/contrib/devtools/fix-copyright-headers.py
+++ b/contrib/devtools/fix-copyright-headers.py
@@ -1,5 +1,5 @@
-#!/usr/bin/env python
-'''
+#!/usr/bin/env python3
+"""
Run this script to update all the copyright headers of files
that were changed this year.
@@ -10,37 +10,58 @@ For example:
it will change it to
// Copyright (c) 2009-2015 The Bitcoin Core developers
-'''
-import os
+"""
+import subprocess
import time
import re
-year = time.gmtime()[0]
-CMD_GIT_DATE = 'git log --format=@%%at -1 %s | date +"%%Y" -u -f -'
-CMD_REGEX= "perl -pi -e 's/(20\d\d)(?:-20\d\d)? The Bitcoin/$1-%s The Bitcoin/' %s"
-REGEX_CURRENT= re.compile("%s The Bitcoin" % year)
-CMD_LIST_FILES= "find %s | grep %s"
+CMD_GIT_LIST_FILES = ['git', 'ls-files']
+CMD_GIT_DATE = ['git', 'log', '--format=%ad', '--date=short', '-1']
+CMD_PERL_REGEX = ['perl', '-pi', '-e']
+REGEX_TEMPLATE = 's/(20\\d\\d)(?:-20\\d\\d)? The Bitcoin/$1-%s The Bitcoin/'
-FOLDERS = ["./qa", "./src"]
+FOLDERS = ["qa/", "src/"]
EXTENSIONS = [".cpp",".h", ".py"]
+
def get_git_date(file_path):
- r = os.popen(CMD_GIT_DATE % file_path)
- for l in r:
- # Result is one line, so just return
- return l.replace("\n","")
- return ""
-
-n=1
-for folder in FOLDERS:
- for extension in EXTENSIONS:
- for file_path in os.popen(CMD_LIST_FILES % (folder, extension)):
- file_path = os.getcwd() + file_path[1:-1]
- if file_path.endswith(extension):
- git_date = get_git_date(file_path)
- if str(year) == git_date:
- # Only update if current year is not found
- if REGEX_CURRENT.search(open(file_path, "r").read()) is None:
- print n,"Last git edit", git_date, "-", file_path
- os.popen(CMD_REGEX % (year,file_path))
+ d = subprocess.run(CMD_GIT_DATE + [file_path],
+ stdout=subprocess.PIPE,
+ check=True,
+ universal_newlines=True).stdout
+ # yyyy-mm-dd
+ return d.split('-')[0]
+
+
+def skip_file(file_path):
+ for ext in EXTENSIONS:
+ if file_path.endswith(ext):
+ return False
+ else:
+ return True
+
+if __name__ == "__main__":
+ year = str(time.gmtime()[0])
+ regex_current = re.compile("%s The Bitcoin" % year)
+ n = 1
+ for folder in FOLDERS:
+ for file_path in subprocess.run(
+ CMD_GIT_LIST_FILES + [folder],
+ stdout=subprocess.PIPE,
+ check=True,
+ universal_newlines=True
+ ).stdout.split("\n"):
+ if skip_file(file_path):
+ # print(file_path, "(skip)")
+ continue
+ git_date = get_git_date(file_path)
+ if not year == git_date:
+ # print(file_path, year, "(skip)")
+ continue
+ if regex_current.search(open(file_path, "r").read()) is not None:
+ # already up to date
+ # print(file_path, year, "(skip)")
+ continue
+ print(n, file_path, "(update to %s)" % year)
+ subprocess.run(CMD_PERL_REGEX + [REGEX_TEMPLATE % year, file_path], check=True)
n = n + 1
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index 301fea85c1..c61d652641 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python
'''
Perform basic ELF security checks on a series of executables.
Exit status will be 0 if successful, and the program will be silent.
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index e26c0fbb94..8f8685006e 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python
# Copyright (c) 2014 Wladimir J. van der Laan
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index fed7626aab..324b7bcd85 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
'''
Test script for security-check.py
'''
diff --git a/contrib/devtools/update-translations.py b/contrib/devtools/update-translations.py
index 2b6e807b47..78b9f9d179 100755
--- a/contrib/devtools/update-translations.py
+++ b/contrib/devtools/update-translations.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# Copyright (c) 2014 Wladimir J. van der Laan
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh
new file mode 100755
index 0000000000..ee47d138f3
--- /dev/null
+++ b/contrib/gitian-build.sh
@@ -0,0 +1,388 @@
+# What to do
+sign=false
+verify=false
+build=false
+setupenv=false
+
+# Systems to build
+linux=true
+windows=true
+osx=true
+
+# Other Basic variables
+SIGNER=
+VERSION=
+commit=false
+url=https://github.com/bitcoin/bitcoin
+proc=2
+mem=2000
+lxc=true
+osslTarUrl=http://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz
+osslPatchUrl=https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch
+scriptName=$(basename -- "$0")
+signProg="gpg --detach-sign"
+commitFiles=true
+
+# Help Message
+read -d '' usage <<- EOF
+Usage: $scriptName [-c|u|v|b|s|B|o|h|j|m|] signer version
+
+Run this script from the directory containing the bitcoin, gitian-builder, gitian.sigs, and bitcoin-detached-sigs.
+
+Arguments:
+signer GPG signer to sign each build assert file
+version Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified
+
+Options:
+-c|--commit Indicate that the version argument is for a commit or branch
+-u|--url Specify the URL of the repository. Default is https://github.com/bitcoin/bitcoin
+-v|--verify Verify the gitian build
+-b|--build Do a gitiain build
+-s|--sign Make signed binaries for Windows and Mac OSX
+-B|--buildsign Build both signed and unsigned binaries
+-o|--os Specify which Operating Systems the build is for. Default is lwx. l for linux, w for windows, x for osx
+-j Number of processes to use. Default 2
+-m Memory to allocate in MiB. Default 2000
+--kvm Use KVM instead of LXC
+--setup Setup the gitian building environment. Uses KVM. If you want to use lxc, use the --lxc option. Only works on Debian-based systems (Ubuntu, Debian)
+--detach-sign Create the assert file for detached signing. Will not commit anything.
+--no-commit Do not commit anything to git
+-h|--help Print this help message
+EOF
+
+# Get options and arguments
+while :; do
+ case $1 in
+ # Verify
+ -v|--verify)
+ verify=true
+ ;;
+ # Build
+ -b|--build)
+ build=true
+ ;;
+ # Sign binaries
+ -s|--sign)
+ sign=true
+ ;;
+ # Build then Sign
+ -B|--buildsign)
+ sign=true
+ build=true
+ ;;
+ # PGP Signer
+ -S|--signer)
+ if [ -n "$2" ]
+ then
+ SIGNER=$2
+ shift
+ else
+ echo 'Error: "--signer" requires a non-empty argument.'
+ exit 1
+ fi
+ ;;
+ # Operating Systems
+ -o|--os)
+ if [ -n "$2" ]
+ then
+ linux=false
+ windows=false
+ osx=false
+ if [[ "$2" = *"l"* ]]
+ then
+ linux=true
+ fi
+ if [[ "$2" = *"w"* ]]
+ then
+ windows=true
+ fi
+ if [[ "$2" = *"x"* ]]
+ then
+ osx=true
+ fi
+ shift
+ else
+ echo 'Error: "--os" requires an argument containing an l (for linux), w (for windows), or x (for Mac OSX)\n'
+ exit 1
+ fi
+ ;;
+ # Help message
+ -h|--help)
+ echo "$usage"
+ exit 0
+ ;;
+ # Commit or branch
+ -c|--commit)
+ commit=true
+ ;;
+ # Number of Processes
+ -j)
+ if [ -n "$2" ]
+ then
+ proc=$2
+ shift
+ else
+ echo 'Error: "-j" requires an argument'
+ exit 1
+ fi
+ ;;
+ # Memory to allocate
+ -m)
+ if [ -n "$2" ]
+ then
+ mem=$2
+ shift
+ else
+ echo 'Error: "-m" requires an argument'
+ exit 1
+ fi
+ ;;
+ # URL
+ -u)
+ if [ -n "$2" ]
+ then
+ url=$2
+ shift
+ else
+ echo 'Error: "-u" requires an argument'
+ exit 1
+ fi
+ ;;
+ # kvm
+ --kvm)
+ lxc=false
+ ;;
+ # Detach sign
+ --detach-sign)
+ signProg="true"
+ commitFiles=false
+ ;;
+ # Commit files
+ --no-commit)
+ commitFiles=false
+ ;;
+ # Setup
+ --setup)
+ setup=true
+ ;;
+ *) # Default case: If no more options then break out of the loop.
+ break
+ esac
+ shift
+done
+
+# Set up LXC
+if [[ $lxc = true ]]
+then
+ export USE_LXC=1
+ export LXC_BRIDGE=lxcbr0
+ sudo ifconfig lxcbr0 up 10.0.2.2
+fi
+
+# Check for OSX SDK
+if [[ ! -e "gitian-builder/inputs/MacOSX10.11.sdk.tar.gz" && $osx == true ]]
+then
+ echo "Cannot build for OSX, SDK does not exist. Will build for other OSes"
+ osx=false
+fi
+
+# Get signer
+if [[ -n"$1" ]]
+then
+ SIGNER=$1
+ shift
+fi
+
+# Get version
+if [[ -n "$1" ]]
+then
+ VERSION=$1
+ COMMIT=$VERSION
+ shift
+fi
+
+# Check that a signer is specified
+if [[ $SIGNER == "" ]]
+then
+ echo "$scriptName: Missing signer."
+ echo "Try $scriptName --help for more information"
+ exit 1
+fi
+
+# Check that a version is specified
+if [[ $VERSION == "" ]]
+then
+ echo "$scriptName: Missing version."
+ echo "Try $scriptName --help for more information"
+ exit 1
+fi
+
+# Add a "v" if no -c
+if [[ $commit = false ]]
+then
+ COMMIT="v${VERSION}"
+fi
+echo ${COMMIT}
+
+# Setup build environment
+if [[ $setup = true ]]
+then
+ sudo apt-get install ruby apache2 git apt-cacher-ng python-vm-builder qemu-kvm qemu-utils
+ git clone https://github.com/bitcoin-core/gitian.sigs.git
+ git clone https://github.com/bitcoin-core/bitcoin-detached-sigs.git
+ git clone https://github.com/devrandom/gitian-builder.git
+ pushd ./gitian-builder
+ if [[ -n "$USE_LXC" ]]
+ then
+ sudo apt-get install lxc
+ bin/make-base-vm --suite trusty --arch amd64 --lxc
+ else
+ bin/make-base-vm --suite trusty --arch amd64
+ fi
+ popd
+fi
+
+# Set up build
+pushd ./bitcoin
+git fetch
+git checkout ${COMMIT}
+popd
+
+# Build
+if [[ $build = true ]]
+then
+ # Make output folder
+ mkdir -p ./bitcoin-binaries/${VERSION}
+
+ # Build Dependencies
+ echo ""
+ echo "Building Dependencies"
+ echo ""
+ pushd ./gitian-builder
+ mkdir -p inputs
+ wget -N -P inputs $osslPatchUrl
+ wget -N -P inputs $osslTarUrl
+ make -C ../bitcoin/depends download SOURCES_PATH=`pwd`/cache/common
+
+ # Linux
+ if [[ $linux = true ]]
+ then
+ echo ""
+ echo "Compiling ${VERSION} Linux"
+ echo ""
+ ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/${VERSION}
+ fi
+ # Windows
+ if [[ $windows = true ]]
+ then
+ echo ""
+ echo "Compiling ${VERSION} Windows"
+ echo ""
+ ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+ mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz
+ mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../bitcoin-binaries/${VERSION}
+ fi
+ # Mac OSX
+ if [[ $osx = true ]]
+ then
+ echo ""
+ echo "Compiling ${VERSION} Mac OSX"
+ echo ""
+ ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
+ mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz
+ mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../bitcoin-binaries/${VERSION}
+ fi
+ popd
+
+ if [[ $commitFiles = true ]]
+ then
+ # Commit to gitian.sigs repo
+ echo ""
+ echo "Committing ${VERSION} Unsigned Sigs"
+ echo ""
+ pushd gitian.sigs
+ git add ${VERSION}-linux/${SIGNER}
+ git add ${VERSION}-win-unsigned/${SIGNER}
+ git add ${VERSION}-osx-unsigned/${SIGNER}
+ git commit -a -m "Add ${VERSION} unsigned sigs for ${SIGNER}"
+ popd
+ fi
+fi
+
+# Verify the build
+if [[ $verify = true ]]
+then
+ # Linux
+ pushd ./gitian-builder
+ echo ""
+ echo "Verifying v${VERSION} Linux"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ # Windows
+ echo ""
+ echo "Verifying v${VERSION} Windows"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+ # Mac OSX
+ echo ""
+ echo "Verifying v${VERSION} Mac OSX"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
+ # Signed Windows
+ echo ""
+ echo "Verifying v${VERSION} Signed Windows"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ # Signed Mac OSX
+ echo ""
+ echo "Verifying v${VERSION} Signed Mac OSX"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ popd
+fi
+
+# Sign binaries
+if [[ $sign = true ]]
+then
+
+ pushd ./gitian-builder
+ # Sign Windows
+ if [[ $windows = true ]]
+ then
+ echo ""
+ echo "Signing ${VERSION} Windows"
+ echo ""
+ ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
+ mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/${VERSION}
+ mv build/out/bitcoin-*win32-setup.exe ../bitcoin-binaries/${VERSION}
+ fi
+ # Sign Mac OSX
+ if [[ $osx = true ]]
+ then
+ echo ""
+ echo "Signing ${VERSION} Mac OSX"
+ echo ""
+ ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/${VERSION}/bitcoin-${VERSION}-osx.dmg
+ fi
+ popd
+
+ if [[ $commitFiles = true ]]
+ then
+ # Commit Sigs
+ pushd gitian.sigs
+ echo ""
+ echo "Committing ${VERSION} Signed Sigs"
+ echo ""
+ git add ${VERSION}-win-signed/${SIGNER}
+ git add ${VERSION}-osx-signed/${SIGNER}
+ git commit -a -m "Add ${VERSION} signed binary sigs for ${SIGNER}"
+ popd
+ fi
+fi
diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py
index 0f6fde2a6e..8badb4b318 100755
--- a/contrib/linearize/linearize-data.py
+++ b/contrib/linearize/linearize-data.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
#
# linearize-data.py: Construct a linear, no-fork version of the chain.
#
diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py
index 854cf1f9ee..cb40c664fa 100755
--- a/contrib/linearize/linearize-hashes.py
+++ b/contrib/linearize/linearize-hashes.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
#
# linearize-hashes.py: List blocks in a linear, no-fork version of the chain.
#
diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh
new file mode 100755
index 0000000000..46d2d825d4
--- /dev/null
+++ b/contrib/macdeploy/extract-osx-sdk.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+set -e
+
+INPUTFILE="Xcode_7.3.1.dmg"
+HFSFILENAME="5.hfs"
+SDKDIR="Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk"
+
+7z x "${INPUTFILE}" "${HFSFILENAME}"
+SDKNAME="$(basename "${SDKDIR}")"
+SDKDIRINODE=$(ifind -n "${SDKDIR}" "${HFSFILENAME}")
+fls "${HFSFILENAME}" -rpF ${SDKDIRINODE} |
+ while read type inode filename; do
+ inode="${inode::-1}"
+ if [ "${filename:0:14}" = "usr/share/man/" ]; then
+ continue
+ fi
+ filename="${SDKNAME}/$filename"
+ echo "Extracting $filename ..."
+ mkdir -p "$(dirname "$filename")"
+ if [ "$type" = "l/l" ]; then
+ ln -s "$(icat "${HFSFILENAME}" $inode)" "$filename"
+ else
+ icat "${HFSFILENAME}" $inode >"$filename"
+ fi
+done
+echo "Building ${SDKNAME}.tar.gz ..."
+MTIME="$(istat "${HFSFILENAME}" "${SDKDIRINODE}" | perl -nle 'm/Content Modified:\s+(.*?)\s\(/ && print $1')"
+find "${SDKNAME}" | sort | tar --no-recursion --mtime="${MTIME}" --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > "${SDKNAME}.tar.gz"
+echo 'All done!'
diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py
index a3d0352187..f43dc0b218 100755
--- a/contrib/seeds/generate-seeds.py
+++ b/contrib/seeds/generate-seeds.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# Copyright (c) 2014 Wladimir J. van der Laan
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/verifybinaries/README.md b/contrib/verifybinaries/README.md
index 8970f3daa4..ed3e14fb6c 100644
--- a/contrib/verifybinaries/README.md
+++ b/contrib/verifybinaries/README.md
@@ -1,13 +1,33 @@
### Verify Binaries
+
+#### Preparation:
+
+Make sure you obtain the proper release signing key and verify the fingerprint with several independent sources.
+
+```sh
+$ gpg --fingerprint "Bitcoin Core binary release signing key"
+pub 4096R/36C2E964 2015-06-24 [expires: 2017-02-13]
+ Key fingerprint = 01EA 5486 DE18 A882 D4C2 6845 90C8 019E 36C2 E964
+uid Wladimir J. van der Laan (Bitcoin Core binary release signing key) <laanwj@gmail.com>
+```
+
+#### Usage:
+
This script attempts to download the signature file `SHA256SUMS.asc` from https://bitcoin.org.
It first checks if the signature passes, and then downloads the files specified in the file, and checks if the hashes of these files match those that are specified in the signature file.
The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2.
-Usage:
```sh
./verify.sh bitcoin-core-0.11.2
./verify.sh bitcoin-core-0.12.0
+./verify.sh bitcoin-core-0.13.0-rc3
+```
+
+If you do not want to keep the downloaded binaries, specify anything as the second parameter.
+
+```sh
+./verify.sh bitcoin-core-0.13.0 delete
```
diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh
index 657c3bd33c..e22b911743 100755
--- a/contrib/verifybinaries/verify.sh
+++ b/contrib/verifybinaries/verify.sh
@@ -14,11 +14,11 @@ function clean_up {
done
}
-WORKINGDIR="/tmp/bitcoin"
+WORKINGDIR="/tmp/bitcoin_verify_binaries"
TMPFILE="hashes.tmp"
SIGNATUREFILENAME="SHA256SUMS.asc"
-RCSUBDIR="test/"
+RCSUBDIR="test"
BASEDIR="https://bitcoin.org/bin/"
VERSIONPREFIX="bitcoin-core-"
RCVERSIONSTRING="rc"
@@ -43,7 +43,7 @@ if [ -n "$1" ]; then
# and simultaneously add RCSUBDIR to BASEDIR, where we will look for SIGNATUREFILENAME
if [[ $VERSION == *"$RCVERSIONSTRING"* ]]; then
BASEDIR="$BASEDIR${VERSION/%-$RCVERSIONSTRING*}/"
- BASEDIR="$BASEDIR$RCSUBDIR"
+ BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSIONSTRING${VERSION: -1}/"
else
BASEDIR="$BASEDIR$VERSION/"
fi
@@ -93,7 +93,7 @@ fi
FILES=$(awk '{print $2}' "$TMPFILE")
#and download these one by one
-for file in in $FILES
+for file in $FILES
do
wget --quiet -N "$BASEDIR$file"
done
@@ -108,11 +108,16 @@ if [ $? -eq 1 ]; then
exit 1
elif [ $? -gt 1 ]; then
echo "Error executing 'diff'"
- exit 2
+ exit 2
fi
-#everything matches! clean up the mess
-clean_up $FILES $SIGNATUREFILENAME $TMPFILE
+if [ -n "$2" ]; then
+ echo "Clean up the binaries"
+ clean_up $FILES $SIGNATUREFILENAME $TMPFILE
+else
+ echo "Keep the binaries in $WORKINGDIR"
+ clean_up $TMPFILE
+fi
echo -e "Verified hashes of \n$FILES"
diff --git a/depends/config.site.in b/depends/config.site.in
index e731537bf7..27e3aedd8e 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -19,9 +19,6 @@ fi
if test -z $with_protoc_bindir; then
with_protoc_bindir=$depends_prefix/native/bin
fi
-if test -z $with_comparison_tool; then
- with_comparison_tool=$depends_prefix/native/share/BitcoindComparisonTool_jar/BitcoindComparisonTool.jar
-fi
if test -z $enable_wallet && test -n "@no_wallet@"; then
diff --git a/depends/packages/native_comparisontool.mk b/depends/packages/native_comparisontool.mk
deleted file mode 100644
index e0ae0cec70..0000000000
--- a/depends/packages/native_comparisontool.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-package=native_comparisontool
-$(package)_version=8c6666f
-$(package)_download_path=https://github.com/theuni/bitcoind-comparisontool/raw/master
-$(package)_file_name=pull-tests-$($(package)_version).jar
-$(package)_sha256_hash=a865332b3827abcde684ab79f5f43c083b0b6a4c97ff5508c79f29fee24f11cd
-$(package)_install_dirname=BitcoindComparisonTool_jar
-$(package)_install_filename=BitcoindComparisonTool.jar
-
-define $(package)_extract_cmds
-endef
-
-define $(package)_configure_cmds
-endef
-
-define $(package)_build_cmds
-endef
-
-define $(package)_stage_cmds
- mkdir -p $($(package)_staging_prefix_dir)/share/$($(package)_install_dirname) && \
- cp $($(package)_source) $($(package)_staging_prefix_dir)/share/$($(package)_install_dirname)/$($(package)_install_filename)
-endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index ba2a05248c..4cf44385b8 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -1,5 +1,5 @@
packages:=boost openssl libevent zeromq
-native_packages := native_ccache native_comparisontool
+native_packages := native_ccache
qt_native_packages = native_protobuf
qt_packages = qrencode protobuf
diff --git a/depends/packages/qt46.mk b/depends/packages/qt46.mk
deleted file mode 100644
index 8fb30a5c44..0000000000
--- a/depends/packages/qt46.mk
+++ /dev/null
@@ -1,66 +0,0 @@
-PACKAGE=qt46
-$(package)_version=4.6.4
-$(package)_download_path=http://download.qt-project.org/archive/qt/4.6/
-$(package)_file_name=qt-everywhere-opensource-src-$($(package)_version).tar.gz
-$(package)_sha256_hash=9ad4d46c721b53a429ed5a2eecfd3c239a9ab566562f183f99d3125f1a234250
-$(package)_dependencies=openssl freetype dbus libX11 xproto libXext libICE libSM
-$(package)_patches=stlfix.patch
-
-define $(package)_set_vars
-$(package)_config_opts = -prefix $(host_prefix) -headerdir $(host_prefix)/include/qt4 -bindir $(build_prefix)/bin
-$(package)_config_opts += -release -no-separate-debug-info -opensource -confirm-license
-$(package)_config_opts += -stl -qt-zlib
-
-$(package)_config_opts += -nomake examples -nomake tests -nomake tools -nomake translations -nomake demos -nomake docs
-$(package)_config_opts += -no-audio-backend -no-glib -no-nis -no-cups -no-iconv -no-gif -no-pch
-$(package)_config_opts += -no-xkb -no-xrender -no-xrandr -no-xfixes -no-xcursor -no-xinerama -no-xsync -no-xinput -no-mitshm -no-xshape
-$(package)_config_opts += -no-libtiff -no-fontconfig -openssl-linked
-$(package)_config_opts += -no-sql-db2 -no-sql-ibase -no-sql-oci -no-sql-tds -no-sql-mysql
-$(package)_config_opts += -no-sql-odbc -no-sql-psql -no-sql-sqlite -no-sql-sqlite2
-$(package)_config_opts += -no-xmlpatterns -no-multimedia -no-phonon -no-scripttools -no-declarative
-$(package)_config_opts += -no-phonon-backend -no-webkit -no-javascript-jit -no-script
-$(package)_config_opts += -no-svg -no-libjpeg -no-libtiff -no-libpng -no-libmng -no-qt3support -no-opengl
-
-$(package)_config_opts_x86_64_linux += -platform linux-g++-64
-$(package)_config_opts_i686_linux = -platform linux-g++-32
-$(package)_build_env = QT_RCC_TEST=1
-endef
-
-define $(package)_preprocess_cmds
- sed -i.old "s|/include /usr/include||" config.tests/unix/freetype/freetype.pri && \
- sed -i.old "s|src_plugins.depends = src_gui src_sql src_svg|src_plugins.depends = src_gui src_sql|" src/src.pro && \
- sed -i.old "s|\.lower(|\.toLower(|g" src/network/ssl/qsslsocket_openssl.cpp && \
- sed -i.old "s|Key_BackSpace|Key_Backspace|" src/gui/itemviews/qabstractitemview.cpp && \
- sed -i.old "s|/usr/X11R6/lib64|$(host_prefix)/lib|" mkspecs/*/*.conf && \
- sed -i.old "s|/usr/X11R6/lib|$(host_prefix)/lib|" mkspecs/*/*.conf && \
- sed -i.old "s|/usr/X11R6/include|$(host_prefix)/include|" mkspecs/*/*.conf && \
- sed -i.old "s|QMAKE_LFLAGS_SHLIB\t+= -shared|QMAKE_LFLAGS_SHLIB\t+= -shared -Wl,--exclude-libs,ALL|" mkspecs/common/g++.conf && \
- sed -i.old "/SSLv2_client_method/d" src/network/ssl/qsslsocket_openssl.cpp src/network/ssl/qsslsocket_openssl_symbols.cpp && \
- sed -i.old "/SSLv2_server_method/d" src/network/ssl/qsslsocket_openssl.cpp src/network/ssl/qsslsocket_openssl_symbols.cpp && \
- patch -p1 < $($(package)_patch_dir)/stlfix.patch
-endef
-
-define $(package)_config_cmds
- export PKG_CONFIG_SYSROOT_DIR=/ && \
- export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \
- export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \
- export CPATH=$(host_prefix)/include && \
- OPENSSL_LIBS='-L$(host_prefix)/lib -lssl -lcrypto' ./configure $($(package)_config_opts) && \
- cd tools/linguist/lrelease; ../../../bin/qmake -o Makefile lrelease.pro
-endef
-
-define $(package)_build_cmds
- export CPATH=$(host_prefix)/include && \
- $(MAKE) -C src && \
- $(MAKE) -C tools/linguist/lrelease
-endef
-
-define $(package)_stage_cmds
- $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) install && \
- $(MAKE) -C tools/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install
-endef
-
-define $(package)_postprocess_cmds
- rm -rf mkspecs/ lib/cmake/ lib/*.prl lib/*.la && \
- find native/bin -type f -exec mv {} {}-qt4 \;
-endef
diff --git a/doc/README_osx.md b/doc/README_osx.md
index 6a5c672277..2a4460478c 100644
--- a/doc/README_osx.md
+++ b/doc/README_osx.md
@@ -36,11 +36,26 @@ Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.1
```
Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file.
-To create a tarball suitable for Gitian input, mount the dmg in OS X, then create it with:
+To create a tarball suitable for Gitian input, there are two options:
+
+Using Mac OS X, you can mount the dmg, and then create it with:
```
+ $ hdiutil attach Xcode_7.3.1.dmg
$ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk
```
+Alternatively, you can use 7zip and SleuthKit to extract the files one by one.
+The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure
+the dmg file is in the current directory, and then run the script. You may wish
+to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when
+you've confirmed the extraction succeeded.
+
+```bash
+apt-get install p7zip-full sleuthkit
+contrib/macdeploy/extract-osx-sdk.sh
+rm -rf 5.hfs MacOSX10.11.sdk
+```
+
The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries
which are created using these tools. The build process has been designed to
avoid including the SDK's files in Gitian's outputs. All interim tarballs are
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index bf669235e3..7fbb174030 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -3,6 +3,8 @@ Unauthenticated REST Interface
The REST API can be enabled with the `-rest` option.
+The interface runs on the same port as the JSON-RPC interface, by default port 8332 for mainnet and port 18332 for testnet.
+
Supported API
-------------
diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md
index d923301467..55283d6dce 100644
--- a/doc/build-openbsd.md
+++ b/doc/build-openbsd.md
@@ -1,6 +1,6 @@
OpenBSD build guide
======================
-(updated for OpenBSD 5.7)
+(updated for OpenBSD 5.9)
This guide describes how to build bitcoind and command-line utilities on OpenBSD.
@@ -15,11 +15,10 @@ Run the following as root to install the base dependencies for building:
pkg_add gmake libtool libevent
pkg_add autoconf # (select highest version, e.g. 2.69)
pkg_add automake # (select highest version, e.g. 1.15)
-pkg_add python # (select version 2.7.x, not 3.x)
-ln -sf /usr/local/bin/python2.7 /usr/local/bin/python2
+pkg_add python # (select highest version, e.g. 3.5)
```
-The default C++ compiler that comes with OpenBSD 5.7 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core. It is possible to patch it up to compile, but with the planned transition to C++11 this is a losing battle. So here we will be installing a newer compiler.
+The default C++ compiler that comes with OpenBSD 5.9 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core, primarily as it has no C++11 support, but even before there were issues. So here we will be installing a newer compiler.
GCC
-------
@@ -27,7 +26,7 @@ GCC
You can install a newer version of gcc with:
```bash
-pkg_add g++ # (select newest 4.x version, e.g. 4.9.2)
+pkg_add g++ # (select newest 4.x version, e.g. 4.9.3)
```
This compiler will not overwrite the system compiler, it will be installed as `egcc` and `eg++` in `/usr/local/bin`.
@@ -49,18 +48,15 @@ BOOST_PREFIX="${BITCOIN_ROOT}/boost"
mkdir -p $BOOST_PREFIX
# Fetch the source and verify that it is not tampered with
-wget http://heanet.dl.sourceforge.net/project/boost/boost/1.59.0/boost_1_59_0.tar.bz2
-echo '727a932322d94287b62abb1bd2d41723eec4356a7728909e38adb65ca25241ca boost_1_59_0.tar.bz2' | sha256 -c
-# MUST output: (SHA256) boost_1_59_0.tar.bz2: OK
-tar -xjf boost_1_59_0.tar.bz2
+curl -o boost_1_61_0.tar.bz2 http://heanet.dl.sourceforge.net/project/boost/boost/1.61.0/boost_1_61_0.tar.bz2
+echo 'a547bd06c2fd9a71ba1d169d9cf0339da7ebf4753849a8f7d6fdb8feee99b640 boost_1_61_0.tar.bz2' | sha256 -c
+# MUST output: (SHA256) boost_1_61_0.tar.bz2: OK
+tar -xjf boost_1_61_0.tar.bz2
-# Boost 1.59 needs two small patches for OpenBSD
-cd boost_1_59_0
+# Boost 1.61 needs one small patch for OpenBSD
+cd boost_1_61_0
# Also here: https://gist.githubusercontent.com/laanwj/bf359281dc319b8ff2e1/raw/92250de8404b97bb99d72ab898f4a8cb35ae1ea3/patch-boost_test_impl_execution_monitor_ipp.patch
patch -p0 < /usr/ports/devel/boost/patches/patch-boost_test_impl_execution_monitor_ipp
-# https://github.com/boostorg/filesystem/commit/90517e459681790a091566dce27ca3acabf9a70c
-sed 's/__OPEN_BSD__/__OpenBSD__/g' < libs/filesystem/src/path.cpp > libs/filesystem/src/path.cpp.tmp
-mv libs/filesystem/src/path.cpp.tmp libs/filesystem/src/path.cpp
# Build w/ minimum configuration necessary for bitcoin
echo 'using gcc : : eg++ : <cxxflags>"-fvisibility=hidden -fPIC" <linkflags>"" <archiver>"ar" <striper>"strip" <ranlib>"ranlib" <rc>"" : ;' > user-config.jam
@@ -84,7 +80,7 @@ BDB_PREFIX="${BITCOIN_ROOT}/db4"
mkdir -p $BDB_PREFIX
# Fetch the source and verify that it is not tampered with
-wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
+curl -o db-4.8.30.NC.tar.gz 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
echo '12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz' | sha256 -c
# MUST output: (SHA256) db-4.8.30.NC.tar.gz: OK
tar -xzf db-4.8.30.NC.tar.gz
@@ -93,9 +89,25 @@ tar -xzf db-4.8.30.NC.tar.gz
cd db-4.8.30.NC/build_unix/
# Note: Do a static build so that it can be embedded into the executable, instead of having to find a .so at runtime
../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX CC=egcc CXX=eg++ CPP=ecpp
-make install
+make install # do NOT use -jX, this is broken
```
+### Resource limits
+
+The standard ulimit restrictions in OpenBSD are very strict:
+
+ data(kbytes) 1572864
+
+This is, unfortunately, no longer enough to compile some `.cpp` files in the project,
+at least with gcc 4.9.3 (see issue https://github.com/bitcoin/bitcoin/issues/6658).
+If your user is in the `staff` group the limit can be raised with:
+
+ ulimit -d 3000000
+
+The change will only affect the current shell and processes spawned by it. To
+make the change system-wide, change `datasize-cur` and `datasize-max` in
+`/etc/login.conf`, and reboot.
+
### Building Bitcoin Core
**Important**: use `gmake`, not `make`. The non-GNU `make` will exit with a horrible error.
@@ -123,7 +135,7 @@ To configure without wallet:
Build and run the tests:
```bash
-gmake
+gmake # can use -jX here for parallelism
gmake check
```
diff --git a/doc/build-unix.md b/doc/build-unix.md
index bd89978cc2..62e3e793e9 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -293,9 +293,10 @@ These steps can be performed on, for example, an Ubuntu VM. The depends system
will also work on other Linux distributions, however the commands for
installing the toolchain will be different.
-First install the toolchain:
+Make sure you install the build requirements mentioned above.
+Then, install the toolchain and curl:
- sudo apt-get install g++-arm-linux-gnueabihf
+ sudo apt-get install g++-arm-linux-gnueabihf curl
To build executables for ARM:
diff --git a/doc/build-windows.md b/doc/build-windows.md
index 2b9233d1e1..129774491b 100644
--- a/doc/build-windows.md
+++ b/doc/build-windows.md
@@ -16,9 +16,11 @@ These steps can be performed on, for example, an Ubuntu VM. The depends system
will also work on other Linux distributions, however the commands for
installing the toolchain will be different.
-First install the toolchains:
+Make sure you install the build requirements mentioned in
+[build-unix.md](/doc/build-unix.md).
+Then, install the toolchains and curl:
- sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev g++-mingw-w64-x86-64 mingw-w64-x86-64-dev
+ sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev g++-mingw-w64-x86-64 mingw-w64-x86-64-dev curl
To build executables for Windows 32-bit:
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 95c46b05fe..70c0690ba3 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -14,6 +14,7 @@ gradually.
- No indentation for public/protected/private or for namespaces.
- No extra spaces inside parenthesis; don't do ( this )
- No space after function names; one space after if, for and while.
+ - `++i` is preferred over `i++`.
Block style example:
```c++
@@ -24,7 +25,7 @@ class Class
bool Function(char* psz, int n)
{
// Comment summarising what this section of code does
- for (int i = 0; i < n; i++) {
+ for (int i = 0; i < n; ++i) {
// When something fails, return early
if (!Something())
return false;
@@ -231,9 +232,9 @@ General Bitcoin Core
- *Rationale*: Makes sure that they pass thorough testing, and that the tester will keep passing
on the master branch. Otherwise all new pull requests will start failing the tests, resulting in
confusion and mayhem
-
+
- *Explanation*: If the test suite is to be updated for a change, this has to
- be done first
+ be done first
Wallet
-------
diff --git a/doc/release-notes.md b/doc/release-notes.md
index b99192ae97..58994a6839 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -41,6 +41,14 @@ report issues about Windows XP to the issue tracker.
Notable changes
===============
+Low-level RPC changes
+----------------------
+
+- `importprunedfunds` only accepts two required arguments. Some versions accept
+ an optional third arg, which was always ignored. Make sure to never pass more
+ than two arguments.
+
+
0.14.0 Change log
=================
@@ -51,6 +59,12 @@ git merge commit are mentioned.
### RPC and REST
+UTXO set query (`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n>/.../<txid>-<n>.<bin|hex|json>`) responses
+were changed to return status code HTTP_BAD_REQUEST (400) instead of HTTP_INTERNAL_SERVER_ERROR (500) when requests
+contain invalid parameters.
+
+The first boolean argument to `getaddednodeinfo` has been removed. This is an incompatible change.
+
### Configuration and command-line options
### Block and transaction handling
diff --git a/doc/release-notes/release-notes-0.12.1.md b/doc/release-notes/release-notes-0.12.1.md
new file mode 100644
index 0000000000..610cd481de
--- /dev/null
+++ b/doc/release-notes/release-notes-0.12.1.md
@@ -0,0 +1,198 @@
+Bitcoin Core version 0.12.1 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.12.1/>
+
+This is a new minor version release, including the BIP9, BIP68 and BIP112
+softfork, various bugfixes and updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+Upgrading and downgrading
+=========================
+
+How to Upgrade
+--------------
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes for older versions), then run the
+installer (on Windows) or just copy over /Applications/Bitcoin-Qt (on Mac) or
+bitcoind/bitcoin-qt (on Linux).
+
+Downgrade warning
+-----------------
+
+### Downgrade to a version < 0.12.0
+
+Because release 0.12.0 and later will obfuscate the chainstate on every
+fresh sync or reindex, the chainstate is not backwards-compatible with
+pre-0.12 versions of Bitcoin Core or other software.
+
+If you want to downgrade after you have done a reindex with 0.12.0 or later,
+you will need to reindex when you first start Bitcoin Core version 0.11 or
+earlier.
+
+Notable changes
+===============
+
+First version bits BIP9 softfork deployment
+-------------------------------------------
+
+This release includes a soft fork deployment to enforce [BIP68][],
+[BIP112][] and [BIP113][] using the [BIP9][] deployment mechanism.
+
+The deployment sets the block version number to 0x20000001 between
+midnight 1st May 2016 and midnight 1st May 2017 to signal readiness for
+deployment. The version number consists of 0x20000000 to indicate version
+bits together with setting bit 0 to indicate support for this combined
+deployment, shown as "csv" in the `getblockchaininfo` RPC call.
+
+For more information about the soft forking change, please see
+<https://github.com/bitcoin/bitcoin/pull/7648>
+
+This specific backport pull-request can be viewed at
+<https://github.com/bitcoin/bitcoin/pull/7543>
+
+[BIP9]: https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki
+[BIP68]: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki
+[BIP112]: https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki
+[BIP113]: https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki
+
+BIP68 soft fork to enforce sequence locks for relative locktime
+---------------------------------------------------------------
+
+[BIP68][] introduces relative lock-time consensus-enforced semantics of
+the sequence number field to enable a signed transaction input to remain
+invalid for a defined period of time after confirmation of its corresponding
+outpoint.
+
+For more information about the implementation, see
+<https://github.com/bitcoin/bitcoin/pull/7184>
+
+BIP112 soft fork to enforce OP_CHECKSEQUENCEVERIFY
+--------------------------------------------------
+
+[BIP112][] redefines the existing OP_NOP3 as OP_CHECKSEQUENCEVERIFY (CSV)
+for a new opcode in the Bitcoin scripting system that in combination with
+[BIP68][] allows execution pathways of a script to be restricted based
+on the age of the output being spent.
+
+For more information about the implementation, see
+<https://github.com/bitcoin/bitcoin/pull/7524>
+
+BIP113 locktime enforcement soft fork
+-------------------------------------
+
+Bitcoin Core 0.11.2 previously introduced mempool-only locktime
+enforcement using GetMedianTimePast(). This release seeks to
+consensus enforce the rule.
+
+Bitcoin transactions currently may specify a locktime indicating when
+they may be added to a valid block. Current consensus rules require
+that blocks have a block header time greater than the locktime specified
+in any transaction in that block.
+
+Miners get to choose what time they use for their header time, with the
+consensus rule being that no node will accept a block whose time is more
+than two hours in the future. This creates a incentive for miners to
+set their header times to future values in order to include locktimed
+transactions which weren't supposed to be included for up to two more
+hours.
+
+The consensus rules also specify that valid blocks may have a header
+time greater than that of the median of the 11 previous blocks. This
+GetMedianTimePast() time has a key feature we generally associate with
+time: it can't go backwards.
+
+[BIP113][] specifies a soft fork enforced in this release that
+weakens this perverse incentive for individual miners to use a future
+time by requiring that valid blocks have a computed GetMedianTimePast()
+greater than the locktime specified in any transaction in that block.
+
+Mempool inclusion rules currently require transactions to be valid for
+immediate inclusion in a block in order to be accepted into the mempool.
+This release begins applying the BIP113 rule to received transactions,
+so transaction whose time is greater than the GetMedianTimePast() will
+no longer be accepted into the mempool.
+
+**Implication for miners:** you will begin rejecting transactions that
+would not be valid under BIP113, which will prevent you from producing
+invalid blocks when BIP113 is enforced on the network. Any
+transactions which are valid under the current rules but not yet valid
+under the BIP113 rules will either be mined by other miners or delayed
+until they are valid under BIP113. Note, however, that time-based
+locktime transactions are more or less unseen on the network currently.
+
+**Implication for users:** GetMedianTimePast() always trails behind the
+current time, so a transaction locktime set to the present time will be
+rejected by nodes running this release until the median time moves
+forward. To compensate, subtract one hour (3,600 seconds) from your
+locktimes to allow those transactions to be included in mempools at
+approximately the expected time.
+
+For more information about the implementation, see
+<https://github.com/bitcoin/bitcoin/pull/6566>
+
+Miscellaneous
+-------------
+
+The p2p alert system is off by default. To turn on, use `-alert` with
+startup configuration.
+
+0.12.1 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, refactors and string updates. For convenience in locating
+the code changes and accompanying discussion, both the pull request and
+git merge commit are mentioned.
+
+### RPC and other APIs
+- #7739 `7ffc2bd` Add abandoned status to listtransactions (jonasschnelli)
+
+### Block and transaction handling
+- #7543 `834aaef` Backport BIP9, BIP68 and BIP112 with softfork (btcdrak)
+
+### P2P protocol and network code
+- #7804 `90f1d24` Track block download times per individual block (sipa)
+- #7832 `4c3a00d` Reduce block timeout to 10 minutes (laanwj)
+
+### Validation
+- #7821 `4226aac` init: allow shutdown during 'Activating best chain...' (laanwj)
+- #7835 `46898e7` Version 2 transactions remain non-standard until CSV activates (sdaftuar)
+
+### Build system
+- #7487 `00d57b4` Workaround Travis-side CI issues (luke-jr)
+- #7606 `a10da9a` No need to set -L and --location for curl (MarcoFalke)
+- #7614 `ca8f160` Add curl to packages (now needed for depends) (luke-jr)
+- #7776 `a784675` Remove unnecessary executables from gitian release (laanwj)
+
+### Wallet
+- #7715 `19866c1` Fix calculation of balances and available coins. (morcos)
+
+### Miscellaneous
+- #7617 `f04f4fd` Fix markdown syntax and line terminate LogPrint (MarcoFalke)
+- #7747 `4d035bc` added depends cross compile info (accraze)
+- #7741 `a0cea89` Mark p2p alert system as deprecated (btcdrak)
+- #7780 `c5f94f6` Disable bad-chain alert (btcdrak)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- accraze
+- Alex Morcos
+- BtcDrak
+- Jonas Schnelli
+- Luke Dashjr
+- MarcoFalke
+- Mark Friedenbach
+- NicolasDorier
+- Pieter Wuille
+- Suhas Daftuar
+- Wladimir J. van der Laan
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
+
diff --git a/doc/release-notes/release-notes-0.13.0.md b/doc/release-notes/release-notes-0.13.0.md
new file mode 100644
index 0000000000..5dd3f5a651
--- /dev/null
+++ b/doc/release-notes/release-notes-0.13.0.md
@@ -0,0 +1,863 @@
+Bitcoin Core version 0.13.0 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.13.0/>
+
+This is a new major version release, including new features, various bugfixes
+and performance improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+Compatibility
+==============
+
+Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support),
+an OS initially released in 2001. This means that not even critical security
+updates will be released anymore. Without security updates, using a bitcoin
+wallet on a XP machine is irresponsible at least.
+
+In addition to that, with 0.12.x there have been varied reports of Bitcoin Core
+randomly crashing on Windows XP. It is [not clear](https://github.com/bitcoin/bitcoin/issues/7681#issuecomment-217439891)
+what the source of these crashes is, but it is likely that upstream
+libraries such as Qt are no longer being tested on XP.
+
+We do not have time nor resources to provide support for an OS that is
+end-of-life. From 0.13.0 on, Windows XP is no longer supported. Users are
+suggested to upgrade to a newer verion of Windows, or install an alternative OS
+that is supported.
+
+No attempt is made to prevent installing or running the software on Windows XP,
+you can still do so at your own risk, but do not expect it to work: do not
+report issues about Windows XP to the issue tracker.
+
+Notable changes
+===============
+
+Database cache memory increased
+--------------------------------
+
+As a result of growth of the UTXO set, performance with the prior default
+database cache of 100 MiB has suffered.
+For this reason the default was changed to 300 MiB in this release.
+
+For nodes on low-memory systems, the database cache can be changed back to
+100 MiB (or to another value) by either:
+
+- Adding `dbcache=100` in bitcoin.conf
+- Changing it in the GUI under `Options → Size of database cache`
+
+Note that the database cache setting has the most performance impact
+during initial sync of a node, and when catching up after downtime.
+
+
+bitcoin-cli: arguments privacy
+------------------------------
+
+The RPC command line client gained a new argument, `-stdin`
+to read extra arguments from standard input, one per line until EOF/Ctrl-D.
+For example:
+
+ $ src/bitcoin-cli -stdin walletpassphrase
+ mysecretcode
+ 120
+ ..... press Ctrl-D here to end input
+ $
+
+It is recommended to use this for sensitive information such as wallet
+passphrases, as command-line arguments can usually be read from the process
+table by any user on the system.
+
+
+C++11 and Python 3
+------------------
+
+Various code modernizations have been done. The Bitcoin Core code base has
+started using C++11. This means that a C++11-capable compiler is now needed for
+building. Effectively this means GCC 4.7 or higher, or Clang 3.3 or higher.
+
+When cross-compiling for a target that doesn't have C++11 libraries, configure with
+`./configure --enable-glibc-back-compat ... LDFLAGS=-static-libstdc++`.
+
+For running the functional tests in `qa/rpc-tests`, Python3.4 or higher is now
+required.
+
+
+Linux ARM builds
+----------------
+
+Due to popular request, Linux ARM builds have been added to the uploaded
+executables.
+
+The following extra files can be found in the download directory or torrent:
+
+- `bitcoin-${VERSION}-arm-linux-gnueabihf.tar.gz`: Linux binaries for the most
+ common 32-bit ARM architecture.
+- `bitcoin-${VERSION}-aarch64-linux-gnu.tar.gz`: Linux binaries for the most
+ common 64-bit ARM architecture.
+
+ARM builds are still experimental. If you have problems on a certain device or
+Linux distribution combination please report them on the bug tracker, it may be
+possible to resolve them.
+
+Note that Android is not considered ARM Linux in this context. The executables
+are not expected to work out of the box on Android.
+
+
+Compact Block support (BIP 152)
+-------------------------------
+
+Support for block relay using the Compact Blocks protocol has been implemented
+in PR 8068.
+
+The primary goal is reducing the bandwidth spikes at relay time, though in many
+cases it also reduces propagation delay. It is automatically enabled between
+compatible peers.
+[BIP 152](https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki)
+
+As a side-effect, ordinary non-mining nodes will download and upload blocks
+faster if those blocks were produced by miners using similar transaction
+filtering policies. This means that a miner who produces a block with many
+transactions discouraged by your node will be relayed slower than one with
+only transactions already in your memory pool. The overall effect of such
+relay differences on the network may result in blocks which include widely-
+discouraged transactions losing a stale block race, and therefore miners may
+wish to configure their node to take common relay policies into consideration.
+
+
+Hierarchical Deterministic Key Generation
+-----------------------------------------
+Newly created wallets will use hierarchical deterministic key generation
+according to BIP32 (keypath m/0'/0'/k').
+Existing wallets will still use traditional key generation.
+
+Backups of HD wallets, regardless of when they have been created, can
+therefore be used to re-generate all possible private keys, even the
+ones which haven't already been generated during the time of the backup.
+**Attention:** Encrypting the wallet will create a new seed which requires
+a new backup!
+
+Wallet dumps (created using the `dumpwallet` RPC) will contain the deterministic
+seed. This is expected to allow future versions to import the seed and all
+associated funds, but this is not yet implemented.
+
+HD key generation for new wallets can be disabled by `-usehd=0`. Keep in
+mind that this flag only has affect on newly created wallets.
+You can't disable HD key generation once you have created a HD wallet.
+
+There is no distinction between internal (change) and external keys.
+
+HD wallets are incompatible with older versions of Bitcoin Core.
+
+[Pull request](https://github.com/bitcoin/bitcoin/pull/8035/files), [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
+
+
+Segregated Witness
+------------------
+
+The code preparations for Segregated Witness ("segwit"), as described in [BIP
+141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki), [BIP
+143](https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki), [BIP
+144](https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki), and [BIP
+145](https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki) are
+finished and included in this release. However, BIP 141 does not yet specify
+activation parameters on mainnet, and so this release does not support segwit
+use on mainnet. Testnet use is supported, and after BIP 141 is updated with
+proposed parameters, a future release of Bitcoin Core is expected that
+implements those parameters for mainnet.
+
+Furthermore, because segwit activation is not yet specified for mainnet,
+version 0.13.0 will behave similarly as other pre-segwit releases even after a
+future activation of BIP 141 on the network. Upgrading from 0.13.0 will be
+required in order to utilize segwit-related features on mainnet (such as signal
+BIP 141 activation, mine segwit blocks, fully validate segwit blocks, relay
+segwit blocks to other segwit nodes, and use segwit transactions in the
+wallet, etc).
+
+
+Mining transaction selection ("Child Pays For Parent")
+------------------------------------------------------
+
+The mining transaction selection algorithm has been replaced with an algorithm
+that selects transactions based on their feerate inclusive of unconfirmed
+ancestor transactions. This means that a low-fee transaction can become more
+likely to be selected if a high-fee transaction that spends its outputs is
+relayed.
+
+With this change, the `-blockminsize` command line option has been removed.
+
+The command line option `-blockmaxsize` remains an option to specify the
+maximum number of serialized bytes in a generated block. In addition, the new
+command line option `-blockmaxweight` has been added, which specifies the
+maximum "block weight" of a generated block, as defined by [BIP 141 (Segregated
+Witness)] (https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki).
+
+In preparation for Segregated Witness, the mining algorithm has been modified
+to optimize transaction selection for a given block weight, rather than a given
+number of serialized bytes in a block. In this release, transaction selection
+is unaffected by this distinction (as BIP 141 activation is not supported on
+mainnet in this release, see above), but in future releases and after BIP 141
+activation, these calculations would be expected to differ.
+
+For optimal runtime performance, miners using this release should specify
+`-blockmaxweight` on the command line, and not specify `-blockmaxsize`.
+Additionally (or only) specifying `-blockmaxsize`, or relying on default
+settings for both, may result in performance degradation, as the logic to
+support `-blockmaxsize` performs additional computation to ensure that
+constraint is met. (Note that for mainnet, in this release, the equivalent
+parameter for `-blockmaxweight` would be four times the desired
+`-blockmaxsize`. See [BIP 141]
+(https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki) for additional
+details.)
+
+In the future, the `-blockmaxsize` option may be removed, as block creation is
+no longer optimized for this metric. Feedback is requested on whether to
+deprecate or keep this command line option in future releases.
+
+
+Reindexing changes
+------------------
+
+In earlier versions, reindexing did validation while reading through the block
+files on disk. These two have now been split up, so that all blocks are known
+before validation starts. This was necessary to make certain optimizations that
+are available during normal synchronizations also available during reindexing.
+
+The two phases are distinct in the Bitcoin-Qt GUI. During the first one,
+"Reindexing blocks on disk" is shown. During the second (slower) one,
+"Processing blocks on disk" is shown.
+
+It is possible to only redo validation now, without rebuilding the block index,
+using the command line option `-reindex-chainstate` (in addition to
+`-reindex` which does both). This new option is useful when the blocks on disk
+are assumed to be fine, but the chainstate is still corrupted. It is also
+useful for benchmarks.
+
+
+Removal of internal miner
+--------------------------
+
+As CPU mining has been useless for a long time, the internal miner has been
+removed in this release, and replaced with a simpler implementation for the
+test framework.
+
+The overall result of this is that `setgenerate` RPC call has been removed, as
+well as the `-gen` and `-genproclimit` command-line options.
+
+For testing, the `generate` call can still be used to mine a block, and a new
+RPC call `generatetoaddress` has been added to mine to a specific address. This
+works with wallet disabled.
+
+
+New bytespersigop implementation
+--------------------------------
+
+The former implementation of the bytespersigop filter accidentally broke bare
+multisig (which is meant to be controlled by the `permitbaremultisig` option),
+since the consensus protocol always counts these older transaction forms as 20
+sigops for backwards compatibility. Simply fixing this bug by counting more
+accurately would have reintroduced a vulnerability. It has therefore been
+replaced with a new implementation that rather than filter such transactions,
+instead treats them (for fee purposes only) as if they were in fact the size
+of a transaction actually using all 20 sigops.
+
+
+Low-level P2P changes
+----------------------
+
+- The optional new p2p message "feefilter" is implemented and the protocol
+ version is bumped to 70013. Upon receiving a feefilter message from a peer,
+ a node will not send invs for any transactions which do not meet the filter
+ feerate. [BIP 133](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki)
+
+- The P2P alert system has been removed in PR #7692 and the `alert` P2P message
+ is no longer supported.
+
+- The transaction relay mechanism used to relay one quarter of all transactions
+ instantly, while queueing up the rest and sending them out in batch. As
+ this resulted in chains of dependent transactions being reordered, it
+ systematically hurt transaction relay. The relay code was redesigned in PRs
+ \#7840 and #8082, and now always batches transactions announcements while also
+ sorting them according to dependency order. This significantly reduces orphan
+ transactions. To compensate for the removal of instant relay, the frequency of
+ batch sending was doubled for outgoing peers.
+
+- Since PR #7840 the BIP35 `mempool` command is also subject to batch processing.
+ Also the `mempool` message is no longer handled for non-whitelisted peers when
+ `NODE_BLOOM` is disabled through `-peerbloomfilters=0`.
+
+- The maximum size of orphan transactions that are kept in memory until their
+ ancestors arrive has been raised in PR #8179 from 5000 to 99999 bytes. They
+ are now also removed from memory when they are included in a block, conflict
+ with a block, and time out after 20 minutes.
+
+- We respond at most once to a getaddr request during the lifetime of a
+ connection since PR #7856.
+
+- Connections to peers who have recently been the first one to give us a valid
+ new block or transaction are protected from disconnections since PR #8084.
+
+
+Low-level RPC changes
+----------------------
+
+- RPC calls have been added to output detailed statistics for individual mempool
+ entries, as well as to calculate the in-mempool ancestors or descendants of a
+ transaction: see `getmempoolentry`, `getmempoolancestors`, `getmempooldescendants`.
+
+- `gettxoutsetinfo` UTXO hash (`hash_serialized`) has changed. There was a divergence between
+ 32-bit and 64-bit platforms, and the txids were missing in the hashed data. This has been
+ fixed, but this means that the output will be different than from previous versions.
+
+- Full UTF-8 support in the RPC API. Non-ASCII characters in, for example,
+ wallet labels have always been malformed because they weren't taken into account
+ properly in JSON RPC processing. This is no longer the case. This also affects
+ the GUI debug console.
+
+- Asm script outputs replacements for OP_NOP2 and OP_NOP3
+
+ - OP_NOP2 has been renamed to OP_CHECKLOCKTIMEVERIFY by [BIP
+65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki)
+
+ - OP_NOP3 has been renamed to OP_CHECKSEQUENCEVERIFY by [BIP
+112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki)
+
+ - The following outputs are affected by this change:
+
+ - RPC `getrawtransaction` (in verbose mode)
+ - RPC `decoderawtransaction`
+ - RPC `decodescript`
+ - REST `/rest/tx/` (JSON format)
+ - REST `/rest/block/` (JSON format when including extended tx details)
+ - `bitcoin-tx -json`
+
+- The sorting of the output of the `getrawmempool` output has changed.
+
+- New RPC commands: `generatetoaddress`, `importprunedfunds`, `removeprunedfunds`, `signmessagewithprivkey`,
+ `getmempoolancestors`, `getmempooldescendants`, `getmempoolentry`,
+ `createwitnessaddress`, `addwitnessaddress`.
+
+- Removed RPC commands: `setgenerate`, `getgenerate`.
+
+- New options were added to `fundrawtransaction`: `includeWatching`, `changeAddress`, `changePosition` and `feeRate`.
+
+
+Low-level ZMQ changes
+----------------------
+
+- Each ZMQ notification now contains an up-counting sequence number that allows
+ listeners to detect lost notifications.
+ The sequence number is always the last element in a multi-part ZMQ notification and
+ therefore backward compatible. Each message type has its own counter.
+ PR [#7762](https://github.com/bitcoin/bitcoin/pull/7762).
+
+
+0.13.0 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, refactors and string updates. For convenience in locating
+the code changes and accompanying discussion, both the pull request and
+git merge commit are mentioned.
+
+### RPC and other APIs
+
+- #7156 `9ee02cf` Remove cs_main lock from `createrawtransaction` (laanwj)
+- #7326 `2cd004b` Fix typo, wrong information in gettxout help text (paveljanik)
+- #7222 `82429d0` Indicate which transactions are signaling opt-in RBF (sdaftuar)
+- #7480 `b49a623` Changed getnetworkhps value to double to avoid overflow (instagibbs)
+- #7550 `8b958ab` Input-from-stdin mode for bitcoin-cli (laanwj)
+- #7670 `c9a1265` Use cached block hash in blockToJSON() (rat4)
+- #7726 `9af69fa` Correct importaddress help reference to importpubkey (CypherGrue)
+- #7766 `16555b6` Register calls where they are defined (laanwj)
+- #7797 `e662a76` Fix generatetoaddress failing to parse address (mruddy)
+- #7774 `916b15a` Add versionHex in getblock and getblockheader JSON results (mruddy)
+- #7863 `72c54e3` Getblockchaininfo: make bip9_softforks an object, not an array (rustyrussell)
+- #7842 `d97101e` Do not print minping time in getpeerinfo when no ping received yet (paveljanik)
+- #7518 `be14ca5` Add multiple options to fundrawtransaction (promag)
+- #7756 `9e47fce` Add cursor to iterate over utxo set, use this in `gettxoutsetinfo` (laanwj)
+- #7848 `88616d2` Divergence between 32- and 64-bit when hashing >4GB affects `gettxoutsetinfo` (laanwj)
+- #7827 `4205ad7` Speed up `getchaintips` (mrbandrews)
+- #7762 `a1eb344` Append a message sequence number to every ZMQ notification (jonasschnelli)
+- #7688 `46880ed` List solvability in listunspent output and improve help (sipa)
+- #7926 `5725807` Push back `getaddednodeinfo` dead value (instagibbs)
+- #7953 `0630353` Create `signmessagewithprivkey` rpc (achow101)
+- #8049 `c028c7b` Expose information on whether transaction relay is enabled in `getnetworkinfo` (laanwj)
+- #7967 `8c1e49b` Add feerate option to `fundrawtransaction` (jonasschnelli)
+- #8118 `9b6a48c` Reduce unnecessary hashing in `signrawtransaction` (jonasnick)
+- #7957 `79004d4` Add support for transaction sequence number (jonasschnelli)
+- #8153 `75ec320` `fundrawtransaction` feeRate: Use BTC/kB (MarcoFalke)
+- #7292 `7ce9ac5` Expose ancestor/descendant information over RPC (sdaftuar)
+- #8171 `62fcf27` Fix createrawtx sequence number unsigned int parsing (jonasschnelli)
+- #7892 `9c3d0fa` Add full UTF-8 support to RPC (laanwj)
+- #8317 `304eff3` Don't use floating point in rpcwallet (MarcoFalke)
+- #8258 `5a06ebb` Hide softfork in `getblockchaininfo` if timeout is 0 (jl2012)
+- #8244 `1922e5a` Remove unnecessary LOCK(cs_main) in getrawmempool (dcousens)
+
+### Block and transaction handling
+
+- #7056 `6a07208` Save last db read (morcos)
+- #6842 `0192806` Limitfreerelay edge case bugfix (ptschip)
+- #7084 `11d74f6` Replace maxFeeRate of 10000*minRelayTxFee with maxTxFee in mempool (MarcoFalke)
+- #7539 `9f33dba` Add tags to mempool's mapTx indices (sdaftuar)
+- #7592 `26a2a72` Re-remove ERROR logging for mempool rejects (laanwj)
+- #7187 `14d6324` Keep reorgs fast for SequenceLocks checks (morcos)
+- #7594 `01f4267` Mempool: Add tracking of ancestor packages (sdaftuar)
+- #7904 `fc9e334` Txdb: Fix assert crash in new UTXO set cursor (laanwj)
+- #7927 `f9c2ac7` Minor changes to dbwrapper to simplify support for other databases (laanwj)
+- #7933 `e26b620` Fix OOM when deserializing UTXO entries with invalid length (sipa)
+- #8020 `5e374f7` Use SipHash-2-4 for various non-cryptographic hashes (sipa)
+- #8076 `d720980` VerifyDB: don't check blocks that have been pruned (sdaftuar)
+- #8080 `862fd24` Do not use mempool for GETDATA for tx accepted after the last mempool req (gmaxwell)
+- #7997 `a82f033` Replace mapNextTx with slimmer setSpends (kazcw)
+- #8220 `1f86d64` Stop trimming when mapTx is empty (sipa)
+- #8273 `396f9d6` Bump `-dbcache` default to 300MiB (laanwj)
+- #7225 `eb33179` Eliminate unnecessary call to CheckBlock (sdaftuar)
+- #7907 `006cdf6` Optimize and Cleanup CScript::FindAndDelete (pstratem)
+- #7917 `239d419` Optimize reindex (sipa)
+- #7763 `3081fb9` Put hex-encoded version in UpdateTip (sipa)
+- #8149 `d612837` Testnet-only segregated witness (sipa)
+- #8305 `3730393` Improve handling of unconnecting headers (sdaftuar)
+- #8363 `fca1a41` Rename "block cost" to "block weight" (sdaftuar)
+- #8381 `f84ee3d` Make witness v0 outputs non-standard (jl2012)
+- #8364 `3f65ba2` Treat high-sigop transactions as larger rather than rejecting them (sipa)
+
+### P2P protocol and network code
+
+- #6589 `dc0305d` Log bytes recv/sent per command (jonasschnelli)
+- #7164 `3b43cad` Do not download transactions during initial blockchain sync (ptschip)
+- #7458 `898fedf` peers.dat, banlist.dat recreated when missing (kirkalx)
+- #7637 `3da5d1b` Fix memleak in TorController (laanwj, jonasschnelli)
+- #7553 `9f14e5a` Remove vfReachable and modify IsReachable to only use vfLimited (pstratem)
+- #7708 `9426632` De-neuter NODE_BLOOM (pstratem)
+- #7692 `29b2be6` Remove P2P alert system (btcdrak)
+- #7542 `c946a15` Implement "feefilter" P2P message (morcos)
+- #7573 `352fd57` Add `-maxtimeadjustment` command line option (mruddy)
+- #7570 `232592a` Add IPv6 Link-Local Address Support (mruddy)
+- #7874 `e6a4d48` Improve AlreadyHave (morcos)
+- #7856 `64e71b3` Only send one GetAddr response per connection (gmaxwell)
+- #7868 `7daa3ad` Split DNS resolving functionality out of net structures (theuni)
+- #7919 `7617682` Fix headers announcements edge case (sdaftuar)
+- #7514 `d9594bf` Fix IsInitialBlockDownload for testnet (jmacwhyte)
+- #7959 `03cf6e8` fix race that could fail to persist a ban (kazcw)
+- #7840 `3b9a0bf` Several performance and privacy improvements to inv/mempool handling (sipa)
+- #8011 `65aecda` Don't run ThreadMessageHandler at lowered priority (kazcw)
+- #7696 `5c3f8dd` Fix de-serialization bug where AddrMan is left corrupted (EthanHeilman)
+- #7932 `ed749bd` CAddrMan::Deserialize handle corrupt serializations better (pstratem)
+- #7906 `83121cc` Prerequisites for p2p encapsulation changes (theuni)
+- #8033 `18436d8` Fix Socks5() connect failures to be less noisy and less unnecessarily scary (wtogami)
+- #8082 `01d8359` Defer inserting into maprelay until just before relaying (gmaxwell)
+- #7960 `6a22373` Only use AddInventoryKnown for transactions (sdaftuar)
+- #8078 `2156fa2` Disable the mempool P2P command when bloom filters disabled (petertodd)
+- #8065 `67c91f8` Addrman offline attempts (gmaxwell)
+- #7703 `761cddb` Tor: Change auth order to only use password auth if -torpassword (laanwj)
+- #8083 `cd0c513` Add support for dnsseeds with option to filter by servicebits (jonasschnelli)
+- #8173 `4286f43` Use SipHash for node eviction (sipa)
+- #8154 `1445835` Drop vAddrToSend after sending big addr message (kazcw)
+- #7749 `be9711e` Enforce expected outbound services (sipa)
+- #8208 `0a64777` Do not set extra flags for unfiltered DNS seed results (sipa)
+- #8084 `e4bb4a8` Add recently accepted blocks and txn to AttemptToEvictConnection (gmaxwell)
+- #8113 `3f89a53` Rework addnode behaviour (sipa)
+- #8179 `94ab58b` Evict orphans which are included or precluded by accepted blocks (gmaxwell)
+- #8068 `e9d76a1` Compact Blocks (TheBlueMatt)
+- #8204 `0833894` Update petertodd's testnet seed (petertodd)
+- #8247 `5cd35d3` Mark my dnsseed as supporting filtering (sipa)
+- #8275 `042c323` Remove bad chain alert partition check (btcdrak)
+- #8271 `1bc9c80` Do not send witnesses in cmpctblock (sipa)
+- #8312 `ca40ef6` Fix mempool DoS vulnerability from malleated transactions (sdaftuar)
+- #7180 `16ccb74` Account for `sendheaders` `verack` messages (laanwj)
+- #8102 `425278d` Bugfix: use global ::fRelayTxes instead of CNode in version send (sipa)
+- #8408 `b7e2011` Prevent fingerprinting, disk-DoS with compact blocks (sdaftuar)
+
+### Build system
+
+- #7302 `41f1a3e` C++11 build/runtime fixes (theuni)
+- #7322 `fd9356b` c++11: add scoped enum fallbacks to CPPFLAGS rather than defining them locally (theuni)
+- #7441 `a6771fc` Use Debian 8.3 in gitian build guide (fanquake)
+- #7349 `152a821` Build against system UniValue when available (luke-jr)
+- #7520 `621940e` LibreSSL doesn't define OPENSSL_VERSION, use LIBRESSL_VERSION_TEXT instead (paveljanik)
+- #7528 `9b9bfce` autogen.sh: warn about needing autoconf if autoreconf is not found (knocte)
+- #7504 `19324cf` Crystal clean make clean (paveljanik)
+- #7619 `18b3f1b` Add missing sudo entry in gitian VM setup (btcdrak)
+- #7616 `639ec58` [depends] Delete unused patches (MarcoFalke)
+- #7658 `c15eb28` Add curl to Gitian setup instructions (btcdrak)
+- #7710 `909b72b` [Depends] Bump miniupnpc and config.guess+sub (fanquake)
+- #7723 `5131005` build: python 3 compatibility (laanwj)
+- #7477 `28ad4d9` Fix quoting of copyright holders in configure.ac (domob1812)
+- #7711 `a67bc5e` [build-aux] Update Boost & check macros to latest serials (fanquake)
+- #7788 `4dc1b3a` Use relative paths instead of absolute paths in protoc calls (paveljanik)
+- #7809 `bbd210d` depends: some base fixes/changes (theuni)
+- #7603 `73fc922` Build System: Use PACKAGE_TARNAME in NSIS script (JeremyRand)
+- #7905 `187186b` test: move accounting_tests and rpc_wallet_tests to wallet/test (laanwj)
+- #7911 `351abf9` leveldb: integrate leveldb into our buildsystem (theuni)
+- #7944 `a407807` Re-instate TARGET_OS=linux in configure.ac. Removed by 351abf9e035 (randy-waterhouse)
+- #7920 `c3e3cfb` Switch Travis to Trusty (theuni)
+- #7954 `08b37c5` build: quiet annoying warnings without adding new ones (theuni)
+- #7165 `06162f1` build: Enable C++11 in build, require C++11 compiler (laanwj)
+- #7982 `559fbae` build: No need to check for leveldb atomics (theuni)
+- #8002 `f9b4582` [depends] Add -stdlib=libc++ to darwin CXX flags (fanquake)
+- #7993 `6a034ed` [depends] Bump Freetype, ccache, ZeroMQ, miniupnpc, expat (fanquake)
+- #8167 `19ea173` Ship debug tarballs/zips with debug symbols (theuni)
+- #8175 `f0299d8` Add --disable-bench to config flags for windows (laanwj)
+- #7283 `fd9881a` [gitian] Default reference_datetime to commit author date (MarcoFalke)
+- #8181 `9201ce8` Get rid of `CLIENT_DATE` (laanwj)
+- #8133 `fde0ac4` Finish up out-of-tree changes (theuni)
+- #8188 `65a9d7d` Add armhf/aarch64 gitian builds (theuni)
+- #8194 `cca1c8c` [gitian] set correct PATH for wrappers (MarcoFalke)
+- #8198 `5201614` Sync ax_pthread with upstream draft4 (fanquake)
+- #8210 `12a541e` [Qt] Bump to Qt5.6.1 (jonasschnelli)
+- #8285 `da50997` windows: Add testnet link to installer (laanwj)
+- #8304 `0cca2fe` [travis] Update SDK_URL (MarcoFalke)
+- #8310 `6ae20df` Require boost for bench (theuni)
+- #8315 `2e51590` Don't require sudo for Linux (theuni)
+- #8314 `67caef6` Fix pkg-config issues for 0.13 (theuni)
+- #8373 `1fe7f40` Fix OSX non-deterministic dmg (theuni)
+- #8358 `cfd1280` Gbuild: Set memory explicitly (default is too low) (MarcoFalke)
+
+### GUI
+
+- #7154 `00b4b8d` Add InMempool() info to transaction details (jonasschnelli)
+- #7068 `5f3c670` [RPC-Tests] add simple way to run rpc test over QT clients (jonasschnelli)
+- #7218 `a1c185b` Fix misleading translation (MarcoFalke)
+- #7214 `be9a9a3` qt5: Use the fixed font the system recommends (MarcoFalke)
+- #7256 `08ab906` Add note to coin control dialog QT5 workaround (fanquake)
+- #7255 `e289807` Replace some instances of formatWithUnit with formatHtmlWithUnit (fanquake)
+- #7317 `3b57e9c` Fix RPCTimerInterface ordering issue (jonasschnelli)
+- #7327 `c079d79` Transaction View: LastMonth calculation fixed (crowning-)
+- #7334 `e1060c5` coincontrol workaround is still needed in qt5.4 (fixed in qt5.5) (MarcoFalke)
+- #7383 `ae2db67` Rename "amount" to "requested amount" in receive coins table (jonasschnelli)
+- #7396 `cdcbc59` Add option to increase/decrease font size in the console window (jonasschnelli)
+- #7437 `9645218` Disable tab navigation for peers tables (Kefkius)
+- #7604 `354b03d` build: Remove spurious dollar sign. Fixes #7189 (dooglus)
+- #7605 `7f001bd` Remove openssl info from init/log and from Qt debug window (jonasschnelli)
+- #7628 `87d6562` Add 'copy full transaction details' option (ericshawlinux)
+- #7613 `3798e5d` Add autocomplete to bitcoin-qt's console window (GamerSg)
+- #7668 `b24266c` Fix history deletion bug after font size change (achow101)
+- #7680 `41d2dfa` Remove reflection from `about` icon (laanwj)
+- #7686 `f034bce` Remove 0-fee from send dialog (MarcoFalke)
+- #7506 `b88e0b0` Use CCoinControl selection in CWallet::FundTransaction (promag)
+- #7732 `0b98dd7` Debug window: replace "Build date" with "Datadir" (jonasschnelli)
+- #7761 `60db51d` remove trailing output-index from transaction-id (jonasschnelli)
+- #7772 `6383268` Clear the input line after activating autocomplete (paveljanik)
+- #7925 `f604bf6` Fix out-of-tree GUI builds (laanwj)
+- #7939 `574ddc6` Make it possible to show details for multiple transactions (laanwj)
+- #8012 `b33824b` Delay user confirmation of send (Tyler-Hardin)
+- #8006 `7c8558d` Add option to disable the system tray icon (Tyler-Hardin)
+- #8046 `169d379` Fix Cmd-Q / Menu Quit shutdown on OSX (jonasschnelli)
+- #8042 `6929711` Don't allow to open the debug window during splashscreen & verification state (jonasschnelli)
+- #8014 `77b49ac` Sort transactions by date (Tyler-Hardin)
+- #8073 `eb2f6f7` askpassphrasedialog: Clear pass fields on accept (rat4)
+- #8129 `ee1533e` Fix RPC console auto completer (UdjinM6)
+- #7636 `fb0ac48` Add bitcoin address label to request payment QR code (makevoid)
+- #8231 `760a6c7` Fix a bug where the SplashScreen will not be hidden during startup (jonasschnelli)
+- #8256 `af2421c` BUG: bitcoin-qt crash (fsb4000)
+- #8257 `ff03c50` Do not ask a UI question from bitcoind (sipa)
+- #8288 `91abb77` Network-specific example address (laanwj)
+- #7707 `a914968` UI support for abandoned transactions (jonasschnelli)
+- #8207 `f7a403b` Add a link to the Bitcoin-Core repository and website to the About Dialog (MarcoFalke)
+- #8281 `6a87eb0` Remove client name from debug window (laanwj)
+- #8407 `45eba4b` Add dbcache migration path (jonasschnelli)
+
+### Wallet
+
+- #7262 `fc08994` Reduce inefficiency of GetAccountAddress() (dooglus)
+- #7537 `78e81b0` Warn on unexpected EOF while salvaging wallet (laanwj)
+- #7521 `3368895` Don't resend wallet txs that aren't in our own mempool (morcos)
+- #7576 `86a1ec5` Move wallet help string creation to CWallet (jonasschnelli)
+- #7577 `5b3b5a7` Move "load wallet phase" to CWallet (jonasschnelli)
+- #7608 `0735c0c` Move hardcoded file name out of log messages (MarcoFalke)
+- #7649 `4900641` Prevent multiple calls to CWallet::AvailableCoins (promag)
+- #7646 `e5c3511` Fix lockunspent help message (promag)
+- #7558 `b35a591` Add import/removeprunedfunds rpc call (instagibbs)
+- #6215 `48c5adf` add bip32 pub key serialization (jonasschnelli)
+- #7913 `bafd075` Fix for incorrect locking in GetPubKey() (keystore.cpp) (yurizhykin)
+- #8036 `41138f9` init: Move berkeleydb version reporting to wallet (laanwj)
+- #8028 `373b50d` Fix insanity of CWalletDB::WriteTx and CWalletTx::WriteToDisk (pstratem)
+- #8061 `f6b7df3` Improve Wallet encapsulation (pstratem)
+- #7891 `950be19` Always require OS randomness when generating secret keys (sipa)
+- #7689 `b89ef13` Replace OpenSSL AES with ctaes-based version (sipa)
+- #7825 `f972b04` Prevent multiple calls to ExtractDestination (pedrobranco)
+- #8137 `243ac0c` Improve CWallet API with new AccountMove function (pstratem)
+- #8142 `52c3f34` Improve CWallet API with new GetAccountPubkey function (pstratem)
+- #8035 `b67a472` Add simplest BIP32/deterministic key generation implementation (jonasschnelli)
+- #7687 `a6ddb19` Stop treating importaddress'ed scripts as change (sipa)
+- #8298 `aef3811` wallet: Revert input selection post-pruning (laanwj)
+- #8324 `bc94b87` Keep HD seed during salvagewallet (jonasschnelli)
+- #8323 `238300b` Add HD keypath to CKeyMetadata, report metadata in validateaddress (jonasschnelli)
+- #8367 `3b38a6a` Ensure <0.13 clients can't open HD wallets (jonasschnelli)
+- #8378 `ebea651` Move SetMinVersion for FEATURE_HD to SetHDMasterKey (pstratem)
+- #8390 `73adfe3` Correct hdmasterkeyid/masterkeyid name confusion (jonasschnelli)
+- #8206 `18b8ee1` Add HD xpriv to dumpwallet (jonasschnelli)
+- #8389 `c3c82c4` Create a new HD seed after encrypting the wallet (jonasschnelli)
+
+### Tests and QA
+
+- #7320 `d3dfc6d` Test walletpassphrase timeout (MarcoFalke)
+- #7208 `47c5ed1` Make max tip age an option instead of chainparam (laanwj)
+- #7372 `21376af` Trivial: [qa] wallet: Print maintenance (MarcoFalke)
+- #7280 `668906f` [travis] Fail when documentation is outdated (MarcoFalke)
+- #7177 `93b0576` [qa] Change default block priority size to 0 (MarcoFalke)
+- #7236 `02676c5` Use createrawtx locktime parm in txn_clone (dgenr8)
+- #7212 `326ffed` Adds unittests for CAddrMan and CAddrinfo, removes source of non-determinism (EthanHeilman)
+- #7490 `d007511` tests: Remove May15 test (laanwj)
+- #7531 `18cb2d5` Add bip68-sequence.py to extended rpc tests (btcdrak)
+- #7536 `ce5fc02` test: test leading spaces for ParseHex (laanwj)
+- #7620 `1b68de3` [travis] Only run check-doc.py once (MarcoFalke)
+- #7455 `7f96671` [travis] Exit early when check-doc.py fails (MarcoFalke)
+- #7667 `56d2c4e` Move GetTempPath() to testutil (musalbas)
+- #7517 `f1ca891` test: script_error checking in script_invalid tests (laanwj)
+- #7684 `3d0dfdb` Extend tests (MarcoFalke)
+- #7697 `622fe6c` Tests: make prioritise_transaction.py more robust (sdaftuar)
+- #7709 `efde86b` Tests: fix missing import in mempool_packages (sdaftuar)
+- #7702 `29e1131` Add tests verifychain, lockunspent, getbalance, listsinceblock (MarcoFalke)
+- #7720 `3b4324b` rpc-test: Normalize assert() (MarcoFalke)
+- #7757 `26794d4` wallet: Wait for reindex to catch up (MarcoFalke)
+- #7764 `a65b36c` Don't run pruning.py twice (MarcoFalke)
+- #7773 `7c80e72` Fix comments in tests (btcdrak)
+- #7489 `e9723cb` tests: Make proxy_test work on travis servers without IPv6 (laanwj)
+- #7801 `70ac71b` Remove misleading "errorString syntax" (MarcoFalke)
+- #7803 `401c65c` maxblocksinflight: Actually enable test (MarcoFalke)
+- #7802 `3bc71e1` httpbasics: Actually test second connection (MarcoFalke)
+- #7849 `ab8586e` tests: add varints_bitpatterns test (laanwj)
+- #7846 `491171f` Clean up lockorder data of destroyed mutexes (sipa)
+- #7853 `6ef5e00` py2: Unfiddle strings into bytes explicitly (MarcoFalke)
+- #7878 `53adc83` [test] bctest.py: Revert faa41ee (MarcoFalke)
+- #7798 `cabba24` [travis] Print the commit which was evaluated (MarcoFalke)
+- #7833 `b1bf511` tests: Check Content-Type header returned from RPC server (laanwj)
+- #7851 `fa9d86f` pull-tester: Don't mute zmq ImportError (MarcoFalke)
+- #7822 `0e6fd5e` Add listunspent() test for spendable/unspendable UTXO (jpdffonseca)
+- #7912 `59ad568` Tests: Fix deserialization of reject messages (sdaftuar)
+- #7941 `0ea3941` Fixing comment in script_test.json test case (Christewart)
+- #7807 `0ad1041` Fixed miner test values, gave constants for less error-prone values (instagibbs)
+- #7980 `88b77c7` Smartfees: Properly use ordered dict (MarcoFalke)
+- #7814 `77b637f` Switch to py3 (MarcoFalke)
+- #8030 `409a8a1` Revert fatal-ness of missing python-zmq (laanwj)
+- #8018 `3e90fe6` Autofind rpc tests --srcdir (jonasschnelli)
+- #8016 `5767e80` Fix multithread CScheduler and reenable test (paveljanik)
+- #7972 `423ca30` pull-tester: Run rpc test in parallel (MarcoFalke)
+- #8039 `69b3a6d` Bench: Add crypto hash benchmarks (laanwj)
+- #8041 `5b736dd` Fix bip9-softforks blockstore issue (MarcoFalke)
+- #7994 `1f01443` Add op csv tests to script_tests.json (Christewart)
+- #8038 `e2bf830` Various minor fixes (MarcoFalke)
+- #8072 `1b87e5b` Travis: 'make check' in parallel and verbose (MarcoFalke)
+- #8056 `8844ef1` Remove hardcoded "4 nodes" from test_framework (MarcoFalke)
+- #8047 `37f9a1f` Test_framework: Set wait-timeout for bitcoind procs (MarcoFalke)
+- #8095 `6700cc9` Test framework: only cleanup on successful test runs (sdaftuar)
+- #8098 `06bd4f6` Test_framework: Append portseed to tmpdir (MarcoFalke)
+- #8104 `6ff2c8d` Add timeout to sync_blocks() and sync_mempools() (sdaftuar)
+- #8111 `61b8684` Benchmark SipHash (sipa)
+- #8107 `52b803e` Bench: Added base58 encoding/decoding benchmarks (yurizhykin)
+- #8115 `0026e0e` Avoid integer division in the benchmark inner-most loop (gmaxwell)
+- #8090 `a2df115` Adding P2SH(p2pkh) script test case (Christewart)
+- #7992 `ec45cc5` Extend #7956 with one more test (TheBlueMatt)
+- #8139 `ae5575b` Fix interrupted HTTP RPC connection workaround for Python 3.5+ (sipa)
+- #8164 `0f24eaf` [Bitcoin-Tx] fix missing test fixtures, fix 32bit atoi issue (jonasschnelli)
+- #8166 `0b5279f` Src/test: Do not shadow local variables (paveljanik)
+- #8141 `44c1b1c` Continuing port of java comparison tool (mrbandrews)
+- #8201 `36b7400` fundrawtransaction: Fix race, assert amounts (MarcoFalke)
+- #8214 `ed2cd59` Mininode: fail on send_message instead of silent return (MarcoFalke)
+- #8215 `a072d1a` Don't use floating point in wallet tests (MarcoFalke)
+- #8066 `65c2058` Test_framework: Use different rpc_auth_pair for each node (MarcoFalke)
+- #8216 `0d41d70` Assert 'changePosition out of bounds' (MarcoFalke)
+- #8222 `961893f` Enable mempool consistency checks in unit tests (sipa)
+- #7751 `84370d5` test_framework: python3.4 authproxy compat (laanwj)
+- #7744 `d8e862a` test_framework: detect failure of bitcoind startup (laanwj)
+- #8280 `115735d` Increase sync_blocks() timeouts in pruning.py (MarcoFalke)
+- #8340 `af9b7a9` Solve trivial merge conflict in p2p-segwit.py (MarcoFalke)
+- #8067 `3e4cf8f` Travis: use slim generic image, and some fixups (theuni)
+- #7951 `5c7df70` Test_framework: Properly print exception (MarcoFalke)
+- #8070 `7771aa5` Remove non-determinism which is breaking net_tests #8069 (EthanHeilman)
+- #8309 `bb2646a` Add wallet-hd test (MarcoFalke)
+- #8444 `cd0910b` Fix p2p-feefilter.py for changed tx relay behavior (sdaftuar)
+
+### Mining
+
+- #7507 `11c7699` Remove internal miner (Leviathn)
+- #7663 `c87f51e` Make the generate RPC call function for non-regtest (sipa)
+- #7671 `e2ebd25` Add generatetoaddress RPC to mine to an address (achow101)
+- #7935 `66ed450` Versionbits: GBT support (luke-jr)
+- #7600 `66db2d6` Select transactions using feerate-with-ancestors (sdaftuar)
+- #8295 `f5660d3` Mining-related fixups for 0.13.0 (sdaftuar)
+- #7796 `536b75e` Add support for negative fee rates, fixes `prioritizetransaction` (MarcoFalke)
+- #8362 `86edc20` Scale legacy sigop count in CreateNewBlock (sdaftuar)
+- #8489 `8b0eee6` Bugfix: Use pre-BIP141 sigops until segwit activates (GBT) (luke-jr)
+
+### Documentation and miscellaneous
+
+- #7423 `69e2a40` Add example for building with constrained resources (jarret)
+- #8254 `c2c69ed` Add OSX ZMQ requirement to QA readme (fanquake)
+- #8203 `377d131` Clarify documentation for running a tor node (nathaniel-mahieu)
+- #7428 `4b12266` Add example for listing ./configure flags (nathaniel-mahieu)
+- #7847 `3eae681` Add arch linux build example (mruddy)
+- #7968 `ff69aaf` Fedora build requirements (wtogami)
+- #8013 `fbedc09` Fedora build requirements, add gcc-c++ and fix typo (wtogami)
+- #8009 `fbd8478` Fixed invalid example paths in gitian-building.md (JeremyRand)
+- #8240 `63fbdbc` Mention Windows XP end of support in release notes (laanwj)
+- #8303 `5077d2c` Update bips.md for CSV softfork (fanquake)
+- #7789 `e0b3e19` Add note about using the Qt official binary installer (paveljanik)
+- #7791 `e30a5b0` Change Precise to Trusty in gitian-building.md (JeremyRand)
+- #7838 `8bb5d3d` Update gitian build guide to debian 8.4.0 (fanquake)
+- #7855 `b778e59` Replace precise with trusty (MarcoFalke)
+- #7975 `fc23fee` Update bitcoin-core GitHub links (MarcoFalke)
+- #8034 `e3a8207` Add basic git squash workflow (fanquake)
+- #7813 `214ec0b` Update port in tor.md (MarcoFalke)
+- #8193 `37c9830` Use Debian 8.5 in the gitian-build guide (fanquake)
+- #8261 `3685e0c` Clarify help for `getblockchaininfo` (paveljanik)
+- #7185 `ea0f5a2` Note that reviewers should mention the id of the commits they reviewed (pstratem)
+- #7290 `c851d8d` [init] Add missing help for args (MarcoFalke)
+- #7281 `f9fd4c2` Improve CheckInputs() comment about sig verification (petertodd)
+- #7417 `1e06bab` Minor improvements to the release process (PRabahy)
+- #7444 `4cdbd42` Improve block validity/ConnectBlock() comments (petertodd)
+- #7527 `db2e1c0` Fix and cleanup listreceivedbyX documentation (instagibbs)
+- #7541 `b6e00af` Clarify description of blockindex (pinheadmz)
+- #7590 `f06af57` Improving wording related to Boost library requirements [updated] (jonathancross)
+- #7635 `0fa88ef` Add dependency info to test docs (elliotolds)
+- #7609 `3ba07bd` RPM spec file project (AliceWonderMiscreations)
+- #7850 `229a17c` Removed call to `TryCreateDirectory` from `GetDefaultDataDir` in `src/util.cpp` (alexreg)
+- #7888 `ec870e1` Prevector: fix 2 bugs in currently unreached code paths (kazcw)
+- #7922 `90653bc` CBase58Data::SetString: cleanse the full vector (kazcw)
+- #7881 `c4e8390` Update release process (laanwj)
+- #7952 `a9c8b74` Log invalid block hash to make debugging easier (paveljanik)
+- #7974 `8206835` More comments on the design of AttemptToEvictConnection (gmaxwell)
+- #7795 `47a7cfb` UpdateTip: log only one line at most per block (laanwj)
+- #8110 `e7e25ea` Add benchmarking notes (fanquake)
+- #8121 `58f0c92` Update implemented BIPs list (fanquake)
+- #8029 `58725ba` Simplify OS X build notes (fanquake)
+- #8143 `d46b8b5` comment nit: miners don't vote (instagibbs)
+- #8136 `22e0b35` Log/report in 10% steps during VerifyDB (jonasschnelli)
+- #8168 `d366185` util: Add ParseUInt32 and ParseUInt64 (laanwj)
+- #8178 `f7b1bfc` Add git and github tips and tricks to developer notes (sipa)
+- #8177 `67db011` developer notes: updates for C++11 (kazcw)
+- #8229 `8ccdac1` [Doc] Update OS X build notes for 10.11 SDK (fanquake)
+- #8233 `9f1807a` Mention Linux ARM executables in release process and notes (laanwj)
+- #7540 `ff46dd4` Rename OP_NOP3 to OP_CHECKSEQUENCEVERIFY (btcdrak)
+- #8289 `26316ff` bash-completion: Adapt for 0.12 and 0.13 (roques)
+- #7453 `3dc3149` Missing patches from 0.12 (MarcoFalke)
+- #7113 `54a550b` Switch to a more efficient rolling Bloom filter (sipa)
+- #7257 `de9e5ea` Combine common error strings for different options so translations can be shared and reused (luke-jr)
+- #7304 `b8f485c` [contrib] Add clang-format-diff.py (MarcoFalke)
+- #7378 `e6f97ef` devtools: replace github-merge with python version (laanwj)
+- #7395 `0893705` devtools: show pull and commit information in github-merge (laanwj)
+- #7402 `6a5932b` devtools: github-merge get toplevel dir without extra whitespace (achow101)
+- #7425 `20a408c` devtools: Fix utf-8 support in messages for github-merge (laanwj)
+- #7632 `409f843` Delete outdated test-patches reference (Lewuathe)
+- #7662 `386f438` remove unused NOBLKS_VERSION_{START,END} constants (rat4)
+- #7737 `aa0d2b2` devtools: make github-merge.py use py3 (laanwj)
+- #7781 `55db5f0` devtools: Auto-set branch to merge to in github-merge (laanwj)
+- #7934 `f17032f` Improve rolling bloom filter performance and benchmark (sipa)
+- #8004 `2efe38b` signal handling: fReopenDebugLog and fRequestShutdown should be type sig_atomic_t (catilac)
+- #7713 `f6598df` Fixes for verify-commits script (petertodd)
+- #8412 `8360d5b` libconsensus: Expose a flag for BIP112 (jtimon)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- 21E14
+- accraze
+- Adam Brown
+- Alexander Regueiro
+- Alex Morcos
+- Alfie John
+- Alice Wonder
+- AlSzacrel
+- Andrew Chow
+- Andrés G. Aragoneses
+- Bob McElrath
+- BtcDrak
+- calebogden
+- Cédric Félizard
+- Chirag Davé
+- Chris Moore
+- Chris Stewart
+- Christian von Roques
+- Chris Wheeler
+- Cory Fields
+- crowning-
+- Daniel Cousens
+- Daniel Kraft
+- Denis Lukianov
+- Elias Rohrer
+- Elliot Olds
+- Eric Shaw
+- error10
+- Ethan Heilman
+- face
+- fanquake
+- Francesco 'makevoid' Canessa
+- fsb4000
+- Gavin Andresen
+- gladoscc
+- Gregory Maxwell
+- Gregory Sanders
+- instagibbs
+- James O'Beirne
+- Jannes Faber
+- Jarret Dyrbye
+- Jeremy Rand
+- jloughry
+- jmacwhyte
+- Joao Fonseca
+- Johnson Lau
+- Jonas Nick
+- Jonas Schnelli
+- Jonathan Cross
+- João Barbosa
+- Jorge Timón
+- Kaz Wesley
+- Kefkius
+- kirkalx
+- Krzysztof Jurewicz
+- Leviathn
+- lewuathe
+- Luke Dashjr
+- Luv Khemani
+- Marcel Krüger
+- Marco Falke
+- Mark Friedenbach
+- Matt
+- Matt Bogosian
+- Matt Corallo
+- Matthew English
+- Matthew Zipkin
+- mb300sd
+- Mitchell Cash
+- mrbandrews
+- mruddy
+- Murch
+- Mustafa
+- Nathaniel Mahieu
+- Nicolas Dorier
+- Patrick Strateman
+- Paul Rabahy
+- paveljanik
+- Pavel Janík
+- Pavel Vasin
+- Pedro Branco
+- Peter Todd
+- Philip Kaufmann
+- Pieter Wuille
+- Prayag Verma
+- ptschip
+- Puru
+- randy-waterhouse
+- R E Broadley
+- Rusty Russell
+- Suhas Daftuar
+- Suriyaa Kudo
+- TheLazieR Yip
+- Thomas Kerin
+- Tom Harding
+- Tyler Hardin
+- UdjinM6
+- Warren Togami
+- Will Binns
+- Wladimir J. van der Laan
+- Yuri Zhykin
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
diff --git a/doc/release-process.md b/doc/release-process.md
index 41c1ac8556..394b159b31 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -137,9 +137,10 @@ Build output expected:
### Verify other gitian builders signatures to your own. (Optional)
-Add other gitian builders keys to your gpg keyring
+Add other gitian builders keys to your gpg keyring, and/or refresh keys.
gpg --import bitcoin/contrib/gitian-keys/*.pgp
+ gpg --refresh-keys
Verify the signatures
diff --git a/qa/README.md b/qa/README.md
index 723660c6c8..225207cc1c 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -41,8 +41,8 @@ Run all possible tests with
qa/pull-tester/rpc-tests.py -extended
-By default, tests will be run in parallel if you want to specify how many
-tests should be run in parallel, append `-parallel=n` (default n=4).
+By default, tests will be run in parallel. To specify how many jobs to run,
+append `-parallel=n` (default n=4).
If you want to create a basic coverage report for the rpc test suite, append `--coverage`.
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index f65a3eefc3..771f6c7a0f 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -77,8 +77,6 @@ for arg in sys.argv[1:]:
#Set env vars
if "BITCOIND" not in os.environ:
os.environ["BITCOIND"] = BUILDDIR + '/src/bitcoind' + EXEEXT
-if "BITCOINCLI" not in os.environ:
- os.environ["BITCOINCLI"] = BUILDDIR + '/src/bitcoin-cli' + EXEEXT
if EXEEXT == ".exe" and "-win" not in opts:
# https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
@@ -94,24 +92,27 @@ if not (ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
if ENABLE_ZMQ:
try:
import zmq
- except ImportError as e:
- print("WARNING: \"import zmq\" failed. Set ENABLE_ZMQ=0 or " \
- "to run zmq tests, see dependency info in /qa/README.md.")
- ENABLE_ZMQ=0
+ except ImportError:
+ print("ERROR: \"import zmq\" failed. Set ENABLE_ZMQ=0 or "
+ "to run zmq tests, see dependency info in /qa/README.md.")
+ # ENABLE_ZMQ=0
+ raise
-#Tests
testScripts = [
# longest test should go first, to favor running tests in parallel
'p2p-fullblocktest.py',
'walletbackup.py',
'bip68-112-113-p2p.py',
'wallet.py',
+ 'wallet-accounts.py',
'wallet-hd.py',
'wallet-dump.py',
'listtransactions.py',
'receivedby.py',
'mempool_resurrect_test.py',
'txn_doublespend.py --mineblock',
+ 'p2p-segwit.py',
+ 'segwit.py',
'txn_clone.py',
'getchaintips.py',
'rawtransactions.py',
@@ -133,13 +134,12 @@ testScripts = [
'disablewallet.py',
'sendheaders.py',
'keypool.py',
+ 'p2p-mempool.py',
'prioritise_transaction.py',
'invalidblockrequest.py',
'invalidtxrequest.py',
'abandonconflict.py',
'p2p-versionbits-warning.py',
- 'p2p-segwit.py',
- 'segwit.py',
'importprunedfunds.py',
'signmessages.py',
'p2p-compactblocks.py',
@@ -194,6 +194,7 @@ def runtests():
coverage = RPCCoverage()
print("Initializing coverage directory at %s\n" % coverage.dir)
flags = ["--srcdir=%s/src" % BUILDDIR] + passon_args
+ flags.append("--cachedir=%s/qa/cache" % BUILDDIR)
if coverage:
flags.append(coverage.flag)
diff --git a/qa/rpc-tests/abandonconflict.py b/qa/rpc-tests/abandonconflict.py
index c50c3cc562..874df48777 100755
--- a/qa/rpc-tests/abandonconflict.py
+++ b/qa/rpc-tests/abandonconflict.py
@@ -68,7 +68,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# In mempool txs from self should increase balance from change
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance - Decimal("30") + Decimal("24.9996"))
+ assert_equal(newbalance, balance - Decimal("30") + Decimal("24.9996"))
balance = newbalance
# Restart the node with a higher min relay fee so the parent tx is no longer in mempool
@@ -78,16 +78,16 @@ class AbandonConflictTest(BitcoinTestFramework):
self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"])
# Verify txs no longer in mempool
- assert(len(self.nodes[0].getrawmempool()) == 0)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
# Not in mempool txs from self should only reduce balance
# inputs are still spent, but change not received
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance - Decimal("24.9996"))
+ assert_equal(newbalance, balance - Decimal("24.9996"))
# Unconfirmed received funds that are not in mempool, also shouldn't show
# up in unconfirmed balance
unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()
- assert(unconfbalance == newbalance)
+ assert_equal(unconfbalance, newbalance)
# Also shouldn't show up in listunspent
assert(not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)])
balance = newbalance
@@ -96,35 +96,35 @@ class AbandonConflictTest(BitcoinTestFramework):
# including that the child tx was also abandoned
self.nodes[0].abandontransaction(txAB1)
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance + Decimal("30"))
+ assert_equal(newbalance, balance + Decimal("30"))
balance = newbalance
# Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned
stop_node(self.nodes[0],0)
self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.00001"])
- assert(len(self.nodes[0].getrawmempool()) == 0)
- assert(self.nodes[0].getbalance() == balance)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
+ assert_equal(self.nodes[0].getbalance(), balance)
# But if its received again then it is unabandoned
# And since now in mempool, the change is available
# But its child tx remains abandoned
self.nodes[0].sendrawtransaction(signed["hex"])
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance - Decimal("20") + Decimal("14.99998"))
+ assert_equal(newbalance, balance - Decimal("20") + Decimal("14.99998"))
balance = newbalance
# Send child tx again so its unabandoned
self.nodes[0].sendrawtransaction(signed2["hex"])
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance - Decimal("10") - Decimal("14.99998") + Decimal("24.9996"))
+ assert_equal(newbalance, balance - Decimal("10") - Decimal("14.99998") + Decimal("24.9996"))
balance = newbalance
# Remove using high relay fee again
stop_node(self.nodes[0],0)
self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"])
- assert(len(self.nodes[0].getrawmempool()) == 0)
+ assert_equal(len(self.nodes[0].getrawmempool()), 0)
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance - Decimal("24.9996"))
+ assert_equal(newbalance, balance - Decimal("24.9996"))
balance = newbalance
# Create a double spend of AB1 by spending again from only A's 10 output
@@ -143,7 +143,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted
newbalance = self.nodes[0].getbalance()
- assert(newbalance == balance + Decimal("20"))
+ assert_equal(newbalance, balance + Decimal("20"))
balance = newbalance
# There is currently a minor bug around this and so this test doesn't work. See Issue #7315
@@ -151,7 +151,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Don't think C's should either
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
newbalance = self.nodes[0].getbalance()
- #assert(newbalance == balance - Decimal("10"))
+ #assert_equal(newbalance, balance - Decimal("10"))
print("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
print("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
print(str(balance) + " -> " + str(newbalance) + " ?")
diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py
index d86f51b7f3..0dee8ad4ec 100755
--- a/qa/rpc-tests/importprunedfunds.py
+++ b/qa/rpc-tests/importprunedfunds.py
@@ -5,7 +5,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-import decimal
+
class ImportPrunedFundsTest(BitcoinTestFramework):
@@ -20,14 +20,10 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
self.is_network_split=False
self.sync_all()
- def run_test (self):
- import time
- begintime = int(time.time())
-
+ def run_test(self):
print("Mining blocks...")
self.nodes[0].generate(101)
- # sync
self.sync_all()
# address
@@ -72,7 +68,6 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex']
proof2 = self.nodes[0].gettxoutproof([txnid2])
-
txnid3 = self.nodes[0].sendtoaddress(address3, 0.025)
self.nodes[0].generate(1)
rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex']
@@ -82,28 +77,27 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
#Import with no affiliated address
try:
- result1 = self.nodes[1].importprunedfunds(rawtxn1, proof1, "")
+ self.nodes[1].importprunedfunds(rawtxn1, proof1)
except JSONRPCException as e:
assert('No addresses' in e.error['message'])
else:
assert(False)
-
balance1 = self.nodes[1].getbalance("", 0, True)
assert_equal(balance1, Decimal(0))
#Import with affiliated address with no rescan
- self.nodes[1].importaddress(address2, "", False)
- result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2, "")
- balance2 = Decimal(self.nodes[1].getbalance("", 0, True))
+ self.nodes[1].importaddress(address2, "add2", False)
+ result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2)
+ balance2 = self.nodes[1].getbalance("add2", 0, True)
assert_equal(balance2, Decimal('0.05'))
#Import with private key with no rescan
- self.nodes[1].importprivkey(address3_privkey, "", False)
- result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3, "")
- balance3 = Decimal(self.nodes[1].getbalance("", 0, False))
+ self.nodes[1].importprivkey(address3_privkey, "add3", False)
+ result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3)
+ balance3 = self.nodes[1].getbalance("add3", 0, False)
assert_equal(balance3, Decimal('0.025'))
- balance3 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance3 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance3, Decimal('0.075'))
#Addresses Test - after import
@@ -118,7 +112,6 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
assert_equal(address_info['ismine'], True)
#Remove transactions
-
try:
self.nodes[1].removeprunedfunds(txnid1)
except JSONRPCException as e:
@@ -126,18 +119,16 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
else:
assert(False)
-
- balance1 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance1 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance1, Decimal('0.075'))
-
self.nodes[1].removeprunedfunds(txnid2)
- balance2 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance2 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance2, Decimal('0.025'))
self.nodes[1].removeprunedfunds(txnid3)
- balance3 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance3 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance3, Decimal('0.0'))
if __name__ == '__main__':
- ImportPrunedFundsTest ().main ()
+ ImportPrunedFundsTest().main()
diff --git a/qa/rpc-tests/p2p-fullblocktest.py b/qa/rpc-tests/p2p-fullblocktest.py
index 17fd40ef1d..9aee81164f 100755
--- a/qa/rpc-tests/p2p-fullblocktest.py
+++ b/qa/rpc-tests/p2p-fullblocktest.py
@@ -25,9 +25,6 @@ We use the testing framework in which we expect a particular answer from
each test.
'''
-def hash160(s):
- return hashlib.new('ripemd160', sha256(s)).digest()
-
# Use this class for tests that require behavior other than normal "mininode" behavior.
# For now, it is used to serialize a bloated varint (b64).
class CBrokenBlock(CBlock):
diff --git a/qa/rpc-tests/p2p-mempool.py b/qa/rpc-tests/p2p-mempool.py
index 5d2daf39f8..5c5d778f42 100755
--- a/qa/rpc-tests/p2p-mempool.py
+++ b/qa/rpc-tests/p2p-mempool.py
@@ -72,8 +72,11 @@ class TestNode(NodeConnCB):
self.send_message(msg_mempool())
class P2PMempoolTests(BitcoinTestFramework):
- def setup_chain(self):
- initialize_chain_clean(self.options.tmpdir, 2)
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 2
def setup_network(self):
# Start a node with maxuploadtarget of 200 MB (/24h)
diff --git a/qa/rpc-tests/p2p-segwit.py b/qa/rpc-tests/p2p-segwit.py
index cd02692b1e..eb857ed983 100755
--- a/qa/rpc-tests/p2p-segwit.py
+++ b/qa/rpc-tests/p2p-segwit.py
@@ -168,8 +168,11 @@ class UTXO(object):
class SegWitTest(BitcoinTestFramework):
- def setup_chain(self):
- initialize_chain_clean(self.options.tmpdir, 3)
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
def add_options(self, parser):
parser.add_option("--oldbinary", dest="oldbinary",
diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py
index c9c2eaf7f3..b769cd71f2 100755
--- a/qa/rpc-tests/rest.py
+++ b/qa/rpc-tests/rest.py
@@ -179,14 +179,14 @@ class RESTTest (BitcoinTestFramework):
#do some invalid requests
json_request = '{"checkmempool'
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'json', json_request, True)
- assert_equal(response.status, 500) #must be a 500 because we send a invalid json request
+ assert_equal(response.status, 400) #must be a 400 because we send a invalid json request
json_request = '{"checkmempool'
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', json_request, True)
- assert_equal(response.status, 500) #must be a 500 because we send a invalid bin request
+ assert_equal(response.status, 400) #must be a 400 because we send a invalid bin request
response = http_post_call(url.hostname, url.port, '/rest/getutxos/checkmempool'+self.FORMAT_SEPARATOR+'bin', '', True)
- assert_equal(response.status, 500) #must be a 500 because we send a invalid bin request
+ assert_equal(response.status, 400) #must be a 400 because we send a invalid bin request
#test limits
json_request = '/checkmempool/'
@@ -194,14 +194,14 @@ class RESTTest (BitcoinTestFramework):
json_request += txid+'-'+str(n)+'/'
json_request = json_request.rstrip("/")
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True)
- assert_equal(response.status, 500) #must be a 500 because we exceeding the limits
+ assert_equal(response.status, 400) #must be a 400 because we exceeding the limits
json_request = '/checkmempool/'
for x in range(0, 15):
json_request += txid+'-'+str(n)+'/'
json_request = json_request.rstrip("/")
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True)
- assert_equal(response.status, 200) #must be a 500 because we exceeding the limits
+ assert_equal(response.status, 200) #must be a 200 because we are within the limits
self.nodes[0].generate(1) #generate block to not affect upcoming tests
self.sync_all()
diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py
index bf1cc87126..3ac32140ba 100755
--- a/qa/rpc-tests/rpcbind_test.py
+++ b/qa/rpc-tests/rpcbind_test.py
@@ -5,13 +5,11 @@
# Test for -rpcbind, as well as -rpcallowip and -rpcconnect
-import tempfile
-import traceback
-
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from test_framework.netutil import *
+
class RPCBindTest(BitcoinTestFramework):
def __init__(self):
@@ -109,4 +107,4 @@ class RPCBindTest(BitcoinTestFramework):
pass
if __name__ == '__main__':
- RPCBindTest ().main ()
+ RPCBindTest().main()
diff --git a/qa/rpc-tests/segwit.py b/qa/rpc-tests/segwit.py
index 097e119f32..745a1d4750 100755
--- a/qa/rpc-tests/segwit.py
+++ b/qa/rpc-tests/segwit.py
@@ -10,8 +10,6 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from test_framework.mininode import sha256, ripemd160
-import os
-import shutil
NODE_0 = 0
NODE_1 = 1
@@ -76,9 +74,10 @@ def find_unspent(node, min_value):
class SegWitTest(BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 3)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
index 0dfece6b27..a1383729fa 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -48,7 +48,7 @@ class BitcoinTestFramework(object):
if self.setup_clean_chain:
initialize_chain_clean(self.options.tmpdir, self.num_nodes)
else:
- initialize_chain(self.options.tmpdir, self.num_nodes)
+ initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir)
def stop_node(self, num_node):
stop_node(self.nodes[num_node], num_node)
@@ -112,6 +112,8 @@ class BitcoinTestFramework(object):
help="Don't stop bitcoinds after the test execution")
parser.add_option("--srcdir", dest="srcdir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../../src"),
help="Source directory containing bitcoind/bitcoin-cli (default: %default)")
+ parser.add_option("--cachedir", dest="cachedir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../cache"),
+ help="Directory for caching pregenerated datadirs")
parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
help="Root directory for datadirs")
parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true",
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index 8aa34265c5..190fa7f661 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -201,7 +201,7 @@ def wait_for_bitcoind_start(process, url, i):
raise # unkown JSON RPC exception
time.sleep(0.25)
-def initialize_chain(test_dir, num_nodes):
+def initialize_chain(test_dir, num_nodes, cachedir):
"""
Create a cache of a 200-block-long chain (with wallet) for MAX_NODES
Afterward, create num_nodes copies from the cache
@@ -210,7 +210,7 @@ def initialize_chain(test_dir, num_nodes):
assert num_nodes <= MAX_NODES
create_cache = False
for i in range(MAX_NODES):
- if not os.path.isdir(os.path.join('cache', 'node'+str(i))):
+ if not os.path.isdir(os.path.join(cachedir, 'node'+str(i))):
create_cache = True
break
@@ -218,12 +218,12 @@ def initialize_chain(test_dir, num_nodes):
#find and delete old cache directories if any exist
for i in range(MAX_NODES):
- if os.path.isdir(os.path.join("cache","node"+str(i))):
- shutil.rmtree(os.path.join("cache","node"+str(i)))
+ if os.path.isdir(os.path.join(cachedir,"node"+str(i))):
+ shutil.rmtree(os.path.join(cachedir,"node"+str(i)))
# Create cache directories, run bitcoinds:
for i in range(MAX_NODES):
- datadir=initialize_datadir("cache", i)
+ datadir=initialize_datadir(cachedir, i)
args = [ os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir="+datadir, "-discover=0" ]
if i > 0:
args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
@@ -265,13 +265,13 @@ def initialize_chain(test_dir, num_nodes):
wait_bitcoinds()
disable_mocktime()
for i in range(MAX_NODES):
- os.remove(log_filename("cache", i, "debug.log"))
- os.remove(log_filename("cache", i, "db.log"))
- os.remove(log_filename("cache", i, "peers.dat"))
- os.remove(log_filename("cache", i, "fee_estimates.dat"))
+ os.remove(log_filename(cachedir, i, "debug.log"))
+ os.remove(log_filename(cachedir, i, "db.log"))
+ os.remove(log_filename(cachedir, i, "peers.dat"))
+ os.remove(log_filename(cachedir, i, "fee_estimates.dat"))
for i in range(num_nodes):
- from_dir = os.path.join("cache", "node"+str(i))
+ from_dir = os.path.join(cachedir, "node"+str(i))
to_dir = os.path.join(test_dir, "node"+str(i))
shutil.copytree(from_dir, to_dir)
initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf
diff --git a/qa/rpc-tests/wallet-accounts.py b/qa/rpc-tests/wallet-accounts.py
new file mode 100755
index 0000000000..c51181e4f8
--- /dev/null
+++ b/qa/rpc-tests/wallet-accounts.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+# Copyright (c) 2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ start_nodes,
+ start_node,
+ assert_equal,
+ connect_nodes_bi,
+)
+
+
+class WalletAccountsTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+ self.node_args = [[]]
+
+ def setup_network(self):
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.node_args)
+ self.is_network_split = False
+
+ def run_test (self):
+ node = self.nodes[0]
+ # Check that there's no UTXO on any of the nodes
+ assert_equal(len(node.listunspent()), 0)
+
+ node.generate(101)
+
+ assert_equal(node.getbalance(), 50)
+
+ accounts = ["a","b","c","d","e"]
+ amount_to_send = 1.0
+ account_addresses = dict()
+ for account in accounts:
+ address = node.getaccountaddress(account)
+ account_addresses[account] = address
+
+ node.getnewaddress(account)
+ assert_equal(node.getaccount(address), account)
+ assert(address in node.getaddressesbyaccount(account))
+
+ node.sendfrom("", address, amount_to_send)
+
+ node.generate(1)
+
+ for i in range(len(accounts)):
+ from_account = accounts[i]
+ to_account = accounts[(i+1)%len(accounts)]
+ to_address = account_addresses[to_account]
+ node.sendfrom(from_account, to_address, amount_to_send)
+
+ node.generate(1)
+
+ for account in accounts:
+ address = node.getaccountaddress(account)
+ assert(address != account_addresses[account])
+ assert_equal(node.getreceivedbyaccount(account), 2)
+ node.move(account, "", node.getbalance(account))
+
+ node.generate(101)
+
+ expected_account_balances = {"": 5200}
+ for account in accounts:
+ expected_account_balances[account] = 0
+
+ assert_equal(node.listaccounts(), expected_account_balances)
+
+ assert_equal(node.getbalance(""), 5200)
+
+ for account in accounts:
+ address = node.getaccountaddress("")
+ node.setaccount(address, account)
+ assert(address in node.getaddressesbyaccount(account))
+ assert(address not in node.getaddressesbyaccount(""))
+
+ for account in accounts:
+ addresses = []
+ for x in range(10):
+ addresses.append(node.getnewaddress())
+ multisig_address = node.addmultisigaddress(5, addresses, account)
+ node.sendfrom("", multisig_address, 50)
+
+ node.generate(101)
+
+ for account in accounts:
+ assert_equal(node.getbalance(account), 50)
+
+if __name__ == '__main__':
+ WalletAccountsTest().main ()
diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py
index 2ba8bb9b3a..9624abf1fc 100755
--- a/share/qt/extract_strings_qt.py
+++ b/share/qt/extract_strings_qt.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
'''
Extract _("...") strings for translation and convert to Qt stringdefs so that
they can be picked up by Qt linguist.
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 7730aba375..8947aeaca0 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -257,6 +257,8 @@ RES_ICONS = \
qt/res/icons/filesave.png \
qt/res/icons/fontbigger.png \
qt/res/icons/fontsmaller.png \
+ qt/res/icons/hd_disabled.png \
+ qt/res/icons/hd_enabled.png \
qt/res/icons/history.png \
qt/res/icons/info.png \
qt/res/icons/key.png \
@@ -271,14 +273,14 @@ RES_ICONS = \
qt/res/icons/synced.png \
qt/res/icons/transaction0.png \
qt/res/icons/transaction2.png \
+ qt/res/icons/transaction_abandoned.png \
qt/res/icons/transaction_conflicted.png \
qt/res/icons/tx_inout.png \
qt/res/icons/tx_input.png \
qt/res/icons/tx_output.png \
qt/res/icons/tx_mined.png \
qt/res/icons/warning.png \
- qt/res/icons/verify.png \
- qt/res/icons/transaction_abandoned.png
+ qt/res/icons/verify.png
BITCOIN_QT_CPP = \
qt/bantablemodel.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 27e7694748..0748d1a39d 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -97,8 +97,7 @@ BITCOIN_TESTS += \
wallet/test/wallet_test_fixture.h \
wallet/test/accounting_tests.cpp \
wallet/test/wallet_tests.cpp \
- wallet/test/crypto_tests.cpp \
- wallet/test/rpc_wallet_tests.cpp
+ wallet/test/crypto_tests.cpp
endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 8e8ac47455..cb863bda19 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -395,10 +395,8 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
if (!registers.count("privatekeys"))
throw runtime_error("privatekeys register variable must be set.");
- bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
UniValue keysObj = registers["privatekeys"];
- fGivenKeys = true;
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr())
@@ -454,7 +452,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
// if redeemScript given and private keys given,
// add redeemScript to the tempKeystore so it can be signed:
- if (fGivenKeys && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
+ if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
prevOut.exists("redeemScript")) {
UniValue v = prevOut["redeemScript"];
vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
@@ -517,7 +515,7 @@ public:
static void MutateTx(CMutableTransaction& tx, const string& command,
const string& commandVal)
{
- boost::scoped_ptr<Secp256k1Init> ecc;
+ std::unique_ptr<Secp256k1Init> ecc;
if (command == "nversion")
MutateTxVersion(tx, commandVal);
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 5c4c3bd274..df237f8f26 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -75,7 +75,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
}
prefilled_count = cmpctblock.prefilledtxn.size();
- // Calculate map of txids -> positions and check mempool to see what we have (or dont)
+ // Calculate map of txids -> positions and check mempool to see what we have (or don't)
// Because well-formed cmpctblock messages will have a (relatively) uniform distribution
// of short IDs, any highly-uneven distribution of elements can be safely treated as a
// READ_STATUS_FAILED.
diff --git a/src/blockencodings.h b/src/blockencodings.h
index b980e9e286..349fcbd50f 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -53,11 +53,11 @@ public:
}
uint16_t offset = 0;
- for (size_t i = 0; i < indexes.size(); i++) {
- if (uint64_t(indexes[i]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())
+ for (size_t j = 0; j < indexes.size(); j++) {
+ if (uint64_t(indexes[j]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())
throw std::ios_base::failure("indexes overflowed 16 bits");
- indexes[i] = indexes[i] + offset;
- offset = indexes[i] + 1;
+ indexes[j] = indexes[j] + offset;
+ offset = indexes[j] + 1;
}
} else {
for (size_t i = 0; i < indexes.size(); i++) {
diff --git a/src/chain.h b/src/chain.h
index 76a774c123..6588e8f57d 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -137,15 +137,15 @@ enum BlockStatus: uint32_t {
BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
- BLOCK_HAVE_DATA = 8, //! full block available in blk*.dat
- BLOCK_HAVE_UNDO = 16, //! undo data available in rev*.dat
+ BLOCK_HAVE_DATA = 8, //!< full block available in blk*.dat
+ BLOCK_HAVE_UNDO = 16, //!< undo data available in rev*.dat
BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO,
- BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed
- BLOCK_FAILED_CHILD = 64, //! descends from failed block
+ BLOCK_FAILED_VALID = 32, //!< stage after last reached validness failed
+ BLOCK_FAILED_CHILD = 64, //!< descends from failed block
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
- BLOCK_OPT_WITNESS = 128, //! block data in blk*.data was received with a witness-enforcing client
+ BLOCK_OPT_WITNESS = 128, //!< block data in blk*.data was received with a witness-enforcing client
};
/** The block chain is a tree shaped structure starting with the
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index ea6e3aada2..e6be1b5d5b 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -118,7 +118,7 @@ public:
vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); // Luke Dashjr
vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com")); // Christian Decker
vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); // Jeff Garzik
- vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch")); // Jonas Schnelli
+ vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 000b197270..3e24294a64 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -22,9 +22,9 @@ static const unsigned char REJECT_CHECKPOINT = 0x43;
class CValidationState {
private:
enum mode_state {
- MODE_VALID, //! everything ok
- MODE_INVALID, //! network rule violation (DoS value may be set)
- MODE_ERROR, //! run-time error
+ MODE_VALID, //!< everything ok
+ MODE_INVALID, //!< network rule violation (DoS value may be set)
+ MODE_ERROR, //!< run-time error
} mode;
int nDoS;
std::string strRejectReason;
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 09c68fbe55..4fa06135d2 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -117,7 +117,7 @@ std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
bool CDBWrapper::IsEmpty()
{
- boost::scoped_ptr<CDBIterator> it(NewIterator());
+ std::unique_ptr<CDBIterator> it(NewIterator());
it->SeekToFirst();
return !(it->Valid());
}
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 04d3386e9a..6a6c5276cc 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -45,7 +45,7 @@ private:
class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
- HTTPRPCTimerInterface(struct event_base* base) : base(base)
+ HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
{
}
const char* Name()
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index f921305fcc..b296b28503 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -42,8 +42,8 @@ static const size_t MAX_HEADERS_SIZE = 8192;
class HTTPWorkItem : public HTTPClosure
{
public:
- HTTPWorkItem(std::unique_ptr<HTTPRequest> req, const std::string &path, const HTTPRequestHandler& func):
- req(std::move(req)), path(path), func(func)
+ HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
+ req(std::move(_req)), path(_path), func(_func)
{
}
void operator()()
@@ -92,8 +92,8 @@ private:
};
public:
- WorkQueue(size_t maxDepth) : running(true),
- maxDepth(maxDepth),
+ WorkQueue(size_t _maxDepth) : running(true),
+ maxDepth(_maxDepth),
numThreads(0)
{
}
@@ -158,8 +158,8 @@ public:
struct HTTPPathHandler
{
HTTPPathHandler() {}
- HTTPPathHandler(std::string prefix, bool exactMatch, HTTPRequestHandler handler):
- prefix(prefix), exactMatch(exactMatch), handler(handler)
+ HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):
+ prefix(_prefix), exactMatch(_exactMatch), handler(_handler)
{
}
std::string prefix;
@@ -522,8 +522,8 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data)
delete self;
}
-HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void(void)>& handler):
- deleteWhenTriggered(deleteWhenTriggered), handler(handler)
+HTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function<void(void)>& _handler):
+ deleteWhenTriggered(_deleteWhenTriggered), handler(_handler)
{
ev = event_new(base, -1, 0, httpevent_callback_fn, this);
assert(ev);
@@ -539,7 +539,7 @@ void HTTPEvent::trigger(struct timeval* tv)
else
evtimer_add(ev, tv); // trigger after timeval passed
}
-HTTPRequest::HTTPRequest(struct evhttp_request* req) : req(req),
+HTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req),
replySent(false)
{
}
diff --git a/src/httpserver.h b/src/httpserver.h
index 0e30e666a6..49d67f4b88 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -33,7 +33,7 @@ void InterruptHTTPServer();
void StopHTTPServer();
/** Handler for requests to a certain HTTP path */
-typedef std::function<void(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
+typedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
/** Register handler for prefix.
* If multiple handlers match a prefix, the first-registered one will
* be invoked.
diff --git a/src/init.cpp b/src/init.cpp
index 51784fe06b..27843fa882 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -162,7 +162,7 @@ public:
static CCoinsViewDB *pcoinsdbview = NULL;
static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
-static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle;
+static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
void Interrupt(boost::thread_group& threadGroup)
{
@@ -380,7 +380,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY));
- strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));
+ strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));
strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET));
#ifdef ENABLE_WALLET
@@ -483,7 +483,7 @@ std::string LicenseInfo()
{
const std::string URL_SOURCE_CODE = "<https://github.com/bitcoin/bitcoin>";
const std::string URL_WEBSITE = "<https://bitcoincore.org>";
- // todo: remove urls from translations on next change
+
return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2009, COPYRIGHT_YEAR) + " ") + "\n" +
"\n" +
strprintf(_("Please contribute if you find %s useful. "
@@ -495,9 +495,9 @@ std::string LicenseInfo()
"\n" +
"\n" +
_("This is experimental software.") + "\n" +
- _("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.") + "\n" +
+ strprintf(_("Distributed under the MIT software license, see the accompanying file %s or %s"), "COPYING", "<https://opensource.org/licenses/MIT>") + "\n" +
"\n" +
- _("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.") +
+ strprintf(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard."), "<https://www.openssl.org>") +
"\n";
}
@@ -1067,7 +1067,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LogPrintf("Using data directory %s\n", strDataDir);
LogPrintf("Using config file %s\n", GetConfigFile().string());
LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD);
- std::ostringstream strErrors;
LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);
if (nScriptCheckThreads) {
@@ -1184,8 +1183,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
fRelayTxes = !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
- bool fBound = false;
if (fListen) {
+ bool fBound = false;
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) {
CService addrBind;
@@ -1271,7 +1270,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// cache size calculations
int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
- nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache
+ nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache
int64_t nBlockTreeDBCache = nTotalCache / 8;
nBlockTreeDBCache = std::min(nBlockTreeDBCache, (GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20);
nTotalCache -= nBlockTreeDBCache;
@@ -1492,18 +1491,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 11: start node
- if (!strErrors.str().empty())
- return InitError(strErrors.str());
-
//// debug print
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
LogPrintf("nBestHeight = %d\n", chainActive.Height());
-#ifdef ENABLE_WALLET
- LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0);
- LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0);
- LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
-#endif
-
if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl(threadGroup, scheduler);
@@ -1516,9 +1506,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#ifdef ENABLE_WALLET
if (pwalletMain) {
- // Add wallet transactions that aren't already in a block to mapTransactions
- pwalletMain->ReacceptWalletTransactions();
-
// Run a thread to flush wallet periodically
threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
}
diff --git a/src/main.cpp b/src/main.cpp
index db457f6f53..aed9591f99 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -196,7 +196,7 @@ namespace {
*
* Memory used: 1.3 MB
*/
- boost::scoped_ptr<CRollingBloomFilter> recentRejects;
+ std::unique_ptr<CRollingBloomFilter> recentRejects;
uint256 hashRecentRejectsChainTip;
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
@@ -532,7 +532,7 @@ CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) {
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
* at most count entries. */
-void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller) {
+void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) {
if (count == 0)
return;
@@ -589,6 +589,10 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl
// We consider the chain that this peer is on invalid.
return;
}
+ if (!State(nodeid)->fHaveWitness && IsWitnessEnabled(pindex->pprev, consensusParams)) {
+ // We wouldn't download this block or its descendants from this peer.
+ return;
+ }
if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
if (pindex->nChainTx)
state->pindexLastCommonBlock = pindex;
@@ -1174,7 +1178,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// nSequence >= maxint-1 on all inputs.
//
// maxint-1 is picked to still allow use of nLockTime by
- // non-replacable transactions. All inputs rather than just one
+ // non-replaceable transactions. All inputs rather than just one
// is for the sake of multi-party protocols, where we don't
// want a single party to be able to disable replacement.
//
@@ -1492,12 +1496,13 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true)) {
+ PrecomputedTransactionData txdata(tx);
+ if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata)) {
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
- if (CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true) &&
- !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true)) {
+ if (CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) &&
+ !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata)) {
// Only the witness is wrong, so the transaction itself may be fine.
state.SetCorruptionPossible();
}
@@ -1513,7 +1518,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
- if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
+ if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata))
{
return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s",
__func__, hash.ToString(), FormatStateMessage(state));
@@ -1910,7 +1915,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
const CScriptWitness *witness = (nIn < ptxTo->wit.vtxinwit.size()) ? &ptxTo->wit.vtxinwit[nIn].scriptWitness : NULL;
- if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore), &error)) {
+ if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) {
return false;
}
return true;
@@ -1969,7 +1974,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
}
}// namespace Consensus
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
@@ -1988,7 +1993,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// is safe because block merkle hashes are still computed and checked,
// and any change will be caught at the next checkpoint. Of course, if
// the checkpoint is for a chain that's invalid due to false scriptSigs
- // this optimisation would allow an invalid chain to be accepted.
+ // this optimization would allow an invalid chain to be accepted.
if (fScriptChecks) {
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const COutPoint &prevout = tx.vin[i].prevout;
@@ -1996,7 +2001,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
assert(coins);
// Verify signature
- CScriptCheck check(*coins, tx, i, flags, cacheStore);
+ CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -2009,7 +2014,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check2(*coins, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
@@ -2405,6 +2410,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
vPos.reserve(block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
+ std::vector<PrecomputedTransactionData> txdata;
+ txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
const CTransaction &tx = block.vtx[i];
@@ -2451,13 +2458,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
+ txdata.emplace_back(tx);
if (!tx.IsCoinBase())
{
nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
- if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL))
+ if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : NULL))
return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state));
control.Add(vChecks);
@@ -3942,7 +3950,7 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
// Create new
CBlockIndex* pindexNew = new CBlockIndex();
if (!pindexNew)
- throw runtime_error("LoadBlockIndex(): new CBlockIndex failed");
+ throw runtime_error(std::string(__func__) + ": new CBlockIndex failed");
mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
@@ -4633,6 +4641,7 @@ std::string GetWarnings(const std::string& strFor)
string strStatusBar;
string strRPC;
string strGUI;
+ const string uiAlertSeperator = "<hr />";
if (!CLIENT_VERSION_IS_RELEASE) {
strStatusBar = "This is a pre-release test build - use at your own risk - do not use for mining or merchant applications";
@@ -4645,18 +4654,19 @@ std::string GetWarnings(const std::string& strFor)
// Misc warnings like out of disk space and clock is wrong
if (strMiscWarning != "")
{
- strStatusBar = strGUI = strMiscWarning;
+ strStatusBar = strMiscWarning;
+ strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + strMiscWarning;
}
if (fLargeWorkForkFound)
{
strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
- strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
+ strGUI += strGUI.empty() ? "" : uiAlertSeperator + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
}
else if (fLargeWorkInvalidChainFound)
{
strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
- strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
+ strGUI += strGUI.empty() ? "" : uiAlertSeperator + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
}
if (strFor == "gui")
@@ -4801,7 +4811,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
{
// If a peer is asking for old blocks, we're almost guaranteed
// they wont have a useful mempool to match against a compact block,
- // and we dont feel like constructing the object for them, so
+ // and we don't feel like constructing the object for them, so
// instead we respond with the full, non-compact block.
if (mi->second->nHeight >= chainActive.Height() - 10) {
CBlockHeaderAndShortTxIDs cmpctblock(block);
@@ -4903,6 +4913,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (strCommand == NetMsgType::VERSION)
{
+ // Feeler connections exist only to verify if address is online.
+ if (pfrom->fFeeler) {
+ assert(pfrom->fInbound == false);
+ pfrom->fDisconnect = true;
+ }
+
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
@@ -5005,11 +5021,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CAddress addr = GetLocalAddress(&pfrom->addr);
if (addr.IsRoutable())
{
- LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
+ LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr);
} else if (IsPeerAddrLocalGood(pfrom)) {
addr.SetIP(pfrom->addrLocal);
- LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString());
+ LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
pfrom->PushAddress(addr);
}
}
@@ -5387,7 +5403,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
vector<CBlock> vHeaders;
int nLimit = MAX_HEADERS_RESULTS;
- LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id);
+ LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom->id);
for (; pindex; pindex = chainActive.Next(pindex))
{
vHeaders.push_back(pindex->GetBlockHeader());
@@ -6705,15 +6721,13 @@ bool SendMessages(CNode* pto)
if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
vector<CBlockIndex*> vToDownload;
NodeId staller = -1;
- FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
+ FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
- if (State(pto->GetId())->fHaveWitness || !IsWitnessEnabled(pindex->pprev, consensusParams)) {
- uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
- vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
- MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
- LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
- pindex->nHeight, pto->id);
- }
+ uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
+ vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
+ MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
+ LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
+ pindex->nHeight, pto->id);
}
if (state.nBlocksInFlight == 0 && staller != -1) {
if (State(staller)->nStallingSince == 0) {
diff --git a/src/main.h b/src/main.h
index d4d70c0180..7a2d432628 100644
--- a/src/main.h
+++ b/src/main.h
@@ -38,6 +38,7 @@ class CScriptCheck;
class CTxMemPool;
class CValidationInterface;
class CValidationState;
+class PrecomputedTransactionData;
struct CNodeStateStats;
struct LockPoints;
@@ -191,7 +192,7 @@ extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
-static const signed int DEFAULT_CHECKBLOCKS = MIN_BLOCKS_TO_KEEP;
+static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat)
@@ -214,7 +215,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
* block is made active. Note that it does not, however, guarantee that the
* specific block passed to it has been checked for validity!
*
- * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
+ * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganization; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
* @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
* @param[in] pblock The block we want to process.
* @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers.
@@ -347,7 +348,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
* instead of being performed inline.
*/
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
- unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL);
+ unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = NULL);
/** Apply the effects of this transaction on the UTXO set represented by view */
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
@@ -421,12 +422,13 @@ private:
unsigned int nFlags;
bool cacheStore;
ScriptError error;
+ PrecomputedTransactionData *txdata;
public:
CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
- CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) :
+ CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue),
- ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { }
+ ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()();
@@ -438,6 +440,7 @@ public:
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
std::swap(error, check.error);
+ std::swap(txdata, check.txdata);
}
ScriptError GetScriptError() const { return error; }
diff --git a/src/net.cpp b/src/net.cpp
index 8fbd8fd192..c5b080f794 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -43,6 +43,9 @@
// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
#define DUMP_ADDRESSES_INTERVAL 900
+// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
+#define FEELER_SLEEP_WINDOW 1
+
#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
@@ -61,6 +64,7 @@
namespace {
const int MAX_OUTBOUND_CONNECTIONS = 8;
+ const int MAX_FEELER_CONNECTIONS = 1;
struct ListenSocket {
SOCKET socket;
@@ -217,7 +221,7 @@ void AdvertiseLocal(CNode *pnode)
}
if (addrLocal.IsRoutable())
{
- LogPrintf("AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
+ LogPrint("net", "AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
pnode->PushAddress(addrLocal);
}
}
@@ -1017,7 +1021,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
CAddress addr;
int nInbound = 0;
- int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS;
+ int nMaxInbound = nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS);
+ assert(nMaxInbound > 0);
if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
@@ -1613,6 +1618,9 @@ void ThreadOpenConnections()
// Initiate network connections
int64_t nStart = GetTime();
+
+ // Minimum time before next feeler connection (in microseconds).
+ int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);
while (true)
{
ProcessOneShot();
@@ -1652,13 +1660,36 @@ void ThreadOpenConnections()
}
}
}
+ assert(nOutbound <= (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS));
- int64_t nANow = GetAdjustedTime();
+ // Feeler Connections
+ //
+ // Design goals:
+ // * Increase the number of connectable addresses in the tried table.
+ //
+ // Method:
+ // * Choose a random address from new and attempt to connect to it if we can connect
+ // successfully it is added to tried.
+ // * Start attempting feeler connections only after node finishes making outbound
+ // connections.
+ // * Only make a feeler connection once every few minutes.
+ //
+ bool fFeeler = false;
+ if (nOutbound >= MAX_OUTBOUND_CONNECTIONS) {
+ int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
+ if (nTime > nNextFeeler) {
+ nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
+ fFeeler = true;
+ } else {
+ continue;
+ }
+ }
+ int64_t nANow = GetAdjustedTime();
int nTries = 0;
while (true)
{
- CAddrInfo addr = addrman.Select();
+ CAddrInfo addr = addrman.Select(fFeeler);
// if we selected an invalid address, restart
if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
@@ -1682,7 +1713,7 @@ void ThreadOpenConnections()
if (nANow - addr.nLastTry < 600 && nTries < 30)
continue;
- // only consider nodes missing relevant services after 40 failed attemps
+ // only consider nodes missing relevant services after 40 failed attempts
if ((addr.nServices & nRelevantServices) != nRelevantServices && nTries < 40)
continue;
@@ -1694,8 +1725,17 @@ void ThreadOpenConnections()
break;
}
- if (addrConnect.IsValid())
- OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant);
+ if (addrConnect.IsValid()) {
+
+ if (fFeeler) {
+ // Add small amount of random noise before connection to avoid synchronization.
+ int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000);
+ MilliSleep(randsleep);
+ LogPrint("net", "Making feeler connection to %s\n", addrConnect.ToString());
+ }
+
+ OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, NULL, false, fFeeler);
+ }
}
}
@@ -1777,7 +1817,7 @@ void ThreadOpenAddedConnections()
}
// if successful, this moves the passed grant to the constructed node
-bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot)
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler)
{
//
// Initiate outbound network connection
@@ -1801,6 +1841,8 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem
pnode->fNetworkNode = true;
if (fOneShot)
pnode->fOneShot = true;
+ if (fFeeler)
+ pnode->fFeeler = true;
return true;
}
@@ -2062,7 +2104,7 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (semOutbound == NULL) {
// initialize semaphore
- int nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections);
+ int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections);
semOutbound = new CSemaphore(nMaxOutbound);
}
@@ -2107,7 +2149,7 @@ bool StopNode()
LogPrintf("StopNode()\n");
MapPort(false);
if (semOutbound)
- for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
+ for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++)
semOutbound->post();
if (fAddressesInitialized)
@@ -2448,6 +2490,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
fWhitelisted = false;
fOneShot = false;
fClient = false; // set by version message
+ fFeeler = false;
fInbound = fInboundIn;
fNetworkNode = false;
fSuccessfullyConnected = false;
diff --git a/src/net.h b/src/net.h
index b5ebe66ce0..b9cc81e4e9 100644
--- a/src/net.h
+++ b/src/net.h
@@ -41,6 +41,8 @@ namespace boost {
static const int PING_INTERVAL = 2 * 60;
/** Time after which to disconnect, after waiting for a ping response (or inactivity). */
static const int TIMEOUT_INTERVAL = 20 * 60;
+/** Run the feeler connection loop once every 2 minutes or 120 seconds. **/
+static const int FEELER_INTERVAL = 120;
/** The maximum number of entries in an 'inv' protocol message */
static const unsigned int MAX_INV_SZ = 50000;
/** The maximum number of new addresses to accumulate before announcing. */
@@ -89,7 +91,7 @@ CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
CNode* FindNode(const NodeId id); //TODO: Remove this
-bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
+bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
@@ -350,6 +352,7 @@ public:
// the network or wire types and the cleaned string used when displayed or logged.
std::string strSubVer, cleanSubVer;
bool fWhitelisted; // This peer can bypass DoS banning.
+ bool fFeeler; // If true this node is being used as a short lived feeler.
bool fOneShot;
bool fClient;
bool fInbound;
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 8d63805643..2fdc59ea07 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -100,7 +100,7 @@ CAmount CTransaction::GetValueOut() const
{
nValueOut += it->nValue;
if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut))
- throw std::runtime_error("CTransaction::GetValueOut(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nValueOut;
}
diff --git a/src/protocol.h b/src/protocol.h
index 015215b2a6..9b474ec79c 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -267,6 +267,9 @@ enum ServiceFlags : uint64_t {
// Indicates that a node can be asked for blocks and transactions including
// witness data.
NODE_WITNESS = (1 << 3),
+ // NODE_XTHIN means the node supports Xtreme Thinblocks
+ // If this is turned off then the node will not service nor make xthin requests
+ NODE_XTHIN = (1 << 4),
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 64b5c83d72..430e6dd0e8 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -578,7 +578,8 @@ int main(int argc, char *argv[])
/// 5. Now that settings and translations are available, ask user for data directory
// User language is set up: pick a data directory
- Intro::pickDataDirectory();
+ if (!Intro::pickDataDirectory())
+ return 0;
/// 6. Determine availability of data directory and parse bitcoin.conf
/// - Do not call GetDataDir(true) before this step finishes
diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc
index 24b0bae3ec..ca5b1fa673 100644
--- a/src/qt/bitcoin.qrc
+++ b/src/qt/bitcoin.qrc
@@ -50,6 +50,8 @@
<file alias="fontsmaller">res/icons/fontsmaller.png</file>
<file alias="prompticon">res/icons/chevron.png</file>
<file alias="transaction_abandoned">res/icons/transaction_abandoned.png</file>
+ <file alias="hd_enabled">res/icons/hd_enabled.png</file>
+ <file alias="hd_disabled">res/icons/hd_disabled.png</file>
</qresource>
<qresource prefix="/movies">
<file alias="spinner-000">res/movies/spinner-000.png</file>
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 2afefb733e..272df3fdae 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -80,7 +80,8 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
clientModel(0),
walletFrame(0),
unitDisplayControl(0),
- labelEncryptionIcon(0),
+ labelWalletEncryptionIcon(0),
+ labelWalletHDStatusIcon(0),
labelConnectionsIcon(0),
labelBlocksIcon(0),
progressBarLabel(0),
@@ -194,7 +195,8 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
frameBlocksLayout->setContentsMargins(3,0,3,0);
frameBlocksLayout->setSpacing(3);
unitDisplayControl = new UnitDisplayStatusBarControl(platformStyle);
- labelEncryptionIcon = new QLabel();
+ labelWalletEncryptionIcon = new QLabel();
+ labelWalletHDStatusIcon = new QLabel();
labelConnectionsIcon = new QLabel();
labelBlocksIcon = new QLabel();
if(enableWallet)
@@ -202,7 +204,8 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(unitDisplayControl);
frameBlocksLayout->addStretch();
- frameBlocksLayout->addWidget(labelEncryptionIcon);
+ frameBlocksLayout->addWidget(labelWalletEncryptionIcon);
+ frameBlocksLayout->addWidget(labelWalletHDStatusIcon);
}
frameBlocksLayout->addStretch();
frameBlocksLayout->addWidget(labelConnectionsIcon);
@@ -988,28 +991,37 @@ bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient)
return false;
}
+void BitcoinGUI::setHDStatus(int hdEnabled)
+{
+ labelWalletHDStatusIcon->setPixmap(platformStyle->SingleColorIcon(hdEnabled ? ":/icons/hd_enabled" : ":/icons/hd_disabled").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelWalletHDStatusIcon->setToolTip(hdEnabled ? tr("HD key generation is <b>enabled</b>") : tr("HD key generation is <b>disabled</b>"));
+
+ // eventually disable the QLabel to set its opacity to 50%
+ labelWalletHDStatusIcon->setEnabled(hdEnabled);
+}
+
void BitcoinGUI::setEncryptionStatus(int status)
{
switch(status)
{
case WalletModel::Unencrypted:
- labelEncryptionIcon->hide();
+ labelWalletEncryptionIcon->hide();
encryptWalletAction->setChecked(false);
changePassphraseAction->setEnabled(false);
encryptWalletAction->setEnabled(true);
break;
case WalletModel::Unlocked:
- labelEncryptionIcon->show();
- labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
- labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
+ labelWalletEncryptionIcon->show();
+ labelWalletEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
break;
case WalletModel::Locked:
- labelEncryptionIcon->show();
- labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
- labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
+ labelWalletEncryptionIcon->show();
+ labelWalletEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelWalletEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 12e7702ed8..41770929b4 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -82,7 +82,8 @@ private:
WalletFrame *walletFrame;
UnitDisplayStatusBarControl *unitDisplayControl;
- QLabel *labelEncryptionIcon;
+ QLabel *labelWalletEncryptionIcon;
+ QLabel *labelWalletHDStatusIcon;
QLabel *labelConnectionsIcon;
QLabel *labelBlocksIcon;
QLabel *progressBarLabel;
@@ -169,6 +170,12 @@ public Q_SLOTS:
*/
void setEncryptionStatus(int status);
+ /** Set the hd-enabled status as shown in the UI.
+ @param[in] status current hd enabled status
+ @see WalletModel::EncryptionStatus
+ */
+ void setHDStatus(int hdEnabled);
+
bool handlePaymentRequest(const SendCoinsRecipient& recipient);
/** Show incoming transaction notification for new transactions. */
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 837f8ba6c1..f53242100c 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -76,7 +76,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
- QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
@@ -85,7 +84,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(clipboardFee()));
connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(clipboardAfterFee()));
connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(clipboardBytes()));
- connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(clipboardPriority()));
connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(clipboardLowOutput()));
connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(clipboardChange()));
@@ -94,7 +92,6 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
ui->labelCoinControlFee->addAction(clipboardFeeAction);
ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
ui->labelCoinControlBytes->addAction(clipboardBytesAction);
- ui->labelCoinControlPriority->addAction(clipboardPriorityAction);
ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
ui->labelCoinControlChange->addAction(clipboardChangeAction);
@@ -124,16 +121,14 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString());
ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84);
- ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100);
- ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170);
- ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 290);
- ui->treeWidget->setColumnWidth(COLUMN_DATE, 110);
- ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100);
- ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100);
+ ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 110);
+ ui->treeWidget->setColumnWidth(COLUMN_LABEL, 190);
+ ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 320);
+ ui->treeWidget->setColumnWidth(COLUMN_DATE, 130);
+ ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 110);
ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it
- ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but don't show it
// default view is sorted by amount desc
@@ -325,12 +320,6 @@ void CoinControlDialog::clipboardBytes()
GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));
}
-// copy label "Priority" to clipboard
-void CoinControlDialog::clipboardPriority()
-{
- GUIUtil::setClipboard(ui->labelCoinControlPriority->text());
-}
-
// copy label "Dust" to clipboard
void CoinControlDialog::clipboardLowOutput()
{
@@ -419,25 +408,6 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
#endif
}
-// return human readable label for priority number
-QString CoinControlDialog::getPriorityLabel(double dPriority, double mempoolEstimatePriority)
-{
- double dPriorityMedium = mempoolEstimatePriority;
-
- if (dPriorityMedium <= 0)
- dPriorityMedium = AllowFreeThreshold(); // not enough data, back to hard-coded
-
- if (dPriority / 1000000 > dPriorityMedium) return tr("highest");
- else if (dPriority / 100000 > dPriorityMedium) return tr("higher");
- else if (dPriority / 10000 > dPriorityMedium) return tr("high");
- else if (dPriority / 1000 > dPriorityMedium) return tr("medium-high");
- else if (dPriority > dPriorityMedium) return tr("medium");
- else if (dPriority * 10 > dPriorityMedium) return tr("low-medium");
- else if (dPriority * 100 > dPriorityMedium) return tr("low");
- else if (dPriority * 1000 > dPriorityMedium) return tr("lower");
- else return tr("lowest");
-}
-
// shows count of locked unspent outputs
void CoinControlDialog::updateLabelLocked()
{
@@ -473,7 +443,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
}
}
- QString sPriorityLabel = tr("none");
CAmount nAmount = 0;
CAmount nPayFee = 0;
CAmount nAfterFee = 0;
@@ -551,11 +520,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes += nQuantity; // account for the witness byte that holds the number of stack items for each input.
}
- // Priority
- double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
- dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
- sPriorityLabel = CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority);
-
// in the subtract fee from amount case, we can tell if zero change already and subtract the bytes, so that fee calculation afterwards is accurate
if (CoinControlDialog::fSubtractFeeFromAmount)
if (nAmount - nPayAmount == 0)
@@ -568,6 +532,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// Allow free? (require at least hard-coded threshold and default to that if no estimate)
+ double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
+ dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
double dPriorityNeeded = std::max(mempoolEstimatePriority, AllowFreeThreshold());
fAllowFree = (dPriority >= dPriorityNeeded);
@@ -617,7 +583,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
QLabel *l3 = dialog->findChild<QLabel *>("labelCoinControlFee");
QLabel *l4 = dialog->findChild<QLabel *>("labelCoinControlAfterFee");
QLabel *l5 = dialog->findChild<QLabel *>("labelCoinControlBytes");
- QLabel *l6 = dialog->findChild<QLabel *>("labelCoinControlPriority");
QLabel *l7 = dialog->findChild<QLabel *>("labelCoinControlLowOutput");
QLabel *l8 = dialog->findChild<QLabel *>("labelCoinControlChange");
@@ -633,7 +598,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee
l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee
l5->setText(((nBytes > 0) ? ASYMP_UTF8 : "") + QString::number(nBytes)); // Bytes
- l6->setText(sPriorityLabel); // Priority
l7->setText(fDust ? tr("yes") : tr("no")); // Dust
l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change
if (nPayFee > 0 && (coinControl->nMinimumTotalFee < nPayFee))
@@ -644,21 +608,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l8->setText(ASYMP_UTF8 + l8->text());
}
- // turn labels "red"
- l5->setStyleSheet((nBytes >= MAX_FREE_TRANSACTION_CREATE_SIZE) ? "color:red;" : "");// Bytes >= 1000
- l6->setStyleSheet((dPriority > 0 && !fAllowFree) ? "color:red;" : ""); // Priority < "medium"
- l7->setStyleSheet((fDust) ? "color:red;" : ""); // Dust = "yes"
+ // turn label red when dust
+ l7->setStyleSheet((fDust) ? "color:red;" : "");
// tool tips
- QString toolTip1 = tr("This label turns red if the transaction size is greater than 1000 bytes.") + "<br /><br />";
- toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))) + "<br /><br />";
- toolTip1 += tr("Can vary +/- 1 byte per input.");
-
- QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />";
- toolTip2 += tr("This label turns red if the priority is smaller than \"medium\".") + "<br /><br />";
- toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000)));
-
- QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
+ QString toolTipDust = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
// how many satoshis the estimated fee can vary per byte we guess wrong
double dFeeVary;
@@ -671,14 +625,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
l3->setToolTip(toolTip4);
l4->setToolTip(toolTip4);
- l5->setToolTip(toolTip1);
- l6->setToolTip(toolTip2);
- l7->setToolTip(toolTip3);
+ l7->setToolTip(toolTipDust);
l8->setToolTip(toolTip4);
dialog->findChild<QLabel *>("labelCoinControlFeeText") ->setToolTip(l3->toolTip());
dialog->findChild<QLabel *>("labelCoinControlAfterFeeText") ->setToolTip(l4->toolTip());
dialog->findChild<QLabel *>("labelCoinControlBytesText") ->setToolTip(l5->toolTip());
- dialog->findChild<QLabel *>("labelCoinControlPriorityText") ->setToolTip(l6->toolTip());
dialog->findChild<QLabel *>("labelCoinControlLowOutputText")->setToolTip(l7->toolTip());
dialog->findChild<QLabel *>("labelCoinControlChangeText") ->setToolTip(l8->toolTip());
@@ -702,7 +653,6 @@ void CoinControlDialog::updateView()
QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
- double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
std::map<QString, std::vector<COutput> > mapCoins;
model->listCoins(mapCoins);
@@ -731,11 +681,8 @@ void CoinControlDialog::updateView()
}
CAmount nSum = 0;
- double dPrioritySum = 0;
int nChildren = 0;
- int nInputSum = 0;
BOOST_FOREACH(const COutput& out, coins.second) {
- int nInputSize = 0;
nSum += out.tx->vout[out.i].nValue;
nChildren++;
@@ -755,11 +702,6 @@ void CoinControlDialog::updateView()
// if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs
if (!treeMode || (!(sAddress == sWalletAddress)))
itemOutput->setText(COLUMN_ADDRESS, sAddress);
-
- CPubKey pubkey;
- CKeyID *keyid = boost::get<CKeyID>(&outputAddress);
- if (keyid && model->getPubKey(*keyid, pubkey) && !pubkey.IsCompressed())
- nInputSize = 29; // 29 = 180 - 151 (public key is 180 bytes, priority free area is 151 bytes)
}
// label
@@ -788,13 +730,6 @@ void CoinControlDialog::updateView()
// confirmations
itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " "));
- // priority
- double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10
- itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority));
- itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " "));
- dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1);
- nInputSum += nInputSize;
-
// transaction hash
uint256 txhash = out.tx->GetHash();
itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(txhash.GetHex()));
@@ -819,12 +754,9 @@ void CoinControlDialog::updateView()
// amount
if (treeMode)
{
- dPrioritySum = dPrioritySum / (nInputSum + 78);
itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")");
itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum));
itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " "));
- itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum, mempoolEstimatePriority));
- itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " "));
}
}
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 1a467eb2ff..7d73421e3a 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -40,7 +40,6 @@ public:
// static because also called from sendcoinsdialog
static void updateLabels(WalletModel*, QDialog*);
- static QString getPriorityLabel(double dPriority, double mempoolEstimatePriority);
static QList<CAmount> payAmounts;
static CCoinControl *coinControl;
@@ -72,11 +71,9 @@ private:
COLUMN_ADDRESS,
COLUMN_DATE,
COLUMN_CONFIRMATIONS,
- COLUMN_PRIORITY,
COLUMN_TXHASH,
COLUMN_VOUT_INDEX,
COLUMN_AMOUNT_INT64,
- COLUMN_PRIORITY_INT64,
COLUMN_DATE_INT64
};
@@ -87,8 +84,6 @@ private:
{
if (column == COLUMN_AMOUNT_INT64)
return COLUMN_AMOUNT;
- else if (column == COLUMN_PRIORITY_INT64)
- return COLUMN_PRIORITY;
else if (column == COLUMN_DATE_INT64)
return COLUMN_DATE;
}
@@ -96,8 +91,6 @@ private:
{
if (column == COLUMN_AMOUNT)
return COLUMN_AMOUNT_INT64;
- else if (column == COLUMN_PRIORITY)
- return COLUMN_PRIORITY_INT64;
else if (column == COLUMN_DATE)
return COLUMN_DATE_INT64;
}
@@ -118,7 +111,6 @@ private Q_SLOTS:
void clipboardFee();
void clipboardAfterFee();
void clipboardBytes();
- void clipboardPriority();
void clipboardLowOutput();
void clipboardChange();
void radioTreeMode(bool);
diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui
index c1fef6b9b1..1ea00eb5c3 100644
--- a/src/qt/forms/coincontroldialog.ui
+++ b/src/qt/forms/coincontroldialog.ui
@@ -140,7 +140,10 @@
</widget>
</item>
<item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlPriorityText">
+ <widget class="QLabel" name="labelCoinControlLowOutputText">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="font">
<font>
<weight>75</weight>
@@ -148,12 +151,15 @@
</font>
</property>
<property name="text">
- <string>Priority:</string>
+ <string>Dust:</string>
</property>
</widget>
</item>
<item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlPriority">
+ <widget class="QLabel" name="labelCoinControlLowOutput">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -161,7 +167,7 @@
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="text">
- <string notr="true">medium</string>
+ <string notr="true">no</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -213,41 +219,6 @@
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlLowOutputText">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Dust:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlLowOutput">
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="contextMenuPolicy">
- <enum>Qt::ActionsContextMenu</enum>
- </property>
- <property name="text">
- <string notr="true">no</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
</layout>
</item>
<item>
@@ -431,7 +402,7 @@
<bool>false</bool>
</property>
<property name="columnCount">
- <number>12</number>
+ <number>10</number>
</property>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>true</bool>
@@ -474,16 +445,6 @@
</column>
<column>
<property name="text">
- <string>Priority</string>
- </property>
- </column>
- <column>
- <property name="text">
- <string/>
- </property>
- </column>
- <column>
- <property name="text">
<string/>
</property>
</column>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index 12d6a62c08..06e09074d1 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -332,7 +332,7 @@
</widget>
</item>
<item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlPriorityText">
+ <widget class="QLabel" name="labelCoinControlLowOutputText">
<property name="font">
<font>
<weight>75</weight>
@@ -340,12 +340,12 @@
</font>
</property>
<property name="text">
- <string>Priority:</string>
+ <string>Dust:</string>
</property>
</widget>
</item>
<item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlPriority">
+ <widget class="QLabel" name="labelCoinControlLowOutput">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -353,7 +353,7 @@
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="text">
- <string notr="true">medium</string>
+ <string notr="true">no</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
@@ -411,36 +411,7 @@
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="labelCoinControlLowOutputText">
- <property name="font">
- <font>
- <weight>75</weight>
- <bold>true</bold>
- </font>
- </property>
- <property name="text">
- <string>Dust:</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLabel" name="labelCoinControlLowOutput">
- <property name="cursor">
- <cursorShape>IBeamCursor</cursorShape>
- </property>
- <property name="contextMenuPolicy">
- <enum>Qt::ActionsContextMenu</enum>
- </property>
- <property name="text">
- <string notr="true">no</string>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
- </property>
- </widget>
- </item>
- </layout>
+ </layout>
</item>
<item>
<layout class="QFormLayout" name="formLayoutCoinControl4">
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 947a4c6821..c00f5e8591 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -930,6 +930,9 @@ QString formatServicesStr(quint64 mask)
case NODE_WITNESS:
strList.append("WITNESS");
break;
+ case NODE_XTHIN:
+ strList.append("XTHIN");
+ break;
default:
strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check));
}
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 6d6af54290..1a241ae0f0 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -165,20 +165,20 @@ QString Intro::getDefaultDataDirectory()
return GUIUtil::boostPathToQString(GetDefaultDataDir());
}
-void Intro::pickDataDirectory()
+bool Intro::pickDataDirectory()
{
namespace fs = boost::filesystem;
QSettings settings;
/* If data directory provided on command line, no need to look at settings
or show a picking dialog */
if(!GetArg("-datadir", "").empty())
- return;
+ return true;
/* 1) Default data directory for operating system */
QString dataDir = getDefaultDataDirectory();
/* 2) Allow QSettings to override default dir */
dataDir = settings.value("strDataDir", dataDir).toString();
- if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR))
+ if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || GetBoolArg("-resetguisettings", false))
{
/* If current default data directory does not exist, let the user choose one */
Intro intro;
@@ -190,7 +190,7 @@ void Intro::pickDataDirectory()
if(!intro.exec())
{
/* Cancel clicked */
- exit(0);
+ return false;
}
dataDir = intro.getDataDirectory();
try {
@@ -204,6 +204,7 @@ void Intro::pickDataDirectory()
}
settings.setValue("strDataDir", dataDir);
+ settings.setValue("fReset", false);
}
/* Only override -datadir if different from the default, to make it possible to
* override -datadir in the bitcoin.conf file in the default data directory
@@ -211,6 +212,7 @@ void Intro::pickDataDirectory()
*/
if(dataDir != getDefaultDataDirectory())
SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
+ return true;
}
void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
diff --git a/src/qt/intro.h b/src/qt/intro.h
index 9e2e96dc9e..ee768a7ad8 100644
--- a/src/qt/intro.h
+++ b/src/qt/intro.h
@@ -35,10 +35,13 @@ public:
/**
* Determine data directory. Let the user choose if the current one doesn't exist.
*
+ * @returns true if a data directory was selected, false if the user cancelled the selection
+ * dialog.
+ *
* @note do NOT call global GetDataDir() before calling this function, this
* will cause the wrong path to be cached.
*/
- static void pickDataDirectory();
+ static bool pickDataDirectory();
/**
* Determine default data directory for operating system.
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index d33ab68277..f82e153b67 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -17,6 +17,7 @@
#include "net.h"
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults
+#include "intro.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
@@ -99,6 +100,9 @@ void OptionsModel::Init(bool resetSettings)
if (!SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
addOverriddenOption("-par");
+ if (!settings.contains("strDataDir"))
+ settings.setValue("strDataDir", Intro::getDefaultDataDirectory());
+
// Wallet
#ifdef ENABLE_WALLET
if (!settings.contains("bSpendZeroConfChange"))
@@ -151,9 +155,19 @@ void OptionsModel::Reset()
{
QSettings settings;
+ // Save the strDataDir setting
+ QString dataDir = Intro::getDefaultDataDirectory();
+ dataDir = settings.value("strDataDir", dataDir).toString();
+
// Remove all entries from our QSettings object
settings.clear();
+ // Set strDataDir
+ settings.setValue("strDataDir", dataDir);
+
+ // Set that this was reset
+ settings.setValue("fReset", true);
+
// default setting for OptionsModel::StartAtStartup - disabled
if (GUIUtil::GetStartOnSystemStartup())
GUIUtil::SetStartOnSystemStartup(false);
diff --git a/src/qt/res/icons/hd_disabled.png b/src/qt/res/icons/hd_disabled.png
new file mode 100644
index 0000000000..687b6d2e38
--- /dev/null
+++ b/src/qt/res/icons/hd_disabled.png
Binary files differ
diff --git a/src/qt/res/icons/hd_enabled.png b/src/qt/res/icons/hd_enabled.png
new file mode 100644
index 0000000000..568dde1cd1
--- /dev/null
+++ b/src/qt/res/icons/hd_enabled.png
Binary files differ
diff --git a/src/qt/res/src/hd_disabled.svg b/src/qt/res/src/hd_disabled.svg
new file mode 100644
index 0000000000..035f4431c7
--- /dev/null
+++ b/src/qt/res/src/hd_disabled.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 595.3 841.9" enable-background="new 0 0 595.3 841.9" xml:space="preserve">
+<g>
+ <path d="M81.3,336.5v66.8h70.4v-66.8H190v174h-38.3v-75.1H81.3v75.1H43v-174H81.3z"/>
+ <path d="M298.7,336.5c11.2,0,21.6,1.8,31.3,5.4c9.7,3.6,18,8.9,25.1,16.1c7.1,7.2,12.6,16.1,16.6,26.8c4,10.7,6,23.3,6,37.8
+ c0,12.7-1.6,24.4-4.9,35.1c-3.3,10.7-8.2,20-14.7,27.8c-6.6,7.8-14.8,13.9-24.6,18.4c-9.8,4.5-21.4,6.7-34.7,6.7h-75.1v-174H298.7z
+ M296,478.3c5.5,0,10.9-0.9,16.1-2.7c5.2-1.8,9.8-4.8,13.9-8.9c4.1-4.1,7.3-9.5,9.7-16.2c2.4-6.7,3.7-14.8,3.7-24.4
+ c0-8.8-0.9-16.7-2.6-23.8s-4.5-13.1-8.4-18.2c-3.9-5-9.1-8.9-15.5-11.6c-6.4-2.7-14.3-4-23.8-4h-27.3v109.7H296z"/>
+</g>
+<g>
+ <g>
+ <line x1="32" y1="555.9" x2="358" y2="293.9"/>
+ </g>
+ <g>
+ <path fill="#FFFFFF" d="M32,580.9c-7.3,0-14.6-3.2-19.5-9.3c-8.6-10.8-6.9-26.5,3.8-35.1l326-262c10.8-8.6,26.5-6.9,35.1,3.8
+ c8.6,10.8,6.9,26.5-3.8,35.1l-326,262C43,579.1,37.5,580.9,32,580.9z"/>
+ </g>
+ <g>
+ <path d="M32,573.9c-5.3,0-10.5-2.3-14-6.7c-6.2-7.7-5-19.1,2.8-25.3l326-262c7.8-6.2,19.1-5,25.3,2.8c6.2,7.7,5,19.1-2.8,25.3
+ l-326,262C40,572.6,36,573.9,32,573.9z"/>
+ </g>
+</g>
+</svg>
diff --git a/src/qt/res/src/hd_enabled.svg b/src/qt/res/src/hd_enabled.svg
new file mode 100644
index 0000000000..cbaa16f8f0
--- /dev/null
+++ b/src/qt/res/src/hd_enabled.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 595.3 841.9" enable-background="new 0 0 595.3 841.9" xml:space="preserve">
+<g>
+ <path d="M81.3,336.5v66.8h70.4v-66.8H190v174h-38.3v-75.1H81.3v75.1H43v-174H81.3z"/>
+ <path d="M298.7,336.5c11.2,0,21.6,1.8,31.3,5.4c9.7,3.6,18,8.9,25.1,16.1c7.1,7.2,12.6,16.1,16.6,26.8c4,10.7,6,23.3,6,37.8
+ c0,12.7-1.6,24.4-4.9,35.1c-3.3,10.7-8.2,20-14.7,27.8c-6.6,7.8-14.8,13.9-24.6,18.4c-9.8,4.5-21.4,6.7-34.7,6.7h-75.1v-174H298.7z
+ M296,478.3c5.5,0,10.9-0.9,16.1-2.7c5.2-1.8,9.8-4.8,13.9-8.9c4.1-4.1,7.3-9.5,9.7-16.2c2.4-6.7,3.7-14.8,3.7-24.4
+ c0-8.8-0.9-16.7-2.6-23.8s-4.5-13.1-8.4-18.2c-3.9-5-9.1-8.9-15.5-11.6c-6.4-2.7-14.3-4-23.8-4h-27.3v109.7H296z"/>
+</g>
+</svg>
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 6d50be56ec..3e96bb18c3 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -69,7 +69,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
QAction *clipboardFeeAction = new QAction(tr("Copy fee"), this);
QAction *clipboardAfterFeeAction = new QAction(tr("Copy after fee"), this);
QAction *clipboardBytesAction = new QAction(tr("Copy bytes"), this);
- QAction *clipboardPriorityAction = new QAction(tr("Copy priority"), this);
QAction *clipboardLowOutputAction = new QAction(tr("Copy dust"), this);
QAction *clipboardChangeAction = new QAction(tr("Copy change"), this);
connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity()));
@@ -77,7 +76,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
connect(clipboardFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardFee()));
connect(clipboardAfterFeeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAfterFee()));
connect(clipboardBytesAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardBytes()));
- connect(clipboardPriorityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardPriority()));
connect(clipboardLowOutputAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardLowOutput()));
connect(clipboardChangeAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardChange()));
ui->labelCoinControlQuantity->addAction(clipboardQuantityAction);
@@ -85,7 +83,6 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
ui->labelCoinControlFee->addAction(clipboardFeeAction);
ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction);
ui->labelCoinControlBytes->addAction(clipboardBytesAction);
- ui->labelCoinControlPriority->addAction(clipboardPriorityAction);
ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction);
ui->labelCoinControlChange->addAction(clipboardChangeAction);
@@ -681,12 +678,6 @@ void SendCoinsDialog::coinControlClipboardBytes()
GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace(ASYMP_UTF8, ""));
}
-// Coin Control: copy label "Priority" to clipboard
-void SendCoinsDialog::coinControlClipboardPriority()
-{
- GUIUtil::setClipboard(ui->labelCoinControlPriority->text());
-}
-
// Coin Control: copy label "Dust" to clipboard
void SendCoinsDialog::coinControlClipboardLowOutput()
{
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index be4f2ee44b..83dac0bd11 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -88,7 +88,6 @@ private Q_SLOTS:
void coinControlClipboardFee();
void coinControlClipboardAfterFee();
void coinControlClipboardBytes();
- void coinControlClipboardPriority();
void coinControlClipboardLowOutput();
void coinControlClipboardChange();
void setMinimumFee();
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 3867310cd6..ae7efc7a0d 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -683,3 +683,8 @@ bool WalletModel::abandonTransaction(uint256 hash) const
LOCK2(cs_main, wallet->cs_wallet);
return wallet->AbandonTransaction(hash);
}
+
+bool WalletModel::hdEnabled() const
+{
+ return wallet->IsHDEnabled();
+}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index e5470bf618..a15ecf899b 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -203,6 +203,8 @@ public:
bool transactionCanBeAbandoned(uint256 hash) const;
bool abandonTransaction(uint256 hash) const;
+ bool hdEnabled() const;
+
private:
CWallet *wallet;
bool fHaveWatchOnly;
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 6ce98ef160..495ebfd834 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -98,6 +98,9 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui)
// Pass through transaction notifications
connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString,QString)));
+
+ // Connect HD enabled state signal
+ connect(this, SIGNAL(hdEnabledStatusChanged(int)), gui, SLOT(setHDStatus(int)));
}
}
@@ -130,6 +133,9 @@ void WalletView::setWalletModel(WalletModel *walletModel)
connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int)));
updateEncryptionStatus();
+ // update HD status
+ Q_EMIT hdEnabledStatusChanged(walletModel->hdEnabled());
+
// Balloon pop-up for new transaction
connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(processNewTransaction(QModelIndex,int,int)));
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index dbb289f425..2045605954 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -117,6 +117,8 @@ Q_SIGNALS:
void message(const QString &title, const QString &message, unsigned int style);
/** Encryption status of wallet changed */
void encryptionStatusChanged(int status);
+ /** HD-Enabled status of wallet changed (only possible during startup) */
+ 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);
};
diff --git a/src/rest.cpp b/src/rest.cpp
index 2dff8d7dad..c815592124 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -420,7 +420,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// throw exception in case of a empty request
std::string strRequestMutable = req->ReadBody();
if (strRequestMutable.length() == 0 && uriParts.size() == 0)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
bool fInputParsed = false;
bool fCheckMemPool = false;
@@ -444,7 +444,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
std::string strOutput = uriParts[i].substr(uriParts[i].find("-")+1);
if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid))
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
txid.SetHex(strTxid);
vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput));
@@ -453,7 +453,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (vOutPoints.size() > 0)
fInputParsed = true;
else
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
}
switch (rf) {
@@ -469,7 +469,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (strRequestMutable.size() > 0)
{
if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Combination of URI scheme inputs and raw post data is not allowed");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Combination of URI scheme inputs and raw post data is not allowed");
CDataStream oss(SER_NETWORK, PROTOCOL_VERSION);
oss << strRequestMutable;
@@ -478,14 +478,14 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
}
} catch (const std::ios_base::failure& e) {
// abort in case of unreadable binary data
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
}
break;
}
case RF_JSON: {
if (!fInputParsed)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
break;
}
default: {
@@ -495,7 +495,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// limit max outpoints
if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
+ return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
// check spentness and form a bitmap (as well as a JSON capable human-readable string representation)
vector<unsigned char> bitmap;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index e3c32d905a..b90410017b 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -632,7 +632,7 @@ struct CCoinsStats
//! Calculate statistics about the unspent transaction output set
static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
{
- boost::scoped_ptr<CCoinsViewCursor> pcursor(view->Cursor());
+ std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
stats.hashBlock = pcursor->GetBestBlock();
@@ -1205,8 +1205,8 @@ static const CRPCCommand commands[] =
{ "hidden", "reconsiderblock", &reconsiderblock, true },
};
-void RegisterBlockchainRPCCommands(CRPCTable &tableRPC)
+void RegisterBlockchainRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index d0675fdb49..3003ea3452 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -26,7 +26,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{
{ "stop", 0 },
{ "setmocktime", 0 },
- { "getaddednodeinfo", 0 },
{ "generate", 0 },
{ "generate", 1 },
{ "generatetoaddress", 0 },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 2479e5d595..14183c8e82 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -227,10 +227,11 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
" \"currentblockweight\": nnn, (numeric) The last block weight\n"
" \"currentblocktx\": nnn, (numeric) The last block transaction\n"
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
- " \"errors\": \"...\" (string) Current errors\n"
+ " \"errors\": \"...\" (string) Current errors\n"
+ " \"networkhashps\": nnn, (numeric) The network hashes per second\n"
" \"pooledtx\": n (numeric) The size of the mem pool\n"
" \"testnet\": true|false (boolean) If using testnet or not\n"
- " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
+ " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmininginfo", "")
@@ -650,7 +651,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
if (nMaxVersionPreVB >= 2) {
// If VB is supported by the client, nMaxVersionPreVB is -1, so we won't get here
- // Because BIP 34 changed how the generation transaction is serialised, we can only use version/force back to v2 blocks
+ // Because BIP 34 changed how the generation transaction is serialized, we can only use version/force back to v2 blocks
// This is safe to do [otherwise-]unconditionally only because we are throwing an exception above if a non-force deployment gets activated
// Note that this can probably also be removed entirely after the first BIP9 non-force deployment (ie, probably segwit) gets activated
aMutable.push_back("version/force");
@@ -918,8 +919,8 @@ static const CRPCCommand commands[] =
{ "util", "estimatesmartpriority", &estimatesmartpriority, true },
};
-void RegisterMiningRPCCommands(CRPCTable &tableRPC)
+void RegisterMiningRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index a8c5bcd177..e96feaa864 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -498,8 +498,8 @@ static const CRPCCommand commands[] =
{ "hidden", "setmocktime", &setmocktime, true },
};
-void RegisterMiscRPCCommands(CRPCTable &tableRPC)
+void RegisterMiscRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 58cf4a56e0..840bfd5a24 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -269,14 +269,13 @@ UniValue disconnectnode(const UniValue& params, bool fHelp)
UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (fHelp || params.size() > 1)
throw runtime_error(
- "getaddednodeinfo dummy ( \"node\" )\n"
+ "getaddednodeinfo ( \"node\" )\n"
"\nReturns information about the given added node, or all added nodes\n"
"(note that onetry addnodes are not listed here)\n"
"\nArguments:\n"
- "1. dummy (boolean, required) Kept for historical purposes but ignored\n"
- "2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
+ "1. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
"\nResult:\n"
"[\n"
" {\n"
@@ -299,10 +298,10 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
- if (params.size() == 2) {
+ if (params.size() == 1) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
- if (info.strAddedNode == params[1].get_str()) {
+ if (info.strAddedNode == params[0].get_str()) {
vInfo.assign(1, info);
found = true;
break;
@@ -484,7 +483,7 @@ UniValue setban(const UniValue& params, bool fHelp)
"\nExamples:\n"
+ HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
- + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\" 86400")
+ + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
);
CSubNet subNet;
@@ -590,8 +589,8 @@ static const CRPCCommand commands[] =
{ "network", "clearbanned", &clearbanned, true },
};
-void RegisterNetRPCCommands(CRPCTable &tableRPC)
+void RegisterNetRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 55d0aac68b..988e0fc5fa 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -38,18 +38,18 @@ enum RPCErrorCode
RPC_PARSE_ERROR = -32700,
//! General application defined errors
- RPC_MISC_ERROR = -1, //! std::exception thrown in command handling
- RPC_FORBIDDEN_BY_SAFE_MODE = -2, //! Server is in safe mode, and command is not allowed in safe mode
- RPC_TYPE_ERROR = -3, //! Unexpected type was passed as parameter
- RPC_INVALID_ADDRESS_OR_KEY = -5, //! Invalid address or key
- RPC_OUT_OF_MEMORY = -7, //! Ran out of memory during operation
- RPC_INVALID_PARAMETER = -8, //! Invalid, missing or duplicate parameter
- RPC_DATABASE_ERROR = -20, //! Database error
- RPC_DESERIALIZATION_ERROR = -22, //! Error parsing or validating structure in raw format
- RPC_VERIFY_ERROR = -25, //! General error during transaction or block submission
- RPC_VERIFY_REJECTED = -26, //! Transaction or block was rejected by network rules
- RPC_VERIFY_ALREADY_IN_CHAIN = -27, //! Transaction already in chain
- RPC_IN_WARMUP = -28, //! Client still warming up
+ RPC_MISC_ERROR = -1, //!< std::exception thrown in command handling
+ RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode
+ RPC_TYPE_ERROR = -3, //!< Unexpected type was passed as parameter
+ RPC_INVALID_ADDRESS_OR_KEY = -5, //!< Invalid address or key
+ RPC_OUT_OF_MEMORY = -7, //!< Ran out of memory during operation
+ RPC_INVALID_PARAMETER = -8, //!< Invalid, missing or duplicate parameter
+ RPC_DATABASE_ERROR = -20, //!< Database error
+ RPC_DESERIALIZATION_ERROR = -22, //!< Error parsing or validating structure in raw format
+ RPC_VERIFY_ERROR = -25, //!< General error during transaction or block submission
+ RPC_VERIFY_REJECTED = -26, //!< Transaction or block was rejected by network rules
+ RPC_VERIFY_ALREADY_IN_CHAIN = -27, //!< Transaction already in chain
+ RPC_IN_WARMUP = -28, //!< Client still warming up
//! Aliases for backward compatibility
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
@@ -57,23 +57,23 @@ enum RPCErrorCode
RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN,
//! P2P client errors
- RPC_CLIENT_NOT_CONNECTED = -9, //! Bitcoin is not connected
- RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks
- RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added
- RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before
- RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes
- RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet
+ RPC_CLIENT_NOT_CONNECTED = -9, //!< Bitcoin is not connected
+ RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //!< Still downloading initial blocks
+ RPC_CLIENT_NODE_ALREADY_ADDED = -23, //!< Node is already added
+ RPC_CLIENT_NODE_NOT_ADDED = -24, //!< Node has not been added before
+ RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes
+ RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
//! Wallet errors
- RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.)
- RPC_WALLET_INSUFFICIENT_FUNDS = -6, //! Not enough funds in wallet or account
- RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //! Invalid account name
- RPC_WALLET_KEYPOOL_RAN_OUT = -12, //! Keypool ran out, call keypoolrefill first
- RPC_WALLET_UNLOCK_NEEDED = -13, //! Enter the wallet passphrase with walletpassphrase first
- RPC_WALLET_PASSPHRASE_INCORRECT = -14, //! The wallet passphrase entered was incorrect
- RPC_WALLET_WRONG_ENC_STATE = -15, //! Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
- RPC_WALLET_ENCRYPTION_FAILED = -16, //! Failed to encrypt the wallet
- RPC_WALLET_ALREADY_UNLOCKED = -17, //! Wallet is already unlocked
+ RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.)
+ RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account
+ RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //!< Invalid account name
+ RPC_WALLET_KEYPOOL_RAN_OUT = -12, //!< Keypool ran out, call keypoolrefill first
+ RPC_WALLET_UNLOCK_NEEDED = -13, //!< Enter the wallet passphrase with walletpassphrase first
+ RPC_WALLET_PASSPHRASE_INCORRECT = -14, //!< The wallet passphrase entered was incorrect
+ RPC_WALLET_WRONG_ENC_STATE = -15, //!< Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
+ RPC_WALLET_ENCRYPTION_FAILED = -16, //!< Failed to encrypt the wallet
+ RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked
};
std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 3270cd384f..9461a7280c 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -910,8 +910,8 @@ static const CRPCCommand commands[] =
{ "blockchain", "verifytxoutproof", &verifytxoutproof, true },
};
-void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC)
+void RegisterRawTransactionRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/register.h b/src/rpc/register.h
index 01aa58a25d..49aee2365f 100644
--- a/src/rpc/register.h
+++ b/src/rpc/register.h
@@ -20,13 +20,13 @@ void RegisterMiningRPCCommands(CRPCTable &tableRPC);
/** Register raw transaction RPC commands */
void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);
-static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC)
+static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
{
- RegisterBlockchainRPCCommands(tableRPC);
- RegisterNetRPCCommands(tableRPC);
- RegisterMiscRPCCommands(tableRPC);
- RegisterMiningRPCCommands(tableRPC);
- RegisterRawTransactionRPCCommands(tableRPC);
+ RegisterBlockchainRPCCommands(t);
+ RegisterNetRPCCommands(t);
+ RegisterMiscRPCCommands(t);
+ RegisterMiningRPCCommands(t);
+ RegisterRawTransactionRPCCommands(t);
}
#endif
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index 62fd9031f8..b629f4278b 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -84,8 +84,8 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
// Regardless of the verification result, the tx did not error.
set_error(err, bitcoinconsensus_ERR_OK);
-
- return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount), NULL);
+ PrecomputedTransactionData txdata(tx);
+ return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), NULL);
} catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index bc027e9f0c..47ea261e31 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1108,9 +1108,40 @@ public:
}
};
+uint256 GetPrevoutHash(const CTransaction& txTo) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].prevout;
+ }
+ return ss.GetHash();
+}
+
+uint256 GetSequenceHash(const CTransaction& txTo) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].nSequence;
+ }
+ return ss.GetHash();
+}
+
+uint256 GetOutputsHash(const CTransaction& txTo) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vout.size(); n++) {
+ ss << txTo.vout[n];
+ }
+ return ss.GetHash();
+}
+
} // anon namespace
-uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion)
+PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
+{
+ hashPrevouts = GetPrevoutHash(txTo);
+ hashSequence = GetSequenceHash(txTo);
+ hashOutputs = GetOutputsHash(txTo);
+}
+
+uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
if (sigversion == SIGVERSION_WITNESS_V0) {
uint256 hashPrevouts;
@@ -1118,27 +1149,16 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
uint256 hashOutputs;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].prevout;
- }
- hashPrevouts = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
}
if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].nSequence;
- }
- hashSequence = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
}
+
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vout.size(); n++) {
- ss << txTo.vout[n];
- }
- hashOutputs = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CHashWriter ss(SER_GETHASH, 0);
ss << txTo.vout[nIn];
@@ -1209,7 +1229,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
int nHashType = vchSig.back();
vchSig.pop_back();
- uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
+ uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
if (!VerifySignature(vchSig, pubkey, sighash))
return false;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index bd2f211663..e5d7865cd3 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -98,13 +98,20 @@ enum
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
+struct PrecomputedTransactionData
+{
+ uint256 hashPrevouts, hashSequence, hashOutputs;
+
+ PrecomputedTransactionData(const CTransaction& tx);
+};
+
enum SigVersion
{
SIGVERSION_BASE = 0,
SIGVERSION_WITNESS_V0 = 1,
};
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion);
+uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL);
class BaseSignatureChecker
{
@@ -133,12 +140,14 @@ private:
const CTransaction* txTo;
unsigned int nIn;
const CAmount amount;
+ const PrecomputedTransactionData* txdata;
protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
- TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn) {}
+ TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
+ TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
bool CheckSequence(const CScriptNum& nSequence) const;
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 050bf8cc42..44551ec2bc 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -22,7 +22,7 @@ private:
bool store;
public:
- CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn) : TransactionSignatureChecker(txToIn, nInIn, amount), store(storeIn) {}
+ CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {}
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
};
diff --git a/src/script/sign.h b/src/script/sign.h
index 6404b4523e..f9aa6fca27 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -51,7 +51,7 @@ public:
MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
};
-/** A signature creator that just produces 72-byte empty signatyres. */
+/** A signature creator that just produces 72-byte empty signatures. */
class DummySignatureCreator : public BaseSignatureCreator {
public:
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index e0b7b7a48a..efb277d347 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -25,17 +25,24 @@ config.status
libtool
.deps/
.dirstamp
-build-aux/
*.lo
*.o
*~
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
src/ecmult_static_context.h
-m4/libtool.m4
-m4/ltoptions.m4
-m4/ltsugar.m4
-m4/ltversion.m4
-m4/lt~obsolete.m4
+build-aux/config.guess
+build-aux/config.sub
+build-aux/depcomp
+build-aux/install-sh
+build-aux/ltmain.sh
+build-aux/m4/libtool.m4
+build-aux/m4/lt~obsolete.m4
+build-aux/m4/ltoptions.m4
+build-aux/m4/ltsugar.m4
+build-aux/m4/ltversion.m4
+build-aux/missing
+build-aux/compile
+build-aux/test-driver
src/stamp-h1
libsecp256k1.pc
diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml
index 4e1e73c39f..2c5c63adad 100644
--- a/src/secp256k1/.travis.yml
+++ b/src/secp256k1/.travis.yml
@@ -6,26 +6,31 @@ addons:
compiler:
- clang
- gcc
+cache:
+ directories:
+ - src/java/guava/
env:
global:
- - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no
+ - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no EXPERIMENTAL=no
+ - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
matrix:
- SCALAR=32bit RECOVERY=yes
- - SCALAR=32bit FIELD=32bit ECDH=yes
+ - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
- SCALAR=64bit
- FIELD=64bit RECOVERY=yes
- FIELD=64bit ENDOMORPHISM=yes
- - FIELD=64bit ENDOMORPHISM=yes ECDH=yes
+ - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
- FIELD=64bit ASM=x86_64
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
- - FIELD=32bit SCHNORR=yes
+ - FIELD=32bit SCHNORR=yes EXPERIMENTAL=yes
- FIELD=32bit ENDOMORPHISM=yes
- BIGNUM=no
- - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes
+ - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes EXPERIMENTAL=yes
- BIGNUM=no STATICPRECOMPUTATION=no
- BUILD=distcheck
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
- EXTRAFLAGS=CFLAGS=-O0
+ - BUILD=check-java ECDH=yes SCHNORR=yes EXPERIMENTAL=yes
matrix:
fast_finish: true
include:
@@ -55,9 +60,11 @@ matrix:
packages:
- gcc-multilib
- libgmp-dev:i386
+before_install: mkdir -p `dirname $GUAVA_JAR`
+install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi
before_script: ./autogen.sh
script:
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
- - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
+ - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
os: linux
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index 7772a4e9d2..3d130bdcbd 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -1,6 +1,12 @@
ACLOCAL_AMFLAGS = -I build-aux/m4
lib_LTLIBRARIES = libsecp256k1.la
+if USE_JNI
+JNI_LIB = libsecp256k1_jni.la
+noinst_LTLIBRARIES = $(JNI_LIB)
+else
+JNI_LIB =
+endif
include_HEADERS = include/secp256k1.h
noinst_HEADERS =
noinst_HEADERS += src/scalar.h
@@ -32,6 +38,7 @@ noinst_HEADERS += src/field_5x52_impl.h
noinst_HEADERS += src/field_5x52_int128_impl.h
noinst_HEADERS += src/field_5x52_asm_impl.h
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
+noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/testrand.h
noinst_HEADERS += src/testrand_impl.h
@@ -45,35 +52,80 @@ noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
+if USE_EXTERNAL_ASM
+COMMON_LIB = libsecp256k1_common.la
+noinst_LTLIBRARIES = $(COMMON_LIB)
+else
+COMMON_LIB =
+endif
+
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsecp256k1.pc
+if USE_EXTERNAL_ASM
+if USE_ASM_ARM
+libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s
+endif
+endif
+
libsecp256k1_la_SOURCES = src/secp256k1.c
-libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
-libsecp256k1_la_LIBADD = $(SECP_LIBS)
+libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
+libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)
+libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c
+libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
noinst_PROGRAMS =
if USE_BENCHMARK
noinst_PROGRAMS += bench_verify bench_sign bench_internal
bench_verify_SOURCES = src/bench_verify.c
-bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_sign_SOURCES = src/bench_sign.c
-bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_internal_SOURCES = src/bench_internal.c
-bench_internal_LDADD = $(SECP_LIBS)
-bench_internal_CPPFLAGS = $(SECP_INCLUDES)
+bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
endif
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
-tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
-tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS)
+tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
+tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
tests_LDFLAGS = -static
TESTS = tests
endif
+JAVAROOT=src/java
+JAVAORG=org/bitcoin
+JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar
+CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA)
+JAVA_FILES= \
+ $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \
+ $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \
+ $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \
+ $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java
+
+if USE_JNI
+
+$(JAVA_GUAVA):
+ @echo Guava is missing. Fetch it via: \
+ wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@)
+ @false
+
+.stamp-java: $(JAVA_FILES)
+ @echo Compiling $^
+ $(AM_V_at)$(CLASSPATH_ENV) javac $^
+ @touch $@
+
+if USE_TESTS
+
+check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java
+ $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test
+
+endif
+endif
+
if USE_ECMULT_STATIC_PRECOMPUTATION
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)
CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
@@ -93,10 +145,10 @@ $(bench_internal_OBJECTS): src/ecmult_static_context.h
src/ecmult_static_context.h: $(gen_context_BIN)
./$(gen_context_BIN)
-CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h
+CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java
endif
-EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h
+EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES)
if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include
diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md
index 6095db4220..8cd344ea81 100644
--- a/src/secp256k1/README.md
+++ b/src/secp256k1/README.md
@@ -1,7 +1,7 @@
libsecp256k1
============
-[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1)
+[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)
Optimized C library for EC operations on curve secp256k1.
diff --git a/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
new file mode 100644
index 0000000000..1fc3627614
--- /dev/null
+++ b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
@@ -0,0 +1,140 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_JNI_INCLUDE_DIR
+#
+# DESCRIPTION
+#
+# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
+# programs using the JNI interface.
+#
+# JNI include directories are usually in the Java distribution. This is
+# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in
+# that order. When this macro completes, a list of directories is left in
+# the variable JNI_INCLUDE_DIRS.
+#
+# Example usage follows:
+#
+# AX_JNI_INCLUDE_DIR
+#
+# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
+# do
+# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
+# done
+#
+# If you want to force a specific compiler:
+#
+# - at the configure.in level, set JAVAC=yourcompiler before calling
+# AX_JNI_INCLUDE_DIR
+#
+# - at the configure level, setenv JAVAC
+#
+# Note: This macro can work with the autoconf M4 macros for Java programs.
+# This particular macro is not part of the original set of macros.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 10
+
+AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
+AC_DEFUN([AX_JNI_INCLUDE_DIR],[
+
+JNI_INCLUDE_DIRS=""
+
+if test "x$JAVA_HOME" != x; then
+ _JTOPDIR="$JAVA_HOME"
+else
+ if test "x$JAVAC" = x; then
+ JAVAC=javac
+ fi
+ AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
+ if test "x$_ACJNI_JAVAC" = xno; then
+ AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
+ fi
+ _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
+ _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
+fi
+
+case "$host_os" in
+ darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
+ _JINC="$_JTOPDIR/Headers";;
+ *) _JINC="$_JTOPDIR/include";;
+esac
+_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
+_AS_ECHO_LOG([_JINC=$_JINC])
+
+# On Mac OS X 10.6.4, jni.h is a symlink:
+# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
+# -> ../../CurrentJDK/Headers/jni.h.
+
+AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
+[
+if test -f "$_JINC/jni.h"; then
+ ac_cv_jni_header_path="$_JINC"
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
+else
+ _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
+ if test -f "$_JTOPDIR/include/jni.h"; then
+ ac_cv_jni_header_path="$_JTOPDIR/include"
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
+ else
+ ac_cv_jni_header_path=none
+ fi
+fi
+])
+
+
+
+# get the likely subdirectories for system specific java includes
+case "$host_os" in
+bsdi*) _JNI_INC_SUBDIRS="bsdos";;
+darwin*) _JNI_INC_SUBDIRS="darwin";;
+freebsd*) _JNI_INC_SUBDIRS="freebsd";;
+linux*) _JNI_INC_SUBDIRS="linux genunix";;
+osf*) _JNI_INC_SUBDIRS="alpha";;
+solaris*) _JNI_INC_SUBDIRS="solaris";;
+mingw*) _JNI_INC_SUBDIRS="win32";;
+cygwin*) _JNI_INC_SUBDIRS="win32";;
+*) _JNI_INC_SUBDIRS="genunix";;
+esac
+
+if test "x$ac_cv_jni_header_path" != "xnone"; then
+ # add any subdirectories that are present
+ for JINCSUBDIR in $_JNI_INC_SUBDIRS
+ do
+ if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
+ fi
+ done
+fi
+])
+
+# _ACJNI_FOLLOW_SYMLINKS <path>
+# Follows symbolic links on <path>,
+# finally setting variable _ACJNI_FOLLOWED
+# ----------------------------------------
+AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
+# find the include directory relative to the javac executable
+_cur="$1"
+while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
+ AC_MSG_CHECKING([symlink for $_cur])
+ _slink=`ls -ld "$_cur" | sed 's/.* -> //'`
+ case "$_slink" in
+ /*) _cur="$_slink";;
+ # 'X' avoids triggering unwanted echo options.
+ *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
+ esac
+ AC_MSG_RESULT([$_cur])
+done
+_ACJNI_FOLLOWED="$_cur"
+])# _ACJNI
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index d41bbb6487..b25d8adb92 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -3,13 +3,13 @@ AC_DEFUN([SECP_INT128_CHECK],[
has_int128=$ac_cv_type___int128
])
-dnl
+dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
AC_DEFUN([SECP_64BIT_ASM_CHECK],[
AC_MSG_CHECKING(for x86_64 assembly availability)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <stdint.h>]],[[
uint64_t a = 11, tmp;
- __asm__ __volatile__("movq $0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
+ __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
]])],[has_64bit_asm=yes],[has_64bit_asm=no])
AC_MSG_RESULT([$has_64bit_asm])
])
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index 786d8dcfb9..0743c36690 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -29,6 +29,7 @@ AC_PROG_CC_C89
if test x"$ac_cv_prog_cc_c89" = x"no"; then
AC_MSG_ERROR([c89 compiler support required])
fi
+AM_PROG_AS
case $host_os in
*darwin*)
@@ -93,23 +94,33 @@ AC_ARG_ENABLE(tests,
[use_tests=$enableval],
[use_tests=yes])
+AC_ARG_ENABLE(openssl_tests,
+ AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]),
+ [enable_openssl_tests=$enableval],
+ [enable_openssl_tests=auto])
+
+AC_ARG_ENABLE(experimental,
+ AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]),
+ [use_experimental=$enableval],
+ [use_experimental=no])
+
AC_ARG_ENABLE(endomorphism,
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
[use_endomorphism=$enableval],
[use_endomorphism=no])
-
+
AC_ARG_ENABLE(ecmult_static_precomputation,
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]),
[use_ecmult_static_precomputation=$enableval],
- [use_ecmult_static_precomputation=yes])
+ [use_ecmult_static_precomputation=auto])
AC_ARG_ENABLE(module_ecdh,
- AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (default is no)]),
+ AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]),
[enable_module_ecdh=$enableval],
[enable_module_ecdh=no])
AC_ARG_ENABLE(module_schnorr,
- AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (default is no)]),
+ AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (experimental)]),
[enable_module_schnorr=$enableval],
[enable_module_schnorr=no])
@@ -118,6 +129,11 @@ AC_ARG_ENABLE(module_recovery,
[enable_module_recovery=$enableval],
[enable_module_recovery=no])
+AC_ARG_ENABLE(jni,
+ AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
+ [use_jni=$enableval],
+ [use_jni=auto])
+
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
@@ -127,8 +143,8 @@ AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto])
-AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|no|auto]
-[Specify assembly optimizations to use. Default is auto])],[req_asm=$withval], [req_asm=auto])
+AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]
+[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto])
AC_CHECK_TYPES([__int128])
@@ -138,6 +154,34 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
[ AC_MSG_RESULT([no])
])
+if test x"$use_ecmult_static_precomputation" != x"no"; then
+ save_cross_compiling=$cross_compiling
+ cross_compiling=no
+ TEMP_CC="$CC"
+ CC="$CC_FOR_BUILD"
+ AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([], [return 0])],
+ [working_native_cc=yes],
+ [working_native_cc=no],[dnl])
+ CC="$TEMP_CC"
+ cross_compiling=$save_cross_compiling
+
+ if test x"$working_native_cc" = x"no"; then
+ set_precomp=no
+ if test x"$use_ecmult_static_precomputation" = x"yes"; then
+ AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
+ else
+ AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
+ fi
+ else
+ AC_MSG_RESULT([ok])
+ set_precomp=yes
+ fi
+else
+ set_precomp=no
+fi
+
if test x"$req_asm" = x"auto"; then
SECP_64BIT_ASM_CHECK
if test x"$has_64bit_asm" = x"yes"; then
@@ -155,6 +199,8 @@ else
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
fi
;;
+ arm)
+ ;;
no)
;;
*)
@@ -247,10 +293,15 @@ else
fi
# select assembly optimization
+use_external_asm=no
+
case $set_asm in
x86_64)
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
;;
+arm)
+ use_external_asm=yes
+ ;;
no)
;;
*)
@@ -305,16 +356,51 @@ esac
if test x"$use_tests" = x"yes"; then
SECP_OPENSSL_CHECK
if test x"$has_openssl_ec" = x"yes"; then
- AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
- SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
- SECP_TEST_LIBS="$CRYPTO_LIBS"
-
- case $host in
- *mingw*)
- SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
- ;;
- esac
+ if test x"$enable_openssl_tests" != x"no"; then
+ AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
+ SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
+ SECP_TEST_LIBS="$CRYPTO_LIBS"
+
+ case $host in
+ *mingw*)
+ SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
+ ;;
+ esac
+ fi
+ else
+ if test x"$enable_openssl_tests" = x"yes"; then
+ AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available])
+ fi
+ fi
+else
+ if test x"$enable_openssl_tests" = x"yes"; then
+ AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled])
+ fi
+fi
+if test x"$use_jni" != x"no"; then
+ AX_JNI_INCLUDE_DIR
+ have_jni_dependencies=yes
+ if test x"$enable_module_schnorr" = x"no"; then
+ have_jni_dependencies=no
+ fi
+ if test x"$enable_module_ecdh" = x"no"; then
+ have_jni_dependencies=no
+ fi
+ if test "x$JNI_INCLUDE_DIRS" = "x"; then
+ have_jni_dependencies=no
+ fi
+ if test "x$have_jni_dependencies" = "xno"; then
+ if test x"$use_jni" = x"yes"; then
+ AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and Schnorr and try again.])
+ fi
+ AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
+ use_jni=no
+ else
+ use_jni=yes
+ for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
+ JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR"
+ done
fi
fi
@@ -345,18 +431,43 @@ fi
AC_C_BIGENDIAN()
+if test x"$use_external_asm" = x"yes"; then
+ AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
+fi
+
+AC_MSG_NOTICE([Using static precomputation: $set_precomp])
AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
AC_MSG_NOTICE([Using field implementation: $set_field])
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
-
AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
+AC_MSG_NOTICE([Using jni: $use_jni])
+
+if test x"$enable_experimental" = x"yes"; then
+ AC_MSG_NOTICE([******])
+ AC_MSG_NOTICE([WARNING: experimental build])
+ AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
+ AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
+ AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr])
+ AC_MSG_NOTICE([******])
+else
+ if test x"$enable_module_schnorr" = x"yes"; then
+ AC_MSG_ERROR([Schnorr signature module is experimental. Use --enable-experimental to allow.])
+ fi
+ if test x"$enable_module_ecdh" = x"yes"; then
+ AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
+ fi
+ if test x"$set_asm" = x"arm"; then
+ AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
+ fi
+fi
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
+AC_SUBST(JNI_INCLUDES)
AC_SUBST(SECP_INCLUDES)
AC_SUBST(SECP_LIBS)
AC_SUBST(SECP_TEST_LIBS)
@@ -367,6 +478,9 @@ AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_pr
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
+AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
+AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
+AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
dnl make sure nothing new is exported so that we don't break the cache
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
diff --git a/src/secp256k1/libsecp256k1.pc.in b/src/secp256k1/libsecp256k1.pc.in
index 1c72dd0003..a0d006f113 100644
--- a/src/secp256k1/libsecp256k1.pc.in
+++ b/src/secp256k1/libsecp256k1.pc.in
@@ -5,7 +5,7 @@ includedir=@includedir@
Name: libsecp256k1
Description: Optimized C library for EC operations on curve secp256k1
-URL: https://github.com/bitcoin/secp256k1
+URL: https://github.com/bitcoin-core/secp256k1
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs.private: @SECP_LIBS@
diff --git a/src/secp256k1/sage/group_prover.sage b/src/secp256k1/sage/group_prover.sage
new file mode 100644
index 0000000000..ab580c5b23
--- /dev/null
+++ b/src/secp256k1/sage/group_prover.sage
@@ -0,0 +1,322 @@
+# This code supports verifying group implementations which have branches
+# or conditional statements (like cmovs), by allowing each execution path
+# to independently set assumptions on input or intermediary variables.
+#
+# The general approach is:
+# * A constraint is a tuple of two sets of of symbolic expressions:
+# the first of which are required to evaluate to zero, the second of which
+# are required to evaluate to nonzero.
+# - A constraint is said to be conflicting if any of its nonzero expressions
+# is in the ideal with basis the zero expressions (in other words: when the
+# zero expressions imply that one of the nonzero expressions are zero).
+# * There is a list of laws that describe the intended behaviour, including
+# laws for addition and doubling. Each law is called with the symbolic point
+# coordinates as arguments, and returns:
+# - A constraint describing the assumptions under which it is applicable,
+# called "assumeLaw"
+# - A constraint describing the requirements of the law, called "require"
+# * Implementations are transliterated into functions that operate as well on
+# algebraic input points, and are called once per combination of branches
+# exectured. Each execution returns:
+# - A constraint describing the assumptions this implementation requires
+# (such as Z1=1), called "assumeFormula"
+# - A constraint describing the assumptions this specific branch requires,
+# but which is by construction guaranteed to cover the entire space by
+# merging the results from all branches, called "assumeBranch"
+# - The result of the computation
+# * All combinations of laws with implementation branches are tried, and:
+# - If the combination of assumeLaw, assumeFormula, and assumeBranch results
+# in a conflict, it means this law does not apply to this branch, and it is
+# skipped.
+# - For others, we try to prove the require constraints hold, assuming the
+# information in assumeLaw + assumeFormula + assumeBranch, and if this does
+# not succeed, we fail.
+# + To prove an expression is zero, we check whether it belongs to the
+# ideal with the assumed zero expressions as basis. This test is exact.
+# + To prove an expression is nonzero, we check whether each of its
+# factors is contained in the set of nonzero assumptions' factors.
+# This test is not exact, so various combinations of original and
+# reduced expressions' factors are tried.
+# - If we succeed, we print out the assumptions from assumeFormula that
+# weren't implied by assumeLaw already. Those from assumeBranch are skipped,
+# as we assume that all constraints in it are complementary with each other.
+#
+# Based on the sage verification scripts used in the Explicit-Formulas Database
+# by Tanja Lange and others, see http://hyperelliptic.org/EFD
+
+class fastfrac:
+ """Fractions over rings."""
+
+ def __init__(self,R,top,bot=1):
+ """Construct a fractional, given a ring, a numerator, and denominator."""
+ self.R = R
+ if parent(top) == ZZ or parent(top) == R:
+ self.top = R(top)
+ self.bot = R(bot)
+ elif top.__class__ == fastfrac:
+ self.top = top.top
+ self.bot = top.bot * bot
+ else:
+ self.top = R(numerator(top))
+ self.bot = R(denominator(top)) * bot
+
+ def iszero(self,I):
+ """Return whether this fraction is zero given an ideal."""
+ return self.top in I and self.bot not in I
+
+ def reduce(self,assumeZero):
+ zero = self.R.ideal(map(numerator, assumeZero))
+ return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot))
+
+ def __add__(self,other):
+ """Add two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top + self.bot * other,self.bot)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot)
+ return NotImplemented
+
+ def __sub__(self,other):
+ """Subtract two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top - self.bot * other,self.bot)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot)
+ return NotImplemented
+
+ def __neg__(self):
+ """Return the negation of a fraction."""
+ return fastfrac(self.R,-self.top,self.bot)
+
+ def __mul__(self,other):
+ """Multiply two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top * other,self.bot)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.top,self.bot * other.bot)
+ return NotImplemented
+
+ def __rmul__(self,other):
+ """Multiply something else with a fraction."""
+ return self.__mul__(other)
+
+ def __div__(self,other):
+ """Divide two fractions."""
+ if parent(other) == ZZ:
+ return fastfrac(self.R,self.top,self.bot * other)
+ if other.__class__ == fastfrac:
+ return fastfrac(self.R,self.top * other.bot,self.bot * other.top)
+ return NotImplemented
+
+ def __pow__(self,other):
+ """Compute a power of a fraction."""
+ if parent(other) == ZZ:
+ if other < 0:
+ # Negative powers require flipping top and bottom
+ return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other))
+ else:
+ return fastfrac(self.R,self.top ^ other,self.bot ^ other)
+ return NotImplemented
+
+ def __str__(self):
+ return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))"
+ def __repr__(self):
+ return "%s" % self
+
+ def numerator(self):
+ return self.top
+
+class constraints:
+ """A set of constraints, consisting of zero and nonzero expressions.
+
+ Constraints can either be used to express knowledge or a requirement.
+
+ Both the fields zero and nonzero are maps from expressions to description
+ strings. The expressions that are the keys in zero are required to be zero,
+ and the expressions that are the keys in nonzero are required to be nonzero.
+
+ Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in
+ nonzero could be multiplied into a single key. This is often much less
+ efficient to work with though, so we keep them separate inside the
+ constraints. This allows higher-level code to do fast checks on the individual
+ nonzero elements, or combine them if needed for stronger checks.
+
+ We can't multiply the different zero elements, as it would suffice for one of
+ the factors to be zero, instead of all of them. Instead, the zero elements are
+ typically combined into an ideal first.
+ """
+
+ def __init__(self, **kwargs):
+ if 'zero' in kwargs:
+ self.zero = dict(kwargs['zero'])
+ else:
+ self.zero = dict()
+ if 'nonzero' in kwargs:
+ self.nonzero = dict(kwargs['nonzero'])
+ else:
+ self.nonzero = dict()
+
+ def negate(self):
+ return constraints(zero=self.nonzero, nonzero=self.zero)
+
+ def __add__(self, other):
+ zero = self.zero.copy()
+ zero.update(other.zero)
+ nonzero = self.nonzero.copy()
+ nonzero.update(other.nonzero)
+ return constraints(zero=zero, nonzero=nonzero)
+
+ def __str__(self):
+ return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero)
+
+ def __repr__(self):
+ return "%s" % self
+
+
+def conflicts(R, con):
+ """Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
+ zero = R.ideal(map(numerator, con.zero))
+ if 1 in zero:
+ return True
+ # First a cheap check whether any of the individual nonzero terms conflict on
+ # their own.
+ for nonzero in con.nonzero:
+ if nonzero.iszero(zero):
+ return True
+ # It can be the case that entries in the nonzero set do not individually
+ # conflict with the zero set, but their combination does. For example, knowing
+ # that either x or y is zero is equivalent to having x*y in the zero set.
+ # Having x or y individually in the nonzero set is not a conflict, but both
+ # simultaneously is, so that is the right thing to check for.
+ if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero):
+ return True
+ return False
+
+
+def get_nonzero_set(R, assume):
+ """Calculate a simple set of nonzero expressions"""
+ zero = R.ideal(map(numerator, assume.zero))
+ nonzero = set()
+ for nz in map(numerator, assume.nonzero):
+ for (f,n) in nz.factor():
+ nonzero.add(f)
+ rnz = zero.reduce(nz)
+ for (f,n) in rnz.factor():
+ nonzero.add(f)
+ return nonzero
+
+
+def prove_nonzero(R, exprs, assume):
+ """Check whether an expression is provably nonzero, given assumptions"""
+ zero = R.ideal(map(numerator, assume.zero))
+ nonzero = get_nonzero_set(R, assume)
+ expl = set()
+ ok = True
+ for expr in exprs:
+ if numerator(expr) in zero:
+ return (False, [exprs[expr]])
+ allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)
+ for (f, n) in allexprs.factor():
+ if f not in nonzero:
+ ok = False
+ if ok:
+ return (True, None)
+ ok = True
+ for (f, n) in zero.reduce(numerator(allexprs)).factor():
+ if f not in nonzero:
+ ok = False
+ if ok:
+ return (True, None)
+ ok = True
+ for expr in exprs:
+ for (f,n) in numerator(expr).factor():
+ if f not in nonzero:
+ ok = False
+ if ok:
+ return (True, None)
+ ok = True
+ for expr in exprs:
+ for (f,n) in zero.reduce(numerator(expr)).factor():
+ if f not in nonzero:
+ expl.add(exprs[expr])
+ if expl:
+ return (False, list(expl))
+ else:
+ return (True, None)
+
+
+def prove_zero(R, exprs, assume):
+ """Check whether all of the passed expressions are provably zero, given assumptions"""
+ r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
+ if not r:
+ return (False, map(lambda x: "Possibly zero denominator: %s" % x, e))
+ zero = R.ideal(map(numerator, assume.zero))
+ nonzero = prod(x for x in assume.nonzero)
+ expl = []
+ for expr in exprs:
+ if not expr.iszero(zero):
+ expl.append(exprs[expr])
+ if not expl:
+ return (True, None)
+ return (False, expl)
+
+
+def describe_extra(R, assume, assumeExtra):
+ """Describe what assumptions are added, given existing assumptions"""
+ zerox = assume.zero.copy()
+ zerox.update(assumeExtra.zero)
+ zero = R.ideal(map(numerator, assume.zero))
+ zeroextra = R.ideal(map(numerator, zerox))
+ nonzero = get_nonzero_set(R, assume)
+ ret = set()
+ # Iterate over the extra zero expressions
+ for base in assumeExtra.zero:
+ if base not in zero:
+ add = []
+ for (f, n) in numerator(base).factor():
+ if f not in nonzero:
+ add += ["%s" % f]
+ if add:
+ ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base])
+ # Iterate over the extra nonzero expressions
+ for nz in assumeExtra.nonzero:
+ nzr = zeroextra.reduce(numerator(nz))
+ if nzr not in zeroextra:
+ for (f,n) in nzr.factor():
+ if zeroextra.reduce(f) not in nonzero:
+ ret.add("%s != 0" % zeroextra.reduce(f))
+ return ", ".join(x for x in ret)
+
+
+def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require):
+ """Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions"""
+ assume = assumeLaw + assumeAssert + assumeBranch
+
+ if conflicts(R, assume):
+ # This formula does not apply
+ return None
+
+ describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)
+
+ ok, msg = prove_zero(R, require.zero, assume)
+ if not ok:
+ return "FAIL, %s fails (assuming %s)" % (str(msg), describe)
+
+ res, expl = prove_nonzero(R, require.nonzero, assume)
+ if not res:
+ return "FAIL, %s fails (assuming %s)" % (str(expl), describe)
+
+ if describe != "":
+ return "OK (assuming %s)" % describe
+ else:
+ return "OK"
+
+
+def concrete_verify(c):
+ for k in c.zero:
+ if k != 0:
+ return (False, c.zero[k])
+ for k in c.nonzero:
+ if k == 0:
+ return (False, c.nonzero[k])
+ return (True, None)
diff --git a/src/secp256k1/sage/secp256k1.sage b/src/secp256k1/sage/secp256k1.sage
new file mode 100644
index 0000000000..a97e732f7f
--- /dev/null
+++ b/src/secp256k1/sage/secp256k1.sage
@@ -0,0 +1,306 @@
+# Test libsecp256k1' group operation implementations using prover.sage
+
+import sys
+
+load("group_prover.sage")
+load("weierstrass_prover.sage")
+
+def formula_secp256k1_gej_double_var(a):
+ """libsecp256k1's secp256k1_gej_double_var, used by various addition functions"""
+ rz = a.Z * a.Y
+ rz = rz * 2
+ t1 = a.X^2
+ t1 = t1 * 3
+ t2 = t1^2
+ t3 = a.Y^2
+ t3 = t3 * 2
+ t4 = t3^2
+ t4 = t4 * 2
+ t3 = t3 * a.X
+ rx = t3
+ rx = rx * 4
+ rx = -rx
+ rx = rx + t2
+ t2 = -t2
+ t3 = t3 * 6
+ t3 = t3 + t2
+ ry = t1 * t3
+ t2 = -t4
+ ry = ry + t2
+ return jacobianpoint(rx, ry, rz)
+
+def formula_secp256k1_gej_add_var(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_var"""
+ if branch == 0:
+ return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b)
+ if branch == 1:
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
+ z22 = b.Z^2
+ z12 = a.Z^2
+ u1 = a.X * z22
+ u2 = b.X * z12
+ s1 = a.Y * z22
+ s1 = s1 * b.Z
+ s2 = b.Y * z12
+ s2 = s2 * a.Z
+ h = -u1
+ h = h + u2
+ i = -s1
+ i = i + s2
+ if branch == 2:
+ r = formula_secp256k1_gej_double_var(a)
+ return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r)
+ if branch == 3:
+ return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity())
+ i2 = i^2
+ h2 = h^2
+ h3 = h2 * h
+ h = h * b.Z
+ rz = a.Z * h
+ t = u1 * h2
+ rx = t
+ rx = rx * 2
+ rx = rx + h3
+ rx = -rx
+ rx = rx + i2
+ ry = -rx
+ ry = ry + t
+ ry = ry * i
+ h3 = h3 * s1
+ h3 = -h3
+ ry = ry + h3
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_ge_var(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1"""
+ if branch == 0:
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b)
+ if branch == 1:
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
+ z12 = a.Z^2
+ u1 = a.X
+ u2 = b.X * z12
+ s1 = a.Y
+ s2 = b.Y * z12
+ s2 = s2 * a.Z
+ h = -u1
+ h = h + u2
+ i = -s1
+ i = i + s2
+ if (branch == 2):
+ r = formula_secp256k1_gej_double_var(a)
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)
+ if (branch == 3):
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())
+ i2 = i^2
+ h2 = h^2
+ h3 = h * h2
+ rz = a.Z * h
+ t = u1 * h2
+ rx = t
+ rx = rx * 2
+ rx = rx + h3
+ rx = -rx
+ rx = rx + i2
+ ry = -rx
+ ry = ry + t
+ ry = ry * i
+ h3 = h3 * s1
+ h3 = -h3
+ ry = ry + h3
+ return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_zinv_var(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_zinv_var"""
+ bzinv = b.Z^(-1)
+ if branch == 0:
+ return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a)
+ if branch == 1:
+ bzinv2 = bzinv^2
+ bzinv3 = bzinv2 * bzinv
+ rx = b.X * bzinv2
+ ry = b.Y * bzinv3
+ rz = 1
+ return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz))
+ azz = a.Z * bzinv
+ z12 = azz^2
+ u1 = a.X
+ u2 = b.X * z12
+ s1 = a.Y
+ s2 = b.Y * z12
+ s2 = s2 * azz
+ h = -u1
+ h = h + u2
+ i = -s1
+ i = i + s2
+ if branch == 2:
+ r = formula_secp256k1_gej_double_var(a)
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)
+ if branch == 3:
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())
+ i2 = i^2
+ h2 = h^2
+ h3 = h * h2
+ rz = a.Z
+ rz = rz * h
+ t = u1 * h2
+ rx = t
+ rx = rx * 2
+ rx = rx + h3
+ rx = -rx
+ rx = rx + i2
+ ry = -rx
+ ry = ry + t
+ ry = ry * i
+ h3 = h3 * s1
+ h3 = -h3
+ ry = ry + h3
+ return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_ge(branch, a, b):
+ """libsecp256k1's secp256k1_gej_add_ge"""
+ zeroes = {}
+ nonzeroes = {}
+ a_infinity = False
+ if (branch & 4) != 0:
+ nonzeroes.update({a.Infinity : 'a_infinite'})
+ a_infinity = True
+ else:
+ zeroes.update({a.Infinity : 'a_finite'})
+ zz = a.Z^2
+ u1 = a.X
+ u2 = b.X * zz
+ s1 = a.Y
+ s2 = b.Y * zz
+ s2 = s2 * a.Z
+ t = u1
+ t = t + u2
+ m = s1
+ m = m + s2
+ rr = t^2
+ m_alt = -u2
+ tt = u1 * m_alt
+ rr = rr + tt
+ degenerate = (branch & 3) == 3
+ if (branch & 1) != 0:
+ zeroes.update({m : 'm_zero'})
+ else:
+ nonzeroes.update({m : 'm_nonzero'})
+ if (branch & 2) != 0:
+ zeroes.update({rr : 'rr_zero'})
+ else:
+ nonzeroes.update({rr : 'rr_nonzero'})
+ rr_alt = s1
+ rr_alt = rr_alt * 2
+ m_alt = m_alt + u1
+ if not degenerate:
+ rr_alt = rr
+ m_alt = m
+ n = m_alt^2
+ q = n * t
+ n = n^2
+ if degenerate:
+ n = m
+ t = rr_alt^2
+ rz = a.Z * m_alt
+ infinity = False
+ if (branch & 8) != 0:
+ if not a_infinity:
+ infinity = True
+ zeroes.update({rz : 'r.z=0'})
+ else:
+ nonzeroes.update({rz : 'r.z!=0'})
+ rz = rz * 2
+ q = -q
+ t = t + q
+ rx = t
+ t = t * 2
+ t = t + q
+ t = t * rr_alt
+ t = t + n
+ ry = -t
+ rx = rx * 4
+ ry = ry * 4
+ if a_infinity:
+ rx = b.X
+ ry = b.Y
+ rz = 1
+ if infinity:
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity())
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz))
+
+def formula_secp256k1_gej_add_ge_old(branch, a, b):
+ """libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx"""
+ a_infinity = (branch & 1) != 0
+ zero = {}
+ nonzero = {}
+ if a_infinity:
+ nonzero.update({a.Infinity : 'a_infinite'})
+ else:
+ zero.update({a.Infinity : 'a_finite'})
+ zz = a.Z^2
+ u1 = a.X
+ u2 = b.X * zz
+ s1 = a.Y
+ s2 = b.Y * zz
+ s2 = s2 * a.Z
+ z = a.Z
+ t = u1
+ t = t + u2
+ m = s1
+ m = m + s2
+ n = m^2
+ q = n * t
+ n = n^2
+ rr = t^2
+ t = u1 * u2
+ t = -t
+ rr = rr + t
+ t = rr^2
+ rz = m * z
+ infinity = False
+ if (branch & 2) != 0:
+ if not a_infinity:
+ infinity = True
+ else:
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity())
+ zero.update({rz : 'r.z=0'})
+ else:
+ nonzero.update({rz : 'r.z!=0'})
+ rz = rz * (0 if a_infinity else 2)
+ rx = t
+ q = -q
+ rx = rx + q
+ q = q * 3
+ t = t * 2
+ t = t + q
+ t = t * rr
+ t = t + n
+ ry = -t
+ rx = rx * (0 if a_infinity else 4)
+ ry = ry * (0 if a_infinity else 4)
+ t = b.X
+ t = t * (1 if a_infinity else 0)
+ rx = rx + t
+ t = b.Y
+ t = t * (1 if a_infinity else 0)
+ ry = ry + t
+ t = (1 if a_infinity else 0)
+ rz = rz + t
+ if infinity:
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity())
+ return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz))
+
+if __name__ == "__main__":
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
+ check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)
+
+ if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
+ check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)
diff --git a/src/secp256k1/sage/weierstrass_prover.sage b/src/secp256k1/sage/weierstrass_prover.sage
new file mode 100644
index 0000000000..03ef2ec901
--- /dev/null
+++ b/src/secp256k1/sage/weierstrass_prover.sage
@@ -0,0 +1,264 @@
+# Prover implementation for Weierstrass curves of the form
+# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws
+# operating on affine and Jacobian coordinates, including the point at infinity
+# represented by a 4th variable in coordinates.
+
+load("group_prover.sage")
+
+
+class affinepoint:
+ def __init__(self, x, y, infinity=0):
+ self.x = x
+ self.y = y
+ self.infinity = infinity
+ def __str__(self):
+ return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity)
+
+
+class jacobianpoint:
+ def __init__(self, x, y, z, infinity=0):
+ self.X = x
+ self.Y = y
+ self.Z = z
+ self.Infinity = infinity
+ def __str__(self):
+ return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity)
+
+
+def point_at_infinity():
+ return jacobianpoint(1, 1, 1, 1)
+
+
+def negate(p):
+ if p.__class__ == affinepoint:
+ return affinepoint(p.x, -p.y)
+ if p.__class__ == jacobianpoint:
+ return jacobianpoint(p.X, -p.Y, p.Z)
+ assert(False)
+
+
+def on_weierstrass_curve(A, B, p):
+ """Return a set of zero-expressions for an affine point to be on the curve"""
+ return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'})
+
+
+def tangential_to_weierstrass_curve(A, B, p12, p3):
+ """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)"""
+ return constraints(zero={
+ (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve'
+ })
+
+
+def colinear(p1, p2, p3):
+ """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear"""
+ return constraints(zero={
+ (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1',
+ (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2',
+ (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3'
+ })
+
+
+def good_affine_point(p):
+ return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'})
+
+
+def good_jacobian_point(p):
+ return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'})
+
+
+def good_point(p):
+ return constraints(nonzero={p.Z^6 : 'nonzero_X'})
+
+
+def finite(p, *affine_fns):
+ con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'})
+ if p.Z != 0:
+ return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con)
+ else:
+ return con
+
+def infinite(p):
+ return constraints(nonzero={p.Infinity : 'infinite_point'})
+
+
+def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC):
+ """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions"""
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ on_weierstrass_curve(A, B, pb) +
+ finite(pA) +
+ finite(pB) +
+ constraints(nonzero={pa.x - pb.x : 'different_x'}))
+ require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
+ colinear(pa, pb, negate(pc))))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC):
+ """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions"""
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ on_weierstrass_curve(A, B, pb) +
+ finite(pA) +
+ finite(pB) +
+ constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'}))
+ require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
+ tangential_to_weierstrass_curve(A, B, pa, negate(pc))))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ on_weierstrass_curve(A, B, pb) +
+ finite(pA) +
+ finite(pB) +
+ constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'}))
+ require = infinite(pC)
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pb) +
+ infinite(pA) +
+ finite(pB))
+ require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'}))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ on_weierstrass_curve(A, B, pa) +
+ infinite(pB) +
+ finite(pA))
+ require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'}))
+ return (assumeLaw, require)
+
+
+def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC):
+ assumeLaw = (good_affine_point(pa) +
+ good_affine_point(pb) +
+ good_jacobian_point(pA) +
+ good_jacobian_point(pB) +
+ infinite(pA) +
+ infinite(pB))
+ require = infinite(pC)
+ return (assumeLaw, require)
+
+
+laws_jacobian_weierstrass = {
+ 'add': law_jacobian_weierstrass_add,
+ 'double': law_jacobian_weierstrass_double,
+ 'add_opposite': law_jacobian_weierstrass_add_opposites,
+ 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a,
+ 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b,
+ 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab
+}
+
+
+def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
+ """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field"""
+ F = Integers(p)
+ print "Formula %s on Z%i:" % (name, p)
+ points = []
+ for x in xrange(0, p):
+ for y in xrange(0, p):
+ point = affinepoint(F(x), F(y))
+ r, e = concrete_verify(on_weierstrass_curve(A, B, point))
+ if r:
+ points.append(point)
+
+ for za in xrange(1, p):
+ for zb in xrange(1, p):
+ for pa in points:
+ for pb in points:
+ for ia in xrange(2):
+ for ib in xrange(2):
+ pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia)
+ pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib)
+ for branch in xrange(0, branches):
+ assumeAssert, assumeBranch, pC = formula(branch, pA, pB)
+ pC.X = F(pC.X)
+ pC.Y = F(pC.Y)
+ pC.Z = F(pC.Z)
+ pC.Infinity = F(pC.Infinity)
+ r, e = concrete_verify(assumeAssert + assumeBranch)
+ if r:
+ match = False
+ for key in laws_jacobian_weierstrass:
+ assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC)
+ r, e = concrete_verify(assumeLaw)
+ if r:
+ if match:
+ print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)
+ else:
+ match = True
+ r, e = concrete_verify(require)
+ if not r:
+ print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e)
+ print
+
+
+def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
+ assumeLaw, require = f(A, B, pa, pb, pA, pB, pC)
+ return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require)
+
+def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
+ """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically"""
+ R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')
+ lift = lambda x: fastfrac(R,x)
+ ax = lift(ax)
+ ay = lift(ay)
+ Az = lift(Az)
+ bx = lift(bx)
+ by = lift(by)
+ Bz = lift(Bz)
+ Ai = lift(Ai)
+ Bi = lift(Bi)
+
+ pa = affinepoint(ax, ay, Ai)
+ pb = affinepoint(bx, by, Bi)
+ pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai)
+ pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi)
+
+ res = {}
+
+ for key in laws_jacobian_weierstrass:
+ res[key] = []
+
+ print ("Formula " + name + ":")
+ count = 0
+ for branch in xrange(branches):
+ assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
+ pC.X = lift(pC.X)
+ pC.Y = lift(pC.Y)
+ pC.Z = lift(pC.Z)
+ pC.Infinity = lift(pC.Infinity)
+
+ for key in laws_jacobian_weierstrass:
+ res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
+
+ for key in res:
+ print " %s:" % key
+ val = res[key]
+ for x in val:
+ if x[0] is not None:
+ print " branch %i: %s" % (x[1], x[0])
+
+ print
diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s
new file mode 100644
index 0000000000..5df561f2fc
--- /dev/null
+++ b/src/secp256k1/src/asm/field_10x26_arm.s
@@ -0,0 +1,919 @@
+@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm:
+/**********************************************************************
+ * Copyright (c) 2014 Wladimir J. van der Laan *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+/*
+ARM implementation of field_10x26 inner loops.
+
+Note:
+
+- To avoid unnecessary loads and make use of available registers, two
+ 'passes' have every time been interleaved, with the odd passes accumulating c' and d'
+ which will be added to c and d respectively in the the even passes
+
+*/
+
+ .syntax unified
+ .arch armv7-a
+ @ eabi attributes - see readelf -A
+ .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes
+ .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no
+ .eabi_attribute 10, 0 @ Tag_FP_arch = none
+ .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte
+ .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP
+ .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed
+ .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6
+ .text
+
+ @ Field constants
+ .set field_R0, 0x3d10
+ .set field_R1, 0x400
+ .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff
+
+ .align 2
+ .global secp256k1_fe_mul_inner
+ .type secp256k1_fe_mul_inner, %function
+ @ Arguments:
+ @ r0 r Restrict: can overlap with a, not with b
+ @ r1 a
+ @ r2 b
+ @ Stack (total 4+10*4 = 44)
+ @ sp + #0 saved 'r' pointer
+ @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9
+secp256k1_fe_mul_inner:
+ stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}
+ sub sp, sp, #48 @ frame=44 + alignment
+ str r0, [sp, #0] @ save result address, we need it only at the end
+
+ /******************************************
+ * Main computation code.
+ ******************************************
+
+ Allocation:
+ r0,r14,r7,r8 scratch
+ r1 a (pointer)
+ r2 b (pointer)
+ r3:r4 c
+ r5:r6 d
+ r11:r12 c'
+ r9:r10 d'
+
+ Note: do not write to r[] here, it may overlap with a[]
+ */
+
+ /* A - interleaved with B */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #9*4] @ b[9]
+ ldr r0, [r1, #1*4] @ a[1]
+ umull r5, r6, r7, r8 @ d = a[0] * b[9]
+ ldr r14, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r8 @ d' = a[1] * b[9]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r5, r6, r0, r14 @ d += a[1] * b[8]
+ ldr r8, [r2, #7*4] @ b[7]
+ umlal r9, r10, r7, r14 @ d' += a[2] * b[8]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r5, r6, r7, r8 @ d += a[2] * b[7]
+ ldr r14, [r2, #6*4] @ b[6]
+ umlal r9, r10, r0, r8 @ d' += a[3] * b[7]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r5, r6, r0, r14 @ d += a[3] * b[6]
+ ldr r8, [r2, #5*4] @ b[5]
+ umlal r9, r10, r7, r14 @ d' += a[4] * b[6]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r5, r6, r7, r8 @ d += a[4] * b[5]
+ ldr r14, [r2, #4*4] @ b[4]
+ umlal r9, r10, r0, r8 @ d' += a[5] * b[5]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r5, r6, r0, r14 @ d += a[5] * b[4]
+ ldr r8, [r2, #3*4] @ b[3]
+ umlal r9, r10, r7, r14 @ d' += a[6] * b[4]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r5, r6, r7, r8 @ d += a[6] * b[3]
+ ldr r14, [r2, #2*4] @ b[2]
+ umlal r9, r10, r0, r8 @ d' += a[7] * b[3]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r14 @ d += a[7] * b[2]
+ ldr r8, [r2, #1*4] @ b[1]
+ umlal r9, r10, r7, r14 @ d' += a[8] * b[2]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r8 @ d += a[8] * b[1]
+ ldr r14, [r2, #0*4] @ b[0]
+ umlal r9, r10, r0, r8 @ d' += a[9] * b[1]
+ ldr r7, [r1, #0*4] @ a[0]
+ umlal r5, r6, r0, r14 @ d += a[9] * b[0]
+ @ r7,r14 used in B
+
+ bic r0, r5, field_not_M @ t9 = d & M
+ str r0, [sp, #4 + 4*9]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ /* B */
+ umull r3, r4, r7, r14 @ c = a[0] * b[0]
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u0 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u0 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t0 = c & M
+ str r14, [sp, #4 + 0*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u0 * R1
+ umlal r3, r4, r0, r14
+
+ /* C - interleaved with D */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #2*4] @ b[2]
+ ldr r14, [r2, #1*4] @ b[1]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[2]
+ ldr r0, [r1, #1*4] @ a[1]
+ umlal r3, r4, r7, r14 @ c += a[0] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r11, r12, r0, r14 @ c' += a[1] * b[1]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r8 @ c += a[1] * b[0]
+ ldr r14, [r2, #9*4] @ b[9]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[0]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r5, r6, r7, r14 @ d += a[2] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r14 @ d' = a[3] * b[9]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r5, r6, r0, r8 @ d += a[3] * b[8]
+ ldr r14, [r2, #7*4] @ b[7]
+ umlal r9, r10, r7, r8 @ d' += a[4] * b[8]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r5, r6, r7, r14 @ d += a[4] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r9, r10, r0, r14 @ d' += a[5] * b[7]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r5, r6, r0, r8 @ d += a[5] * b[6]
+ ldr r14, [r2, #5*4] @ b[5]
+ umlal r9, r10, r7, r8 @ d' += a[6] * b[6]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r5, r6, r7, r14 @ d += a[6] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r9, r10, r0, r14 @ d' += a[7] * b[5]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r8 @ d += a[7] * b[4]
+ ldr r14, [r2, #3*4] @ b[3]
+ umlal r9, r10, r7, r8 @ d' += a[8] * b[4]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r14 @ d += a[8] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r9, r10, r0, r14 @ d' += a[9] * b[3]
+ umlal r5, r6, r0, r8 @ d += a[9] * b[2]
+
+ bic r0, r5, field_not_M @ u1 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u1 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t1 = c & M
+ str r14, [sp, #4 + 1*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u1 * R1
+ umlal r3, r4, r0, r14
+
+ /* D */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u2 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u2 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t2 = c & M
+ str r14, [sp, #4 + 2*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u2 * R1
+ umlal r3, r4, r0, r14
+
+ /* E - interleaved with F */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #4*4] @ b[4]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[4]
+ ldr r8, [r2, #3*4] @ b[3]
+ umlal r3, r4, r7, r8 @ c += a[0] * b[3]
+ ldr r7, [r1, #1*4] @ a[1]
+ umlal r11, r12, r7, r8 @ c' += a[1] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r3, r4, r7, r8 @ c += a[1] * b[2]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[2]
+ ldr r8, [r2, #1*4] @ b[1]
+ umlal r3, r4, r7, r8 @ c += a[2] * b[1]
+ ldr r7, [r1, #3*4] @ a[3]
+ umlal r11, r12, r7, r8 @ c' += a[3] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r3, r4, r7, r8 @ c += a[3] * b[0]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r11, r12, r7, r8 @ c' += a[4] * b[0]
+ ldr r8, [r2, #9*4] @ b[9]
+ umlal r5, r6, r7, r8 @ d += a[4] * b[9]
+ ldr r7, [r1, #5*4] @ a[5]
+ umull r9, r10, r7, r8 @ d' = a[5] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umlal r5, r6, r7, r8 @ d += a[5] * b[8]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r9, r10, r7, r8 @ d' += a[6] * b[8]
+ ldr r8, [r2, #7*4] @ b[7]
+ umlal r5, r6, r7, r8 @ d += a[6] * b[7]
+ ldr r7, [r1, #7*4] @ a[7]
+ umlal r9, r10, r7, r8 @ d' += a[7] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r5, r6, r7, r8 @ d += a[7] * b[6]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r9, r10, r7, r8 @ d' += a[8] * b[6]
+ ldr r8, [r2, #5*4] @ b[5]
+ umlal r5, r6, r7, r8 @ d += a[8] * b[5]
+ ldr r7, [r1, #9*4] @ a[9]
+ umlal r9, r10, r7, r8 @ d' += a[9] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r5, r6, r7, r8 @ d += a[9] * b[4]
+
+ bic r0, r5, field_not_M @ u3 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u3 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t3 = c & M
+ str r14, [sp, #4 + 3*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u3 * R1
+ umlal r3, r4, r0, r14
+
+ /* F */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u4 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u4 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t4 = c & M
+ str r14, [sp, #4 + 4*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u4 * R1
+ umlal r3, r4, r0, r14
+
+ /* G - interleaved with H */
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r8, [r2, #6*4] @ b[6]
+ ldr r14, [r2, #5*4] @ b[5]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[6]
+ ldr r0, [r1, #1*4] @ a[1]
+ umlal r3, r4, r7, r14 @ c += a[0] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r11, r12, r0, r14 @ c' += a[1] * b[5]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r8 @ c += a[1] * b[4]
+ ldr r14, [r2, #3*4] @ b[3]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[4]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r3, r4, r7, r14 @ c += a[2] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r11, r12, r0, r14 @ c' += a[3] * b[3]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r3, r4, r0, r8 @ c += a[3] * b[2]
+ ldr r14, [r2, #1*4] @ b[1]
+ umlal r11, r12, r7, r8 @ c' += a[4] * b[2]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r3, r4, r7, r14 @ c += a[4] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r11, r12, r0, r14 @ c' += a[5] * b[1]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r3, r4, r0, r8 @ c += a[5] * b[0]
+ ldr r14, [r2, #9*4] @ b[9]
+ umlal r11, r12, r7, r8 @ c' += a[6] * b[0]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r5, r6, r7, r14 @ d += a[6] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r14 @ d' = a[7] * b[9]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r8 @ d += a[7] * b[8]
+ ldr r14, [r2, #7*4] @ b[7]
+ umlal r9, r10, r7, r8 @ d' += a[8] * b[8]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r14 @ d += a[8] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r9, r10, r0, r14 @ d' += a[9] * b[7]
+ umlal r5, r6, r0, r8 @ d += a[9] * b[6]
+
+ bic r0, r5, field_not_M @ u5 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u5 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t5 = c & M
+ str r14, [sp, #4 + 5*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u5 * R1
+ umlal r3, r4, r0, r14
+
+ /* H */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u6 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u6 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t6 = c & M
+ str r14, [sp, #4 + 6*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u6 * R1
+ umlal r3, r4, r0, r14
+
+ /* I - interleaved with J */
+ ldr r8, [r2, #8*4] @ b[8]
+ ldr r7, [r1, #0*4] @ a[0]
+ ldr r14, [r2, #7*4] @ b[7]
+ umull r11, r12, r7, r8 @ c' = a[0] * b[8]
+ ldr r0, [r1, #1*4] @ a[1]
+ umlal r3, r4, r7, r14 @ c += a[0] * b[7]
+ ldr r8, [r2, #6*4] @ b[6]
+ umlal r11, r12, r0, r14 @ c' += a[1] * b[7]
+ ldr r7, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r8 @ c += a[1] * b[6]
+ ldr r14, [r2, #5*4] @ b[5]
+ umlal r11, r12, r7, r8 @ c' += a[2] * b[6]
+ ldr r0, [r1, #3*4] @ a[3]
+ umlal r3, r4, r7, r14 @ c += a[2] * b[5]
+ ldr r8, [r2, #4*4] @ b[4]
+ umlal r11, r12, r0, r14 @ c' += a[3] * b[5]
+ ldr r7, [r1, #4*4] @ a[4]
+ umlal r3, r4, r0, r8 @ c += a[3] * b[4]
+ ldr r14, [r2, #3*4] @ b[3]
+ umlal r11, r12, r7, r8 @ c' += a[4] * b[4]
+ ldr r0, [r1, #5*4] @ a[5]
+ umlal r3, r4, r7, r14 @ c += a[4] * b[3]
+ ldr r8, [r2, #2*4] @ b[2]
+ umlal r11, r12, r0, r14 @ c' += a[5] * b[3]
+ ldr r7, [r1, #6*4] @ a[6]
+ umlal r3, r4, r0, r8 @ c += a[5] * b[2]
+ ldr r14, [r2, #1*4] @ b[1]
+ umlal r11, r12, r7, r8 @ c' += a[6] * b[2]
+ ldr r0, [r1, #7*4] @ a[7]
+ umlal r3, r4, r7, r14 @ c += a[6] * b[1]
+ ldr r8, [r2, #0*4] @ b[0]
+ umlal r11, r12, r0, r14 @ c' += a[7] * b[1]
+ ldr r7, [r1, #8*4] @ a[8]
+ umlal r3, r4, r0, r8 @ c += a[7] * b[0]
+ ldr r14, [r2, #9*4] @ b[9]
+ umlal r11, r12, r7, r8 @ c' += a[8] * b[0]
+ ldr r0, [r1, #9*4] @ a[9]
+ umlal r5, r6, r7, r14 @ d += a[8] * b[9]
+ ldr r8, [r2, #8*4] @ b[8]
+ umull r9, r10, r0, r14 @ d' = a[9] * b[9]
+ umlal r5, r6, r0, r8 @ d += a[9] * b[8]
+
+ bic r0, r5, field_not_M @ u7 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u7 * R0
+ umlal r3, r4, r0, r14
+
+ bic r14, r3, field_not_M @ t7 = c & M
+ str r14, [sp, #4 + 7*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u7 * R1
+ umlal r3, r4, r0, r14
+
+ /* J */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u8 = d & M
+ str r0, [sp, #4 + 8*4]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u8 * R0
+ umlal r3, r4, r0, r14
+
+ /******************************************
+ * compute and write back result
+ ******************************************
+ Allocation:
+ r0 r
+ r3:r4 c
+ r5:r6 d
+ r7 t0
+ r8 t1
+ r9 t2
+ r11 u8
+ r12 t9
+ r1,r2,r10,r14 scratch
+
+ Note: do not read from a[] after here, it may overlap with r[]
+ */
+ ldr r0, [sp, #0]
+ add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
+ ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
+ add r1, r0, #3*4
+ stmia r1, {r2,r7,r8,r9,r10}
+
+ bic r2, r3, field_not_M @ r[8] = c & M
+ str r2, [r0, #8*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u8 * R1
+ umlal r3, r4, r11, r14
+ movw r14, field_R0 @ c += d * R0
+ umlal r3, r4, r5, r14
+ adds r3, r3, r12 @ c += t9
+ adc r4, r4, #0
+
+ add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
+ ldmia r1, {r7,r8,r9}
+
+ ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
+ str r2, [r0, #9*4]
+ mov r3, r3, lsr #22 @ c >>= 22
+ orr r3, r3, r4, asl #10
+ mov r4, r4, lsr #22
+ movw r14, field_R1 << 4 @ c += d * (R1 << 4)
+ umlal r3, r4, r5, r14
+
+ movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
+ umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
+ adds r5, r5, r7 @ d.lo += t0
+ mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
+ adc r6, r6, 0 @ d.hi += carry
+
+ bic r2, r5, field_not_M @ r[0] = d & M
+ str r2, [r0, #0*4]
+
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
+ umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
+ adds r5, r5, r8 @ d.lo += t1
+ adc r6, r6, #0 @ d.hi += carry
+ adds r5, r5, r1 @ d.lo += tmp.lo
+ mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
+ adc r6, r6, r2 @ d.hi += carry + tmp.hi
+
+ bic r2, r5, field_not_M @ r[1] = d & M
+ str r2, [r0, #1*4]
+ mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
+ orr r5, r5, r6, asl #6
+
+ add r5, r5, r9 @ d += t2
+ str r5, [r0, #2*4] @ r[2] = d
+
+ add sp, sp, #48
+ ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
+ .size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner
+
+ .align 2
+ .global secp256k1_fe_sqr_inner
+ .type secp256k1_fe_sqr_inner, %function
+ @ Arguments:
+ @ r0 r Can overlap with a
+ @ r1 a
+ @ Stack (total 4+10*4 = 44)
+ @ sp + #0 saved 'r' pointer
+ @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9
+secp256k1_fe_sqr_inner:
+ stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}
+ sub sp, sp, #48 @ frame=44 + alignment
+ str r0, [sp, #0] @ save result address, we need it only at the end
+ /******************************************
+ * Main computation code.
+ ******************************************
+
+ Allocation:
+ r0,r14,r2,r7,r8 scratch
+ r1 a (pointer)
+ r3:r4 c
+ r5:r6 d
+ r11:r12 c'
+ r9:r10 d'
+
+ Note: do not write to r[] here, it may overlap with a[]
+ */
+ /* A interleaved with B */
+ ldr r0, [r1, #1*4] @ a[1]*2
+ ldr r7, [r1, #0*4] @ a[0]
+ mov r0, r0, asl #1
+ ldr r14, [r1, #9*4] @ a[9]
+ umull r3, r4, r7, r7 @ c = a[0] * a[0]
+ ldr r8, [r1, #8*4] @ a[8]
+ mov r7, r7, asl #1
+ umull r5, r6, r7, r14 @ d = a[0]*2 * a[9]
+ ldr r7, [r1, #2*4] @ a[2]*2
+ umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9]
+ ldr r14, [r1, #7*4] @ a[7]
+ umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8]
+ mov r7, r7, asl #1
+ ldr r0, [r1, #3*4] @ a[3]*2
+ umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8]
+ ldr r8, [r1, #6*4] @ a[6]
+ umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7]
+ mov r0, r0, asl #1
+ ldr r7, [r1, #4*4] @ a[4]*2
+ umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7]
+ ldr r14, [r1, #5*4] @ a[5]
+ mov r7, r7, asl #1
+ umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6]
+ umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6]
+ umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5]
+ umlal r9, r10, r14, r14 @ d' += a[5] * a[5]
+
+ bic r0, r5, field_not_M @ t9 = d & M
+ str r0, [sp, #4 + 9*4]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ /* B */
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u0 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u0 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t0 = c & M
+ str r14, [sp, #4 + 0*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u0 * R1
+ umlal r3, r4, r0, r14
+
+ /* C interleaved with D */
+ ldr r0, [r1, #0*4] @ a[0]*2
+ ldr r14, [r1, #1*4] @ a[1]
+ mov r0, r0, asl #1
+ ldr r8, [r1, #2*4] @ a[2]
+ umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1]
+ mov r7, r8, asl #1 @ a[2]*2
+ umull r11, r12, r14, r14 @ c' = a[1] * a[1]
+ ldr r14, [r1, #9*4] @ a[9]
+ umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2]
+ ldr r0, [r1, #3*4] @ a[3]*2
+ ldr r8, [r1, #8*4] @ a[8]
+ umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9]
+ mov r0, r0, asl #1
+ ldr r7, [r1, #4*4] @ a[4]*2
+ umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9]
+ ldr r14, [r1, #7*4] @ a[7]
+ umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8]
+ mov r7, r7, asl #1
+ ldr r0, [r1, #5*4] @ a[5]*2
+ umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8]
+ ldr r8, [r1, #6*4] @ a[6]
+ mov r0, r0, asl #1
+ umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7]
+ umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7]
+ umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6]
+ umlal r9, r10, r8, r8 @ d' += a[6] * a[6]
+
+ bic r0, r5, field_not_M @ u1 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u1 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t1 = c & M
+ str r14, [sp, #4 + 1*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u1 * R1
+ umlal r3, r4, r0, r14
+
+ /* D */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u2 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u2 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t2 = c & M
+ str r14, [sp, #4 + 2*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u2 * R1
+ umlal r3, r4, r0, r14
+
+ /* E interleaved with F */
+ ldr r7, [r1, #0*4] @ a[0]*2
+ ldr r0, [r1, #1*4] @ a[1]*2
+ ldr r14, [r1, #2*4] @ a[2]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #3*4] @ a[3]
+ ldr r2, [r1, #4*4]
+ umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3]
+ mov r0, r0, asl #1
+ umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4]
+ mov r2, r2, asl #1 @ a[4]*2
+ umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3]
+ ldr r8, [r1, #9*4] @ a[9]
+ umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2]
+ ldr r0, [r1, #5*4] @ a[5]*2
+ umlal r11, r12, r14, r14 @ c' += a[2] * a[2]
+ ldr r14, [r1, #8*4] @ a[8]
+ mov r0, r0, asl #1
+ umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9]
+ ldr r7, [r1, #6*4] @ a[6]*2
+ umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #7*4] @ a[7]
+ umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8]
+ umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8]
+ umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7]
+ umlal r9, r10, r8, r8 @ d' += a[7] * a[7]
+
+ bic r0, r5, field_not_M @ u3 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u3 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t3 = c & M
+ str r14, [sp, #4 + 3*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u3 * R1
+ umlal r3, r4, r0, r14
+
+ /* F */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u4 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u4 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t4 = c & M
+ str r14, [sp, #4 + 4*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u4 * R1
+ umlal r3, r4, r0, r14
+
+ /* G interleaved with H */
+ ldr r7, [r1, #0*4] @ a[0]*2
+ ldr r0, [r1, #1*4] @ a[1]*2
+ mov r7, r7, asl #1
+ ldr r8, [r1, #5*4] @ a[5]
+ ldr r2, [r1, #6*4] @ a[6]
+ umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5]
+ ldr r14, [r1, #4*4] @ a[4]
+ mov r0, r0, asl #1
+ umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6]
+ ldr r7, [r1, #2*4] @ a[2]*2
+ umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #3*4] @ a[3]
+ umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4]
+ mov r0, r2, asl #1 @ a[6]*2
+ umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4]
+ ldr r14, [r1, #9*4] @ a[9]
+ umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3]
+ ldr r7, [r1, #7*4] @ a[7]*2
+ umlal r11, r12, r8, r8 @ c' += a[3] * a[3]
+ mov r7, r7, asl #1
+ ldr r8, [r1, #8*4] @ a[8]
+ umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9]
+ umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9]
+ umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8]
+ umlal r9, r10, r8, r8 @ d' += a[8] * a[8]
+
+ bic r0, r5, field_not_M @ u5 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u5 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t5 = c & M
+ str r14, [sp, #4 + 5*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u5 * R1
+ umlal r3, r4, r0, r14
+
+ /* H */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ adds r5, r5, r9 @ d += d'
+ adc r6, r6, r10
+
+ bic r0, r5, field_not_M @ u6 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u6 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t6 = c & M
+ str r14, [sp, #4 + 6*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u6 * R1
+ umlal r3, r4, r0, r14
+
+ /* I interleaved with J */
+ ldr r7, [r1, #0*4] @ a[0]*2
+ ldr r0, [r1, #1*4] @ a[1]*2
+ mov r7, r7, asl #1
+ ldr r8, [r1, #7*4] @ a[7]
+ ldr r2, [r1, #8*4] @ a[8]
+ umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7]
+ ldr r14, [r1, #6*4] @ a[6]
+ mov r0, r0, asl #1
+ umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8]
+ ldr r7, [r1, #2*4] @ a[2]*2
+ umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7]
+ ldr r8, [r1, #5*4] @ a[5]
+ umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6]
+ ldr r0, [r1, #3*4] @ a[3]*2
+ mov r7, r7, asl #1
+ umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6]
+ ldr r14, [r1, #4*4] @ a[4]
+ mov r0, r0, asl #1
+ umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5]
+ mov r2, r2, asl #1 @ a[8]*2
+ umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5]
+ umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4]
+ umlal r11, r12, r14, r14 @ c' += a[4] * a[4]
+ ldr r8, [r1, #9*4] @ a[9]
+ umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9]
+ @ r8 will be used in J
+
+ bic r0, r5, field_not_M @ u7 = d & M
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u7 * R0
+ umlal r3, r4, r0, r14
+ bic r14, r3, field_not_M @ t7 = c & M
+ str r14, [sp, #4 + 7*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u7 * R1
+ umlal r3, r4, r0, r14
+
+ /* J */
+ adds r3, r3, r11 @ c += c'
+ adc r4, r4, r12
+ umlal r5, r6, r8, r8 @ d += a[9] * a[9]
+
+ bic r0, r5, field_not_M @ u8 = d & M
+ str r0, [sp, #4 + 8*4]
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+ movw r14, field_R0 @ c += u8 * R0
+ umlal r3, r4, r0, r14
+
+ /******************************************
+ * compute and write back result
+ ******************************************
+ Allocation:
+ r0 r
+ r3:r4 c
+ r5:r6 d
+ r7 t0
+ r8 t1
+ r9 t2
+ r11 u8
+ r12 t9
+ r1,r2,r10,r14 scratch
+
+ Note: do not read from a[] after here, it may overlap with r[]
+ */
+ ldr r0, [sp, #0]
+ add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
+ ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
+ add r1, r0, #3*4
+ stmia r1, {r2,r7,r8,r9,r10}
+
+ bic r2, r3, field_not_M @ r[8] = c & M
+ str r2, [r0, #8*4]
+ mov r3, r3, lsr #26 @ c >>= 26
+ orr r3, r3, r4, asl #6
+ mov r4, r4, lsr #26
+ mov r14, field_R1 @ c += u8 * R1
+ umlal r3, r4, r11, r14
+ movw r14, field_R0 @ c += d * R0
+ umlal r3, r4, r5, r14
+ adds r3, r3, r12 @ c += t9
+ adc r4, r4, #0
+
+ add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
+ ldmia r1, {r7,r8,r9}
+
+ ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
+ str r2, [r0, #9*4]
+ mov r3, r3, lsr #22 @ c >>= 22
+ orr r3, r3, r4, asl #10
+ mov r4, r4, lsr #22
+ movw r14, field_R1 << 4 @ c += d * (R1 << 4)
+ umlal r3, r4, r5, r14
+
+ movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
+ umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
+ adds r5, r5, r7 @ d.lo += t0
+ mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
+ adc r6, r6, 0 @ d.hi += carry
+
+ bic r2, r5, field_not_M @ r[0] = d & M
+ str r2, [r0, #0*4]
+
+ mov r5, r5, lsr #26 @ d >>= 26
+ orr r5, r5, r6, asl #6
+ mov r6, r6, lsr #26
+
+ movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
+ umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
+ adds r5, r5, r8 @ d.lo += t1
+ adc r6, r6, #0 @ d.hi += carry
+ adds r5, r5, r1 @ d.lo += tmp.lo
+ mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
+ adc r6, r6, r2 @ d.hi += carry + tmp.hi
+
+ bic r2, r5, field_not_M @ r[1] = d & M
+ str r2, [r0, #1*4]
+ mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
+ orr r5, r5, r6, asl #6
+
+ add r5, r5, r9 @ d += t2
+ str r5, [r0, #2*4] @ r[2] = d
+
+ add sp, sp, #48
+ ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
+ .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner
+
diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c
index 5a7c6376e0..cde5e2dbb4 100644
--- a/src/secp256k1/src/bench_ecdh.c
+++ b/src/secp256k1/src/bench_ecdh.c
@@ -28,7 +28,8 @@ static void bench_ecdh_setup(void* arg) {
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
};
- data->ctx = secp256k1_context_create(0);
+ /* create a context with no capabilities */
+ data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
for (i = 0; i < 32; i++) {
data->scalar[i] = i + 1;
}
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index 7809f5f8cf..0809f77bda 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -181,12 +181,12 @@ void bench_field_inverse_var(void* arg) {
}
}
-void bench_field_sqrt_var(void* arg) {
+void bench_field_sqrt(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
for (i = 0; i < 20000; i++) {
- secp256k1_fe_sqrt_var(&data->fe_x, &data->fe_x);
+ secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);
secp256k1_fe_add(&data->fe_x, &data->fe_y);
}
}
@@ -227,6 +227,15 @@ void bench_group_add_affine_var(void* arg) {
}
}
+void bench_group_jacobi_var(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+
+ for (i = 0; i < 20000; i++) {
+ secp256k1_gej_has_quad_y_var(&data->gej_x);
+ }
+}
+
void bench_ecmult_wnaf(void* arg) {
int i;
bench_inv_t *data = (bench_inv_t*)arg;
@@ -299,6 +308,21 @@ void bench_context_sign(void* arg) {
}
}
+#ifndef USE_NUM_NONE
+void bench_num_jacobi(void* arg) {
+ int i;
+ bench_inv_t *data = (bench_inv_t*)arg;
+ secp256k1_num nx, norder;
+
+ secp256k1_scalar_get_num(&nx, &data->scalar_x);
+ secp256k1_scalar_order_get_num(&norder);
+ secp256k1_scalar_get_num(&norder, &data->scalar_y);
+
+ for (i = 0; i < 200000; i++) {
+ secp256k1_num_jacobi(&nx, &norder);
+ }
+}
+#endif
int have_flag(int argc, char** argv, char *flag) {
char** argm = argv + argc;
@@ -333,12 +357,13 @@ int main(int argc, char **argv) {
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000);
- if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt_var", bench_field_sqrt_var, bench_setup, NULL, &data, 10, 20000);
+ if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000);
+ if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);
@@ -350,5 +375,8 @@ int main(int argc, char **argv) {
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20);
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200);
+#ifndef USE_NUM_NONE
+ if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000);
+#endif
return 0;
}
diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c
index 5718320cda..418defa0aa 100644
--- a/src/secp256k1/src/bench_verify.c
+++ b/src/secp256k1/src/bench_verify.c
@@ -11,6 +11,12 @@
#include "util.h"
#include "bench.h"
+#ifdef ENABLE_OPENSSL_TESTS
+#include <openssl/bn.h>
+#include <openssl/ecdsa.h>
+#include <openssl/obj_mac.h>
+#endif
+
typedef struct {
secp256k1_context *ctx;
unsigned char msg[32];
@@ -19,6 +25,9 @@ typedef struct {
size_t siglen;
unsigned char pubkey[33];
size_t pubkeylen;
+#ifdef ENABLE_OPENSSL_TESTS
+ EC_GROUP* ec_group;
+#endif
} benchmark_verify_t;
static void benchmark_verify(void* arg) {
@@ -40,6 +49,36 @@ static void benchmark_verify(void* arg) {
}
}
+#ifdef ENABLE_OPENSSL_TESTS
+static void benchmark_verify_openssl(void* arg) {
+ int i;
+ benchmark_verify_t* data = (benchmark_verify_t*)arg;
+
+ for (i = 0; i < 20000; i++) {
+ data->sig[data->siglen - 1] ^= (i & 0xFF);
+ data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
+ data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
+ {
+ EC_KEY *pkey = EC_KEY_new();
+ const unsigned char *pubkey = &data->pubkey[0];
+ int result;
+
+ CHECK(pkey != NULL);
+ result = EC_KEY_set_group(pkey, data->ec_group);
+ CHECK(result);
+ result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL;
+ CHECK(result);
+ result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0);
+ CHECK(result);
+ EC_KEY_free(pkey);
+ }
+ data->sig[data->siglen - 1] ^= (i & 0xFF);
+ data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
+ data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
+ }
+}
+#endif
+
int main(void) {
int i;
secp256k1_pubkey pubkey;
@@ -62,6 +101,11 @@ int main(void) {
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
+#ifdef ENABLE_OPENSSL_TESTS
+ data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1);
+ run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000);
+ EC_GROUP_free(data.ec_group);
+#endif
secp256k1_context_destroy(data.ctx);
return 0;
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index 90ac94770e..7a6a25318c 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -58,22 +58,24 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
int global_sign;
int skew = 0;
int word = 0;
+
/* 1 2 3 */
int u_last;
int u;
-#ifdef USE_ENDOMORPHISM
int flip;
int bit;
secp256k1_scalar neg_s;
int not_neg_one;
- /* If we are using the endomorphism, we cannot handle even numbers by negating
- * them, since we are working with 128-bit numbers whose negations would be 256
- * bits, eliminating the performance advantage. Instead we use a technique from
+ /* Note that we cannot handle even numbers by negating them to be odd, as is
+ * done in other implementations, since if our scalars were specified to have
+ * width < 256 for performance reasons, their negations would have width 256
+ * and we'd lose any performance benefit. Instead, we use a technique from
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
- * or 2 (for odd) to the number we are encoding, then compensating after the
- * multiplication. */
- /* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */
+ * or 2 (for odd) to the number we are encoding, returning a skew value indicating
+ * this, and having the caller compensate after doing the multiplication. */
+
+ /* Negative numbers will be negated to keep their bit representation below the maximum width */
flip = secp256k1_scalar_is_high(&s);
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
bit = flip ^ (s.d[0] & 1);
@@ -89,11 +91,6 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
global_sign = secp256k1_scalar_cond_negate(&s, flip);
global_sign *= not_neg_one * 2 - 1;
skew = 1 << bit;
-#else
- /* Otherwise, we just negate to force oddness */
- int is_even = secp256k1_scalar_is_even(&s);
- global_sign = secp256k1_scalar_cond_negate(&s, is_even);
-#endif
/* 4 */
u_last = secp256k1_scalar_shr_int(&s, w);
@@ -127,15 +124,13 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_ge tmpa;
secp256k1_fe Z;
+ int skew_1;
+ int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
#ifdef USE_ENDOMORPHISM
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
- int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
- int skew_1;
int skew_lam;
secp256k1_scalar q_1, q_lam;
-#else
- int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)];
#endif
int i;
@@ -145,18 +140,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
#ifdef USE_ENDOMORPHISM
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
- /* no need for zero correction when using endomorphism since even
- * numbers have one added to them anyway */
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1);
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1);
#else
- int is_zero = secp256k1_scalar_is_zero(scalar);
- /* the wNAF ladder cannot handle zero, so bump this to one .. we will
- * correct the result after the fact */
- sc.d[0] += is_zero;
- VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc));
-
- secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1);
+ skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1);
#endif
/* Calculate odd multiples of a.
@@ -179,21 +166,15 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
/* first loop iteration (separated out so we can directly set r, rather
* than having it start at infinity, get doubled several times, then have
* its new value added to it) */
-#ifdef USE_ENDOMORPHISM
i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
secp256k1_gej_set_ge(r, &tmpa);
-
+#ifdef USE_ENDOMORPHISM
i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
secp256k1_gej_add_ge(r, r, &tmpa);
-#else
- i = wnaf[WNAF_SIZE(WINDOW_A - 1)];
- VERIFY_CHECK(i != 0);
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
- secp256k1_gej_set_ge(r, &tmpa);
#endif
/* remaining loop iterations */
for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) {
@@ -202,59 +183,57 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
for (j = 0; j < WINDOW_A - 1; ++j) {
secp256k1_gej_double_nonzero(r, r, NULL);
}
-#ifdef USE_ENDOMORPHISM
+
n = wnaf_1[i];
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
-
+#ifdef USE_ENDOMORPHISM
n = wnaf_lam[i];
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
-#else
- n = wnaf[i];
- VERIFY_CHECK(n != 0);
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
- secp256k1_gej_add_ge(r, r, &tmpa);
#endif
}
secp256k1_fe_mul(&r->z, &r->z, &Z);
-#ifdef USE_ENDOMORPHISM
{
/* Correct for wNAF skew */
secp256k1_ge correction = *a;
secp256k1_ge_storage correction_1_stor;
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_storage correction_lam_stor;
+#endif
secp256k1_ge_storage a2_stor;
secp256k1_gej tmpj;
secp256k1_gej_set_ge(&tmpj, &correction);
secp256k1_gej_double_var(&tmpj, &tmpj, NULL);
secp256k1_ge_set_gej(&correction, &tmpj);
secp256k1_ge_to_storage(&correction_1_stor, a);
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_to_storage(&correction_lam_stor, a);
+#endif
secp256k1_ge_to_storage(&a2_stor, &correction);
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
+#endif
/* Apply the correction */
secp256k1_ge_from_storage(&correction, &correction_1_stor);
secp256k1_ge_neg(&correction, &correction);
secp256k1_gej_add_ge(r, r, &correction);
+#ifdef USE_ENDOMORPHISM
secp256k1_ge_from_storage(&correction, &correction_lam_stor);
secp256k1_ge_neg(&correction, &correction);
secp256k1_ge_mul_lambda(&correction, &correction);
secp256k1_gej_add_ge(r, r, &correction);
- }
-#else
- /* correct for zero */
- r->infinity |= is_zero;
#endif
+ }
}
#endif
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index e6e5f47188..81ae08e100 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -11,6 +11,8 @@
#include "scalar.h"
#include "ecmult.h"
+#include <string.h>
+
/* optimal for 128-bit and 256-bit exponents. */
#define WINDOW_A 5
diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h
index 2d52af5e36..c5ba074244 100644
--- a/src/secp256k1/src/field.h
+++ b/src/secp256k1/src/field.h
@@ -57,6 +57,9 @@ static int secp256k1_fe_is_zero(const secp256k1_fe *a);
static int secp256k1_fe_is_odd(const secp256k1_fe *a);
/** Compare two field elements. Requires magnitude-1 inputs. */
+static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
+
+/** Same as secp256k1_fe_equal, but may be variable time. */
static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
/** Compare two field elements. Requires both inputs to be normalized */
@@ -92,7 +95,10 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
* The input's magnitude can be at most 8. The output magnitude is 1 (but not
* guaranteed to be normalized). The result in r will always be a square
* itself. */
-static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a);
+static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a);
+
+/** Checks whether a field element is a quadratic residue. */
+static int secp256k1_fe_is_quad_var(const secp256k1_fe *a);
/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
* at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 212cc5396a..7b8c079608 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -7,8 +7,6 @@
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
#define _SECP256K1_FIELD_REPR_IMPL_H_
-#include <stdio.h>
-#include <string.h>
#include "util.h"
#include "num.h"
#include "field.h"
@@ -429,6 +427,14 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f
#endif
}
+#if defined(USE_EXTERNAL_ASM)
+
+/* External assembler implementation */
+void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b);
+void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a);
+
+#else
+
#ifdef VERIFY
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
#else
@@ -1037,7 +1043,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
VERIFY_BITS(r[2], 27);
/* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
-
+#endif
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
#ifdef VERIFY
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index b31e24ab81..7a99eb21ec 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -11,7 +11,6 @@
#include "libsecp256k1-config.h"
#endif
-#include <string.h>
#include "util.h"
#include "num.h"
#include "field.h"
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index 9280bb5ea2..0bf22bdd3e 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -137,7 +137,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
VERIFY_BITS(r[2], 52);
VERIFY_BITS(c, 63);
/* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += d * R + t3;;
+ c += d * R + t3;
VERIFY_BITS(c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[3] = c & M; c >>= 52;
@@ -259,7 +259,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
VERIFY_BITS(c, 63);
/* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
- c += d * R + t3;;
+ c += d * R + t3;
VERIFY_BITS(c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[3] = c & M; c >>= 52;
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 77f4aae2f9..52cd902eb3 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -21,6 +21,13 @@
#error "Please select field implementation"
#endif
+SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
+ secp256k1_fe na;
+ secp256k1_fe_negate(&na, a, 1);
+ secp256k1_fe_add(&na, b);
+ return secp256k1_fe_normalizes_to_zero(&na);
+}
+
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
secp256k1_fe_negate(&na, a, 1);
@@ -28,7 +35,7 @@ SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const
return secp256k1_fe_normalizes_to_zero_var(&na);
}
-static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) {
+static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
/** Given that p is congruent to 3 mod 4, we can compute the square root of
* a mod p as the (p+1)/4'th power of a.
*
@@ -123,7 +130,7 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) {
/* Check that a square root was actually calculated */
secp256k1_fe_sqr(&t1, r);
- return secp256k1_fe_equal_var(&t1, a);
+ return secp256k1_fe_equal(&t1, a);
}
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) {
@@ -280,4 +287,29 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k
r[0] = u;
}
+static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
+#ifndef USE_NUM_NONE
+ unsigned char b[32];
+ secp256k1_num n;
+ secp256k1_num m;
+ /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
+ static const unsigned char prime[32] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
+ };
+
+ secp256k1_fe c = *a;
+ secp256k1_fe_normalize_var(&c);
+ secp256k1_fe_get_b32(b, &c);
+ secp256k1_num_set_bin(&n, b, 32);
+ secp256k1_num_set_bin(&m, prime, 32);
+ return secp256k1_num_jacobi(&n, &m) >= 0;
+#else
+ secp256k1_fe r;
+ return secp256k1_fe_sqrt(&r, a);
+#endif
+}
+
#endif
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index ebfe1ca70c..d515716744 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -47,7 +47,7 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se
* and a Y coordinate that is a quadratic residue modulo p. The return value
* is true iff a coordinate with the given X coordinate exists.
*/
-static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x);
+static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x);
/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness
* for Y. Return value indicates whether the result is valid. */
@@ -94,6 +94,9 @@ static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a);
/** Check whether a group element is the point at infinity. */
static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
+/** Check whether a group element's y coordinate is a quadratic residue. */
+static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);
+
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).
* a may not be zero. Constant time. */
static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index 42e2f6e6eb..3e9c4c410d 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -7,8 +7,6 @@
#ifndef _SECP256K1_GROUP_IMPL_H_
#define _SECP256K1_GROUP_IMPL_H_
-#include <string.h>
-
#include "num.h"
#include "field.h"
#include "group.h"
@@ -165,7 +163,7 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
secp256k1_fe_clear(&r->y);
}
-static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) {
+static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
secp256k1_fe x2, x3, c;
r->x = *x;
secp256k1_fe_sqr(&x2, x);
@@ -173,11 +171,11 @@ static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) {
r->infinity = 0;
secp256k1_fe_set_int(&c, 7);
secp256k1_fe_add(&c, &x3);
- return secp256k1_fe_sqrt_var(&r->y, &c);
+ return secp256k1_fe_sqrt(&r->y, &c);
}
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
- if (!secp256k1_ge_set_xquad_var(r, x)) {
+ if (!secp256k1_ge_set_xquad(r, x)) {
return 0;
}
secp256k1_fe_normalize_var(&r->y);
@@ -251,11 +249,23 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
}
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
- /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */
+ /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
+ *
+ * Note that there is an implementation described at
+ * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
+ * which trades a multiply for a square, but in practice this is actually slower,
+ * mainly because it requires more normalizations.
+ */
secp256k1_fe t1,t2,t3,t4;
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
+ *
+ * Having said this, if this function receives a point on a sextic twist, e.g. by
+ * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
+ * since -6 does have a cube root mod p. For this point, this function will not set
+ * the infinity flag even though the point doubles to infinity, and the result
+ * point will be gibberish (z = 0 but infinity = 0).
*/
r->infinity = a->infinity;
if (r->infinity) {
@@ -623,4 +633,18 @@ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
}
#endif
+static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
+ secp256k1_fe yz;
+
+ if (a->infinity) {
+ return 0;
+ }
+
+ /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as
+ * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z
+ is */
+ secp256k1_fe_mul(&yz, &a->y, &a->z);
+ return secp256k1_fe_is_quad_var(&yz);
+}
+
#endif
diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h
index 0ff01e63fa..fca98cab9f 100644
--- a/src/secp256k1/src/hash.h
+++ b/src/secp256k1/src/hash.h
@@ -11,7 +11,7 @@
#include <stdint.h>
typedef struct {
- uint32_t s[32];
+ uint32_t s[8];
uint32_t buf[16]; /* In big endian */
size_t bytes;
} secp256k1_sha256_t;
diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h
index ae55df6d8a..b47e65f830 100644
--- a/src/secp256k1/src/hash_impl.h
+++ b/src/secp256k1/src/hash_impl.h
@@ -269,15 +269,13 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
rng->retry = 0;
}
-
+#undef BE32
#undef Round
-#undef sigma0
#undef sigma1
-#undef Sigma0
+#undef sigma0
#undef Sigma1
-#undef Ch
+#undef Sigma0
#undef Maj
-#undef ReadBE32
-#undef WriteBE32
+#undef Ch
#endif
diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
index 90a498eaa2..be67048fbe 100644
--- a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
+++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
@@ -1,60 +1,478 @@
+/*
+ * Copyright 2013 Google Inc.
+ * Copyright 2014-2016 the libsecp256k1 contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package org.bitcoin;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.math.BigInteger;
import com.google.common.base.Preconditions;
-
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import static org.bitcoin.NativeSecp256k1Util.*;
/**
- * This class holds native methods to handle ECDSA verification.
- * You can find an example library that can be used for this at
- * https://github.com/sipa/secp256k1
+ * <p>This class holds native methods to handle ECDSA verification.</p>
+ *
+ * <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
+ *
+ * <p>To build secp256k1 for use with bitcoinj, run
+ * `./configure --enable-jni --enable-experimental --enable-module-schnorr --enable-module-ecdh`
+ * and `make` then copy `.libs/libsecp256k1.so` to your system library path
+ * or point the JVM to the folder containing it with -Djava.library.path
+ * </p>
*/
public class NativeSecp256k1 {
- public static final boolean enabled;
- static {
- boolean isEnabled = true;
- try {
- System.loadLibrary("javasecp256k1");
- } catch (UnsatisfiedLinkError e) {
- isEnabled = false;
- }
- enabled = isEnabled;
- }
-
+
+ private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ private static final Lock r = rwl.readLock();
+ private static final Lock w = rwl.writeLock();
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
/**
* Verifies the given secp256k1 signature in native code.
* Calling when enabled == false is undefined (probably library not loaded)
- *
+ *
* @param data The data which was signed, must be exactly 32 bytes
* @param signature The signature
* @param pub The public key which did the signing
*/
- public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
+ public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
ByteBuffer byteBuff = nativeECDSABuffer.get();
- if (byteBuff == null) {
- byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
+ if (byteBuff == null || byteBuff.capacity() < 520) {
+ byteBuff = ByteBuffer.allocateDirect(520);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(data);
- byteBuff.putInt(signature.length);
- byteBuff.putInt(pub.length);
byteBuff.put(signature);
byteBuff.put(pub);
- return secp256k1_ecdsa_verify(byteBuff) == 1;
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
+ } finally {
+ r.unlock();
+ }
+ }
+
+ /**
+ * libsecp256k1 Create an ECDSA signature.
+ *
+ * @param data Message hash, 32 bytes
+ * @param key Secret key, 32 bytes
+ *
+ * Return values
+ * @param sig byte array of signature
+ */
+ public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
+ Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
+ byteBuff = ByteBuffer.allocateDirect(32 + 32);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(data);
+ byteBuff.put(sec);
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] sigArr = retByteArray[0];
+ int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(sigArr.length, sigLen, "Got bad signature length.");
+
+ return retVal == 0 ? new byte[0] : sigArr;
+ }
+
+ /**
+ * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
+ *
+ * @param seckey ECDSA Secret key, 32 bytes
+ */
+ public static boolean secKeyVerify(byte[] seckey) {
+ Preconditions.checkArgument(seckey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < seckey.length) {
+ byteBuff = ByteBuffer.allocateDirect(seckey.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seckey);
+
+ r.lock();
+ try {
+ return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
+ } finally {
+ r.unlock();
+ }
+ }
+
+
+ /**
+ * libsecp256k1 Compute Pubkey - computes public key from secret key
+ *
+ * @param seckey ECDSA Secret key, 32 bytes
+ *
+ * Return values
+ * @param pubkey ECDSA Public key, 33 or 65 bytes
+ */
+ //TODO add a 'compressed' arg
+ public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
+ Preconditions.checkArgument(seckey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < seckey.length) {
+ byteBuff = ByteBuffer.allocateDirect(seckey.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seckey);
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] pubArr = retByteArray[0];
+ int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
+
+ return retVal == 0 ? new byte[0]: pubArr;
+ }
+
+ /**
+ * libsecp256k1 Cleanup - This destroys the secp256k1 context object
+ * This should be called at the end of the program for proper cleanup of the context.
+ */
+ public static synchronized void cleanup() {
+ w.lock();
+ try {
+ secp256k1_destroy_context(Secp256k1Context.getContext());
+ } finally {
+ w.unlock();
+ }
+ }
+
+ public static long cloneContext() {
+ r.lock();
+ try {
+ return secp256k1_ctx_clone(Secp256k1Context.getContext());
+ } finally { r.unlock(); }
+ }
+
+ /**
+ * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param seckey 32-byte seckey
+ */
+ public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(privkey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(privkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] privArr = retByteArray[0];
+
+ int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(privArr.length, privLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return privArr;
}
/**
- * @param byteBuff signature format is byte[32] data,
- * native-endian int signatureLength, native-endian int pubkeyLength,
- * byte[signatureLength] signature, byte[pubkeyLength] pub
- * @returns 1 for valid signature, anything else for invalid
+ * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param seckey 32-byte seckey
*/
- private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
+ public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(privkey.length == 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(privkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] privArr = retByteArray[0];
+
+ int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(privArr.length, privLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return privArr;
+ }
+
+ /**
+ * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param pubkey 32-byte seckey
+ */
+ public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(pubkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
+ } finally {
+ r.unlock();
+ }
+
+ byte[] pubArr = retByteArray[0];
+
+ int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return pubArr;
+ }
+
+ /**
+ * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
+ *
+ * @param tweak some bytes to tweak with
+ * @param pubkey 32-byte seckey
+ */
+ public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
+ Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
+ byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(pubkey);
+ byteBuff.put(tweak);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
+ } finally {
+ r.unlock();
+ }
+
+ byte[] pubArr = retByteArray[0];
+
+ int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
+ int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
+
+ assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
+
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return pubArr;
+ }
+
+ /**
+ * libsecp256k1 create ECDH secret - constant time ECDH calculation
+ *
+ * @param seckey byte array of secret key used in exponentiaion
+ * @param pubkey byte array of public key used in exponentiaion
+ */
+ public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
+ Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
+ byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seckey);
+ byteBuff.put(pubkey);
+
+ byte[][] retByteArray;
+ r.lock();
+ try {
+ retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
+ } finally {
+ r.unlock();
+ }
+
+ byte[] resArr = retByteArray[0];
+ int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+
+ assertEquals(resArr.length, 32, "Got bad result length.");
+ assertEquals(retVal, 1, "Failed return value check.");
+
+ return resArr;
+ }
+
+ /**
+ * libsecp256k1 randomize - updates the context randomization
+ *
+ * @param seed 32-byte random seed
+ */
+ public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
+ Preconditions.checkArgument(seed.length == 32 || seed == null);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null || byteBuff.capacity() < seed.length) {
+ byteBuff = ByteBuffer.allocateDirect(seed.length);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(seed);
+
+ w.lock();
+ try {
+ return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
+ } finally {
+ w.unlock();
+ }
+ }
+
+ public static byte[] schnorrSign(byte[] data, byte[] sec) throws AssertFailException {
+ Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
+
+ ByteBuffer byteBuff = nativeECDSABuffer.get();
+ if (byteBuff == null) {
+ byteBuff = ByteBuffer.allocateDirect(32 + 32);
+ byteBuff.order(ByteOrder.nativeOrder());
+ nativeECDSABuffer.set(byteBuff);
+ }
+ byteBuff.rewind();
+ byteBuff.put(data);
+ byteBuff.put(sec);
+
+ byte[][] retByteArray;
+
+ r.lock();
+ try {
+ retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext());
+ } finally {
+ r.unlock();
+ }
+
+ byte[] sigArr = retByteArray[0];
+ int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
+
+ assertEquals(sigArr.length, 64, "Got bad signature length.");
+
+ return retVal == 0 ? new byte[0] : sigArr;
+ }
+
+ private static native long secp256k1_ctx_clone(long context);
+
+ private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
+
+ private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
+
+ private static native void secp256k1_destroy_context(long context);
+
+ private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
+
+ private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
+
+ private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
+
+ private static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context);
+
+ private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
+
}
diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java
new file mode 100644
index 0000000000..f18ce95810
--- /dev/null
+++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java
@@ -0,0 +1,247 @@
+package org.bitcoin;
+
+import com.google.common.io.BaseEncoding;
+import java.util.Arrays;
+import java.math.BigInteger;
+import javax.xml.bind.DatatypeConverter;
+import static org.bitcoin.NativeSecp256k1Util.*;
+
+/**
+ * This class holds test cases defined for testing this library.
+ */
+public class NativeSecp256k1Test {
+
+ //TODO improve comments/add more tests
+ /**
+ * This tests verify() for a valid signature
+ */
+ public static void testVerifyPos() throws AssertFailException{
+ boolean result = false;
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+
+ result = NativeSecp256k1.verify( data, sig, pub);
+ assertEquals( result, true , "testVerifyPos");
+ }
+
+ /**
+ * This tests verify() for a non-valid signature
+ */
+ public static void testVerifyNeg() throws AssertFailException{
+ boolean result = false;
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
+ byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+
+ result = NativeSecp256k1.verify( data, sig, pub);
+ //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
+ assertEquals( result, false , "testVerifyNeg");
+ }
+
+ /**
+ * This tests secret key verify() for a valid secretkey
+ */
+ public static void testSecKeyVerifyPos() throws AssertFailException{
+ boolean result = false;
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ result = NativeSecp256k1.secKeyVerify( sec );
+ //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
+ assertEquals( result, true , "testSecKeyVerifyPos");
+ }
+
+ /**
+ * This tests secret key verify() for a invalid secretkey
+ */
+ public static void testSecKeyVerifyNeg() throws AssertFailException{
+ boolean result = false;
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
+
+ result = NativeSecp256k1.secKeyVerify( sec );
+ //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
+ assertEquals( result, false , "testSecKeyVerifyNeg");
+ }
+
+ /**
+ * This tests public key create() for a valid secretkey
+ */
+ public static void testPubKeyCreatePos() throws AssertFailException{
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.computePubkey( sec);
+ String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos");
+ }
+
+ /**
+ * This tests public key create() for a invalid secretkey
+ */
+ public static void testPubKeyCreateNeg() throws AssertFailException{
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.computePubkey( sec);
+ String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( pubkeyString, "" , "testPubKeyCreateNeg");
+ }
+
+ /**
+ * This tests sign() for a valid secretkey
+ */
+ public static void testSignPos() throws AssertFailException{
+
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.sign(data, sec);
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
+ }
+
+ /**
+ * This tests sign() for a invalid secretkey
+ */
+ public static void testSignNeg() throws AssertFailException{
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.sign(data, sec);
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString, "" , "testSignNeg");
+ }
+
+ /**
+ * This tests private key tweak-add
+ */
+ public static void testPrivKeyTweakAdd_1() throws AssertFailException {
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1");
+ }
+
+ /**
+ * This tests private key tweak-mul
+ */
+ public static void testPrivKeyTweakMul_1() throws AssertFailException {
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1");
+ }
+
+ /**
+ * This tests private key tweak-add uncompressed
+ */
+ public static void testPrivKeyTweakAdd_2() throws AssertFailException {
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2");
+ }
+
+ /**
+ * This tests private key tweak-mul uncompressed
+ */
+ public static void testPrivKeyTweakMul_2() throws AssertFailException {
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+ byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
+
+ byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2");
+ }
+
+ /**
+ * This tests seed randomization
+ */
+ public static void testRandomize() throws AssertFailException {
+ byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
+ boolean result = NativeSecp256k1.randomize(seed);
+ assertEquals( result, true, "testRandomize");
+ }
+
+ /**
+ * This tests signSchnorr() for a valid secretkey
+ */
+ public static void testSchnorrSign() throws AssertFailException{
+
+ byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.schnorrSign(data, sec);
+ String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( sigString, "C5E929AA058B982048760422D3B563749B7D0E50C5EBD8CD2FFC23214BD6A2F1B072C13880997EBA847CF20F2F90FCE07C1CA33A890A4127095A351127F8D95F" , "testSchnorrSign");
+ }
+
+ /**
+ * This tests signSchnorr() for a valid secretkey
+ */
+ public static void testCreateECDHSecret() throws AssertFailException{
+
+ byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
+ byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
+
+ byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);
+ String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
+ assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret");
+ }
+
+ public static void main(String[] args) throws AssertFailException{
+
+
+ System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n");
+
+ assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" );
+
+ //Test verify() success/fail
+ testVerifyPos();
+ testVerifyNeg();
+
+ //Test secKeyVerify() success/fail
+ testSecKeyVerifyPos();
+ testSecKeyVerifyNeg();
+
+ //Test computePubkey() success/fail
+ testPubKeyCreatePos();
+ testPubKeyCreateNeg();
+
+ //Test sign() success/fail
+ testSignPos();
+ testSignNeg();
+
+ //Test Schnorr (partial support) //TODO
+ testSchnorrSign();
+ //testSchnorrVerify
+ //testSchnorrRecovery
+
+ //Test privKeyTweakAdd() 1
+ testPrivKeyTweakAdd_1();
+
+ //Test privKeyTweakMul() 2
+ testPrivKeyTweakMul_1();
+
+ //Test privKeyTweakAdd() 3
+ testPrivKeyTweakAdd_2();
+
+ //Test privKeyTweakMul() 4
+ testPrivKeyTweakMul_2();
+
+ //Test randomize()
+ testRandomize();
+
+ //Test ECDH
+ testCreateECDHSecret();
+
+ NativeSecp256k1.cleanup();
+
+ System.out.println(" All tests passed." );
+
+ }
+}
diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java
new file mode 100644
index 0000000000..04732ba044
--- /dev/null
+++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014-2016 the libsecp256k1 contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.bitcoin;
+
+public class NativeSecp256k1Util{
+
+ public static void assertEquals( int val, int val2, String message ) throws AssertFailException{
+ if( val != val2 )
+ throw new AssertFailException("FAIL: " + message);
+ }
+
+ public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{
+ if( val != val2 )
+ throw new AssertFailException("FAIL: " + message);
+ else
+ System.out.println("PASS: " + message);
+ }
+
+ public static void assertEquals( String val, String val2, String message ) throws AssertFailException{
+ if( !val.equals(val2) )
+ throw new AssertFailException("FAIL: " + message);
+ else
+ System.out.println("PASS: " + message);
+ }
+
+ public static class AssertFailException extends Exception {
+ public AssertFailException(String message) {
+ super( message );
+ }
+ }
+}
diff --git a/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java
new file mode 100644
index 0000000000..216c986a8b
--- /dev/null
+++ b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014-2016 the libsecp256k1 contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.bitcoin;
+
+/**
+ * This class holds the context reference used in native methods
+ * to handle ECDSA operations.
+ */
+public class Secp256k1Context {
+ private static final boolean enabled; //true if the library is loaded
+ private static final long context; //ref to pointer to context obj
+
+ static { //static initializer
+ boolean isEnabled = true;
+ long contextRef = -1;
+ try {
+ System.loadLibrary("secp256k1");
+ contextRef = secp256k1_init_context();
+ } catch (UnsatisfiedLinkError e) {
+ System.out.println("UnsatisfiedLinkError: " + e.toString());
+ isEnabled = false;
+ }
+ enabled = isEnabled;
+ context = contextRef;
+ }
+
+ public static boolean isEnabled() {
+ return enabled;
+ }
+
+ public static long getContext() {
+ if(!enabled) return -1; //sanity check
+ return context;
+ }
+
+ private static native long secp256k1_init_context();
+}
diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
index bb4cd70728..dba9524dd4 100644
--- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
+++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
@@ -1,23 +1,411 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
#include "org_bitcoin_NativeSecp256k1.h"
#include "include/secp256k1.h"
+#include "include/secp256k1_ecdh.h"
+#include "include/secp256k1_recovery.h"
+#include "include/secp256k1_schnorr.h"
-JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
- (JNIEnv* env, jclass classObject, jobject byteBufferObject)
+
+SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
+ (JNIEnv* env, jclass classObject, jlong ctx_l)
+{
+ const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx);
+
+ (void)classObject;(void)env;
+
+ return ctx_clone_l;
+
+}
+
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+
+ (void)classObject;
+
+ return secp256k1_context_randomize(ctx, seed);
+
+}
+
+SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
+ (JNIEnv* env, jclass classObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ secp256k1_context_destroy(ctx);
+
+ (void)classObject;(void)env;
+}
+
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+
+ unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* sigdata = { (unsigned char*) (data + 32) };
+ const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };
+
+ secp256k1_ecdsa_signature sig;
+ secp256k1_pubkey pubkey;
+
+ int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
+
+ if( ret ) {
+ ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
+
+ if( ret ) {
+ ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);
+ }
+ }
+
+ (void)classObject;
+
+ return ret;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ unsigned char* secKey = (unsigned char*) (data + 32);
+
+ jobjectArray retArray;
+ jbyteArray sigArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ secp256k1_ecdsa_signature sig[72];
+
+ int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );
+
+ unsigned char outputSer[72];
+ size_t outputLen = 72;
+
+ if( ret ) {
+ int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ sigArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+
+ (void)classObject;
+
+ return secp256k1_ec_seckey_verify(ctx, secKey);
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+
+ secp256k1_pubkey pubkey;
+
+ jobjectArray retArray;
+ jbyteArray pubkeyArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);
+
+ unsigned char outputSer[65];
+ size_t outputLen = 65;
+
+ if( ret ) {
+ int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ pubkeyArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (privkey + 32);
+
+ jobjectArray retArray;
+ jbyteArray privArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ int privkeylen = 32;
+
+ int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak);
+
+ intsarray[0] = privkeylen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ privArray = (*env)->NewByteArray(env, privkeylen);
+ (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
+ (*env)->SetObjectArrayElement(env, retArray, 0, privArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (privkey + 32);
+
+ jobjectArray retArray;
+ jbyteArray privArray, intsByteArray;
+ unsigned char intsarray[2];
+
+ int privkeylen = 32;
+
+ int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak);
+
+ intsarray[0] = privkeylen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ privArray = (*env)->NewByteArray(env, privkeylen);
+ (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
+ (*env)->SetObjectArrayElement(env, retArray, 0, privArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/
+ unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (pkey + publen);
+
+ jobjectArray retArray;
+ jbyteArray pubArray, intsByteArray;
+ unsigned char intsarray[2];
+ unsigned char outputSer[65];
+ size_t outputLen = 65;
+
+ secp256k1_pubkey pubkey;
+ int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
+
+ if( ret ) {
+ ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak);
+ }
+
+ if( ret ) {
+ int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ pubArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
{
- unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
- int sigLen = *((int*)(data + 32));
- int pubLen = *((int*)(data + 32 + 4));
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* tweak = (unsigned char*) (pkey + publen);
+
+ jobjectArray retArray;
+ jbyteArray pubArray, intsByteArray;
+ unsigned char intsarray[2];
+ unsigned char outputSer[65];
+ size_t outputLen = 65;
+
+ secp256k1_pubkey pubkey;
+ int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
+
+ if ( ret ) {
+ ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak);
+ }
+
+ if( ret ) {
+ int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
+ }
+
+ intsarray[0] = outputLen;
+ intsarray[1] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ pubArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
+ (*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
- return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen);
+ intsByteArray = (*env)->NewByteArray(env, 2);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
}
-static void __javasecp256k1_attach(void) __attribute__((constructor));
-static void __javasecp256k1_detach(void) __attribute__((destructor));
+SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine
+ (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys)
+{
+ (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys;
-static void __javasecp256k1_attach(void) {
- secp256k1_start(SECP256K1_START_VERIFY);
+ return 0;
}
-static void __javasecp256k1_detach(void) {
- secp256k1_stop();
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ unsigned char* secKey = (unsigned char*) (data + 32);
+
+ jobjectArray retArray;
+ jbyteArray sigArray, intsByteArray;
+ unsigned char intsarray[1];
+ unsigned char sig[64];
+
+ int ret = secp256k1_schnorr_sign(ctx, sig, data, secKey, NULL, NULL);
+
+ intsarray[0] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ sigArray = (*env)->NewByteArray(env, 64);
+ (*env)->SetByteArrayRegion(env, sigArray, 0, 64, (jbyte*)sig);
+ (*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 1);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
+}
+
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
+{
+ secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
+ const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
+ const unsigned char* pubdata = (const unsigned char*) (secdata + 32);
+
+ jobjectArray retArray;
+ jbyteArray outArray, intsByteArray;
+ unsigned char intsarray[1];
+ secp256k1_pubkey pubkey;
+ unsigned char nonce_res[32];
+ size_t outputLen = 32;
+
+ int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
+
+ if (ret) {
+ ret = secp256k1_ecdh(
+ ctx,
+ nonce_res,
+ &pubkey,
+ secdata
+ );
+ }
+
+ intsarray[0] = ret;
+
+ retArray = (*env)->NewObjectArray(env, 2,
+ (*env)->FindClass(env, "[B"),
+ (*env)->NewByteArray(env, 1));
+
+ outArray = (*env)->NewByteArray(env, outputLen);
+ (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res);
+ (*env)->SetObjectArrayElement(env, retArray, 0, outArray);
+
+ intsByteArray = (*env)->NewByteArray(env, 1);
+ (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
+ (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
+
+ (void)classObject;
+
+ return retArray;
}
diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
index d7fb004fa8..4125a1f523 100644
--- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
+++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h
@@ -1,5 +1,6 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
+#include "include/secp256k1.h"
/* Header for class org_bitcoin_NativeSecp256k1 */
#ifndef _Included_org_bitcoin_NativeSecp256k1
@@ -9,11 +10,116 @@ extern "C" {
#endif
/*
* Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ctx_clone
+ * Signature: (J)J
+ */
+SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_context_randomize
+ * Signature: (Ljava/nio/ByteBuffer;J)I
+ */
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_privkey_tweak_add
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_privkey_tweak_mul
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_pubkey_tweak_add
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
+ (JNIEnv *, jclass, jobject, jlong, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_pubkey_tweak_mul
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
+ (JNIEnv *, jclass, jobject, jlong, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_destroy_context
+ * Signature: (J)V
+ */
+SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_ecdsa_verify
- * Signature: (Ljava/nio/ByteBuffer;)I
+ * Signature: (Ljava/nio/ByteBuffer;JII)I
+ */
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
+ (JNIEnv *, jclass, jobject, jlong, jint, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ecdsa_sign
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ec_seckey_verify
+ * Signature: (Ljava/nio/ByteBuffer;J)I
+ */
+SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ec_pubkey_create
+ * Signature: (Ljava/nio/ByteBuffer;J)[[B
*/
-JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
- (JNIEnv *, jclass, jobject);
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
+ (JNIEnv *, jclass, jobject, jlong);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ec_pubkey_parse
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
+ (JNIEnv *, jclass, jobject, jlong, jint);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_schnorr_sign
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l);
+
+/*
+ * Class: org_bitcoin_NativeSecp256k1
+ * Method: secp256k1_ecdh
+ * Signature: (Ljava/nio/ByteBuffer;JI)[[B
+ */
+SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
+ (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen);
+
#ifdef __cplusplus
}
diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c
new file mode 100644
index 0000000000..a52939e7e7
--- /dev/null
+++ b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include "org_bitcoin_Secp256k1Context.h"
+#include "include/secp256k1.h"
+
+SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
+ (JNIEnv* env, jclass classObject)
+{
+ secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+
+ (void)classObject;(void)env;
+
+ return (uintptr_t)ctx;
+}
+
diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h
new file mode 100644
index 0000000000..0d2bc84b7f
--- /dev/null
+++ b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h
@@ -0,0 +1,22 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+#include "include/secp256k1.h"
+/* Header for class org_bitcoin_Secp256k1Context */
+
+#ifndef _Included_org_bitcoin_Secp256k1Context
+#define _Included_org_bitcoin_Secp256k1Context
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: org_bitcoin_Secp256k1Context
+ * Method: secp256k1_init_context
+ * Signature: ()J
+ */
+SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/secp256k1/src/modules/ecdh/Makefile.am.include b/src/secp256k1/src/modules/ecdh/Makefile.am.include
index 670b9c1152..e3088b4697 100644
--- a/src/secp256k1/src/modules/ecdh/Makefile.am.include
+++ b/src/secp256k1/src/modules/ecdh/Makefile.am.include
@@ -4,5 +4,5 @@ noinst_HEADERS += src/modules/ecdh/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_ecdh
bench_ecdh_SOURCES = src/bench_ecdh.c
-bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
diff --git a/src/secp256k1/src/modules/recovery/Makefile.am.include b/src/secp256k1/src/modules/recovery/Makefile.am.include
index 5de3ea33ea..bf23c26e71 100644
--- a/src/secp256k1/src/modules/recovery/Makefile.am.include
+++ b/src/secp256k1/src/modules/recovery/Makefile.am.include
@@ -4,5 +4,5 @@ noinst_HEADERS += src/modules/recovery/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_recover
bench_recover_SOURCES = src/bench_recover.c
-bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
diff --git a/src/secp256k1/src/modules/schnorr/Makefile.am.include b/src/secp256k1/src/modules/schnorr/Makefile.am.include
index b3bfa7d5cc..f1af8e8325 100644
--- a/src/secp256k1/src/modules/schnorr/Makefile.am.include
+++ b/src/secp256k1/src/modules/schnorr/Makefile.am.include
@@ -6,5 +6,5 @@ noinst_HEADERS += src/modules/schnorr/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_schnorr_verify
bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c
-bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS)
+bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h
index ebfa71eb44..7bb9c5be8c 100644
--- a/src/secp256k1/src/num.h
+++ b/src/secp256k1/src/num.h
@@ -32,6 +32,9 @@ static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsi
/** Compute a modular inverse. The input must be less than the modulus. */
static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m);
+/** Compute the jacobi symbol (a|b). b must be positive and odd. */
+static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b);
+
/** Compare the absolute value of two numbers. */
static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b);
@@ -57,6 +60,9 @@ static void secp256k1_num_shift(secp256k1_num *r, int bits);
/** Check whether a number is zero. */
static int secp256k1_num_is_zero(const secp256k1_num *a);
+/** Check whether a number is one. */
+static int secp256k1_num_is_one(const secp256k1_num *a);
+
/** Check whether a number is strictly negative. */
static int secp256k1_num_is_neg(const secp256k1_num *a);
diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h
index 7b6a89719a..3a46495eea 100644
--- a/src/secp256k1/src/num_gmp_impl.h
+++ b/src/secp256k1/src/num_gmp_impl.h
@@ -144,6 +144,32 @@ static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a,
memset(v, 0, sizeof(v));
}
+static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) {
+ int ret;
+ mpz_t ga, gb;
+ secp256k1_num_sanity(a);
+ secp256k1_num_sanity(b);
+ VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1));
+
+ mpz_inits(ga, gb, NULL);
+
+ mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data);
+ mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data);
+ if (a->neg) {
+ mpz_neg(ga, ga);
+ }
+
+ ret = mpz_jacobi(ga, gb);
+
+ mpz_clears(ga, gb, NULL);
+
+ return ret;
+}
+
+static int secp256k1_num_is_one(const secp256k1_num *a) {
+ return (a->limbs == 1 && a->data[0] == 1);
+}
+
static int secp256k1_num_is_zero(const secp256k1_num *a) {
return (a->limbs == 1 && a->data[0] == 0);
}
diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h
index 88ea97de86..c5baf4df41 100644
--- a/src/secp256k1/src/scalar_impl.h
+++ b/src/secp256k1/src/scalar_impl.h
@@ -7,8 +7,6 @@
#ifndef _SECP256K1_SCALAR_IMPL_H_
#define _SECP256K1_SCALAR_IMPL_H_
-#include <string.h>
-
#include "group.h"
#include "scalar.h"
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 62d192baeb..7973d60c36 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -4,8 +4,6 @@
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
-#define SECP256K1_BUILD (1)
-
#include "include/secp256k1.h"
#include "util.h"
@@ -152,7 +150,6 @@ static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) {
secp256k1_ge Q;
- (void)ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pubkey != NULL);
memset(pubkey, 0, sizeof(*pubkey));
@@ -170,7 +167,6 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o
size_t len;
int ret = 0;
- (void)ctx;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(outputlen != NULL);
ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65));
@@ -216,7 +212,7 @@ static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const
int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
secp256k1_scalar r, s;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(input != NULL);
@@ -234,7 +230,7 @@ int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp25
int ret = 1;
int overflow = 0;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(input64 != NULL);
@@ -253,7 +249,7 @@ int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp25
int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) {
secp256k1_scalar r, s;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output != NULL);
ARG_CHECK(outputlen != NULL);
ARG_CHECK(sig != NULL);
@@ -265,7 +261,7 @@ int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsign
int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) {
secp256k1_scalar r, s;
- (void)ctx;
+ VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output64 != NULL);
ARG_CHECK(sig != NULL);
@@ -398,7 +394,6 @@ int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char
int overflow;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
- (void)ctx;
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
ret = !overflow && !secp256k1_scalar_is_zero(&sec);
@@ -437,7 +432,6 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
ARG_CHECK(tweak != NULL);
- (void)ctx;
secp256k1_scalar_set_b32(&term, tweak, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
@@ -485,7 +479,6 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
ARG_CHECK(tweak != NULL);
- (void)ctx;
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
secp256k1_scalar_set_b32(&sec, seckey, NULL);
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 687a5f2fdd..b32cb90813 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -473,6 +473,8 @@ void test_num_negate(void) {
}
void test_num_add_sub(void) {
+ int i;
+ secp256k1_scalar s;
secp256k1_num n1;
secp256k1_num n2;
secp256k1_num n1p2, n2p1, n1m2, n2m1;
@@ -498,6 +500,110 @@ void test_num_add_sub(void) {
CHECK(!secp256k1_num_eq(&n2p1, &n1));
secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */
CHECK(secp256k1_num_eq(&n2p1, &n1));
+
+ /* check is_one */
+ secp256k1_scalar_set_int(&s, 1);
+ secp256k1_scalar_get_num(&n1, &s);
+ CHECK(secp256k1_num_is_one(&n1));
+ /* check that 2^n + 1 is never 1 */
+ secp256k1_scalar_get_num(&n2, &s);
+ for (i = 0; i < 250; ++i) {
+ secp256k1_num_add(&n1, &n1, &n1); /* n1 *= 2 */
+ secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */
+ CHECK(!secp256k1_num_is_one(&n1p2));
+ }
+}
+
+void test_num_mod(void) {
+ int i;
+ secp256k1_scalar s;
+ secp256k1_num order, n;
+
+ /* check that 0 mod anything is 0 */
+ random_scalar_order_test(&s);
+ secp256k1_scalar_get_num(&order, &s);
+ secp256k1_scalar_set_int(&s, 0);
+ secp256k1_scalar_get_num(&n, &s);
+ secp256k1_num_mod(&n, &order);
+ CHECK(secp256k1_num_is_zero(&n));
+
+ /* check that anything mod 1 is 0 */
+ secp256k1_scalar_set_int(&s, 1);
+ secp256k1_scalar_get_num(&order, &s);
+ secp256k1_scalar_get_num(&n, &s);
+ secp256k1_num_mod(&n, &order);
+ CHECK(secp256k1_num_is_zero(&n));
+
+ /* check that increasing the number past 2^256 does not break this */
+ random_scalar_order_test(&s);
+ secp256k1_scalar_get_num(&n, &s);
+ /* multiply by 2^8, which'll test this case with high probability */
+ for (i = 0; i < 8; ++i) {
+ secp256k1_num_add(&n, &n, &n);
+ }
+ secp256k1_num_mod(&n, &order);
+ CHECK(secp256k1_num_is_zero(&n));
+}
+
+void test_num_jacobi(void) {
+ secp256k1_scalar sqr;
+ secp256k1_scalar small;
+ secp256k1_scalar five; /* five is not a quadratic residue */
+ secp256k1_num order, n;
+ int i;
+ /* squares mod 5 are 1, 4 */
+ const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 };
+
+ /* check some small values with 5 as the order */
+ secp256k1_scalar_set_int(&five, 5);
+ secp256k1_scalar_get_num(&order, &five);
+ for (i = 0; i < 10; ++i) {
+ secp256k1_scalar_set_int(&small, i);
+ secp256k1_scalar_get_num(&n, &small);
+ CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]);
+ }
+
+ /** test large values with 5 as group order */
+ secp256k1_scalar_get_num(&order, &five);
+ /* we first need a scalar which is not a multiple of 5 */
+ do {
+ secp256k1_num fiven;
+ random_scalar_order_test(&sqr);
+ secp256k1_scalar_get_num(&fiven, &five);
+ secp256k1_scalar_get_num(&n, &sqr);
+ secp256k1_num_mod(&n, &fiven);
+ } while (secp256k1_num_is_zero(&n));
+ /* next force it to be a residue. 2 is a nonresidue mod 5 so we can
+ * just multiply by two, i.e. add the number to itself */
+ if (secp256k1_num_jacobi(&n, &order) == -1) {
+ secp256k1_num_add(&n, &n, &n);
+ }
+
+ /* test residue */
+ CHECK(secp256k1_num_jacobi(&n, &order) == 1);
+ /* test nonresidue */
+ secp256k1_num_add(&n, &n, &n);
+ CHECK(secp256k1_num_jacobi(&n, &order) == -1);
+
+ /** test with secp group order as order */
+ secp256k1_scalar_order_get_num(&order);
+ random_scalar_order_test(&sqr);
+ secp256k1_scalar_sqr(&sqr, &sqr);
+ /* test residue */
+ secp256k1_scalar_get_num(&n, &sqr);
+ CHECK(secp256k1_num_jacobi(&n, &order) == 1);
+ /* test nonresidue */
+ secp256k1_scalar_mul(&sqr, &sqr, &five);
+ secp256k1_scalar_get_num(&n, &sqr);
+ CHECK(secp256k1_num_jacobi(&n, &order) == -1);
+ /* test multiple of the order*/
+ CHECK(secp256k1_num_jacobi(&order, &order) == 0);
+
+ /* check one less than the order */
+ secp256k1_scalar_set_int(&small, 1);
+ secp256k1_scalar_get_num(&n, &small);
+ secp256k1_num_sub(&n, &order, &n);
+ CHECK(secp256k1_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */
}
void run_num_smalltests(void) {
@@ -505,6 +611,8 @@ void run_num_smalltests(void) {
for (i = 0; i < 100*count; i++) {
test_num_negate();
test_num_add_sub();
+ test_num_mod();
+ test_num_jacobi();
}
}
#endif
@@ -689,6 +797,10 @@ void scalar_test(void) {
secp256k1_scalar_inverse(&inv, &inv);
/* Inverting one must result in one. */
CHECK(secp256k1_scalar_is_one(&inv));
+#ifndef USE_NUM_NONE
+ secp256k1_scalar_get_num(&invnum, &inv);
+ CHECK(secp256k1_num_is_one(&invnum));
+#endif
}
}
@@ -855,7 +967,7 @@ void run_scalar_tests(void) {
secp256k1_scalar zzv;
#endif
int overflow;
- unsigned char chal[32][2][32] = {
+ unsigned char chal[33][2][32] = {
{{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff,
@@ -1111,9 +1223,17 @@ void run_scalar_tests(void) {
{0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}
+ 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}},
+ {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb,
+ 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03},
+ {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb,
+ 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}}
};
- unsigned char res[32][2][32] = {
+ unsigned char res[33][2][32] = {
{{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9,
0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1,
0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6,
@@ -1369,10 +1489,18 @@ void run_scalar_tests(void) {
{0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2,
0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38,
0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34,
- 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}
+ 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}},
+ {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34,
+ 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13,
+ 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,
+ 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5},
+ {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34,
+ 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13,
+ 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46,
+ 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}}
};
secp256k1_scalar_set_int(&one, 1);
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < 33; i++) {
secp256k1_scalar_set_b32(&x, chal[i][0], &overflow);
CHECK(!overflow);
secp256k1_scalar_set_b32(&y, chal[i][1], &overflow);
@@ -1446,7 +1574,7 @@ void random_fe_non_zero(secp256k1_fe *nz) {
void random_fe_non_square(secp256k1_fe *ns) {
secp256k1_fe r;
random_fe_non_zero(ns);
- if (secp256k1_fe_sqrt_var(&r, ns)) {
+ if (secp256k1_fe_sqrt(&r, ns)) {
secp256k1_fe_negate(ns, ns, 1);
}
}
@@ -1641,7 +1769,7 @@ void run_sqr(void) {
void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) {
secp256k1_fe r1, r2;
- int v = secp256k1_fe_sqrt_var(&r1, a);
+ int v = secp256k1_fe_sqrt(&r1, a);
CHECK((v == 0) == (k == NULL));
if (k != NULL) {
@@ -1951,8 +2079,8 @@ void test_add_neg_y_diff_x(void) {
* of the sum to be wrong (since infinity has no xy coordinates).
* HOWEVER, if the x-coordinates are different, infinity is the
* wrong answer, and such degeneracies are exposed. This is the
- * root of https://github.com/bitcoin/secp256k1/issues/257 which
- * this test is a regression test for.
+ * root of https://github.com/bitcoin-core/secp256k1/issues/257
+ * which this test is a regression test for.
*
* These points were generated in sage as
* # secp256k1 params
@@ -2051,15 +2179,16 @@ void run_ec_combine(void) {
void test_group_decompress(const secp256k1_fe* x) {
/* The input itself, normalized. */
secp256k1_fe fex = *x;
- secp256k1_fe tmp;
+ secp256k1_fe fez;
/* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */
secp256k1_ge ge_quad, ge_even, ge_odd;
+ secp256k1_gej gej_quad;
/* Return values of the above calls. */
int res_quad, res_even, res_odd;
secp256k1_fe_normalize_var(&fex);
- res_quad = secp256k1_ge_set_xquad_var(&ge_quad, &fex);
+ res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex);
res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0);
res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1);
@@ -2085,13 +2214,29 @@ void test_group_decompress(const secp256k1_fe* x) {
CHECK(secp256k1_fe_equal_var(&ge_odd.x, x));
/* Check that the Y coordinate result in ge_quad is a square. */
- CHECK(secp256k1_fe_sqrt_var(&tmp, &ge_quad.y));
- secp256k1_fe_sqr(&tmp, &tmp);
- CHECK(secp256k1_fe_equal_var(&tmp, &ge_quad.y));
+ CHECK(secp256k1_fe_is_quad_var(&ge_quad.y));
/* Check odd/even Y in ge_odd, ge_even. */
CHECK(secp256k1_fe_is_odd(&ge_odd.y));
CHECK(!secp256k1_fe_is_odd(&ge_even.y));
+
+ /* Check secp256k1_gej_has_quad_y_var. */
+ secp256k1_gej_set_ge(&gej_quad, &ge_quad);
+ CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
+ do {
+ random_fe_test(&fez);
+ } while (secp256k1_fe_is_zero(&fez));
+ secp256k1_gej_rescale(&gej_quad, &fez);
+ CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
+ secp256k1_gej_neg(&gej_quad, &gej_quad);
+ CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad));
+ do {
+ random_fe_test(&fez);
+ } while (secp256k1_fe_is_zero(&fez));
+ secp256k1_gej_rescale(&gej_quad, &fez);
+ CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad));
+ secp256k1_gej_neg(&gej_quad, &gej_quad);
+ CHECK(secp256k1_gej_has_quad_y_var(&gej_quad));
}
}
@@ -2383,9 +2528,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
secp256k1_scalar x, shift;
int wnaf[256] = {0};
int i;
-#ifdef USE_ENDOMORPHISM
int skew;
-#endif
secp256k1_scalar num = *number;
secp256k1_scalar_set_int(&x, 0);
@@ -2395,10 +2538,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
for (i = 0; i < 16; ++i) {
secp256k1_scalar_shr_int(&num, 8);
}
- skew = secp256k1_wnaf_const(wnaf, num, w);
-#else
- secp256k1_wnaf_const(wnaf, num, w);
#endif
+ skew = secp256k1_wnaf_const(wnaf, num, w);
for (i = WNAF_SIZE(w); i >= 0; --i) {
secp256k1_scalar t;
@@ -2417,10 +2558,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
}
secp256k1_scalar_add(&x, &x, &t);
}
-#ifdef USE_ENDOMORPHISM
- /* Skew num because when encoding 128-bit numbers as odd we use an offset */
+ /* Skew num because when encoding numbers as odd we use an offset */
secp256k1_scalar_cadd_bit(&num, skew == 2, 1);
-#endif
CHECK(secp256k1_scalar_eq(&x, &num));
}
@@ -3484,12 +3623,14 @@ void run_ecdsa_end_to_end(void) {
int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) {
static const unsigned char zeroes[32] = {0};
+#ifdef ENABLE_OPENSSL_TESTS
static const unsigned char max_scalar[32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40
};
+#endif
int ret = 0;
@@ -3607,13 +3748,13 @@ static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) {
static void damage_array(unsigned char *sig, size_t *len) {
int pos;
int action = secp256k1_rand_bits(3);
- if (action < 1) {
+ if (action < 1 && *len > 3) {
/* Delete a byte. */
pos = secp256k1_rand_int(*len);
memmove(sig + pos, sig + pos + 1, *len - pos - 1);
(*len)--;
return;
- } else if (action < 2) {
+ } else if (action < 2 && *len < 2048) {
/* Insert a byte. */
pos = secp256k1_rand_int(1 + *len);
memmove(sig + pos + 1, sig + pos, *len - pos);
@@ -3785,6 +3926,7 @@ void run_ecdsa_der_parse(void) {
int certainly_der = 0;
int certainly_not_der = 0;
random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der);
+ CHECK(buflen <= 2048);
for (j = 0; j < 16; j++) {
int ret = 0;
if (j > 0) {
diff --git a/src/serialize.h b/src/serialize.h
index 378ed39074..04ab9aa2e7 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -322,8 +322,8 @@ uint64_t ReadCompactSize(Stream& is)
* 0: [0x00] 256: [0x81 0x00]
* 1: [0x01] 16383: [0xFE 0x7F]
* 127: [0x7F] 16384: [0xFF 0x00]
- * 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F]
- * 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F]
+ * 128: [0x80 0x00] 16511: [0xFF 0x7F]
+ * 255: [0x80 0x7F] 65535: [0x82 0xFE 0x7F]
* 2^32: [0x8E 0xFE 0xFE 0xFF 0x00]
*/
diff --git a/src/sync.h b/src/sync.h
index 0c58fb6b4e..7733910749 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -171,7 +171,10 @@ public:
typedef CMutexLock<CCriticalSection> CCriticalBlock;
-#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
+#define PASTE(x, y) x ## y
+#define PASTE2(x, y) PASTE(x, y)
+
+#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
#define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
#define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 01eb2aee9e..ac3ab4c83f 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -121,7 +121,6 @@ public:
BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
- std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
SelectParams(CBaseChainParams::MAIN);
@@ -179,7 +178,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
- std::vector<unsigned char> result;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
@@ -247,7 +245,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
- std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py
index 95dd3e81b4..882b5c67b8 100755
--- a/src/test/bitcoin-util-test.py
+++ b/src/test/bitcoin-util-test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# Copyright 2014 BitPay, Inc.
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 3884bf3fe3..d2392cfb22 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -283,7 +283,6 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
std::vector<CTransaction> vtx_missing;
BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK);
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
- bool mutated;
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
BOOST_CHECK(!mutated);
}
diff --git a/src/test/buildenv.py.in b/src/test/buildenv.py.in
index 1618bdeb76..153f34a3db 100644
--- a/src/test/buildenv.py.in
+++ b/src/test/buildenv.py.in
@@ -1,2 +1,2 @@
-#!/usr/bin/python
+#!/usr/bin/env python
exeext="@EXEEXT@"
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index a0bdcf4afb..d4d825d199 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
uint256 in2 = GetRandHash();
BOOST_CHECK(dbw.Write(key2, in2));
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
// Be sure to seek past the obfuscation key (if it exists)
it->Seek(key);
@@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(iterator_ordering)
BOOST_CHECK(dbw.Write(key, value));
}
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
for (int c=0; c<2; ++c) {
int seek_start;
if (c == 0)
@@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
}
}
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
for (int c=0; c<2; ++c) {
int seek_start;
if (c == 0)
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 6511e6ffa2..267d1b55e1 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -150,4 +150,26 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
BOOST_CHECK(addrman2.size() == 0);
}
+BOOST_AUTO_TEST_CASE(cnode_simple_test)
+{
+ SOCKET hSocket = INVALID_SOCKET;
+
+ in_addr ipv4Addr;
+ ipv4Addr.s_addr = 0xa0b0c001;
+
+ CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
+ std::string pszDest = "";
+ bool fInboundIn = false;
+
+ // Test that fFeeler is false by default.
+ CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn);
+ BOOST_CHECK(pnode1->fInbound == false);
+ BOOST_CHECK(pnode1->fFeeler == false);
+
+ fInboundIn = true;
+ CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn);
+ BOOST_CHECK(pnode2->fInbound == true);
+ BOOST_CHECK(pnode2->fFeeler == false);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index 74ffe0cc74..e9c8691745 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -122,7 +122,6 @@ BOOST_AUTO_TEST_CASE(pmt_malleability)
std::vector<bool> vMatch = boost::assign::list_of(false)(false)(false)(false)(false)(false)(false)(false)(false)(true)(true)(false);
CPartialMerkleTree tree(vTxid, vMatch);
- std::vector<uint256> vTxid2;
std::vector<unsigned int> vIndex;
BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull());
}
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index bbda6a48f4..a15915aad2 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -18,18 +18,6 @@
using namespace std;
-UniValue
-createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
-{
- UniValue result(UniValue::VARR);
- result.push_back(nRequired);
- UniValue addresses(UniValue::VARR);
- if (address1) addresses.push_back(address1);
- if (address2) addresses.push_back(address2);
- result.push_back(addresses);
- return result;
-}
-
UniValue CallRPC(string args)
{
vector<string> vArgs;
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 5224b57ca4..1a01593a8e 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -107,18 +107,20 @@ BOOST_AUTO_TEST_CASE(sign)
}
// All of the above should be OK, and the txTos have valid signatures
// Check to make sure signature verification fails if we use the wrong ScriptSig:
- for (int i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++) {
+ PrecomputedTransactionData txdata(txTo[i]);
for (int j = 0; j < 8; j++)
{
CScript sigSave = txTo[i].vin[0].scriptSig;
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
- bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)();
+ bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else
BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
txTo[i].vin[0].scriptSig = sigSave;
}
+ }
}
BOOST_AUTO_TEST_CASE(norecurse)
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index fd4f174b40..b5af400bc5 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -7,6 +7,7 @@
#include "test/test_bitcoin.h"
#include "clientversion.h"
+#include "checkqueue.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "key.h"
@@ -153,6 +154,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
BOOST_CHECK(state.IsValid());
+ PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
@@ -168,7 +170,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err),
+ witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err),
strTest);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
@@ -237,6 +239,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
CValidationState state;
fValid = CheckTransaction(tx, state) && state.IsValid();
+ PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
@@ -252,7 +255,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
}
const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err);
+ witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err);
}
BOOST_CHECK_MESSAGE(!fValid, strTest);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
@@ -419,6 +422,86 @@ void ReplaceRedeemScript(CScript& script, const CScript& redeemScript)
script = PushAll(stack);
}
+BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
+ CMutableTransaction mtx;
+ mtx.nVersion = 1;
+
+ CKey key;
+ key.MakeNewKey(false);
+ CBasicKeyStore keystore;
+ keystore.AddKeyPubKey(key, key.GetPubKey());
+ CKeyID hash = key.GetPubKey().GetID();
+ CScript scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(hash.begin(), hash.end());
+
+ vector<int> sigHashes;
+ sigHashes.push_back(SIGHASH_NONE | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_ALL | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_NONE);
+ sigHashes.push_back(SIGHASH_SINGLE);
+ sigHashes.push_back(SIGHASH_ALL);
+
+ // create a big transaction of 4500 inputs signed by the same key
+ for(uint32_t ij = 0; ij < 4500; ij++) {
+ uint32_t i = mtx.vin.size();
+ uint256 prevId;
+ prevId.SetHex("0000000000000000000000000000000000000000000000000000000000000100");
+ COutPoint outpoint(prevId, i);
+
+ mtx.vin.resize(mtx.vin.size() + 1);
+ mtx.vin[i].prevout = outpoint;
+ mtx.vin[i].scriptSig = CScript();
+
+ mtx.vout.resize(mtx.vout.size() + 1);
+ mtx.vout[i].nValue = 1000;
+ mtx.vout[i].scriptPubKey = CScript() << OP_1;
+ }
+
+ // sign all inputs
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()));
+ assert(hashSigned);
+ }
+
+ CTransaction tx;
+ CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION);
+ WithOrVersion(&ssout, 0) << mtx;
+ WithOrVersion(&ssout, 0) >> tx;
+
+ // check all inputs concurrently, with the cache
+ PrecomputedTransactionData txdata(tx);
+ boost::thread_group threadGroup;
+ CCheckQueue<CScriptCheck> scriptcheckqueue(128);
+ CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
+
+ for (int i=0; i<20; i++)
+ threadGroup.create_thread(boost::bind(&CCheckQueue<CScriptCheck>::Thread, boost::ref(scriptcheckqueue)));
+
+ CCoins coins;
+ coins.nVersion = 1;
+ coins.fCoinBase = false;
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ CTxOut txout;
+ txout.nValue = 1000;
+ txout.scriptPubKey = scriptPubKey;
+ coins.vout.push_back(txout);
+ }
+
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ std::vector<CScriptCheck> vChecks;
+ CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
+ vChecks.push_back(CScriptCheck());
+ check.swap(vChecks.back());
+ control.Add(vChecks);
+ }
+
+ bool controlCheck = control.Wait();
+ assert(controlCheck);
+
+ threadGroup.interrupt_all();
+ threadGroup.join_all();
+}
+
BOOST_AUTO_TEST_CASE(test_witness)
{
CBasicKeyStore keystore, keystore2;
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index e467a4171d..efd4498747 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -243,11 +243,7 @@ BOOST_AUTO_TEST_CASE(util_IsHex)
BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
{
- int i;
- int count=0;
-
seed_insecure_rand(true);
-
for (int mod=2;mod<11;mod++)
{
int mask = 1;
@@ -256,10 +252,9 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
//mask is 2^ceil(log2(mod))-1
while(mask<mod-1)mask=(mask<<1)+1;
- count = 0;
+ int count = 0;
//How often does it get a zero from the uniform range [0,mod)?
- for (i=0;i<10000;i++)
- {
+ for (int i = 0; i < 10000; i++) {
uint32_t rval;
do{
rval=insecure_rand()&mask;
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 078c29def3..4f11c7b951 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -173,7 +173,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex)
{
- boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
+ std::unique_ptr<CDBIterator> pcursor(NewIterator());
pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256()));
diff --git a/src/txdb.h b/src/txdb.h
index 5b98d2792c..adb3f66327 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -92,7 +92,7 @@ public:
private:
CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256 &hashBlockIn):
CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
- boost::scoped_ptr<CDBIterator> pcursor;
+ std::unique_ptr<CDBIterator> pcursor;
std::pair<char, uint256> keyTmp;
friend class CCoinsViewDB;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index b631c48484..0a00d757a2 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -576,7 +576,6 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed)
{
// Remove transactions which depend on inputs of tx, recursively
- list<CTransaction> result;
LOCK(cs);
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
auto it = mapNextTx.find(txin.prevout);
diff --git a/src/util.cpp b/src/util.cpp
index 9a9209c621..ee12f2b443 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -801,11 +801,10 @@ int GetNumCores()
std::string CopyrightHolders(const std::string& strPrefix)
{
- std::string strCopyrightHolders = strPrefix + _(COPYRIGHT_HOLDERS);
- if (strCopyrightHolders.find("%s") != strCopyrightHolders.npos) {
- strCopyrightHolders = strprintf(strCopyrightHolders, _(COPYRIGHT_HOLDERS_SUBSTITUTION));
- }
- if (strCopyrightHolders.find("Bitcoin Core developers") == strCopyrightHolders.npos) {
+ std::string strCopyrightHolders = strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION));
+
+ // Check for untranslated substitution to make sure Bitcoin Core copyright is not removed by accident
+ if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Bitcoin Core") == std::string::npos) {
strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers";
}
return strCopyrightHolders;
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index c906785e9e..a809c9ad64 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -43,7 +43,7 @@ void CDBEnv::EnvShutdown()
if (ret != 0)
LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb)
- DbEnv(0).remove(strPath.c_str(), 0);
+ DbEnv((u_int32_t)0).remove(strPath.c_str(), 0);
}
void CDBEnv::Reset()
@@ -284,7 +284,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
pdb = NULL;
--bitdb.mapFileUseCount[strFile];
strFile = "";
- throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFile));
+ throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename));
}
if (fCreate && !Exists(string("version"))) {
@@ -387,11 +387,11 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
while (fSuccess) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
- if (ret == DB_NOTFOUND) {
+ int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue);
+ if (ret1 == DB_NOTFOUND) {
pcursor->close();
break;
- } else if (ret != 0) {
+ } else if (ret1 != 0) {
pcursor->close();
fSuccess = false;
break;
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 01b8c71a04..a0f673ecfc 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -228,19 +228,17 @@ protected:
return pcursor;
}
- int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT)
+ int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false)
{
// Read at cursor
Dbt datKey;
- if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
+ unsigned int fFlags = DB_NEXT;
+ if (setRange) {
datKey.set_data(&ssKey[0]);
datKey.set_size(ssKey.size());
+ fFlags = DB_SET_RANGE;
}
Dbt datValue;
- if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
- datValue.set_data(&ssValue[0]);
- datValue.set_size(ssValue.size());
- }
datKey.set_flags(DB_DBT_MALLOC);
datValue.set_flags(DB_DBT_MALLOC);
int ret = pcursor->get(&datKey, &datValue, fFlags);
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index fe8b53ceb0..42ebdb9b9b 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -257,14 +257,13 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp)
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
- if (fHelp || params.size() < 2 || params.size() > 3)
+ if (fHelp || params.size() != 2)
throw runtime_error(
"importprunedfunds\n"
"\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n"
"\nArguments:\n"
"1. \"rawtransaction\" (string, required) A raw transaction in hex funding an already-existing address in wallet\n"
"2. \"txoutproof\" (string, required) The hex output from gettxoutproof that contains the transaction\n"
- "3. \"label\" (string, optional) An optional label\n"
);
CTransaction tx;
@@ -277,10 +276,6 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp)
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
- string strLabel = "";
- if (params.size() == 3)
- strLabel = params[2].get_str();
-
//Search partial merkle tree in proof for our transaction and index in valid block
vector<uint256> vMatch;
vector<unsigned int> vIndex;
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index aa0a9374c1..0ba6706baf 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1176,10 +1176,10 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
if (fByAccounts)
{
- tallyitem& item = mapAccountTally[strAccount];
- item.nAmount += nAmount;
- item.nConf = min(item.nConf, nConf);
- item.fIsWatchonly = fIsWatchonly;
+ tallyitem& _item = mapAccountTally[strAccount];
+ _item.nAmount += nAmount;
+ _item.nConf = min(_item.nConf, nConf);
+ _item.fIsWatchonly = fIsWatchonly;
}
else
{
@@ -1195,9 +1195,9 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
UniValue transactions(UniValue::VARR);
if (it != mapTally.end())
{
- BOOST_FOREACH(const uint256& item, (*it).second.txids)
+ BOOST_FOREACH(const uint256& _item, (*it).second.txids)
{
- transactions.push_back(item.GetHex());
+ transactions.push_back(_item.GetHex());
}
}
obj.push_back(Pair("txids", transactions));
@@ -2617,8 +2617,8 @@ static const CRPCCommand commands[] =
{ "wallet", "removeprunedfunds", &removeprunedfunds, true },
};
-void RegisterWalletRPCCommands(CRPCTable &tableRPC)
+void RegisterWalletRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index a5de7e2de1..3a68ccf1b2 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -7,6 +7,6 @@
class CRPCTable;
-void RegisterWalletRPCCommands(CRPCTable &tableRPC);
+void RegisterWalletRPCCommands(CRPCTable &t);
#endif //BITCOIN_WALLET_RPCWALLET_H
diff --git a/src/wallet/test/rpc_wallet_tests.cpp b/src/wallet/test/rpc_wallet_tests.cpp
deleted file mode 100644
index 4e7d177f51..0000000000
--- a/src/wallet/test/rpc_wallet_tests.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright (c) 2013-2015 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "rpc/server.h"
-#include "rpc/client.h"
-
-#include "base58.h"
-#include "main.h"
-#include "wallet/wallet.h"
-
-#include "wallet/test/wallet_test_fixture.h"
-
-#include <boost/algorithm/string.hpp>
-#include <boost/test/unit_test.hpp>
-
-#include <univalue.h>
-
-using namespace std;
-
-extern UniValue createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
-extern UniValue CallRPC(string args);
-
-extern CWallet* pwalletMain;
-
-BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, WalletTestingSetup)
-
-BOOST_AUTO_TEST_CASE(rpc_addmultisig)
-{
- rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
-
- // old, 65-byte-long:
- const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8";
- // new, compressed:
- const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
-
- UniValue v;
- CBitcoinAddress address;
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false));
- address.SetString(v.get_str());
- BOOST_CHECK(address.IsValid() && address.IsScript());
-
- BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error);
-
- BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error);
- BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error);
-
- string short1(address1Hex, address1Hex + sizeof(address1Hex) - 2); // last byte missing
- BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error);
-
- string short2(address1Hex + 1, address1Hex + sizeof(address1Hex)); // first byte missing
- BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
-}
-
-BOOST_AUTO_TEST_CASE(rpc_wallet)
-{
- // Test RPC calls for various wallet statistics
- UniValue r;
- CPubKey demoPubkey;
- CBitcoinAddress demoAddress;
- UniValue retValue;
- string strAccount = "walletDemoAccount";
- CBitcoinAddress setaccountDemoAddress;
- {
- LOCK(pwalletMain->cs_wallet);
-
- demoPubkey = pwalletMain->GenerateNewKey();
- demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
- string strPurpose = "receive";
- BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
- CWalletDB walletdb(pwalletMain->strWalletFile);
- CAccount account;
- account.vchPubKey = demoPubkey;
- pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose);
- walletdb.WriteAccount(strAccount, account);
- });
-
- CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey();
- setaccountDemoAddress = CBitcoinAddress(CTxDestination(setaccountDemoPubkey.GetID()));
- }
- /*********************************
- * setaccount
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("setaccount " + setaccountDemoAddress.ToString() + " nullaccount"));
- /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ is not owned by the test wallet. */
- BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
- /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */
- BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error);
-
-
- /*********************************
- * getbalance
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getbalance"));
- BOOST_CHECK_NO_THROW(CallRPC("getbalance " + demoAddress.ToString()));
-
- /*********************************
- * listunspent
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
- BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error);
- BOOST_CHECK_NO_THROW(r = CallRPC("listunspent 0 1 []"));
- BOOST_CHECK(r.get_array().empty());
-
- /*********************************
- * listreceivedbyaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
-
- /*********************************
- * listreceivedbyaccount
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
- BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
-
- /*********************************
- * listsinceblock
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listsinceblock"));
-
- /*********************************
- * listtransactions
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions"));
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString()));
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " 20"));
- BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " 20 0"));
- BOOST_CHECK_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " not_int"), runtime_error);
-
- /*********************************
- * listlockunspent
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listlockunspent"));
-
- /*********************************
- * listaccounts
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listaccounts"));
-
- /*********************************
- * listaddressgroupings
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("listaddressgroupings"));
-
- /*********************************
- * getrawchangeaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress"));
-
- /*********************************
- * getnewaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getnewaddress"));
- BOOST_CHECK_NO_THROW(CallRPC("getnewaddress getnewaddress_demoaccount"));
-
- /*********************************
- * getaccountaddress
- *********************************/
- BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\""));
- BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account
- BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
- BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get());
-
- /*********************************
- * getaccount
- *********************************/
- BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error);
- BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString()));
-
- /*********************************
- * signmessage + verifymessage
- *********************************/
- BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage"));
- BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error);
- /* Should throw error because this address is not loaded in the wallet */
- BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error);
-
- /* missing arguments */
- BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString()), runtime_error);
- BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str()), runtime_error);
- /* Illegal address */
- BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error);
- /* wrong address */
- BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false);
- /* Correct address and signature but wrong message */
- BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false);
- /* Correct address, message and signature*/
- BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true);
-
- /*********************************
- * getaddressesbyaccount
- *********************************/
- BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
- BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
- UniValue arr = retValue.get_array();
- BOOST_CHECK(arr.size() > 0);
- BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
-
- /*********************************
- * fundrawtransaction
- *********************************/
- BOOST_CHECK_THROW(CallRPC("fundrawtransaction 28z"), runtime_error);
- BOOST_CHECK_THROW(CallRPC("fundrawtransaction 01000000000180969800000000001976a91450ce0a4b0ee0ddeb633da85199728b940ac3fe9488ac00000000"), runtime_error);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index 9036ee26d8..a76db37617 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -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.
+
#include "wallet/test/wallet_test_fixture.h"
#include "rpc/server.h"
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index c6c5058984..acf980c784 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
// they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change
empty_wallet();
- for (int i = 0; i < 20; i++)
+ for (int j = 0; j < 20; j++)
add_coin(50000 * COIN);
BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
@@ -296,7 +296,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
int fails = 0;
- for (int i = 0; i < RANDOM_REPEATS; i++)
+ for (int j = 0; j < RANDOM_REPEATS; j++)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
@@ -317,7 +317,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(25 * CENT);
fails = 0;
- for (int i = 0; i < RANDOM_REPEATS; i++)
+ for (int j = 0; j < RANDOM_REPEATS; j++)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 888aa029a3..10aca2e499 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -98,7 +98,7 @@ CPubKey CWallet::GenerateNewKey()
CKeyMetadata metadata(nCreationTime);
// use HD key derivation if HD was enabled during wallet creation
- if (!hdChain.masterKeyID.IsNull()) {
+ if (IsHDEnabled()) {
// for now we use a fixed keypath scheme of m/0'/0'/k
CKey key; //master key seed (256bit)
CExtKey masterKey; //hd master key
@@ -108,7 +108,7 @@ CPubKey CWallet::GenerateNewKey()
// try to get the master key
if (!GetKey(hdChain.masterKeyID, key))
- throw std::runtime_error("CWallet::GenerateNewKey(): Master key not found");
+ throw std::runtime_error(std::string(__func__) + ": Master key not found");
masterKey.SetMaster(key.begin(), key.size());
@@ -135,7 +135,7 @@ CPubKey CWallet::GenerateNewKey()
// update the chain model in the database
if (!CWalletDB(strWalletFile).WriteHDChain(hdChain))
- throw std::runtime_error("CWallet::GenerateNewKey(): Writing HD chain model failed");
+ throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
} else {
secret.MakeNewKey(fCompressed);
}
@@ -152,7 +152,7 @@ CPubKey CWallet::GenerateNewKey()
nTimeFirstKey = nCreationTime;
if (!AddKeyPubKey(secret, pubkey))
- throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
+ throw std::runtime_error(std::string(__func__) + ": AddKey failed");
return pubkey;
}
@@ -628,7 +628,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
Unlock(strWalletPassphrase);
// if we are using HD, replace the HD master key (seed) with a new one
- if (!hdChain.masterKeyID.IsNull()) {
+ if (IsHDEnabled()) {
CKey key;
CPubKey masterPubKey = GenerateNewHDMasterKey();
if (!SetHDMasterKey(masterPubKey))
@@ -1094,7 +1094,7 @@ isminetype CWallet::IsMine(const CTxOut& txout) const
CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const
{
if (!MoneyRange(txout.nValue))
- throw std::runtime_error("CWallet::GetCredit(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
return ((IsMine(txout) & filter) ? txout.nValue : 0);
}
@@ -1123,7 +1123,7 @@ bool CWallet::IsChange(const CTxOut& txout) const
CAmount CWallet::GetChange(const CTxOut& txout) const
{
if (!MoneyRange(txout.nValue))
- throw std::runtime_error("CWallet::GetChange(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
return (IsChange(txout) ? txout.nValue : 0);
}
@@ -1147,7 +1147,7 @@ CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) co
{
nDebit += GetDebit(txin, filter);
if (!MoneyRange(nDebit))
- throw std::runtime_error("CWallet::GetDebit(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nDebit;
}
@@ -1159,7 +1159,7 @@ CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) c
{
nCredit += GetCredit(txout, filter);
if (!MoneyRange(nCredit))
- throw std::runtime_error("CWallet::GetCredit(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nCredit;
}
@@ -1171,7 +1171,7 @@ CAmount CWallet::GetChange(const CTransaction& tx) const
{
nChange += GetChange(txout);
if (!MoneyRange(nChange))
- throw std::runtime_error("CWallet::GetChange(): value out of range");
+ throw std::runtime_error(std::string(__func__) + ": value out of range");
}
return nChange;
}
@@ -1200,7 +1200,7 @@ CPubKey CWallet::GenerateNewHDMasterKey()
// write the key&metadata to the database
if (!AddKeyPubKey(key, pubkey))
- throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
+ throw std::runtime_error(std::string(__func__) + ": AddKeyPubKey failed");
}
return pubkey;
@@ -1227,12 +1227,17 @@ bool CWallet::SetHDChain(const CHDChain& chain, bool memonly)
{
LOCK(cs_wallet);
if (!memonly && !CWalletDB(strWalletFile).WriteHDChain(chain))
- throw runtime_error("AddHDChain(): writing chain failed");
+ throw runtime_error(std::string(__func__) + ": writing chain failed");
hdChain = chain;
return true;
}
+bool CWallet::IsHDEnabled()
+{
+ return !hdChain.masterKeyID.IsNull();
+}
+
int64_t CWalletTx::GetTxTime() const
{
int64_t n = nTimeSmart;
@@ -2456,7 +2461,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
AddToWallet(wtxNew);
// Notify that old coins are spent
- set<CWalletTx*> setCoins;
BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
{
CWalletTx &coin = mapWallet[txin.prevout.hash];
@@ -2707,7 +2711,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
- throw runtime_error("TopUpKeyPool(): writing generated key failed");
+ throw runtime_error(std::string(__func__) + ": writing generated key failed");
setKeyPool.insert(nEnd);
LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
}
@@ -2734,9 +2738,9 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
- throw runtime_error("ReserveKeyFromKeyPool(): read failed");
+ throw runtime_error(std::string(__func__) + ": read failed");
if (!HaveKey(keypool.vchPubKey.GetID()))
- throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool");
+ throw runtime_error(std::string(__func__) + ": unknown key in key pool");
assert(keypool.vchPubKey.IsValid());
LogPrintf("keypool reserve %d\n", nIndex);
}
@@ -2795,7 +2799,7 @@ int64_t CWallet::GetOldestKeyPoolTime()
CWalletDB walletdb(strWalletFile);
int64_t nIndex = *(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
- throw runtime_error("GetOldestKeyPoolTime(): read oldest key in keypool failed");
+ throw runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
assert(keypool.vchPubKey.IsValid());
return keypool.nTime;
}
@@ -3022,11 +3026,11 @@ void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
{
CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool))
- throw runtime_error("GetAllReserveKeyHashes(): read failed");
+ throw runtime_error(std::string(__func__) + ": read failed");
assert(keypool.vchPubKey.IsValid());
CKeyID keyID = keypool.vchPubKey.GetID();
if (!HaveKey(keyID))
- throw runtime_error("GetAllReserveKeyHashes(): unknown key in key pool");
+ throw runtime_error(std::string(__func__) + ": unknown key in key pool");
setAddress.insert(keyID);
}
}
@@ -3133,7 +3137,7 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
mapKeyBirth[it->first] = it->second.nCreateTime;
// map in which we'll infer heights of other keys
- CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganised; use a 144-block safety margin
+ CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin
std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
std::set<CKeyID> setKeys;
GetKeys(setKeys);
@@ -3322,12 +3326,11 @@ bool CWallet::InitLoadWallet()
if (fFirstRun)
{
// Create new keyUser and set as default key
- if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && walletInstance->hdChain.masterKeyID.IsNull()) {
+ if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && !walletInstance->IsHDEnabled()) {
// generate a new master key
- CKey key;
CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey();
if (!walletInstance->SetHDMasterKey(masterPubKey))
- throw std::runtime_error("CWallet::GenerateNewKey(): Storing master key failed");
+ throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
}
CPubKey newDefaultKey;
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
@@ -3340,9 +3343,9 @@ bool CWallet::InitLoadWallet()
}
else if (mapArgs.count("-usehd")) {
bool useHD = GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET);
- if (!walletInstance->hdChain.masterKeyID.IsNull() && !useHD)
+ if (walletInstance->IsHDEnabled() && !useHD)
return InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
- if (walletInstance->hdChain.masterKeyID.IsNull() && useHD)
+ if (!walletInstance->IsHDEnabled() && useHD)
return InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile));
}
@@ -3412,7 +3415,17 @@ bool CWallet::InitLoadWallet()
}
walletInstance->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
+ {
+ LOCK(walletInstance->cs_wallet);
+ LogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
+ LogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size());
+ LogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size());
+ }
+ // Add wallet transactions that aren't already in a block to mapTransactions
+ walletInstance->ReacceptWalletTransactions();
+
pwalletMain = walletInstance;
+
return true;
}
@@ -3530,7 +3543,6 @@ CWalletKey::CWalletKey(int64_t nExpires)
int CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
{
AssertLockHeld(cs_main);
- CBlock blockTmp;
// Update the tx's hashBlock
hashBlock = pindex->GetBlockHash();
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 952acd1535..c06513650c 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -582,6 +582,8 @@ private:
CHDChain hdChain;
bool fFileBacked;
+
+ std::set<int64_t> setKeyPool;
public:
/*
* Main wallet lock.
@@ -594,7 +596,18 @@ public:
std::string strWalletFile;
- std::set<int64_t> setKeyPool;
+ void LoadKeyPool(int nIndex, const CKeyPool &keypool)
+ {
+ setKeyPool.insert(nIndex);
+
+ // If no metadata exists yet, create a default with the pool key's
+ // creation time. Note that this may be overwritten by actually
+ // stored metadata for that key later, which is fine.
+ CKeyID keyid = keypool.vchPubKey.GetID();
+ if (mapKeyMetadata.count(keyid) == 0)
+ mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
+ }
+
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
@@ -902,6 +915,9 @@ public:
bool SetHDChain(const CHDChain& chain, bool memonly);
const CHDChain& GetHDChain() { return hdChain; }
+ /* Returns true if HD is enabled */
+ bool IsHDEnabled();
+
/* Generates a new HD master key (will not be activated) */
CPubKey GenerateNewHDMasterKey();
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 543522ca64..80bfe8255d 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -18,7 +18,6 @@
#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
-#include <boost/scoped_ptr.hpp>
#include <boost/thread.hpp>
using namespace std;
@@ -215,23 +214,23 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
Dbc* pcursor = GetCursor();
if (!pcursor)
- throw runtime_error("CWalletDB::ListAccountCreditDebit(): cannot create DB cursor");
- unsigned int fFlags = DB_SET_RANGE;
+ throw runtime_error(std::string(__func__) + ": cannot create DB cursor");
+ bool setRange = true;
while (true)
{
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- if (fFlags == DB_SET_RANGE)
+ if (setRange)
ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0)));
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
- fFlags = DB_NEXT;
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange);
+ setRange = false;
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
{
pcursor->close();
- throw runtime_error("CWalletDB::ListAccountCreditDebit(): error scanning DB");
+ throw runtime_error(std::string(__func__) + ": error scanning DB");
}
// Unserialize
@@ -556,14 +555,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> nIndex;
CKeyPool keypool;
ssValue >> keypool;
- pwallet->setKeyPool.insert(nIndex);
-
- // If no metadata exists yet, create a default with the pool key's
- // creation time. Note that this may be overwritten by actually
- // stored metadata for that key later, which is fine.
- CKeyID keyid = keypool.vchPubKey.GetID();
- if (pwallet->mapKeyMetadata.count(keyid) == 0)
- pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
+
+ pwallet->LoadKeyPool(nIndex, keypool);
}
else if (strType == "version")
{
@@ -893,8 +886,8 @@ void ThreadFlushWalletDB(const string& strFile)
if (nRefCount == 0)
{
boost::this_thread::interruption_point();
- map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile);
- if (mi != bitdb.mapFileUseCount.end())
+ map<string, int>::iterator _mi = bitdb.mapFileUseCount.find(strFile);
+ if (_mi != bitdb.mapFileUseCount.end())
{
LogPrint("db", "Flushing %s\n", strFile);
nLastFlushed = nWalletDBUpdated;
@@ -904,7 +897,7 @@ void ThreadFlushWalletDB(const string& strFile)
bitdb.CloseDb(strFile);
bitdb.CheckpointLSN(strFile);
- bitdb.mapFileUseCount.erase(mi++);
+ bitdb.mapFileUseCount.erase(_mi++);
LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
}
}
@@ -947,7 +940,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe
}
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
- boost::scoped_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
+ std::unique_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
int ret = pdbCopy->open(NULL, // Txn pointer
filename.c_str(), // Filename
"main", // Logical db name
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index 22f02a3d0d..751ded3957 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -12,7 +12,7 @@ class CBlockIndex;
class CZMQAbstractPublishNotifier : public CZMQAbstractNotifier
{
private:
- uint32_t nSequence; //! upcounting per message sequence number
+ uint32_t nSequence; //!< upcounting per message sequence number
public: