aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md28
-rw-r--r--doc/README.md1
-rw-r--r--doc/benchmarking.md30
-rw-r--r--doc/bips.md6
-rwxr-xr-xqa/rpc-tests/abandonconflict.py4
-rwxr-xr-xqa/rpc-tests/bip65-cltv-p2p.py3
-rwxr-xr-xqa/rpc-tests/bip65-cltv.py4
-rwxr-xr-xqa/rpc-tests/bip68-112-113-p2p.py3
-rwxr-xr-xqa/rpc-tests/bip68-sequence.py4
-rwxr-xr-xqa/rpc-tests/bip9-softforks.py3
-rwxr-xr-xqa/rpc-tests/bipdersig-p2p.py3
-rwxr-xr-xqa/rpc-tests/bipdersig.py4
-rwxr-xr-xqa/rpc-tests/blockchain.py10
-rwxr-xr-xqa/rpc-tests/decodescript.py9
-rwxr-xr-xqa/rpc-tests/disablewallet.py9
-rwxr-xr-xqa/rpc-tests/forknotify.py5
-rwxr-xr-xqa/rpc-tests/fundrawtransaction.py11
-rwxr-xr-xqa/rpc-tests/getblocktemplate_longpoll.py5
-rwxr-xr-xqa/rpc-tests/getblocktemplate_proposals.py9
-rwxr-xr-xqa/rpc-tests/getchaintips.py5
-rwxr-xr-xqa/rpc-tests/httpbasics.py9
-rwxr-xr-xqa/rpc-tests/importprunedfunds.py9
-rwxr-xr-xqa/rpc-tests/invalidateblock.py9
-rwxr-xr-xqa/rpc-tests/invalidblockrequest.py1
-rwxr-xr-xqa/rpc-tests/invalidtxrequest.py1
-rwxr-xr-xqa/rpc-tests/keypool.py11
-rwxr-xr-xqa/rpc-tests/listtransactions.py6
-rwxr-xr-xqa/rpc-tests/maxblocksinflight.py9
-rwxr-xr-xqa/rpc-tests/maxuploadtarget.py12
-rwxr-xr-xqa/rpc-tests/mempool_limit.py12
-rwxr-xr-xqa/rpc-tests/mempool_packages.py4
-rwxr-xr-xqa/rpc-tests/mempool_reorg.py4
-rwxr-xr-xqa/rpc-tests/mempool_resurrect_test.py5
-rwxr-xr-xqa/rpc-tests/mempool_spendcoinbase.py5
-rwxr-xr-xqa/rpc-tests/merkle_blocks.py7
-rwxr-xr-xqa/rpc-tests/multi_rpc.py16
-rwxr-xr-xqa/rpc-tests/nodehandling.py6
-rwxr-xr-xqa/rpc-tests/p2p-acceptblock.py6
-rwxr-xr-xqa/rpc-tests/p2p-feefilter.py6
-rwxr-xr-xqa/rpc-tests/p2p-fullblocktest.py1
-rwxr-xr-xqa/rpc-tests/p2p-versionbits-warning.py6
-rwxr-xr-xqa/rpc-tests/prioritise_transaction.py8
-rwxr-xr-xqa/rpc-tests/proxy_test.py6
-rwxr-xr-xqa/rpc-tests/pruning.py8
-rwxr-xr-xqa/rpc-tests/rawtransactions.py9
-rwxr-xr-xqa/rpc-tests/receivedby.py7
-rwxr-xr-xqa/rpc-tests/reindex.py7
-rwxr-xr-xqa/rpc-tests/replace-by-fee.py5
-rwxr-xr-xqa/rpc-tests/rest.py9
-rwxr-xr-xqa/rpc-tests/rpcbind_test.py4
-rwxr-xr-xqa/rpc-tests/sendheaders.py8
-rwxr-xr-xqa/rpc-tests/signmessages.py9
-rwxr-xr-xqa/rpc-tests/signrawtransactions.py9
-rwxr-xr-xqa/rpc-tests/smartfees.py5
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py31
-rw-r--r--qa/rpc-tests/test_framework/util.py61
-rwxr-xr-xqa/rpc-tests/txn_clone.py5
-rwxr-xr-xqa/rpc-tests/txn_doublespend.py5
-rwxr-xr-xqa/rpc-tests/wallet.py7
-rwxr-xr-xqa/rpc-tests/walletbackup.py9
-rwxr-xr-xqa/rpc-tests/zapwallettxes.py9
-rwxr-xr-xqa/rpc-tests/zmq_test.py6
-rwxr-xr-xshare/qt/extract_strings_qt.py4
-rw-r--r--src/Makefile.am68
-rw-r--r--src/Makefile.bench.include3
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/bench/base58.cpp56
-rw-r--r--src/bench/bench.cpp35
-rw-r--r--src/bench/bench.h7
-rw-r--r--src/bench/crypto_hash.cpp25
-rw-r--r--src/crypto/aes.cpp217
-rw-r--r--src/crypto/aes.h118
-rw-r--r--src/crypto/ctaes/COPYING21
-rw-r--r--src/crypto/ctaes/README.md41
-rw-r--r--src/crypto/ctaes/bench.c170
-rw-r--r--src/crypto/ctaes/ctaes.c556
-rw-r--r--src/crypto/ctaes/ctaes.h41
-rw-r--r--src/crypto/ctaes/test.c110
-rw-r--r--src/init.cpp28
-rw-r--r--src/key.cpp3
-rw-r--r--src/main.cpp95
-rw-r--r--src/net.cpp19
-rw-r--r--src/net.h7
-rw-r--r--src/qt/askpassphrasedialog.cpp21
-rw-r--r--src/qt/askpassphrasedialog.h1
-rw-r--r--src/qt/bitcoingui.cpp12
-rw-r--r--src/qt/bitcoingui.h1
-rw-r--r--src/qt/overviewpage.cpp2
-rw-r--r--src/qt/transactionview.cpp2
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/random.cpp66
-rw-r--r--src/random.h11
-rw-r--r--src/rpc/net.cpp2
-rw-r--r--src/rpc/rawtransaction.cpp2
-rw-r--r--src/test/crypto_tests.cpp191
-rw-r--r--src/test/data/script_tests.json7
-rw-r--r--src/test/script_tests.cpp5
-rw-r--r--src/test/sighash_tests.cpp1
-rw-r--r--src/txmempool.cpp10
-rw-r--r--src/txmempool.h1
-rw-r--r--src/util.cpp2
-rw-r--r--src/util.h7
-rw-r--r--src/wallet/crypter.cpp92
-rw-r--r--src/wallet/crypter.h15
-rw-r--r--src/wallet/rpcwallet.cpp40
-rw-r--r--src/wallet/test/crypto_tests.cpp230
-rw-r--r--src/wallet/wallet.cpp79
-rw-r--r--src/wallet/wallet.h4
-rw-r--r--src/wallet/walletdb.cpp40
-rw-r--r--src/wallet/walletdb.h1
110 files changed, 2575 insertions, 425 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 53d6527d40..5c1138b812 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -17,13 +17,13 @@ To contribute a patch, the workflow is as follows:
- Create topic branch
- Commit patches
-The project coding conventions in [doc/developer-notes.md](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.
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 "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.
@@ -35,13 +35,27 @@ The title of the pull request should be prefixed by the component or area that t
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
+ 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://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments) 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).
-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. If your pull request is accepted for merging, you may be asked by a maintainer to squash and or rebase your commits before it will be merged. The length of time required for peer review is unpredictable and will vary from patch to patch.
+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.
+
+ git checkout your_branch_name
+ git rebase -i HEAD~n
+ # n is normally the number of commits in the pull
+ # set commits from 'pick' to 'squash', save and quit
+ # on the next screen, edit/refine commit messages
+ # 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.
Pull Request Philosophy
@@ -61,7 +75,7 @@ Refactoring is a necessary part of any software project's evolution. The followi
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
@@ -69,7 +83,7 @@ Project maintainers aim for a quick turnaround on refactoring pull requests, so
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.
diff --git a/doc/README.md b/doc/README.md
index 357334dfb2..c30f29452b 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -57,6 +57,7 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th
- [Shared Libraries](shared-libraries.md)
- [BIPS](bips.md)
- [Dnsseed Policy](dnsseed-policy.md)
+- [Benchmarking](benchmarking.md)
### Resources
* Discuss on the [BitcoinTalk](https://bitcointalk.org/) forums, in the [Development & Technical Discussion board](https://bitcointalk.org/index.php?board=6.0).
diff --git a/doc/benchmarking.md b/doc/benchmarking.md
new file mode 100644
index 0000000000..0ba75afcda
--- /dev/null
+++ b/doc/benchmarking.md
@@ -0,0 +1,30 @@
+Benchmarking
+============
+
+Bitcoin Core has an internal benchmarking framework, with benchmarks
+for cryptographic algorithms such as SHA1, SHA256, SHA512 and RIPEMD160. As well as the rolling bloom filter.
+
+After compiling bitcoin-core, the benchmarks can be run with:
+`src/bench/bench_bitcoin`
+
+The output will look similar to:
+```
+#Benchmark,count,min,max,average
+RIPEMD160,448,0.001245033173334,0.002638196945190,0.002461894814457
+RollingBloom-refresh,1,0.000635000000000,0.000635000000000,0.000635000000000
+RollingBloom-refresh,1,0.000108000000000,0.000108000000000,0.000108000000000
+RollingBloom-refresh,1,0.000107000000000,0.000107000000000,0.000107000000000
+RollingBloom-refresh,1,0.000204000000000,0.000204000000000,0.000204000000000
+SHA1,640,0.000909024336207,0.001938136418660,0.001843086257577
+SHA256,256,0.002209486499909,0.008500099182129,0.004300644621253
+SHA512,384,0.001319904176016,0.002813005447388,0.002615700786312
+Sleep100ms,10,0.205592155456543,0.210056066513062,0.104166316986084
+Trig,67108864,0.000000014997003,0.000000015448112,0.000000015188842
+```
+
+More benchmarks are needed for, in no particular order:
+- Script Validation
+- CCoinDBView caching
+- Coins database
+- Memory pool
+- Wallet coin selection
diff --git a/doc/bips.md b/doc/bips.md
index b8efabbcf2..b4b62e781e 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -1,5 +1,6 @@
-BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.12.0**):
+BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.13.0**):
+* [`BIP 9`](https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki): The changes allowing multiple soft-forks to be deployed in parallel have been implemented since **v0.12.1** ([PR #7575](https://github.com/bitcoin/bitcoin/pull/7575))
* [`BIP 11`](https://github.com/bitcoin/bips/blob/master/bip-0011.mediawiki): Multisig outputs are standard since **v0.6.0** ([PR #669](https://github.com/bitcoin/bitcoin/pull/669)).
* [`BIP 13`](https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki): The address format for P2SH addresses has been implemented since **v0.6.0** ([PR #669](https://github.com/bitcoin/bitcoin/pull/669)).
* [`BIP 14`](https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki): The subversion string is being used as User Agent since **v0.6.0** ([PR #669](https://github.com/bitcoin/bitcoin/pull/669)).
@@ -16,8 +17,11 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.12.0**):
* [`BIP 61`](https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki): The 'reject' protocol message (and the protocol version bump to 70002) was added in **v0.9.0** ([PR #3185](https://github.com/bitcoin/bitcoin/pull/3185)).
* [`BIP 65`](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki): The CHECKLOCKTIMEVERIFY softfork was merged in **v0.12.0** ([PR #6351](https://github.com/bitcoin/bitcoin/pull/6351)), and backported to **v0.11.2** and **v0.10.4**. Mempool-only CLTV was added in [PR #6124](https://github.com/bitcoin/bitcoin/pull/6124).
* [`BIP 66`](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki): The strict DER rules and associated version 3 blocks have been implemented since **v0.10.0** ([PR #5713](https://github.com/bitcoin/bitcoin/pull/5713)).
+* [`BIP 68`](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki): Sequence locks have been implemented as of **v0.12.1** ([PR #7184](https://github.com/bitcoin/bitcoin/pull/7184)).
* [`BIP 70`](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki) [`71`](https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki) [`72`](https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki): Payment Protocol support has been available in Bitcoin Core GUI since **v0.9.0** ([PR #5216](https://github.com/bitcoin/bitcoin/pull/5216)).
* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)).
+* [`BIP 112`](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki): The CHECKSEQUENCEVERIFY opcode has been implemented since **v0.12.1** ([PR #7524](https://github.com/bitcoin/bitcoin/pull/7524)).
+* [`BIP 113`](https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki): Median time past lock-time calculations have been implemented since **v0.12.1** ([PR #6566](https://github.com/bitcoin/bitcoin/pull/6566)).
* [`BIP 125`](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki): Opt-in full replace-by-fee signaling honoured in mempool and mining as of **v0.12.0** ([PR 6871](https://github.com/bitcoin/bitcoin/pull/6871)).
* [`BIP 130`](https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki): direct headers announcement is negotiated with peer versions `>=70012` as of **v0.12.0** ([PR 6494](https://github.com/bitcoin/bitcoin/pull/6494)).
* [`BIP 133`](https://github.com/bitcoin/bips/blob/master/bip-0133.mediawiki): feefilter messages are respected and sent for peer versions `>=70013` as of **v0.13.0** ([PR 7542](https://github.com/bitcoin/bitcoin/pull/7542)).
diff --git a/qa/rpc-tests/abandonconflict.py b/qa/rpc-tests/abandonconflict.py
index b6c4b9db48..c50c3cc562 100755
--- a/qa/rpc-tests/abandonconflict.py
+++ b/qa/rpc-tests/abandonconflict.py
@@ -9,6 +9,10 @@ from test_framework.util import *
import urllib.parse
class AbandonConflictTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py
index 60923b9dda..754b6873b7 100755
--- a/qa/rpc-tests/bip65-cltv-p2p.py
+++ b/qa/rpc-tests/bip65-cltv-p2p.py
@@ -37,11 +37,12 @@ Mine 1 old version block, see that the node rejects.
class BIP65Test(ComparisonTestFramework):
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def setup_network(self):
# Must set the blockversion for this test
- self.nodes = start_nodes(1, self.options.tmpdir,
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=3']],
binary=[self.options.testbinary])
diff --git a/qa/rpc-tests/bip65-cltv.py b/qa/rpc-tests/bip65-cltv.py
index 9d83fc947b..abba7fc20e 100755
--- a/qa/rpc-tests/bip65-cltv.py
+++ b/qa/rpc-tests/bip65-cltv.py
@@ -11,6 +11,10 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class BIP65Test(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 3
+ self.setup_clean_chain = False
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/bip68-112-113-p2p.py b/qa/rpc-tests/bip68-112-113-p2p.py
index eedb60e3a0..8ba0704384 100755
--- a/qa/rpc-tests/bip68-112-113-p2p.py
+++ b/qa/rpc-tests/bip68-112-113-p2p.py
@@ -94,11 +94,12 @@ def all_rlt_txs(txarray):
class BIP68_112_113Test(ComparisonTestFramework):
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def setup_network(self):
# Must set the blockversion for this test
- self.nodes = start_nodes(1, self.options.tmpdir,
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=4']],
binary=[self.options.testbinary])
diff --git a/qa/rpc-tests/bip68-sequence.py b/qa/rpc-tests/bip68-sequence.py
index 717f7562cd..a12bf10ebd 100755
--- a/qa/rpc-tests/bip68-sequence.py
+++ b/qa/rpc-tests/bip68-sequence.py
@@ -22,6 +22,10 @@ SEQUENCE_LOCKTIME_MASK = 0x0000ffff
NOT_FINAL_ERROR = "64: non-BIP68-final"
class BIP68Test(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/bip9-softforks.py b/qa/rpc-tests/bip9-softforks.py
index a8fb878dcb..aae258315e 100755
--- a/qa/rpc-tests/bip9-softforks.py
+++ b/qa/rpc-tests/bip9-softforks.py
@@ -32,10 +32,11 @@ test that enforcement has triggered
class BIP9SoftForksTest(ComparisonTestFramework):
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def setup_network(self):
- self.nodes = start_nodes(1, self.options.tmpdir,
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1']],
binary=[self.options.testbinary])
diff --git a/qa/rpc-tests/bipdersig-p2p.py b/qa/rpc-tests/bipdersig-p2p.py
index c462730840..4e4936a4ae 100755
--- a/qa/rpc-tests/bipdersig-p2p.py
+++ b/qa/rpc-tests/bipdersig-p2p.py
@@ -45,11 +45,12 @@ Mine 1 old version block, see that the node rejects.
class BIP66Test(ComparisonTestFramework):
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def setup_network(self):
# Must set the blockversion for this test
- self.nodes = start_nodes(1, self.options.tmpdir,
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=2']],
binary=[self.options.testbinary])
diff --git a/qa/rpc-tests/bipdersig.py b/qa/rpc-tests/bipdersig.py
index f2d2c14a72..17c2ced79a 100755
--- a/qa/rpc-tests/bipdersig.py
+++ b/qa/rpc-tests/bipdersig.py
@@ -11,6 +11,10 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class BIP66Test(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 3
+ self.setup_clean_chain = False
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py
index c84047b5dd..410b85d15e 100755
--- a/qa/rpc-tests/blockchain.py
+++ b/qa/rpc-tests/blockchain.py
@@ -13,7 +13,6 @@ from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import (
- initialize_chain,
assert_equal,
assert_raises,
assert_is_hex_string,
@@ -32,12 +31,13 @@ class BlockchainTest(BitcoinTestFramework):
"""
- def setup_chain(self):
- print("Initializing test directory " + self.options.tmpdir)
- initialize_chain(self.options.tmpdir)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = False
+ self.num_nodes = 2
def setup_network(self, split=False):
- self.nodes = start_nodes(2, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes, 0, 1)
self.is_network_split = False
self.sync_all()
diff --git a/qa/rpc-tests/decodescript.py b/qa/rpc-tests/decodescript.py
index 0037542e62..24768c2655 100755
--- a/qa/rpc-tests/decodescript.py
+++ b/qa/rpc-tests/decodescript.py
@@ -11,12 +11,13 @@ from io import BytesIO
class DecodeScriptTest(BitcoinTestFramework):
"""Tests decoding scripts via RPC command "decodescript"."""
- def setup_chain(self):
- print('Initializing test directory ' + self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self, split=False):
- self.nodes = start_nodes(1, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
self.is_network_split = False
def decodescript_script_sig(self):
diff --git a/qa/rpc-tests/disablewallet.py b/qa/rpc-tests/disablewallet.py
index b25d2ba335..36c147edad 100755
--- a/qa/rpc-tests/disablewallet.py
+++ b/qa/rpc-tests/disablewallet.py
@@ -13,12 +13,13 @@ from test_framework.util import *
class DisableWalletTest (BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self, split=False):
- self.nodes = start_nodes(1, self.options.tmpdir, [['-disablewallet']])
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [['-disablewallet']])
self.is_network_split = False
self.sync_all()
diff --git a/qa/rpc-tests/forknotify.py b/qa/rpc-tests/forknotify.py
index 421f3dd872..5a3f75c808 100755
--- a/qa/rpc-tests/forknotify.py
+++ b/qa/rpc-tests/forknotify.py
@@ -12,6 +12,11 @@ from test_framework.util import *
class ForkNotifyTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
+
alert_filename = None # Set by setup_network
def setup_network(self):
diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py
index 74849603f7..57b850a6a9 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/qa/rpc-tests/fundrawtransaction.py
@@ -9,12 +9,13 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class RawTransactionsTest(BitcoinTestFramework):
- def setup_chain(self):
- print(("Initializing test directory "+self.options.tmpdir))
- initialize_chain_clean(self.options.tmpdir, 4)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
def setup_network(self, split=False):
- self.nodes = start_nodes(4, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
@@ -521,7 +522,7 @@ class RawTransactionsTest(BitcoinTestFramework):
stop_nodes(self.nodes)
wait_bitcoinds()
- self.nodes = start_nodes(4, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
# This test is not meant to test fee estimation and we'd like
# to be sure all txs are sent at a consistent desired feerate
for node in self.nodes:
diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py
index e443347077..3cddf4046a 100755
--- a/qa/rpc-tests/getblocktemplate_longpoll.py
+++ b/qa/rpc-tests/getblocktemplate_longpoll.py
@@ -26,6 +26,11 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
Test longpolling with getblocktemplate.
'''
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
def run_test(self):
print("Warning: this test will take about 70 seconds in the best case. Be patient.")
self.nodes[0].generate(10)
diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py
index 1ad2af4c2e..7a4f8f8fdc 100755
--- a/qa/rpc-tests/getblocktemplate_proposals.py
+++ b/qa/rpc-tests/getblocktemplate_proposals.py
@@ -70,6 +70,15 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
Test block proposals with getblocktemplate.
'''
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
+
+ def setup_network(self):
+ self.nodes = self.setup_nodes()
+ connect_nodes_bi(self.nodes, 0, 1)
+
def run_test(self):
node = self.nodes[0]
node.generate(1) # Mine a block to leave initial block download
diff --git a/qa/rpc-tests/getchaintips.py b/qa/rpc-tests/getchaintips.py
index da354b0c97..1c66b8c289 100755
--- a/qa/rpc-tests/getchaintips.py
+++ b/qa/rpc-tests/getchaintips.py
@@ -11,9 +11,12 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
class GetChainTipsTest (BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
def run_test (self):
- BitcoinTestFramework.run_test (self)
tips = self.nodes[0].getchaintips ()
assert_equal (len (tips), 1)
diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py
index c62edc8e13..10bc927e1a 100755
--- a/qa/rpc-tests/httpbasics.py
+++ b/qa/rpc-tests/httpbasics.py
@@ -14,8 +14,13 @@ import http.client
import urllib.parse
class HTTPBasicsTest (BitcoinTestFramework):
- def setup_nodes(self):
- return start_nodes(4, self.options.tmpdir)
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 3
+ self.setup_clean_chain = False
+
+ def setup_network(self):
+ self.nodes = self.setup_nodes()
def run_test(self):
diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py
index def1d891c3..d86f51b7f3 100755
--- a/qa/rpc-tests/importprunedfunds.py
+++ b/qa/rpc-tests/importprunedfunds.py
@@ -9,12 +9,13 @@ import decimal
class ImportPrunedFundsTest(BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 4)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 2
def setup_network(self, split=False):
- self.nodes = start_nodes(2, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
self.is_network_split=False
self.sync_all()
diff --git a/qa/rpc-tests/invalidateblock.py b/qa/rpc-tests/invalidateblock.py
index 2e3a449f5e..0faadd33ab 100755
--- a/qa/rpc-tests/invalidateblock.py
+++ b/qa/rpc-tests/invalidateblock.py
@@ -13,10 +13,11 @@ from test_framework.util import *
class InvalidateTest(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 = []
self.is_network_split = False
diff --git a/qa/rpc-tests/invalidblockrequest.py b/qa/rpc-tests/invalidblockrequest.py
index 78dc7199da..3d8107a76c 100755
--- a/qa/rpc-tests/invalidblockrequest.py
+++ b/qa/rpc-tests/invalidblockrequest.py
@@ -25,6 +25,7 @@ class InvalidBlockRequestTest(ComparisonTestFramework):
''' Can either run this test as 1 node with expected answers, or two and compare them.
Change the "outcome" variable from each TestInstance object to only do the comparison. '''
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def run_test(self):
diff --git a/qa/rpc-tests/invalidtxrequest.py b/qa/rpc-tests/invalidtxrequest.py
index d4200b0e88..93205d79de 100755
--- a/qa/rpc-tests/invalidtxrequest.py
+++ b/qa/rpc-tests/invalidtxrequest.py
@@ -19,6 +19,7 @@ class InvalidTxRequestTest(ComparisonTestFramework):
''' Can either run this test as 1 node with expected answers, or two and compare them.
Change the "outcome" variable from each TestInstance object to only do the comparison. '''
def __init__(self):
+ super().__init__()
self.num_nodes = 1
def run_test(self):
diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py
index bdc144bfbc..c75303ecbf 100755
--- a/qa/rpc-tests/keypool.py
+++ b/qa/rpc-tests/keypool.py
@@ -5,8 +5,6 @@
# Exercise the wallet keypool, and interaction with wallet encryption/locking
-# Add python-bitcoinrpc to module search path:
-
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -65,12 +63,13 @@ class KeyPoolTest(BitcoinTestFramework):
except JSONRPCException as e:
assert(e.error['code']==-12)
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain(self.options.tmpdir)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = False
+ self.num_nodes = 1
def setup_network(self):
- self.nodes = start_nodes(1, self.options.tmpdir)
+ self.nodes = self.setup_nodes()
if __name__ == '__main__':
KeyPoolTest().main()
diff --git a/qa/rpc-tests/listtransactions.py b/qa/rpc-tests/listtransactions.py
index 8dad687edd..5ec6ce17e0 100755
--- a/qa/rpc-tests/listtransactions.py
+++ b/qa/rpc-tests/listtransactions.py
@@ -17,11 +17,15 @@ def txFromHex(hexstring):
return tx
class ListTransactionsTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
def setup_nodes(self):
#This test requires mocktime
enable_mocktime()
- return start_nodes(4, self.options.tmpdir)
+ return start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
# Simple send, 0 to 1:
diff --git a/qa/rpc-tests/maxblocksinflight.py b/qa/rpc-tests/maxblocksinflight.py
index 6f105a77e3..1df1c484be 100755
--- a/qa/rpc-tests/maxblocksinflight.py
+++ b/qa/rpc-tests/maxblocksinflight.py
@@ -76,12 +76,13 @@ class MaxBlocksInFlightTest(BitcoinTestFramework):
default=os.getenv("BITCOIND", "bitcoind"),
help="Binary to test max block requests behavior")
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self):
- self.nodes = start_nodes(1, self.options.tmpdir,
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[['-debug', '-whitelist=127.0.0.1']],
binary=[self.options.testbinary])
diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py
index ec802d8155..5087f07620 100755
--- a/qa/rpc-tests/maxuploadtarget.py
+++ b/qa/rpc-tests/maxuploadtarget.py
@@ -80,17 +80,19 @@ class TestNode(NodeConnCB):
return success
class MaxUploadTest(BitcoinTestFramework):
- def __init__(self):
- self.utxo = []
- self.txouts = gen_return_txouts()
def add_options(self, parser):
parser.add_option("--testbinary", dest="testbinary",
default=os.getenv("BITCOIND", "bitcoind"),
help="bitcoind binary to test")
- def setup_chain(self):
- initialize_chain_clean(self.options.tmpdir, 2)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ self.utxo = []
+ self.txouts = gen_return_txouts()
def setup_network(self):
# Start a node with maxuploadtarget of 200 MB (/24h)
diff --git a/qa/rpc-tests/mempool_limit.py b/qa/rpc-tests/mempool_limit.py
index bc208709e9..4438c152df 100755
--- a/qa/rpc-tests/mempool_limit.py
+++ b/qa/rpc-tests/mempool_limit.py
@@ -10,9 +10,6 @@ from test_framework.util import *
class MempoolLimitTest(BitcoinTestFramework):
- def __init__(self):
- self.txouts = gen_return_txouts()
-
def setup_network(self):
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0", "-debug"]))
@@ -20,9 +17,12 @@ class MempoolLimitTest(BitcoinTestFramework):
self.sync_all()
self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 2)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ self.txouts = gen_return_txouts()
def run_test(self):
txids = []
diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py
index 7ac85c1b6d..693ff593b3 100755
--- a/qa/rpc-tests/mempool_packages.py
+++ b/qa/rpc-tests/mempool_packages.py
@@ -13,6 +13,10 @@ MAX_ANCESTORS = 25
MAX_DESCENDANTS = 25
class MempoolPackagesTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/mempool_reorg.py b/qa/rpc-tests/mempool_reorg.py
index 608e9d0a06..301b094eb0 100755
--- a/qa/rpc-tests/mempool_reorg.py
+++ b/qa/rpc-tests/mempool_reorg.py
@@ -13,6 +13,10 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class MempoolCoinbaseTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
alert_filename = None # Set by setup_network
diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py
index b4d9f0a1a2..3db12cbf76 100755
--- a/qa/rpc-tests/mempool_resurrect_test.py
+++ b/qa/rpc-tests/mempool_resurrect_test.py
@@ -14,6 +14,11 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class MempoolCoinbaseTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 1
+ self.setup_clean_chain = False
+
def setup_network(self):
# Just need one node for this test
args = ["-checkmempool", "-debug=mempool"]
diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py
index c23f5ef10a..d5e4bf52d2 100755
--- a/qa/rpc-tests/mempool_spendcoinbase.py
+++ b/qa/rpc-tests/mempool_spendcoinbase.py
@@ -19,6 +19,11 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class MempoolSpendCoinbaseTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 1
+ self.setup_clean_chain = False
+
def setup_network(self):
# Just need one node for this test
args = ["-checkmempool", "-debug=mempool"]
diff --git a/qa/rpc-tests/merkle_blocks.py b/qa/rpc-tests/merkle_blocks.py
index 9419d9a714..b2155d7fc3 100755
--- a/qa/rpc-tests/merkle_blocks.py
+++ b/qa/rpc-tests/merkle_blocks.py
@@ -12,9 +12,10 @@ from test_framework.util import *
class MerkleBlockTest(BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 4)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/multi_rpc.py b/qa/rpc-tests/multi_rpc.py
index 577d80949d..24373b257d 100755
--- a/qa/rpc-tests/multi_rpc.py
+++ b/qa/rpc-tests/multi_rpc.py
@@ -8,18 +8,21 @@
#
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
+from test_framework.util import str_to_b64str, assert_equal
+import os
import http.client
import urllib.parse
class HTTPBasicsTest (BitcoinTestFramework):
- def setup_nodes(self):
- return start_nodes(4, self.options.tmpdir)
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = False
+ self.num_nodes = 1
def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain(self.options.tmpdir)
+ super().setup_chain()
#Append rpcauth to bitcoin.conf before initialization
rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144"
rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
@@ -27,6 +30,9 @@ class HTTPBasicsTest (BitcoinTestFramework):
f.write(rpcauth+"\n")
f.write(rpcauth2+"\n")
+ def setup_network(self):
+ self.nodes = self.setup_nodes()
+
def run_test(self):
##################################################
diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py
index 1b6ba021a0..e9682c4908 100755
--- a/qa/rpc-tests/nodehandling.py
+++ b/qa/rpc-tests/nodehandling.py
@@ -14,6 +14,12 @@ import http.client
import urllib.parse
class NodeHandlingTest (BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
def run_test(self):
###########################
# setban/listbanned tests #
diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py
index 21e4c2f468..015ec34eff 100755
--- a/qa/rpc-tests/p2p-acceptblock.py
+++ b/qa/rpc-tests/p2p-acceptblock.py
@@ -111,8 +111,10 @@ class AcceptBlockTest(BitcoinTestFramework):
default=os.getenv("BITCOIND", "bitcoind"),
help="bitcoind binary to test")
- 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):
# Node0 will be used to test behavior of processing unrequested blocks
diff --git a/qa/rpc-tests/p2p-feefilter.py b/qa/rpc-tests/p2p-feefilter.py
index 5fb51ed0fe..cd0501a314 100755
--- a/qa/rpc-tests/p2p-feefilter.py
+++ b/qa/rpc-tests/p2p-feefilter.py
@@ -46,6 +46,12 @@ class TestNode(SingleNodeConnCB):
self.sync_with_ping()
class FeeFilterTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
+
def setup_network(self):
# Node1 will be used to generate txs which should be relayed from Node0
# to our test node
diff --git a/qa/rpc-tests/p2p-fullblocktest.py b/qa/rpc-tests/p2p-fullblocktest.py
index 56df8ffd01..aa0501c5e9 100755
--- a/qa/rpc-tests/p2p-fullblocktest.py
+++ b/qa/rpc-tests/p2p-fullblocktest.py
@@ -29,6 +29,7 @@ class FullBlockTest(ComparisonTestFramework):
''' Can either run this test as 1 node with expected answers, or two and compare them.
Change the "outcome" variable from each TestInstance object to only do the comparison. '''
def __init__(self):
+ super().__init__()
self.num_nodes = 1
self.block_heights = {}
self.coinbase_key = CECKey()
diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/qa/rpc-tests/p2p-versionbits-warning.py
index 8c8c2358f7..962cafef0b 100755
--- a/qa/rpc-tests/p2p-versionbits-warning.py
+++ b/qa/rpc-tests/p2p-versionbits-warning.py
@@ -59,8 +59,10 @@ class TestNode(NodeConnCB):
class VersionBitsWarningTest(BitcoinTestFramework):
- def setup_chain(self):
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py
index 6ab88602b5..e1771231c0 100755
--- a/qa/rpc-tests/prioritise_transaction.py
+++ b/qa/rpc-tests/prioritise_transaction.py
@@ -14,11 +14,11 @@ from test_framework.mininode import COIN, MAX_BLOCK_SIZE
class PrioritiseTransactionTest(BitcoinTestFramework):
def __init__(self):
- self.txouts = gen_return_txouts()
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ self.txouts = gen_return_txouts()
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py
index 6c7b201d56..27160cae07 100755
--- a/qa/rpc-tests/proxy_test.py
+++ b/qa/rpc-tests/proxy_test.py
@@ -36,6 +36,10 @@ addnode connect to generic DNS name
class ProxyTest(BitcoinTestFramework):
def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
self.have_ipv6 = test_ipv6_local()
# Create two proxies on different ports
# ... one unauthenticated
@@ -77,7 +81,7 @@ class ProxyTest(BitcoinTestFramework):
]
if self.have_ipv6:
args[3] = ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
- return start_nodes(4, self.options.tmpdir, extra_args=args)
+ return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args)
def node_test(self, node, proxies, auth, test_onion=True):
rv = []
diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py
index eac2272db2..d225e29b50 100755
--- a/qa/rpc-tests/pruning.py
+++ b/qa/rpc-tests/pruning.py
@@ -20,14 +20,14 @@ def calc_usage(blockdir):
class PruneTest(BitcoinTestFramework):
def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+
self.utxo = []
self.address = ["",""]
self.txouts = gen_return_txouts()
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 3)
-
def setup_network(self):
self.nodes = []
self.is_network_split = False
diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py
index 7f7b6887a8..df02c1697f 100755
--- a/qa/rpc-tests/rawtransactions.py
+++ b/qa/rpc-tests/rawtransactions.py
@@ -14,12 +14,13 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class RawTransactionsTest(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, split=False):
- self.nodes = start_nodes(3, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
#connect to a local machine for debugging
#url = "http://bitcoinrpc:DP6DvqZtqXarpeNWyN3LZTFchCCyCUuHwNF7E8pX99x1@%s:%d" % ('127.0.0.1', 18332)
diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py
index a3f97669ea..4f17b661cb 100755
--- a/qa/rpc-tests/receivedby.py
+++ b/qa/rpc-tests/receivedby.py
@@ -27,10 +27,15 @@ def get_sub_array_from_array(object_array, to_match):
class ReceivedByTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
def setup_nodes(self):
#This test requires mocktime
enable_mocktime()
- return start_nodes(4, self.options.tmpdir)
+ return start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
'''
diff --git a/qa/rpc-tests/reindex.py b/qa/rpc-tests/reindex.py
index a3f4d6ea01..abbbb10336 100755
--- a/qa/rpc-tests/reindex.py
+++ b/qa/rpc-tests/reindex.py
@@ -12,9 +12,10 @@ import time
class ReindexTest(BitcoinTestFramework):
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self):
self.nodes = []
diff --git a/qa/rpc-tests/replace-by-fee.py b/qa/rpc-tests/replace-by-fee.py
index 4afc3981da..34c0f9d795 100755
--- a/qa/rpc-tests/replace-by-fee.py
+++ b/qa/rpc-tests/replace-by-fee.py
@@ -68,6 +68,11 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
class ReplaceByFeeTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 1
+ self.setup_clean_chain = False
+
def setup_network(self):
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug",
diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py
index ec9515528e..c9c2eaf7f3 100755
--- a/qa/rpc-tests/rest.py
+++ b/qa/rpc-tests/rest.py
@@ -47,12 +47,13 @@ def http_post_call(host, port, path, requestdata = '', response_object = 0):
class RESTTest (BitcoinTestFramework):
FORMAT_SEPARATOR = "."
- 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, split=False):
- self.nodes = start_nodes(3, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py
index 7b7c01f993..572273566b 100755
--- a/qa/rpc-tests/rpcbind_test.py
+++ b/qa/rpc-tests/rpcbind_test.py
@@ -24,7 +24,7 @@ def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected):
if allow_ips:
base_args += ['-rpcallowip=' + x for x in allow_ips]
binds = ['-rpcbind='+addr for addr in addresses]
- nodes = start_nodes(1, tmpdir, [base_args + binds], connect_to)
+ nodes = start_nodes(self.num_nodes, tmpdir, [base_args + binds], connect_to)
try:
pid = bitcoind_processes[0].pid
assert_equal(set(get_bind_addrs(pid)), set(expected))
@@ -38,7 +38,7 @@ def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport):
at a non-localhost IP.
'''
base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
- nodes = start_nodes(1, tmpdir, [base_args])
+ nodes = start_nodes(self.num_nodes, tmpdir, [base_args])
try:
# connect to node through non-loopback interface
url = "http://rt:rt@%s:%d" % (rpchost, rpcport,)
diff --git a/qa/rpc-tests/sendheaders.py b/qa/rpc-tests/sendheaders.py
index 96d1da729b..6ab17d59b3 100755
--- a/qa/rpc-tests/sendheaders.py
+++ b/qa/rpc-tests/sendheaders.py
@@ -208,12 +208,14 @@ class TestNode(BaseNode):
BaseNode.__init__(self)
class SendHeadersTest(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):
self.nodes = []
- self.nodes = start_nodes(2, self.options.tmpdir, [["-debug", "-logtimemicros=1"]]*2)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [["-debug", "-logtimemicros=1"]]*2)
connect_nodes(self.nodes[0], 1)
# mine count blocks and return the new tip
diff --git a/qa/rpc-tests/signmessages.py b/qa/rpc-tests/signmessages.py
index 4a47c0ca1e..31b6f14a26 100755
--- a/qa/rpc-tests/signmessages.py
+++ b/qa/rpc-tests/signmessages.py
@@ -10,12 +10,13 @@ from test_framework.util import *
class SignMessagesTest(BitcoinTestFramework):
"""Tests RPC commands for signing and verifying messages."""
- def setup_chain(self):
- print('Initializing test directory ' + self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self, split=False):
- self.nodes = start_nodes(1, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
self.is_network_split = False
def run_test(self):
diff --git a/qa/rpc-tests/signrawtransactions.py b/qa/rpc-tests/signrawtransactions.py
index a06ac53191..c61a280616 100755
--- a/qa/rpc-tests/signrawtransactions.py
+++ b/qa/rpc-tests/signrawtransactions.py
@@ -10,12 +10,13 @@ from test_framework.util import *
class SignRawTransactionsTest(BitcoinTestFramework):
"""Tests transaction signing via RPC command "signrawtransaction"."""
- def setup_chain(self):
- print('Initializing test directory ' + self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 1)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 1
def setup_network(self, split=False):
- self.nodes = start_nodes(1, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
self.is_network_split = False
def successful_signing_test(self):
diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py
index 8fcb99c1b7..d76fba4b07 100755
--- a/qa/rpc-tests/smartfees.py
+++ b/qa/rpc-tests/smartfees.py
@@ -145,6 +145,11 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True):
class EstimateFeeTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 3
+ self.setup_clean_chain = False
+
def setup_network(self):
'''
We'll setup the network to have 3 nodes that all mine with different parameters.
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
index 3480de6c6e..30e8b5755d 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -15,7 +15,6 @@ import traceback
from .util import (
initialize_chain,
- assert_equal,
start_nodes,
connect_nodes_bi,
sync_blocks,
@@ -32,21 +31,26 @@ from .authproxy import JSONRPCException
class BitcoinTestFramework(object):
- # These may be over-ridden by subclasses:
+ def __init__(self):
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+ self.nodes = None
+
def run_test(self):
- for node in self.nodes:
- assert_equal(node.getblockcount(), 200)
- assert_equal(node.getbalance(), 25*50)
+ raise NotImplementedError
def add_options(self, parser):
pass
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
- initialize_chain(self.options.tmpdir)
+ if self.setup_clean_chain:
+ initialize_chain_clean(self.options.tmpdir, self.num_nodes)
+ else:
+ initialize_chain(self.options.tmpdir, self.num_nodes)
def setup_nodes(self):
- return start_nodes(4, self.options.tmpdir)
+ return start_nodes(self.num_nodes, self.options.tmpdir)
def setup_network(self, split = False):
self.nodes = self.setup_nodes()
@@ -115,6 +119,8 @@ class BitcoinTestFramework(object):
self.add_options(parser)
(self.options, self.args) = parser.parse_args()
+ self.options.tmpdir += '/' + str(self.options.port_seed)
+
if self.options.trace_rpc:
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
@@ -161,9 +167,11 @@ class BitcoinTestFramework(object):
else:
print("Note: bitcoinds were not stopped and may still be running")
- if not self.options.nocleanup and not self.options.noshutdown:
+ if not self.options.nocleanup and not self.options.noshutdown and success:
print("Cleaning up")
shutil.rmtree(self.options.tmpdir)
+ else:
+ print("Not cleaning up dir %s" % self.options.tmpdir)
if success:
print("Tests successful")
@@ -181,9 +189,10 @@ class BitcoinTestFramework(object):
class ComparisonTestFramework(BitcoinTestFramework):
- # Can override the num_nodes variable to indicate how many nodes to run.
def __init__(self):
+ super().__init__()
self.num_nodes = 2
+ self.setup_clean_chain = True
def add_options(self, parser):
parser.add_option("--testbinary", dest="testbinary",
@@ -193,10 +202,6 @@ class ComparisonTestFramework(BitcoinTestFramework):
default=os.getenv("BITCOIND", "bitcoind"),
help="bitcoind binary to use for reference nodes (if any)")
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, self.num_nodes)
-
def setup_network(self):
self.nodes = start_nodes(
self.num_nodes, self.options.tmpdir,
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index 6784177aaa..fc66ef287d 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -35,6 +35,8 @@ PORT_MIN = 11000
# The number of ports to "reserve" for p2p and rpc, each
PORT_RANGE = 5000
+BITCOIND_PROC_WAIT_TIMEOUT = 60
+
class PortSeed:
# Must be initialized with a unique integer for each process
@@ -119,30 +121,34 @@ def hex_str_to_bytes(hex_str):
def str_to_b64str(string):
return b64encode(string.encode('utf-8')).decode('ascii')
-def sync_blocks(rpc_connections, wait=1):
+def sync_blocks(rpc_connections, wait=1, timeout=60):
"""
- Wait until everybody has the same block count
+ Wait until everybody has the same tip
"""
- while True:
- counts = [ x.getblockcount() for x in rpc_connections ]
- if counts == [ counts[0] ]*len(counts):
- break
+ while timeout > 0:
+ tips = [ x.getbestblockhash() for x in rpc_connections ]
+ if tips == [ tips[0] ]*len(tips):
+ return True
time.sleep(wait)
+ timeout -= wait
+ raise AssertionError("Block sync failed")
-def sync_mempools(rpc_connections, wait=1):
+def sync_mempools(rpc_connections, wait=1, timeout=60):
"""
Wait until everybody has the same transactions in their memory
pools
"""
- while True:
+ while timeout > 0:
pool = set(rpc_connections[0].getrawmempool())
num_match = 1
for i in range(1, len(rpc_connections)):
if set(rpc_connections[i].getrawmempool()) == pool:
num_match = num_match+1
if num_match == len(rpc_connections):
- break
+ return True
time.sleep(wait)
+ timeout -= wait
+ raise AssertionError("Mempool sync failed")
bitcoind_processes = {}
@@ -182,24 +188,28 @@ def wait_for_bitcoind_start(process, url, i):
raise # unkown JSON RPC exception
time.sleep(0.25)
-def initialize_chain(test_dir):
+def initialize_chain(test_dir, num_nodes):
"""
- Create (or copy from cache) a 200-block-long chain and
- 4 wallets.
+ Create a cache of a 200-block-long chain (with wallet) for MAX_NODES
+ Afterward, create num_nodes copies from the cache
"""
- if (not os.path.isdir(os.path.join("cache","node0"))
- or not os.path.isdir(os.path.join("cache","node1"))
- or not os.path.isdir(os.path.join("cache","node2"))
- or not os.path.isdir(os.path.join("cache","node3"))):
+ 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))):
+ create_cache = True
+ break
+
+ if create_cache:
#find and delete old cache directories if any exist
- for i in range(4):
+ 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)))
# Create cache directories, run bitcoinds:
- for i in range(4):
+ for i in range(MAX_NODES):
datadir=initialize_datadir("cache", i)
args = [ os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir="+datadir, "-discover=0" ]
if i > 0:
@@ -212,15 +222,18 @@ def initialize_chain(test_dir):
print("initialize_chain: RPC succesfully started")
rpcs = []
- for i in range(4):
+ for i in range(MAX_NODES):
try:
rpcs.append(get_rpc_proxy(rpc_url(i), i))
except:
sys.stderr.write("Error connecting to "+url+"\n")
sys.exit(1)
- # Create a 200-block-long chain; each of the 4 nodes
+ # Create a 200-block-long chain; each of the 4 first nodes
# gets 25 mature blocks and 25 immature.
+ # Note: To preserve compatibility with older versions of
+ # initialize_chain, only 4 nodes will generate coins.
+ #
# blocks are created with timestamps 10 minutes apart
# starting from 2010 minutes in the past
enable_mocktime()
@@ -238,13 +251,13 @@ def initialize_chain(test_dir):
stop_nodes(rpcs)
wait_bitcoinds()
disable_mocktime()
- for i in range(4):
+ 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"))
- for i in range(4):
+ for i in range(num_nodes):
from_dir = os.path.join("cache", "node"+str(i))
to_dir = os.path.join(test_dir, "node"+str(i))
shutil.copytree(from_dir, to_dir)
@@ -325,7 +338,7 @@ def stop_node(node, i):
node.stop()
except http.client.CannotSendRequest as e:
print("WARN: Unable to stop node: " + repr(e))
- bitcoind_processes[i].wait()
+ bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
del bitcoind_processes[i]
def stop_nodes(nodes):
@@ -343,7 +356,7 @@ def set_node_times(nodes, t):
def wait_bitcoinds():
# Wait for all bitcoinds to cleanly exit
for bitcoind in bitcoind_processes.values():
- bitcoind.wait()
+ bitcoind.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
bitcoind_processes.clear()
def connect_nodes(from_connection, node_num):
diff --git a/qa/rpc-tests/txn_clone.py b/qa/rpc-tests/txn_clone.py
index 5710c29aa6..22f850ece6 100755
--- a/qa/rpc-tests/txn_clone.py
+++ b/qa/rpc-tests/txn_clone.py
@@ -12,6 +12,11 @@ from test_framework.util import *
class TxnMallTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
def add_options(self, parser):
parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true",
help="Test double-spend of 1-confirmed transaction")
diff --git a/qa/rpc-tests/txn_doublespend.py b/qa/rpc-tests/txn_doublespend.py
index 1fbb207e22..84944c3c19 100755
--- a/qa/rpc-tests/txn_doublespend.py
+++ b/qa/rpc-tests/txn_doublespend.py
@@ -12,6 +12,11 @@ from test_framework.util import *
class TxnMallTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+ self.setup_clean_chain = False
+
def add_options(self, parser):
parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true",
help="Test double-spend of 1-confirmed transaction")
diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py
index f321f5e90b..9dda712f4f 100755
--- a/qa/rpc-tests/wallet.py
+++ b/qa/rpc-tests/wallet.py
@@ -19,9 +19,10 @@ class WalletTest (BitcoinTestFramework):
raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)"%(str(fee), str(target_fee)))
return curr_balance
- def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 4)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
def setup_network(self, split=False):
self.nodes = start_nodes(3, self.options.tmpdir)
diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py
index c3d53669c9..b991d5c761 100755
--- a/qa/rpc-tests/walletbackup.py
+++ b/qa/rpc-tests/walletbackup.py
@@ -41,15 +41,16 @@ logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, str
class WalletBackupTest(BitcoinTestFramework):
- def setup_chain(self):
- logging.info("Initializing test directory "+self.options.tmpdir)
- initialize_chain_clean(self.options.tmpdir, 4)
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
# This mirrors how the network was setup in the bash test
def setup_network(self, split=False):
# nodes 1, 2,3 are spenders, let's give them a keypool=100
extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
- self.nodes = start_nodes(4, self.options.tmpdir, extra_args)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[1], 3)
connect_nodes(self.nodes[2], 3)
diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py
index 2f8214f87c..17ba53a844 100755
--- a/qa/rpc-tests/zapwallettxes.py
+++ b/qa/rpc-tests/zapwallettxes.py
@@ -9,12 +9,13 @@ from test_framework.util import *
class ZapWalletTXesTest (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, split=False):
- self.nodes = start_nodes(3, self.options.tmpdir)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
diff --git a/qa/rpc-tests/zmq_test.py b/qa/rpc-tests/zmq_test.py
index f5617a084d..3a116317fe 100755
--- a/qa/rpc-tests/zmq_test.py
+++ b/qa/rpc-tests/zmq_test.py
@@ -17,6 +17,10 @@ import urllib.parse
class ZMQTest (BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 4
+
port = 28332
def setup_nodes(self):
@@ -25,7 +29,7 @@ class ZMQTest (BitcoinTestFramework):
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock")
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx")
self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % self.port)
- return start_nodes(4, self.options.tmpdir, extra_args=[
+ return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
['-zmqpubhashtx=tcp://127.0.0.1:'+str(self.port), '-zmqpubhashblock=tcp://127.0.0.1:'+str(self.port)],
[],
[],
diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py
index 7728a43775..2ba8bb9b3a 100755
--- a/share/qt/extract_strings_qt.py
+++ b/share/qt/extract_strings_qt.py
@@ -32,7 +32,7 @@ def parse_po(text):
in_msgstr = False
# message start
in_msgid = True
-
+
msgid = [line[6:]]
elif line.startswith('msgstr '):
in_msgid = False
@@ -67,7 +67,7 @@ f.write("""
#include <QtGlobal>
-// Automatically generated by extract_strings.py
+// Automatically generated by extract_strings_qt.py
#ifdef __GNUC__
#define UNUSED __attribute__((unused))
#else
diff --git a/src/Makefile.am b/src/Makefile.am
index 3c056386fa..ea49efe92d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,13 +15,12 @@ LIBUNIVALUE = $(UNIVALUE_LIBS)
endif
BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
-BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
+BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS)
LIBBITCOIN_SERVER=libbitcoin_server.a
-LIBBITCOIN_WALLET=libbitcoin_wallet.a
LIBBITCOIN_COMMON=libbitcoin_common.a
LIBBITCOIN_CONSENSUS=libbitcoin_consensus.a
LIBBITCOIN_CLI=libbitcoin_cli.a
@@ -30,32 +29,32 @@ LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
LIBBITCOINQT=qt/libbitcoinqt.a
LIBSECP256K1=secp256k1/libsecp256k1.la
+if ENABLE_ZMQ
+LIBBITCOIN_ZMQ=libbitcoin_zmq.a
+endif
+if BUILD_BITCOIN_LIBS
+LIBBITCOINCONSENSUS=libbitcoinconsensus.la
+endif
+if ENABLE_WALLET
+LIBBITCOIN_WALLET=libbitcoin_wallet.a
+endif
+
$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
# Make is not made aware of per-object dependencies to avoid limiting building parallelization
# But to build the less dependent modules first, we manually select their order here:
EXTRA_LIBRARIES += \
- crypto/libbitcoin_crypto.a \
- libbitcoin_util.a \
- libbitcoin_common.a \
- libbitcoin_consensus.a \
- libbitcoin_server.a \
- libbitcoin_cli.a
-if ENABLE_WALLET
-BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
-EXTRA_LIBRARIES += libbitcoin_wallet.a
-endif
-if ENABLE_ZMQ
-EXTRA_LIBRARIES += libbitcoin_zmq.a
-endif
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_CLI) \
+ $(LIBBITCOIN_WALLET) \
+ $(LIBBITCOIN_ZMQ)
-if BUILD_BITCOIN_LIBS
-lib_LTLIBRARIES = libbitcoinconsensus.la
-LIBBITCOINCONSENSUS=libbitcoinconsensus.la
-else
-LIBBITCOINCONSENSUS=
-endif
+lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
bin_PROGRAMS =
TESTS =
@@ -196,8 +195,6 @@ libbitcoin_server_a_SOURCES = \
$(BITCOIN_CORE_H)
if ENABLE_ZMQ
-LIBBITCOIN_ZMQ=libbitcoin_zmq.a
-
libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS)
libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_zmq_a_SOURCES = \
@@ -225,6 +222,8 @@ libbitcoin_wallet_a_SOURCES = \
crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES)
crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_a_SOURCES = \
+ crypto/aes.cpp \
+ crypto/aes.h \
crypto/common.h \
crypto/hmac_sha256.cpp \
crypto/hmac_sha256.h \
@@ -345,21 +344,15 @@ bitcoind_LDADD = \
$(LIBBITCOIN_COMMON) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_WALLET) \
+ $(LIBBITCOIN_ZMQ) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_CRYPTO) \
$(LIBLEVELDB) \
$(LIBMEMENV) \
$(LIBSECP256K1)
-if ENABLE_ZMQ
-bitcoind_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
-endif
-
-if ENABLE_WALLET
-bitcoind_LDADD += libbitcoin_wallet.a
-endif
-
-bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
+bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS)
# bitcoin-cli binary #
bitcoin_cli_SOURCES = bitcoin-cli.cpp
@@ -374,7 +367,8 @@ endif
bitcoin_cli_LDADD = \
$(LIBBITCOIN_CLI) \
$(LIBUNIVALUE) \
- $(LIBBITCOIN_UTIL)
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CRYPTO)
bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS)
#
@@ -417,6 +411,12 @@ libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
endif
#
+CTAES_DIST = crypto/ctaes/bench.c
+CTAES_DIST += crypto/ctaes/ctaes.c
+CTAES_DIST += crypto/ctaes/ctaes.h
+CTAES_DIST += crypto/ctaes/README.md
+CTAES_DIST += crypto/ctaes/test.c
+
CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a
CLEANFILES += $(EXTRA_LIBRARIES)
CLEANFILES += *.gcda *.gcno
@@ -434,7 +434,7 @@ CLEANFILES += zmq/*.gcda zmq/*.gcno
DISTCLEANFILES = obj/build.h
-EXTRA_DIST = leveldb
+EXTRA_DIST = leveldb $(CTAES_DIST)
clean-local:
-$(MAKE) -C leveldb clean
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 65fd24e051..4067ceb399 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -9,7 +9,8 @@ bench_bench_bitcoin_SOURCES = \
bench/bench.h \
bench/Examples.cpp \
bench/rollingbloom.cpp \
- bench/crypto_hash.cpp
+ bench/crypto_hash.cpp \
+ bench/base58.cpp
bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 897a7dd4a2..77cf1001e1 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -95,6 +95,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
endif
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
new file mode 100644
index 0000000000..1279c3e7df
--- /dev/null
+++ b/src/bench/base58.cpp
@@ -0,0 +1,56 @@
+// 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 "bench.h"
+
+#include "main.h"
+#include "base58.h"
+
+#include <vector>
+#include <string>
+
+
+static void Base58Encode(benchmark::State& state)
+{
+ unsigned char buff[32] = {
+ 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
+ 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
+ 200, 24
+ };
+ unsigned char* b = buff;
+ while (state.KeepRunning()) {
+ EncodeBase58(b, b + 32);
+ }
+}
+
+
+static void Base58CheckEncode(benchmark::State& state)
+{
+ unsigned char buff[32] = {
+ 17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
+ 227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
+ 200, 24
+ };
+ unsigned char* b = buff;
+ std::vector<unsigned char> vch;
+ vch.assign(b, b + 32);
+ while (state.KeepRunning()) {
+ EncodeBase58Check(vch);
+ }
+}
+
+
+static void Base58Decode(benchmark::State& state)
+{
+ const char* addr = "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem";
+ std::vector<unsigned char> vch;
+ while (state.KeepRunning()) {
+ DecodeBase58(addr, vch);
+ }
+}
+
+
+BENCHMARK(Base58Encode);
+BENCHMARK(Base58CheckEncode);
+BENCHMARK(Base58Decode);
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 6ee3cdc27a..227546a7a7 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -5,6 +5,7 @@
#include "bench.h"
#include <iostream>
+#include <iomanip>
#include <sys/time.h>
using namespace benchmark;
@@ -25,7 +26,7 @@ BenchRunner::BenchRunner(std::string name, BenchFunction func)
void
BenchRunner::RunAll(double elapsedTimeForOne)
{
- std::cout << "Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << "\n";
+ std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << "\n";
for (std::map<std::string,BenchFunction>::iterator it = benchmarks.begin();
it != benchmarks.end(); ++it) {
@@ -38,22 +39,34 @@ BenchRunner::RunAll(double elapsedTimeForOne)
bool State::KeepRunning()
{
+ if (count & countMask) {
+ ++count;
+ return true;
+ }
double now;
if (count == 0) {
- beginTime = now = gettimedouble();
+ lastTime = beginTime = now = gettimedouble();
}
else {
- // timeCheckCount is used to avoid calling gettime most of the time,
- // so benchmarks that run very quickly get consistent results.
- if ((count+1)%timeCheckCount != 0) {
- ++count;
- return true; // keep going
- }
now = gettimedouble();
- double elapsedOne = (now - lastTime)/timeCheckCount;
+ double elapsed = now - lastTime;
+ double elapsedOne = elapsed * countMaskInv;
if (elapsedOne < minTime) minTime = elapsedOne;
if (elapsedOne > maxTime) maxTime = elapsedOne;
- if (elapsedOne*timeCheckCount < maxElapsed/16) timeCheckCount *= 2;
+ if (elapsed*128 < maxElapsed) {
+ // If the execution was much too fast (1/128th of maxElapsed), increase the count mask by 8x and restart timing.
+ // The restart avoids including the overhead of this code in the measurement.
+ countMask = ((countMask<<3)|7) & ((1LL<<60)-1);
+ countMaskInv = 1./(countMask+1);
+ count = 0;
+ minTime = std::numeric_limits<double>::max();
+ maxTime = std::numeric_limits<double>::min();
+ return true;
+ }
+ if (elapsed*16 < maxElapsed) {
+ countMask = ((countMask<<1)|1) & ((1LL<<60)-1);
+ countMaskInv = 1./(countMask+1);
+ }
}
lastTime = now;
++count;
@@ -64,7 +77,7 @@ bool State::KeepRunning()
// Output results
double average = (now-beginTime)/count;
- std::cout << name << "," << count << "," << minTime << "," << maxTime << "," << average << "\n";
+ std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << "\n";
return false;
}
diff --git a/src/bench/bench.h b/src/bench/bench.h
index 5ce13c642b..f13b145aaf 100644
--- a/src/bench/bench.h
+++ b/src/bench/bench.h
@@ -40,14 +40,15 @@ namespace benchmark {
std::string name;
double maxElapsed;
double beginTime;
- double lastTime, minTime, maxTime;
+ double lastTime, minTime, maxTime, countMaskInv;
int64_t count;
- int64_t timeCheckCount;
+ int64_t countMask;
public:
State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
minTime = std::numeric_limits<double>::max();
maxTime = std::numeric_limits<double>::min();
- timeCheckCount = 1;
+ countMask = 1;
+ countMaskInv = 1./(countMask + 1);
}
bool KeepRunning();
};
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index 6b753f6308..168006154f 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -6,6 +6,8 @@
#include "bench.h"
#include "bloom.h"
+#include "hash.h"
+#include "uint256.h"
#include "utiltime.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
@@ -39,6 +41,16 @@ static void SHA256(benchmark::State& state)
CSHA256().Write(begin_ptr(in), in.size()).Finalize(hash);
}
+static void SHA256_32b(benchmark::State& state)
+{
+ std::vector<uint8_t> in(32,0);
+ while (state.KeepRunning()) {
+ for (int i = 0; i < 1000000; i++) {
+ CSHA256().Write(begin_ptr(in), in.size()).Finalize(&in[0]);
+ }
+ }
+}
+
static void SHA512(benchmark::State& state)
{
uint8_t hash[CSHA512::OUTPUT_SIZE];
@@ -47,7 +59,20 @@ static void SHA512(benchmark::State& state)
CSHA512().Write(begin_ptr(in), in.size()).Finalize(hash);
}
+static void SipHash_32b(benchmark::State& state)
+{
+ uint256 x;
+ while (state.KeepRunning()) {
+ for (int i = 0; i < 1000000; i++) {
+ *((uint64_t*)x.begin()) = SipHashUint256(0, i, x);
+ }
+ }
+}
+
BENCHMARK(RIPEMD160);
BENCHMARK(SHA1);
BENCHMARK(SHA256);
BENCHMARK(SHA512);
+
+BENCHMARK(SHA256_32b);
+BENCHMARK(SipHash_32b);
diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp
new file mode 100644
index 0000000000..1d469d0fb4
--- /dev/null
+++ b/src/crypto/aes.cpp
@@ -0,0 +1,217 @@
+// 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 "aes.h"
+#include "crypto/common.h"
+
+#include <assert.h>
+#include <string.h>
+
+extern "C" {
+#include "crypto/ctaes/ctaes.c"
+}
+
+AES128Encrypt::AES128Encrypt(const unsigned char key[16])
+{
+ AES128_init(&ctx, key);
+}
+
+AES128Encrypt::~AES128Encrypt()
+{
+ memset(&ctx, 0, sizeof(ctx));
+}
+
+void AES128Encrypt::Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const
+{
+ AES128_encrypt(&ctx, 1, ciphertext, plaintext);
+}
+
+AES128Decrypt::AES128Decrypt(const unsigned char key[16])
+{
+ AES128_init(&ctx, key);
+}
+
+AES128Decrypt::~AES128Decrypt()
+{
+ memset(&ctx, 0, sizeof(ctx));
+}
+
+void AES128Decrypt::Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const
+{
+ AES128_decrypt(&ctx, 1, plaintext, ciphertext);
+}
+
+AES256Encrypt::AES256Encrypt(const unsigned char key[32])
+{
+ AES256_init(&ctx, key);
+}
+
+AES256Encrypt::~AES256Encrypt()
+{
+ memset(&ctx, 0, sizeof(ctx));
+}
+
+void AES256Encrypt::Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const
+{
+ AES256_encrypt(&ctx, 1, ciphertext, plaintext);
+}
+
+AES256Decrypt::AES256Decrypt(const unsigned char key[32])
+{
+ AES256_init(&ctx, key);
+}
+
+AES256Decrypt::~AES256Decrypt()
+{
+ memset(&ctx, 0, sizeof(ctx));
+}
+
+void AES256Decrypt::Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const
+{
+ AES256_decrypt(&ctx, 1, plaintext, ciphertext);
+}
+
+
+template <typename T>
+static int CBCEncrypt(const T& enc, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out)
+{
+ int written = 0;
+ int padsize = size % AES_BLOCKSIZE;
+ unsigned char mixed[AES_BLOCKSIZE];
+
+ if (!data || !size || !out)
+ return 0;
+
+ if (!pad && padsize != 0)
+ return 0;
+
+ memcpy(mixed, iv, AES_BLOCKSIZE);
+
+ // Write all but the last block
+ while (written + AES_BLOCKSIZE <= size) {
+ for (int i = 0; i != AES_BLOCKSIZE; i++)
+ mixed[i] ^= *data++;
+ enc.Encrypt(out + written, mixed);
+ memcpy(mixed, out + written, AES_BLOCKSIZE);
+ written += AES_BLOCKSIZE;
+ }
+ if (pad) {
+ // For all that remains, pad each byte with the value of the remaining
+ // space. If there is none, pad by a full block.
+ for (int i = 0; i != padsize; i++)
+ mixed[i] ^= *data++;
+ for (int i = padsize; i != AES_BLOCKSIZE; i++)
+ mixed[i] ^= AES_BLOCKSIZE - padsize;
+ enc.Encrypt(out + written, mixed);
+ written += AES_BLOCKSIZE;
+ }
+ return written;
+}
+
+template <typename T>
+static int CBCDecrypt(const T& dec, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out)
+{
+ unsigned char padsize = 0;
+ int written = 0;
+ bool fail = false;
+ const unsigned char* prev = iv;
+
+ if (!data || !size || !out)
+ return 0;
+
+ if (size % AES_BLOCKSIZE != 0)
+ return 0;
+
+ // Decrypt all data. Padding will be checked in the output.
+ while (written != size) {
+ dec.Decrypt(out, data + written);
+ for (int i = 0; i != AES_BLOCKSIZE; i++)
+ *out++ ^= prev[i];
+ prev = data + written;
+ written += AES_BLOCKSIZE;
+ }
+
+ // When decrypting padding, attempt to run in constant-time
+ if (pad) {
+ // If used, padding size is the value of the last decrypted byte. For
+ // it to be valid, It must be between 1 and AES_BLOCKSIZE.
+ padsize = *--out;
+ fail = !padsize | (padsize > AES_BLOCKSIZE);
+
+ // If not well-formed, treat it as though there's no padding.
+ padsize *= !fail;
+
+ // All padding must equal the last byte otherwise it's not well-formed
+ for (int i = AES_BLOCKSIZE; i != 0; i--)
+ fail |= ((i > AES_BLOCKSIZE - padsize) & (*out-- != padsize));
+
+ written -= padsize;
+ }
+ return written * !fail;
+}
+
+AES256CBCEncrypt::AES256CBCEncrypt(const unsigned char key[AES256_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn)
+ : enc(key), pad(padIn)
+{
+ memcpy(iv, ivIn, AES_BLOCKSIZE);
+}
+
+int AES256CBCEncrypt::Encrypt(const unsigned char* data, int size, unsigned char* out) const
+{
+ return CBCEncrypt(enc, iv, data, size, pad, out);
+}
+
+AES256CBCEncrypt::~AES256CBCEncrypt()
+{
+ memset(iv, 0, sizeof(iv));
+}
+
+AES256CBCDecrypt::AES256CBCDecrypt(const unsigned char key[AES256_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn)
+ : dec(key), pad(padIn)
+{
+ memcpy(iv, ivIn, AES_BLOCKSIZE);
+}
+
+
+int AES256CBCDecrypt::Decrypt(const unsigned char* data, int size, unsigned char* out) const
+{
+ return CBCDecrypt(dec, iv, data, size, pad, out);
+}
+
+AES256CBCDecrypt::~AES256CBCDecrypt()
+{
+ memset(iv, 0, sizeof(iv));
+}
+
+AES128CBCEncrypt::AES128CBCEncrypt(const unsigned char key[AES128_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn)
+ : enc(key), pad(padIn)
+{
+ memcpy(iv, ivIn, AES_BLOCKSIZE);
+}
+
+AES128CBCEncrypt::~AES128CBCEncrypt()
+{
+ memset(iv, 0, AES_BLOCKSIZE);
+}
+
+int AES128CBCEncrypt::Encrypt(const unsigned char* data, int size, unsigned char* out) const
+{
+ return CBCEncrypt(enc, iv, data, size, pad, out);
+}
+
+AES128CBCDecrypt::AES128CBCDecrypt(const unsigned char key[AES128_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn)
+ : dec(key), pad(padIn)
+{
+ memcpy(iv, ivIn, AES_BLOCKSIZE);
+}
+
+AES128CBCDecrypt::~AES128CBCDecrypt()
+{
+ memset(iv, 0, AES_BLOCKSIZE);
+}
+
+int AES128CBCDecrypt::Decrypt(const unsigned char* data, int size, unsigned char* out) const
+{
+ return CBCDecrypt(dec, iv, data, size, pad, out);
+}
diff --git a/src/crypto/aes.h b/src/crypto/aes.h
new file mode 100644
index 0000000000..8cae357c12
--- /dev/null
+++ b/src/crypto/aes.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+//
+// C++ wrapper around ctaes, a constant-time AES implementation
+
+#ifndef BITCOIN_CRYPTO_AES_H
+#define BITCOIN_CRYPTO_AES_H
+
+extern "C" {
+#include "crypto/ctaes/ctaes.h"
+}
+
+static const int AES_BLOCKSIZE = 16;
+static const int AES128_KEYSIZE = 16;
+static const int AES256_KEYSIZE = 32;
+
+/** An encryption class for AES-128. */
+class AES128Encrypt
+{
+private:
+ AES128_ctx ctx;
+
+public:
+ AES128Encrypt(const unsigned char key[16]);
+ ~AES128Encrypt();
+ void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
+};
+
+/** A decryption class for AES-128. */
+class AES128Decrypt
+{
+private:
+ AES128_ctx ctx;
+
+public:
+ AES128Decrypt(const unsigned char key[16]);
+ ~AES128Decrypt();
+ void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
+};
+
+/** An encryption class for AES-256. */
+class AES256Encrypt
+{
+private:
+ AES256_ctx ctx;
+
+public:
+ AES256Encrypt(const unsigned char key[32]);
+ ~AES256Encrypt();
+ void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
+};
+
+/** A decryption class for AES-256. */
+class AES256Decrypt
+{
+private:
+ AES256_ctx ctx;
+
+public:
+ AES256Decrypt(const unsigned char key[32]);
+ ~AES256Decrypt();
+ void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
+};
+
+class AES256CBCEncrypt
+{
+public:
+ AES256CBCEncrypt(const unsigned char key[AES256_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn);
+ ~AES256CBCEncrypt();
+ int Encrypt(const unsigned char* data, int size, unsigned char* out) const;
+
+private:
+ const AES256Encrypt enc;
+ const bool pad;
+ unsigned char iv[AES_BLOCKSIZE];
+};
+
+class AES256CBCDecrypt
+{
+public:
+ AES256CBCDecrypt(const unsigned char key[AES256_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn);
+ ~AES256CBCDecrypt();
+ int Decrypt(const unsigned char* data, int size, unsigned char* out) const;
+
+private:
+ const AES256Decrypt dec;
+ const bool pad;
+ unsigned char iv[AES_BLOCKSIZE];
+};
+
+class AES128CBCEncrypt
+{
+public:
+ AES128CBCEncrypt(const unsigned char key[AES128_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn);
+ ~AES128CBCEncrypt();
+ int Encrypt(const unsigned char* data, int size, unsigned char* out) const;
+
+private:
+ const AES128Encrypt enc;
+ const bool pad;
+ unsigned char iv[AES_BLOCKSIZE];
+};
+
+class AES128CBCDecrypt
+{
+public:
+ AES128CBCDecrypt(const unsigned char key[AES128_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn);
+ ~AES128CBCDecrypt();
+ int Decrypt(const unsigned char* data, int size, unsigned char* out) const;
+
+private:
+ const AES128Decrypt dec;
+ const bool pad;
+ unsigned char iv[AES_BLOCKSIZE];
+};
+
+#endif // BITCOIN_CRYPTO_AES_H
diff --git a/src/crypto/ctaes/COPYING b/src/crypto/ctaes/COPYING
new file mode 100644
index 0000000000..415b202a2a
--- /dev/null
+++ b/src/crypto/ctaes/COPYING
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Pieter Wuille
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/src/crypto/ctaes/README.md b/src/crypto/ctaes/README.md
new file mode 100644
index 0000000000..0e7fe17751
--- /dev/null
+++ b/src/crypto/ctaes/README.md
@@ -0,0 +1,41 @@
+ctaes
+=====
+
+Simple C module for constant-time AES encryption and decryption.
+
+Features:
+* Simple, pure C code without any dependencies.
+* No tables or data-dependent branches whatsoever, but using bit sliced approach from https://eprint.iacr.org/2009/129.pdf.
+* Very small object code: slightly over 4k of executable code when compiled with -Os.
+* Slower than implementations based on precomputed tables or specialized instructions, but can do ~15 MB/s on modern CPUs.
+
+Performance
+-----------
+
+Compiled with GCC 5.3.1 with -O3, on an Intel(R) Core(TM) i7-4800MQ CPU, numbers in CPU cycles:
+
+| Algorithm | Key schedule | Encryption per byte | Decryption per byte |
+| --------- | ------------:| -------------------:| -------------------:|
+| AES-128 | 2.8k | 154 | 161 |
+| AES-192 | 3.1k | 169 | 181 |
+| AES-256 | 4.0k | 191 | 203 |
+
+Build steps
+-----------
+
+Object code:
+
+ $ gcc -O3 ctaes.c -c -o ctaes.o
+
+Tests:
+
+ $ gcc -O3 ctaes.c test.c -o test
+
+Benchmark:
+
+ $ gcc -O3 ctaes.c bench.c -o bench
+
+Review
+------
+
+Results of a formal review of the code can be found in http://bitcoin.sipa.be/ctaes/review.zip
diff --git a/src/crypto/ctaes/bench.c b/src/crypto/ctaes/bench.c
new file mode 100644
index 0000000000..a86df496c8
--- /dev/null
+++ b/src/crypto/ctaes/bench.c
@@ -0,0 +1,170 @@
+#include <stdio.h>
+#include <math.h>
+#include "sys/time.h"
+
+#include "ctaes.h"
+
+static double gettimedouble(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_usec * 0.000001 + tv.tv_sec;
+}
+
+static void print_number(double x) {
+ double y = x;
+ int c = 0;
+ if (y < 0.0) {
+ y = -y;
+ }
+ while (y < 100.0) {
+ y *= 10.0;
+ c++;
+ }
+ printf("%.*f", c, x);
+}
+
+static void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {
+ int i;
+ double min = HUGE_VAL;
+ double sum = 0.0;
+ double max = 0.0;
+ for (i = 0; i < count; i++) {
+ double begin, total;
+ if (setup != NULL) {
+ setup(data);
+ }
+ begin = gettimedouble();
+ benchmark(data);
+ total = gettimedouble() - begin;
+ if (teardown != NULL) {
+ teardown(data);
+ }
+ if (total < min) {
+ min = total;
+ }
+ if (total > max) {
+ max = total;
+ }
+ sum += total;
+ }
+ printf("%s: min ", name);
+ print_number(min * 1000000000.0 / iter);
+ printf("ns / avg ");
+ print_number((sum / count) * 1000000000.0 / iter);
+ printf("ns / max ");
+ print_number(max * 1000000000.0 / iter);
+ printf("ns\n");
+}
+
+static void bench_AES128_init(void* data) {
+ AES128_ctx* ctx = (AES128_ctx*)data;
+ int i;
+ for (i = 0; i < 50000; i++) {
+ AES128_init(ctx, (unsigned char*)ctx);
+ }
+}
+
+static void bench_AES128_encrypt_setup(void* data) {
+ AES128_ctx* ctx = (AES128_ctx*)data;
+ static const unsigned char key[16] = {0};
+ AES128_init(ctx, key);
+}
+
+static void bench_AES128_encrypt(void* data) {
+ const AES128_ctx* ctx = (const AES128_ctx*)data;
+ unsigned char scratch[16] = {0};
+ int i;
+ for (i = 0; i < 4000000 / 16; i++) {
+ AES128_encrypt(ctx, 1, scratch, scratch);
+ }
+}
+
+static void bench_AES128_decrypt(void* data) {
+ const AES128_ctx* ctx = (const AES128_ctx*)data;
+ unsigned char scratch[16] = {0};
+ int i;
+ for (i = 0; i < 4000000 / 16; i++) {
+ AES128_decrypt(ctx, 1, scratch, scratch);
+ }
+}
+
+static void bench_AES192_init(void* data) {
+ AES192_ctx* ctx = (AES192_ctx*)data;
+ int i;
+ for (i = 0; i < 50000; i++) {
+ AES192_init(ctx, (unsigned char*)ctx);
+ }
+}
+
+static void bench_AES192_encrypt_setup(void* data) {
+ AES192_ctx* ctx = (AES192_ctx*)data;
+ static const unsigned char key[16] = {0};
+ AES192_init(ctx, key);
+}
+
+static void bench_AES192_encrypt(void* data) {
+ const AES192_ctx* ctx = (const AES192_ctx*)data;
+ unsigned char scratch[16] = {0};
+ int i;
+ for (i = 0; i < 4000000 / 16; i++) {
+ AES192_encrypt(ctx, 1, scratch, scratch);
+ }
+}
+
+static void bench_AES192_decrypt(void* data) {
+ const AES192_ctx* ctx = (const AES192_ctx*)data;
+ unsigned char scratch[16] = {0};
+ int i;
+ for (i = 0; i < 4000000 / 16; i++) {
+ AES192_decrypt(ctx, 1, scratch, scratch);
+ }
+}
+
+static void bench_AES256_init(void* data) {
+ AES256_ctx* ctx = (AES256_ctx*)data;
+ int i;
+ for (i = 0; i < 50000; i++) {
+ AES256_init(ctx, (unsigned char*)ctx);
+ }
+}
+
+
+static void bench_AES256_encrypt_setup(void* data) {
+ AES256_ctx* ctx = (AES256_ctx*)data;
+ static const unsigned char key[16] = {0};
+ AES256_init(ctx, key);
+}
+
+static void bench_AES256_encrypt(void* data) {
+ const AES256_ctx* ctx = (const AES256_ctx*)data;
+ unsigned char scratch[16] = {0};
+ int i;
+ for (i = 0; i < 4000000 / 16; i++) {
+ AES256_encrypt(ctx, 1, scratch, scratch);
+ }
+}
+
+static void bench_AES256_decrypt(void* data) {
+ const AES256_ctx* ctx = (const AES256_ctx*)data;
+ unsigned char scratch[16] = {0};
+ int i;
+ for (i = 0; i < 4000000 / 16; i++) {
+ AES256_decrypt(ctx, 1, scratch, scratch);
+ }
+}
+
+int main(void) {
+ AES128_ctx ctx128;
+ AES192_ctx ctx192;
+ AES256_ctx ctx256;
+ run_benchmark("aes128_init", bench_AES128_init, NULL, NULL, &ctx128, 20, 50000);
+ run_benchmark("aes128_encrypt_byte", bench_AES128_encrypt, bench_AES128_encrypt_setup, NULL, &ctx128, 20, 4000000);
+ run_benchmark("aes128_decrypt_byte", bench_AES128_decrypt, bench_AES128_encrypt_setup, NULL, &ctx128, 20, 4000000);
+ run_benchmark("aes192_init", bench_AES192_init, NULL, NULL, &ctx192, 20, 50000);
+ run_benchmark("aes192_encrypt_byte", bench_AES192_encrypt, bench_AES192_encrypt_setup, NULL, &ctx192, 20, 4000000);
+ run_benchmark("aes192_decrypt_byte", bench_AES192_decrypt, bench_AES192_encrypt_setup, NULL, &ctx192, 20, 4000000);
+ run_benchmark("aes256_init", bench_AES256_init, NULL, NULL, &ctx256, 20, 50000);
+ run_benchmark("aes256_encrypt_byte", bench_AES256_encrypt, bench_AES256_encrypt_setup, NULL, &ctx256, 20, 4000000);
+ run_benchmark("aes256_decrypt_byte", bench_AES256_decrypt, bench_AES256_encrypt_setup, NULL, &ctx256, 20, 4000000);
+ return 0;
+}
diff --git a/src/crypto/ctaes/ctaes.c b/src/crypto/ctaes/ctaes.c
new file mode 100644
index 0000000000..2389fc0bb2
--- /dev/null
+++ b/src/crypto/ctaes/ctaes.c
@@ -0,0 +1,556 @@
+ /*********************************************************************
+ * Copyright (c) 2016 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+/* Constant time, unoptimized, concise, plain C, AES implementation
+ * Based On:
+ * Emilia Kasper and Peter Schwabe, Faster and Timing-Attack Resistant AES-GCM
+ * http://www.iacr.org/archive/ches2009/57470001/57470001.pdf
+ * But using 8 16-bit integers representing a single AES state rather than 8 128-bit
+ * integers representing 8 AES states.
+ */
+
+#include "ctaes.h"
+
+/* Slice variable slice_i contains the i'th bit of the 16 state variables in this order:
+ * 0 1 2 3
+ * 4 5 6 7
+ * 8 9 10 11
+ * 12 13 14 15
+ */
+
+/** Convert a byte to sliced form, storing it corresponding to given row and column in s */
+static void LoadByte(AES_state* s, unsigned char byte, int r, int c) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ s->slice[i] |= (byte & 1) << (r * 4 + c);
+ byte >>= 1;
+ }
+}
+
+/** Load 16 bytes of data into 8 sliced integers */
+static void LoadBytes(AES_state *s, const unsigned char* data16) {
+ int c;
+ for (c = 0; c < 4; c++) {
+ int r;
+ for (r = 0; r < 4; r++) {
+ LoadByte(s, *(data16++), r, c);
+ }
+ }
+}
+
+/** Convert 8 sliced integers into 16 bytes of data */
+static void SaveBytes(unsigned char* data16, const AES_state *s) {
+ int c;
+ for (c = 0; c < 4; c++) {
+ int r;
+ for (r = 0; r < 4; r++) {
+ int b;
+ uint8_t v = 0;
+ for (b = 0; b < 8; b++) {
+ v |= ((s->slice[b] >> (r * 4 + c)) & 1) << b;
+ }
+ *(data16++) = v;
+ }
+ }
+}
+
+/* S-box implementation based on the gate logic from:
+ * Joan Boyar and Rene Peralta, A depth-16 circuit for the AES S-box.
+ * https://eprint.iacr.org/2011/332.pdf
+*/
+static void SubBytes(AES_state *s, int inv) {
+ /* Load the bit slices */
+ uint16_t U0 = s->slice[7], U1 = s->slice[6], U2 = s->slice[5], U3 = s->slice[4];
+ uint16_t U4 = s->slice[3], U5 = s->slice[2], U6 = s->slice[1], U7 = s->slice[0];
+
+ uint16_t T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16;
+ uint16_t T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, D;
+ uint16_t M1, M6, M11, M13, M15, M20, M21, M22, M23, M25, M37, M38, M39, M40;
+ uint16_t M41, M42, M43, M44, M45, M46, M47, M48, M49, M50, M51, M52, M53, M54;
+ uint16_t M55, M56, M57, M58, M59, M60, M61, M62, M63;
+
+ if (inv) {
+ uint16_t R5, R13, R17, R18, R19;
+ /* Undo linear postprocessing */
+ T23 = U0 ^ U3;
+ T22 = ~(U1 ^ U3);
+ T2 = ~(U0 ^ U1);
+ T1 = U3 ^ U4;
+ T24 = ~(U4 ^ U7);
+ R5 = U6 ^ U7;
+ T8 = ~(U1 ^ T23);
+ T19 = T22 ^ R5;
+ T9 = ~(U7 ^ T1);
+ T10 = T2 ^ T24;
+ T13 = T2 ^ R5;
+ T3 = T1 ^ R5;
+ T25 = ~(U2 ^ T1);
+ R13 = U1 ^ U6;
+ T17 = ~(U2 ^ T19);
+ T20 = T24 ^ R13;
+ T4 = U4 ^ T8;
+ R17 = ~(U2 ^ U5);
+ R18 = ~(U5 ^ U6);
+ R19 = ~(U2 ^ U4);
+ D = U0 ^ R17;
+ T6 = T22 ^ R17;
+ T16 = R13 ^ R19;
+ T27 = T1 ^ R18;
+ T15 = T10 ^ T27;
+ T14 = T10 ^ R18;
+ T26 = T3 ^ T16;
+ } else {
+ /* Linear preprocessing. */
+ T1 = U0 ^ U3;
+ T2 = U0 ^ U5;
+ T3 = U0 ^ U6;
+ T4 = U3 ^ U5;
+ T5 = U4 ^ U6;
+ T6 = T1 ^ T5;
+ T7 = U1 ^ U2;
+ T8 = U7 ^ T6;
+ T9 = U7 ^ T7;
+ T10 = T6 ^ T7;
+ T11 = U1 ^ U5;
+ T12 = U2 ^ U5;
+ T13 = T3 ^ T4;
+ T14 = T6 ^ T11;
+ T15 = T5 ^ T11;
+ T16 = T5 ^ T12;
+ T17 = T9 ^ T16;
+ T18 = U3 ^ U7;
+ T19 = T7 ^ T18;
+ T20 = T1 ^ T19;
+ T21 = U6 ^ U7;
+ T22 = T7 ^ T21;
+ T23 = T2 ^ T22;
+ T24 = T2 ^ T10;
+ T25 = T20 ^ T17;
+ T26 = T3 ^ T16;
+ T27 = T1 ^ T12;
+ D = U7;
+ }
+
+ /* Non-linear transformation (identical to the code in SubBytes) */
+ M1 = T13 & T6;
+ M6 = T3 & T16;
+ M11 = T1 & T15;
+ M13 = (T4 & T27) ^ M11;
+ M15 = (T2 & T10) ^ M11;
+ M20 = T14 ^ M1 ^ (T23 & T8) ^ M13;
+ M21 = (T19 & D) ^ M1 ^ T24 ^ M15;
+ M22 = T26 ^ M6 ^ (T22 & T9) ^ M13;
+ M23 = (T20 & T17) ^ M6 ^ M15 ^ T25;
+ M25 = M22 & M20;
+ M37 = M21 ^ ((M20 ^ M21) & (M23 ^ M25));
+ M38 = M20 ^ M25 ^ (M21 | (M20 & M23));
+ M39 = M23 ^ ((M22 ^ M23) & (M21 ^ M25));
+ M40 = M22 ^ M25 ^ (M23 | (M21 & M22));
+ M41 = M38 ^ M40;
+ M42 = M37 ^ M39;
+ M43 = M37 ^ M38;
+ M44 = M39 ^ M40;
+ M45 = M42 ^ M41;
+ M46 = M44 & T6;
+ M47 = M40 & T8;
+ M48 = M39 & D;
+ M49 = M43 & T16;
+ M50 = M38 & T9;
+ M51 = M37 & T17;
+ M52 = M42 & T15;
+ M53 = M45 & T27;
+ M54 = M41 & T10;
+ M55 = M44 & T13;
+ M56 = M40 & T23;
+ M57 = M39 & T19;
+ M58 = M43 & T3;
+ M59 = M38 & T22;
+ M60 = M37 & T20;
+ M61 = M42 & T1;
+ M62 = M45 & T4;
+ M63 = M41 & T2;
+
+ if (inv){
+ /* Undo linear preprocessing */
+ uint16_t P0 = M52 ^ M61;
+ uint16_t P1 = M58 ^ M59;
+ uint16_t P2 = M54 ^ M62;
+ uint16_t P3 = M47 ^ M50;
+ uint16_t P4 = M48 ^ M56;
+ uint16_t P5 = M46 ^ M51;
+ uint16_t P6 = M49 ^ M60;
+ uint16_t P7 = P0 ^ P1;
+ uint16_t P8 = M50 ^ M53;
+ uint16_t P9 = M55 ^ M63;
+ uint16_t P10 = M57 ^ P4;
+ uint16_t P11 = P0 ^ P3;
+ uint16_t P12 = M46 ^ M48;
+ uint16_t P13 = M49 ^ M51;
+ uint16_t P14 = M49 ^ M62;
+ uint16_t P15 = M54 ^ M59;
+ uint16_t P16 = M57 ^ M61;
+ uint16_t P17 = M58 ^ P2;
+ uint16_t P18 = M63 ^ P5;
+ uint16_t P19 = P2 ^ P3;
+ uint16_t P20 = P4 ^ P6;
+ uint16_t P22 = P2 ^ P7;
+ uint16_t P23 = P7 ^ P8;
+ uint16_t P24 = P5 ^ P7;
+ uint16_t P25 = P6 ^ P10;
+ uint16_t P26 = P9 ^ P11;
+ uint16_t P27 = P10 ^ P18;
+ uint16_t P28 = P11 ^ P25;
+ uint16_t P29 = P15 ^ P20;
+ s->slice[7] = P13 ^ P22;
+ s->slice[6] = P26 ^ P29;
+ s->slice[5] = P17 ^ P28;
+ s->slice[4] = P12 ^ P22;
+ s->slice[3] = P23 ^ P27;
+ s->slice[2] = P19 ^ P24;
+ s->slice[1] = P14 ^ P23;
+ s->slice[0] = P9 ^ P16;
+ } else {
+ /* Linear postprocessing */
+ uint16_t L0 = M61 ^ M62;
+ uint16_t L1 = M50 ^ M56;
+ uint16_t L2 = M46 ^ M48;
+ uint16_t L3 = M47 ^ M55;
+ uint16_t L4 = M54 ^ M58;
+ uint16_t L5 = M49 ^ M61;
+ uint16_t L6 = M62 ^ L5;
+ uint16_t L7 = M46 ^ L3;
+ uint16_t L8 = M51 ^ M59;
+ uint16_t L9 = M52 ^ M53;
+ uint16_t L10 = M53 ^ L4;
+ uint16_t L11 = M60 ^ L2;
+ uint16_t L12 = M48 ^ M51;
+ uint16_t L13 = M50 ^ L0;
+ uint16_t L14 = M52 ^ M61;
+ uint16_t L15 = M55 ^ L1;
+ uint16_t L16 = M56 ^ L0;
+ uint16_t L17 = M57 ^ L1;
+ uint16_t L18 = M58 ^ L8;
+ uint16_t L19 = M63 ^ L4;
+ uint16_t L20 = L0 ^ L1;
+ uint16_t L21 = L1 ^ L7;
+ uint16_t L22 = L3 ^ L12;
+ uint16_t L23 = L18 ^ L2;
+ uint16_t L24 = L15 ^ L9;
+ uint16_t L25 = L6 ^ L10;
+ uint16_t L26 = L7 ^ L9;
+ uint16_t L27 = L8 ^ L10;
+ uint16_t L28 = L11 ^ L14;
+ uint16_t L29 = L11 ^ L17;
+ s->slice[7] = L6 ^ L24;
+ s->slice[6] = ~(L16 ^ L26);
+ s->slice[5] = ~(L19 ^ L28);
+ s->slice[4] = L6 ^ L21;
+ s->slice[3] = L20 ^ L22;
+ s->slice[2] = L25 ^ L29;
+ s->slice[1] = ~(L13 ^ L27);
+ s->slice[0] = ~(L6 ^ L23);
+ }
+}
+
+#define BIT_RANGE(from,to) (((1 << ((to) - (from))) - 1) << (from))
+
+#define BIT_RANGE_LEFT(x,from,to,shift) (((x) & BIT_RANGE((from), (to))) << (shift))
+#define BIT_RANGE_RIGHT(x,from,to,shift) (((x) & BIT_RANGE((from), (to))) >> (shift))
+
+static void ShiftRows(AES_state* s) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ uint16_t v = s->slice[i];
+ s->slice[i] =
+ (v & BIT_RANGE(0, 4)) |
+ BIT_RANGE_LEFT(v, 4, 5, 3) | BIT_RANGE_RIGHT(v, 5, 8, 1) |
+ BIT_RANGE_LEFT(v, 8, 10, 2) | BIT_RANGE_RIGHT(v, 10, 12, 2) |
+ BIT_RANGE_LEFT(v, 12, 15, 1) | BIT_RANGE_RIGHT(v, 15, 16, 3);
+ }
+}
+
+static void InvShiftRows(AES_state* s) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ uint16_t v = s->slice[i];
+ s->slice[i] =
+ (v & BIT_RANGE(0, 4)) |
+ BIT_RANGE_LEFT(v, 4, 7, 1) | BIT_RANGE_RIGHT(v, 7, 8, 3) |
+ BIT_RANGE_LEFT(v, 8, 10, 2) | BIT_RANGE_RIGHT(v, 10, 12, 2) |
+ BIT_RANGE_LEFT(v, 12, 13, 3) | BIT_RANGE_RIGHT(v, 13, 16, 1);
+ }
+}
+
+#define ROT(x,b) (((x) >> ((b) * 4)) | ((x) << ((4-(b)) * 4)))
+
+static void MixColumns(AES_state* s, int inv) {
+ /* The MixColumns transform treats the bytes of the columns of the state as
+ * coefficients of a 3rd degree polynomial over GF(2^8) and multiplies them
+ * by the fixed polynomial a(x) = {03}x^3 + {01}x^2 + {01}x + {02}, modulo
+ * x^4 + {01}.
+ *
+ * In the inverse transform, we multiply by the inverse of a(x),
+ * a^-1(x) = {0b}x^3 + {0d}x^2 + {09}x + {0e}. This is equal to
+ * a(x) * ({04}x^2 + {05}), so we can reuse the forward transform's code
+ * (found in OpenSSL's bsaes-x86_64.pl, attributed to Jussi Kivilinna)
+ *
+ * In the bitsliced representation, a multiplication of every column by x
+ * mod x^4 + 1 is simply a right rotation.
+ */
+
+ /* Shared for both directions is a multiplication by a(x), which can be
+ * rewritten as (x^3 + x^2 + x) + {02}*(x^3 + {01}).
+ *
+ * First compute s into the s? variables, (x^3 + {01}) * s into the s?_01
+ * variables and (x^3 + x^2 + x)*s into the s?_123 variables.
+ */
+ uint16_t s0 = s->slice[0], s1 = s->slice[1], s2 = s->slice[2], s3 = s->slice[3];
+ uint16_t s4 = s->slice[4], s5 = s->slice[5], s6 = s->slice[6], s7 = s->slice[7];
+ uint16_t s0_01 = s0 ^ ROT(s0, 1), s0_123 = ROT(s0_01, 1) ^ ROT(s0, 3);
+ uint16_t s1_01 = s1 ^ ROT(s1, 1), s1_123 = ROT(s1_01, 1) ^ ROT(s1, 3);
+ uint16_t s2_01 = s2 ^ ROT(s2, 1), s2_123 = ROT(s2_01, 1) ^ ROT(s2, 3);
+ uint16_t s3_01 = s3 ^ ROT(s3, 1), s3_123 = ROT(s3_01, 1) ^ ROT(s3, 3);
+ uint16_t s4_01 = s4 ^ ROT(s4, 1), s4_123 = ROT(s4_01, 1) ^ ROT(s4, 3);
+ uint16_t s5_01 = s5 ^ ROT(s5, 1), s5_123 = ROT(s5_01, 1) ^ ROT(s5, 3);
+ uint16_t s6_01 = s6 ^ ROT(s6, 1), s6_123 = ROT(s6_01, 1) ^ ROT(s6, 3);
+ uint16_t s7_01 = s7 ^ ROT(s7, 1), s7_123 = ROT(s7_01, 1) ^ ROT(s7, 3);
+ /* Now compute s = s?_123 + {02} * s?_01. */
+ s->slice[0] = s7_01 ^ s0_123;
+ s->slice[1] = s7_01 ^ s0_01 ^ s1_123;
+ s->slice[2] = s1_01 ^ s2_123;
+ s->slice[3] = s7_01 ^ s2_01 ^ s3_123;
+ s->slice[4] = s7_01 ^ s3_01 ^ s4_123;
+ s->slice[5] = s4_01 ^ s5_123;
+ s->slice[6] = s5_01 ^ s6_123;
+ s->slice[7] = s6_01 ^ s7_123;
+ if (inv) {
+ /* In the reverse direction, we further need to multiply by
+ * {04}x^2 + {05}, which can be written as {04} * (x^2 + {01}) + {01}.
+ *
+ * First compute (x^2 + {01}) * s into the t?_02 variables: */
+ uint16_t t0_02 = s->slice[0] ^ ROT(s->slice[0], 2);
+ uint16_t t1_02 = s->slice[1] ^ ROT(s->slice[1], 2);
+ uint16_t t2_02 = s->slice[2] ^ ROT(s->slice[2], 2);
+ uint16_t t3_02 = s->slice[3] ^ ROT(s->slice[3], 2);
+ uint16_t t4_02 = s->slice[4] ^ ROT(s->slice[4], 2);
+ uint16_t t5_02 = s->slice[5] ^ ROT(s->slice[5], 2);
+ uint16_t t6_02 = s->slice[6] ^ ROT(s->slice[6], 2);
+ uint16_t t7_02 = s->slice[7] ^ ROT(s->slice[7], 2);
+ /* And then update s += {04} * t?_02 */
+ s->slice[0] ^= t6_02;
+ s->slice[1] ^= t6_02 ^ t7_02;
+ s->slice[2] ^= t0_02 ^ t7_02;
+ s->slice[3] ^= t1_02 ^ t6_02;
+ s->slice[4] ^= t2_02 ^ t6_02 ^ t7_02;
+ s->slice[5] ^= t3_02 ^ t7_02;
+ s->slice[6] ^= t4_02;
+ s->slice[7] ^= t5_02;
+ }
+}
+
+static void AddRoundKey(AES_state* s, const AES_state* round) {
+ int b;
+ for (b = 0; b < 8; b++) {
+ s->slice[b] ^= round->slice[b];
+ }
+}
+
+/** column_0(s) = column_c(a) */
+static void GetOneColumn(AES_state* s, const AES_state* a, int c) {
+ int b;
+ for (b = 0; b < 8; b++) {
+ s->slice[b] = (a->slice[b] >> c) & 0x1111;
+ }
+}
+
+/** column_c1(r) |= (column_0(s) ^= column_c2(a)) */
+static void KeySetupColumnMix(AES_state* s, AES_state* r, const AES_state* a, int c1, int c2) {
+ int b;
+ for (b = 0; b < 8; b++) {
+ r->slice[b] |= ((s->slice[b] ^= ((a->slice[b] >> c2) & 0x1111)) & 0x1111) << c1;
+ }
+}
+
+/** Rotate the rows in s one position upwards, and xor in r */
+static void KeySetupTransform(AES_state* s, const AES_state* r) {
+ int b;
+ for (b = 0; b < 8; b++) {
+ s->slice[b] = ((s->slice[b] >> 4) | (s->slice[b] << 12)) ^ r->slice[b];
+ }
+}
+
+/* Multiply the cells in s by x, as polynomials over GF(2) mod x^8 + x^4 + x^3 + x + 1 */
+static void MultX(AES_state* s) {
+ uint16_t top = s->slice[7];
+ s->slice[7] = s->slice[6];
+ s->slice[6] = s->slice[5];
+ s->slice[5] = s->slice[4];
+ s->slice[4] = s->slice[3] ^ top;
+ s->slice[3] = s->slice[2] ^ top;
+ s->slice[2] = s->slice[1];
+ s->slice[1] = s->slice[0] ^ top;
+ s->slice[0] = top;
+}
+
+/** Expand the cipher key into the key schedule.
+ *
+ * state must be a pointer to an array of size nrounds + 1.
+ * key must be a pointer to 4 * nkeywords bytes.
+ *
+ * AES128 uses nkeywords = 4, nrounds = 10
+ * AES192 uses nkeywords = 6, nrounds = 12
+ * AES256 uses nkeywords = 8, nrounds = 14
+ */
+static void AES_setup(AES_state* rounds, const uint8_t* key, int nkeywords, int nrounds)
+{
+ int i;
+
+ /* The one-byte round constant */
+ AES_state rcon = {{1,0,0,0,0,0,0,0}};
+ /* The number of the word being generated, modulo nkeywords */
+ int pos = 0;
+ /* The column representing the word currently being processed */
+ AES_state column;
+
+ for (i = 0; i < nrounds + 1; i++) {
+ int b;
+ for (b = 0; b < 8; b++) {
+ rounds[i].slice[b] = 0;
+ }
+ }
+
+ /* The first nkeywords round columns are just taken from the key directly. */
+ for (i = 0; i < nkeywords; i++) {
+ int r;
+ for (r = 0; r < 4; r++) {
+ LoadByte(&rounds[i >> 2], *(key++), r, i & 3);
+ }
+ }
+
+ GetOneColumn(&column, &rounds[(nkeywords - 1) >> 2], (nkeywords - 1) & 3);
+
+ for (i = nkeywords; i < 4 * (nrounds + 1); i++) {
+ /* Transform column */
+ if (pos == 0) {
+ SubBytes(&column, 0);
+ KeySetupTransform(&column, &rcon);
+ MultX(&rcon);
+ } else if (nkeywords > 6 && pos == 4) {
+ SubBytes(&column, 0);
+ }
+ if (++pos == nkeywords) pos = 0;
+ KeySetupColumnMix(&column, &rounds[i >> 2], &rounds[(i - nkeywords) >> 2], i & 3, (i - nkeywords) & 3);
+ }
+}
+
+static void AES_encrypt(const AES_state* rounds, int nrounds, unsigned char* cipher16, const unsigned char* plain16) {
+ AES_state s = {{0}};
+ int round;
+
+ LoadBytes(&s, plain16);
+ AddRoundKey(&s, rounds++);
+
+ for (round = 1; round < nrounds; round++) {
+ SubBytes(&s, 0);
+ ShiftRows(&s);
+ MixColumns(&s, 0);
+ AddRoundKey(&s, rounds++);
+ }
+
+ SubBytes(&s, 0);
+ ShiftRows(&s);
+ AddRoundKey(&s, rounds);
+
+ SaveBytes(cipher16, &s);
+}
+
+static void AES_decrypt(const AES_state* rounds, int nrounds, unsigned char* plain16, const unsigned char* cipher16) {
+ /* Most AES decryption implementations use the alternate scheme
+ * (the Equivalent Inverse Cipher), which looks more like encryption, but
+ * needs different round constants. We can't reuse any code here anyway, so
+ * don't bother. */
+ AES_state s = {{0}};
+ int round;
+
+ rounds += nrounds;
+
+ LoadBytes(&s, cipher16);
+ AddRoundKey(&s, rounds--);
+
+ for (round = 1; round < nrounds; round++) {
+ InvShiftRows(&s);
+ SubBytes(&s, 1);
+ AddRoundKey(&s, rounds--);
+ MixColumns(&s, 1);
+ }
+
+ InvShiftRows(&s);
+ SubBytes(&s, 1);
+ AddRoundKey(&s, rounds);
+
+ SaveBytes(plain16, &s);
+}
+
+void AES128_init(AES128_ctx* ctx, const unsigned char* key16) {
+ AES_setup(ctx->rk, key16, 4, 10);
+}
+
+void AES128_encrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16) {
+ while (blocks--) {
+ AES_encrypt(ctx->rk, 10, cipher16, plain16);
+ cipher16 += 16;
+ plain16 += 16;
+ }
+}
+
+void AES128_decrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16) {
+ while (blocks--) {
+ AES_decrypt(ctx->rk, 10, plain16, cipher16);
+ cipher16 += 16;
+ plain16 += 16;
+ }
+}
+
+void AES192_init(AES192_ctx* ctx, const unsigned char* key24) {
+ AES_setup(ctx->rk, key24, 6, 12);
+}
+
+void AES192_encrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16) {
+ while (blocks--) {
+ AES_encrypt(ctx->rk, 12, cipher16, plain16);
+ cipher16 += 16;
+ plain16 += 16;
+ }
+
+}
+
+void AES192_decrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16) {
+ while (blocks--) {
+ AES_decrypt(ctx->rk, 12, plain16, cipher16);
+ cipher16 += 16;
+ plain16 += 16;
+ }
+}
+
+void AES256_init(AES256_ctx* ctx, const unsigned char* key32) {
+ AES_setup(ctx->rk, key32, 8, 14);
+}
+
+void AES256_encrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16) {
+ while (blocks--) {
+ AES_encrypt(ctx->rk, 14, cipher16, plain16);
+ cipher16 += 16;
+ plain16 += 16;
+ }
+}
+
+void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16) {
+ while (blocks--) {
+ AES_decrypt(ctx->rk, 14, plain16, cipher16);
+ cipher16 += 16;
+ plain16 += 16;
+ }
+}
diff --git a/src/crypto/ctaes/ctaes.h b/src/crypto/ctaes/ctaes.h
new file mode 100644
index 0000000000..2f0af04216
--- /dev/null
+++ b/src/crypto/ctaes/ctaes.h
@@ -0,0 +1,41 @@
+ /*********************************************************************
+ * Copyright (c) 2016 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _CTAES_H_
+#define _CTAES_H_ 1
+
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct {
+ uint16_t slice[8];
+} AES_state;
+
+typedef struct {
+ AES_state rk[11];
+} AES128_ctx;
+
+typedef struct {
+ AES_state rk[13];
+} AES192_ctx;
+
+typedef struct {
+ AES_state rk[15];
+} AES256_ctx;
+
+void AES128_init(AES128_ctx* ctx, const unsigned char* key16);
+void AES128_encrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16);
+void AES128_decrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16);
+
+void AES192_init(AES192_ctx* ctx, const unsigned char* key24);
+void AES192_encrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16);
+void AES192_decrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16);
+
+void AES256_init(AES256_ctx* ctx, const unsigned char* key32);
+void AES256_encrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16);
+void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16);
+
+#endif
diff --git a/src/crypto/ctaes/test.c b/src/crypto/ctaes/test.c
new file mode 100644
index 0000000000..fce1696acd
--- /dev/null
+++ b/src/crypto/ctaes/test.c
@@ -0,0 +1,110 @@
+ /*********************************************************************
+ * Copyright (c) 2016 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#include "ctaes.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+typedef struct {
+ int keysize;
+ const char* key;
+ const char* plain;
+ const char* cipher;
+} ctaes_test;
+
+static const ctaes_test ctaes_tests[] = {
+ /* AES test vectors from FIPS 197. */
+ {128, "000102030405060708090a0b0c0d0e0f", "00112233445566778899aabbccddeeff", "69c4e0d86a7b0430d8cdb78070b4c55a"},
+ {192, "000102030405060708090a0b0c0d0e0f1011121314151617", "00112233445566778899aabbccddeeff", "dda97ca4864cdfe06eaf70a0ec0d7191"},
+ {256, "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "00112233445566778899aabbccddeeff", "8ea2b7ca516745bfeafc49904b496089"},
+
+ /* AES-ECB test vectors from NIST sp800-38a. */
+ {128, "2b7e151628aed2a6abf7158809cf4f3c", "6bc1bee22e409f96e93d7e117393172a", "3ad77bb40d7a3660a89ecaf32466ef97"},
+ {128, "2b7e151628aed2a6abf7158809cf4f3c", "ae2d8a571e03ac9c9eb76fac45af8e51", "f5d3d58503b9699de785895a96fdbaaf"},
+ {128, "2b7e151628aed2a6abf7158809cf4f3c", "30c81c46a35ce411e5fbc1191a0a52ef", "43b1cd7f598ece23881b00e3ed030688"},
+ {128, "2b7e151628aed2a6abf7158809cf4f3c", "f69f2445df4f9b17ad2b417be66c3710", "7b0c785e27e8ad3f8223207104725dd4"},
+ {192, "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "6bc1bee22e409f96e93d7e117393172a", "bd334f1d6e45f25ff712a214571fa5cc"},
+ {192, "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "ae2d8a571e03ac9c9eb76fac45af8e51", "974104846d0ad3ad7734ecb3ecee4eef"},
+ {192, "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "30c81c46a35ce411e5fbc1191a0a52ef", "ef7afd2270e2e60adce0ba2face6444e"},
+ {192, "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "f69f2445df4f9b17ad2b417be66c3710", "9a4b41ba738d6c72fb16691603c18e0e"},
+ {256, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "6bc1bee22e409f96e93d7e117393172a", "f3eed1bdb5d2a03c064b5a7e3db181f8"},
+ {256, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "ae2d8a571e03ac9c9eb76fac45af8e51", "591ccb10d410ed26dc5ba74a31362870"},
+ {256, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "30c81c46a35ce411e5fbc1191a0a52ef", "b6ed21b99ca6f4f9f153e7b1beafed1d"},
+ {256, "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "f69f2445df4f9b17ad2b417be66c3710", "23304b7a39f9f3ff067d8d8f9e24ecc7"}
+};
+
+static void from_hex(unsigned char* data, int len, const char* hex) {
+ int p;
+ for (p = 0; p < len; p++) {
+ int v = 0;
+ int n;
+ for (n = 0; n < 2; n++) {
+ assert((*hex >= '0' && *hex <= '9') || (*hex >= 'a' && *hex <= 'f'));
+ if (*hex >= '0' && *hex <= '9') {
+ v |= (*hex - '0') << (4 * (1 - n));
+ } else {
+ v |= (*hex - 'a' + 10) << (4 * (1 - n));
+ }
+ hex++;
+ }
+ *(data++) = v;
+ }
+ assert(*hex == 0);
+}
+
+int main(void) {
+ int i;
+ int fail = 0;
+ for (i = 0; i < sizeof(ctaes_tests) / sizeof(ctaes_tests[0]); i++) {
+ unsigned char key[32], plain[16], cipher[16], ciphered[16], deciphered[16];
+ const ctaes_test* test = &ctaes_tests[i];
+ assert(test->keysize == 128 || test->keysize == 192 || test->keysize == 256);
+ from_hex(plain, 16, test->plain);
+ from_hex(cipher, 16, test->cipher);
+ switch (test->keysize) {
+ case 128: {
+ AES128_ctx ctx;
+ from_hex(key, 16, test->key);
+ AES128_init(&ctx, key);
+ AES128_encrypt(&ctx, 1, ciphered, plain);
+ AES128_decrypt(&ctx, 1, deciphered, cipher);
+ break;
+ }
+ case 192: {
+ AES192_ctx ctx;
+ from_hex(key, 24, test->key);
+ AES192_init(&ctx, key);
+ AES192_encrypt(&ctx, 1, ciphered, plain);
+ AES192_decrypt(&ctx, 1, deciphered, cipher);
+ break;
+ }
+ case 256: {
+ AES256_ctx ctx;
+ from_hex(key, 32, test->key);
+ AES256_init(&ctx, key);
+ AES256_encrypt(&ctx, 1, ciphered, plain);
+ AES256_decrypt(&ctx, 1, deciphered, cipher);
+ break;
+ }
+ }
+ if (memcmp(cipher, ciphered, 16)) {
+ fprintf(stderr, "E(key=\"%s\", plain=\"%s\") != \"%s\"\n", test->key, test->plain, test->cipher);
+ fail++;
+ }
+ if (memcmp(plain, deciphered, 16)) {
+ fprintf(stderr, "D(key=\"%s\", cipher=\"%s\") != \"%s\"\n", test->key, test->cipher, test->plain);
+ fail++;
+ }
+ }
+ if (fail == 0) {
+ fprintf(stderr, "All tests succesful\n");
+ } else {
+ fprintf(stderr, "%i tests failed\n", fail);
+ }
+ return (fail != 0);
+}
diff --git a/src/init.cpp b/src/init.cpp
index 8688381ecf..9a22501859 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -123,7 +123,7 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
// shutdown thing.
//
-volatile sig_atomic_t fRequestShutdown = false;
+std::atomic<bool> fRequestShutdown(false);
void StartShutdown()
{
@@ -134,6 +134,11 @@ bool ShutdownRequested()
return fRequestShutdown;
}
+/**
+ * This is a minimally invasive approach to shutdown on LevelDB read errors from the
+ * chainstate, while keeping user interface out of the common library, which is shared
+ * between bitcoind, and bitcoin-qt and non-server tools.
+*/
class CCoinsViewErrorCatcher : public CCoinsViewBacked
{
public:
@@ -1109,6 +1114,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fListen = GetBoolArg("-listen", DEFAULT_LISTEN);
fDiscover = GetBoolArg("-discover", true);
fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
+ fRelayTxes = !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
bool fBound = false;
if (fListen) {
@@ -1269,8 +1275,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
uiInterface.InitMessage(_("Verifying blocks..."));
if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
- LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n",
- MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", DEFAULT_CHECKBLOCKS));
+ LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks",
+ MIN_BLOCKS_TO_KEEP);
}
{
@@ -1373,10 +1379,18 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
vImportFiles.push_back(strFile);
}
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
- if (chainActive.Tip() == NULL) {
- LogPrintf("Waiting for genesis block to be imported...\n");
- while (!fRequestShutdown && chainActive.Tip() == NULL)
+
+ // Wait for genesis block to be processed
+ bool fHaveGenesis = false;
+ while (!fHaveGenesis && !fRequestShutdown) {
+ {
+ LOCK(cs_main);
+ fHaveGenesis = (chainActive.Tip() != NULL);
+ }
+
+ if (!fHaveGenesis) {
MilliSleep(10);
+ }
}
// ********************************************************* Step 11: start node
@@ -1387,8 +1401,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!strErrors.str().empty())
return InitError(strErrors.str());
- RandAddSeedPerfmon();
-
//// debug print
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
LogPrintf("nBestHeight = %d\n", chainActive.Height());
diff --git a/src/key.cpp b/src/key.cpp
index 6a3d9aa140..79023566c3 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -124,9 +124,8 @@ bool CKey::Check(const unsigned char *vch) {
}
void CKey::MakeNewKey(bool fCompressedIn) {
- RandAddSeedPerfmon();
do {
- GetRandBytes(vch, sizeof(vch));
+ GetStrongRandBytes(vch, sizeof(vch));
} while (!Check(vch));
fValid = true;
fCompressed = fCompressedIn;
diff --git a/src/main.cpp b/src/main.cpp
index f66de42aa8..162c8b986c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -40,6 +40,7 @@
#include <sstream>
#include <boost/algorithm/string/replace.hpp>
+#include <boost/algorithm/string/join.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/math/distributions/poisson.hpp>
@@ -79,6 +80,10 @@ uint64_t nPruneTarget = 0;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
+std::map<uint256, CTransaction> mapRelay;
+std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
+CCriticalSection cs_mapRelay;
+
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
@@ -2571,16 +2576,10 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
- LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utx)\n", __func__,
- chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion,
- log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
- Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
-
cvBlockChange.notify_all();
- // Check the version of the last 100 blocks to see if we need to upgrade:
static bool fWarned = false;
+ std::vector<std::string> warningMessages;
if (!IsInitialBlockDownload())
{
int nUpgraded = 0;
@@ -2596,10 +2595,11 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
fWarned = true;
}
} else {
- LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit);
+ warningMessages.push_back(strprintf("unknown new rules are about to activate (versionbit %i)", bit));
}
}
}
+ // Check the version of the last 100 blocks to see if we need to upgrade:
for (int i = 0; i < 100 && pindex != NULL; i++)
{
int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus());
@@ -2608,7 +2608,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
pindex = pindex->pprev;
}
if (nUpgraded > 0)
- LogPrintf("%s: %d of last 100 blocks have unexpected version\n", __func__, nUpgraded);
+ warningMessages.push_back(strprintf("%d of last 100 blocks have unexpected version", nUpgraded));
if (nUpgraded > 100/2)
{
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
@@ -2619,6 +2619,15 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
}
}
}
+ LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utx)", __func__,
+ chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->nVersion,
+ log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
+ Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
+ if (!warningMessages.empty())
+ LogPrintf(" warning='%s'", boost::algorithm::join(warningMessages, ", "));
+ LogPrintf("\n");
+
}
/** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */
@@ -3870,6 +3879,11 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))));
if (pindex->nHeight < chainActive.Height()-nCheckDepth)
break;
+ if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
+ // If pruning, only go back as far as we have data.
+ LogPrintf("VerifyDB(): block verification stopping at height %d (pruning, no data)\n", pindex->nHeight);
+ break;
+ }
CBlock block;
// check level 0: read from disk
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
@@ -4490,24 +4504,28 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
else if (inv.IsKnownType())
{
+ CTransaction tx;
// Send stream from relay memory
- bool pushed = false;
+ bool push = false;
{
LOCK(cs_mapRelay);
map<uint256, CTransaction>::iterator mi = mapRelay.find(inv.hash);
if (mi != mapRelay.end()) {
- pfrom->PushMessage(inv.GetCommand(), (*mi).second);
- pushed = true;
+ tx = (*mi).second;
+ push = true;
}
}
- if (!pushed && inv.type == MSG_TX) {
- CTransaction tx;
- if (mempool.lookup(inv.hash, tx)) {
- pfrom->PushMessage(NetMsgType::TX, tx);
- pushed = true;
+ if (!push && inv.type == MSG_TX) {
+ int64_t txtime;
+ // To protect privacy, do not answer getdata using the mempool when
+ // that TX couldn't have been INVed in reply to a MEMPOOL request.
+ if (mempool.lookup(inv.hash, tx, txtime) && txtime <= pfrom->timeLastMempoolReq) {
+ push = true;
}
}
- if (!pushed) {
+ if (push) {
+ pfrom->PushMessage(inv.GetCommand(), tx);
+ } else {
vNotFound.push_back(inv);
}
}
@@ -4536,7 +4554,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams)
{
- RandAddSeedPerfmon();
LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
@@ -4789,7 +4806,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return error("message inv size() = %u", vInv.size());
}
- bool fBlocksOnly = GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
+ bool fBlocksOnly = !fRelayTxes;
// Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true
if (pfrom->fWhitelisted && GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))
@@ -4804,7 +4821,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
const CInv &inv = vInv[nInv];
boost::this_thread::interruption_point();
- pfrom->AddInventoryKnown(inv);
bool fAlreadyHave = AlreadyHave(inv);
LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id);
@@ -4834,6 +4850,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
else
{
+ pfrom->AddInventoryKnown(inv);
if (fBlocksOnly)
LogPrint("net", "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->id);
else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload())
@@ -4972,7 +4989,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
- if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
+ if (!fRelayTxes && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
{
LogPrint("net", "transaction sent in violation of protocol peer=%d\n", pfrom->id);
return true;
@@ -5221,10 +5238,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CBlock block;
vRecv >> block;
- CInv inv(MSG_BLOCK, block.GetHash());
- LogPrint("net", "received block %s peer=%d\n", inv.hash.ToString(), pfrom->id);
-
- pfrom->AddInventoryKnown(inv);
+ LogPrint("net", "received block %s peer=%d\n", block.GetHash().ToString(), pfrom->id);
CValidationState state;
// Process all blocks from whitelisted peers, even if not requested,
@@ -5237,7 +5251,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
- state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
+ state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash());
if (nDoS > 0) {
LOCK(cs_main);
Misbehaving(pfrom->GetId(), nDoS);
@@ -5809,9 +5823,7 @@ bool SendMessages(CNode* pto)
hashToAnnounce.ToString(), chainActive.Tip()->GetBlockHash().ToString());
}
- // If the peer announced this block to us, don't inv it back.
- // (Since block announcements may not be via inv's, we can't solely rely on
- // setInventoryKnown to track this.)
+ // If the peer's chain has this block, don't inv it back.
if (!PeerHasHeader(&state, pindex)) {
pto->PushInventory(CInv(MSG_BLOCK, hashToAnnounce));
LogPrint("net", "%s: sending inv peer=%d hash=%s\n", __func__,
@@ -5901,6 +5913,7 @@ bool SendMessages(CNode* pto)
vInv.clear();
}
}
+ pto->timeLastMempoolReq = GetTime();
}
// Determine transactions to relay
@@ -5944,14 +5957,26 @@ bool SendMessages(CNode* pto)
if (filterrate && feeRate.GetFeePerK() < filterrate) {
continue;
}
- if (pto->pfilter) {
- CTransaction tx;
- if (!mempool.lookup(hash, tx)) continue;
- if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
- }
+ CTransaction tx;
+ if (!mempool.lookup(hash, tx)) continue;
+ if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(tx)) continue;
// Send
vInv.push_back(CInv(MSG_TX, hash));
nRelayedTransactions++;
+ {
+ LOCK(cs_mapRelay);
+ // Expire old relay messages
+ while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
+ {
+ mapRelay.erase(vRelayExpiration.front().second);
+ vRelayExpiration.pop_front();
+ }
+
+ auto ret = mapRelay.insert(std::make_pair(hash, tx));
+ if (ret.second) {
+ vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, hash));
+ }
+ }
if (vInv.size() == MAX_INV_SZ) {
pto->PushMessage(NetMsgType::INV, vInv);
vInv.clear();
diff --git a/src/net.cpp b/src/net.cpp
index bbd23d292a..c09e3aedb6 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -76,6 +76,7 @@ const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
bool fDiscover = true;
bool fListen = true;
uint64_t nLocalServices = NODE_NETWORK;
+bool fRelayTxes = true;
CCriticalSection cs_mapLocalHost;
std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfLimited[NET_MAX] = {};
@@ -89,9 +90,6 @@ std::string strSubVersion;
std::vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
-std::map<uint256, CTransaction> mapRelay;
-std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
-CCriticalSection cs_mapRelay;
limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
static std::deque<std::string> vOneShots;
@@ -470,7 +468,7 @@ void CNode::PushVersion()
else
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
- nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY));
+ nLocalHostNonce, strSubVersion, nBestHeight, ::fRelayTxes);
}
@@ -2080,18 +2078,6 @@ instance_of_cnetcleanup;
void RelayTransaction(const CTransaction& tx)
{
CInv inv(MSG_TX, tx.GetHash());
- {
- LOCK(cs_mapRelay);
- // Expire old relay messages
- while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
- {
- mapRelay.erase(vRelayExpiration.front().second);
- vRelayExpiration.pop_front();
- }
-
- mapRelay.insert(std::make_pair(inv.hash, tx));
- vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv.hash));
- }
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{
@@ -2396,6 +2382,7 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
fRelayTxes = false;
fSentAddr = false;
pfilter = new CBloomFilter();
+ timeLastMempoolReq = 0;
nPingNonceSent = 0;
nPingUsecStart = 0;
nPingUsecTime = 0;
diff --git a/src/net.h b/src/net.h
index 998ee49260..403653e8c8 100644
--- a/src/net.h
+++ b/src/net.h
@@ -17,6 +17,7 @@
#include "sync.h"
#include "uint256.h"
+#include <atomic>
#include <deque>
#include <stdint.h>
@@ -152,6 +153,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
extern bool fDiscover;
extern bool fListen;
extern uint64_t nLocalServices;
+extern bool fRelayTxes;
extern uint64_t nLocalHostNonce;
extern CAddrMan addrman;
@@ -160,9 +162,6 @@ extern int nMaxConnections;
extern std::vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
-extern std::map<uint256, CTransaction> mapRelay;
-extern std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
-extern CCriticalSection cs_mapRelay;
extern limitedmap<uint256, int64_t> mapAlreadyAskedFor;
extern std::vector<std::string> vAddedNodes;
@@ -413,6 +412,8 @@ public:
// Used for BIP35 mempool sending, also protected by cs_inventory
bool fSendMempool;
+ // Last time a "MEMPOOL" request was serviced.
+ std::atomic<int64_t> timeLastMempoolReq;
// Ping time measurement:
// The pong reply we're expecting, or 0 if no pong expected.
uint64_t nPingNonceSent;
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index 415bffb991..e8aa79679c 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -77,10 +77,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
AskPassphraseDialog::~AskPassphraseDialog()
{
- // Attempt to overwrite text so that they do not linger around in memory
- ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
- ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
- ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
+ secureClearPassFields();
delete ui;
}
@@ -103,6 +100,8 @@ void AskPassphraseDialog::accept()
newpass1.assign(ui->passEdit2->text().toStdString().c_str());
newpass2.assign(ui->passEdit3->text().toStdString().c_str());
+ secureClearPassFields();
+
switch(mode)
{
case Encrypt: {
@@ -260,3 +259,17 @@ bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
}
return QDialog::eventFilter(object, event);
}
+
+static void SecureClearQLineEdit(QLineEdit* edit)
+{
+ // Attempt to overwrite text so that they do not linger around in memory
+ edit->setText(QString(" ").repeated(edit->text().size()));
+ edit->clear();
+}
+
+void AskPassphraseDialog::secureClearPassFields()
+{
+ SecureClearQLineEdit(ui->passEdit1);
+ SecureClearQLineEdit(ui->passEdit2);
+ SecureClearQLineEdit(ui->passEdit3);
+}
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index 727b5a1ada..34bf7ccb31 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -42,6 +42,7 @@ private:
private Q_SLOTS:
void textChanged();
+ void secureClearPassFields();
protected:
bool event(QEvent *event);
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 4998848e9f..50c19c3848 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -320,12 +320,14 @@ void BitcoinGUI::createActions()
aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About %1").arg(tr(PACKAGE_NAME)), this);
aboutAction->setStatusTip(tr("Show information about %1").arg(tr(PACKAGE_NAME)));
aboutAction->setMenuRole(QAction::AboutRole);
+ aboutAction->setEnabled(false);
aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(tr(PACKAGE_NAME)));
optionsAction->setMenuRole(QAction::PreferencesRole);
+ optionsAction->setEnabled(false);
toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
@@ -343,6 +345,8 @@ void BitcoinGUI::createActions()
openRPCConsoleAction = new QAction(platformStyle->TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
+ // initially disable the debug window menu item
+ openRPCConsoleAction->setEnabled(false);
usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
@@ -911,6 +915,14 @@ void BitcoinGUI::closeEvent(QCloseEvent *event)
QMainWindow::closeEvent(event);
}
+void BitcoinGUI::showEvent(QShowEvent *event)
+{
+ // enable the debug window when the main window shows up
+ openRPCConsoleAction->setEnabled(true);
+ aboutAction->setEnabled(true);
+ optionsAction->setEnabled(true);
+}
+
#ifdef ENABLE_WALLET
void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label)
{
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 33639ed5a2..12e7702ed8 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -72,6 +72,7 @@ public:
protected:
void changeEvent(QEvent *e);
void closeEvent(QCloseEvent *event);
+ void showEvent(QShowEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
bool eventFilter(QObject *object, QEvent *event);
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index d577345e49..6a0404cbf7 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -219,7 +219,7 @@ void OverviewPage::setWalletModel(WalletModel *model)
filter->setDynamicSortFilter(true);
filter->setSortRole(Qt::EditRole);
filter->setShowInactive(false);
- filter->sort(TransactionTableModel::Status, Qt::DescendingOrder);
+ filter->sort(TransactionTableModel::Date, Qt::DescendingOrder);
ui->listTransactions->setModel(filter);
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index eb6111e682..199a7b2d77 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -203,7 +203,7 @@ void TransactionView::setModel(WalletModel *model)
transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
transactionView->setSortingEnabled(true);
- transactionView->sortByColumn(TransactionTableModel::Status, Qt::DescendingOrder);
+ transactionView->sortByColumn(TransactionTableModel::Date, Qt::DescendingOrder);
transactionView->verticalHeader()->hide();
transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH);
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index a0d0e70442..3867310cd6 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -447,7 +447,7 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri
bool WalletModel::backupWallet(const QString &filename)
{
- return BackupWallet(*wallet, filename.toLocal8Bit().data());
+ return wallet->BackupWallet(filename.toLocal8Bit().data());
}
// Handlers for core signals
diff --git a/src/random.cpp b/src/random.cpp
index 6155c0d8cf..d9a8cc145e 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -5,14 +5,17 @@
#include "random.h"
+#include "crypto/sha512.h"
#include "support/cleanse.h"
#ifdef WIN32
#include "compat.h" // for Windows API
+#include <wincrypt.h>
#endif
#include "serialize.h" // for begin_ptr(vec)
#include "util.h" // for LogPrint()
#include "utilstrencodings.h" // for GetTime()
+#include <stdlib.h>
#include <limits>
#ifndef WIN32
@@ -22,6 +25,12 @@
#include <openssl/err.h>
#include <openssl/rand.h>
+static void RandFailure()
+{
+ LogPrintf("Failed to read randomness, aborting\n");
+ abort();
+}
+
static inline int64_t GetPerformanceCounter()
{
int64_t nCounter = 0;
@@ -43,7 +52,7 @@ void RandAddSeed()
memory_cleanse((void*)&nCounter, sizeof(nCounter));
}
-void RandAddSeedPerfmon()
+static void RandAddSeedPerfmon()
{
RandAddSeed();
@@ -83,14 +92,65 @@ void RandAddSeedPerfmon()
#endif
}
+/** Get 32 bytes of system entropy. */
+static void GetOSRand(unsigned char *ent32)
+{
+#ifdef WIN32
+ HCRYPTPROV hProvider;
+ int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+ if (!ret) {
+ RandFailure();
+ }
+ ret = CryptGenRandom(hProvider, 32, ent32);
+ if (!ret) {
+ RandFailure();
+ }
+ CryptReleaseContext(hProvider, 0);
+#else
+ int f = open("/dev/urandom", O_RDONLY);
+ if (f == -1) {
+ RandFailure();
+ }
+ int have = 0;
+ do {
+ ssize_t n = read(f, ent32 + have, 32 - have);
+ if (n <= 0 || n + have > 32) {
+ RandFailure();
+ }
+ have += n;
+ } while (have < 32);
+ close(f);
+#endif
+}
+
void GetRandBytes(unsigned char* buf, int num)
{
if (RAND_bytes(buf, num) != 1) {
- LogPrintf("%s: OpenSSL RAND_bytes() failed with error: %s\n", __func__, ERR_error_string(ERR_get_error(), NULL));
- assert(false);
+ RandFailure();
}
}
+void GetStrongRandBytes(unsigned char* out, int num)
+{
+ assert(num <= 32);
+ CSHA512 hasher;
+ unsigned char buf[64];
+
+ // First source: OpenSSL's RNG
+ RandAddSeedPerfmon();
+ GetRandBytes(buf, 32);
+ hasher.Write(buf, 32);
+
+ // Second source: OS RNG
+ GetOSRand(buf);
+ hasher.Write(buf, 32);
+
+ // Produce output
+ hasher.Finalize(buf);
+ memcpy(out, buf, num);
+ memory_cleanse(buf, 64);
+}
+
uint64_t GetRand(uint64_t nMax)
{
if (nMax == 0)
diff --git a/src/random.h b/src/random.h
index 1a2d3e8ee2..31b80bd565 100644
--- a/src/random.h
+++ b/src/random.h
@@ -10,11 +10,8 @@
#include <stdint.h>
-/**
- * Seed OpenSSL PRNG with additional entropy data
- */
+/* Seed OpenSSL PRNG with additional entropy data */
void RandAddSeed();
-void RandAddSeedPerfmon();
/**
* Functions to gather random data via the OpenSSL PRNG
@@ -25,6 +22,12 @@ int GetRandInt(int nMax);
uint256 GetRandHash();
/**
+ * Function to gather random data from multiple sources, failing whenever any
+ * of those source fail to provide a result.
+ */
+void GetStrongRandBytes(unsigned char* buf, int num);
+
+/**
* Seed insecure_rand using the random pool.
* @param Deterministic Use a deterministic seed
*/
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index e09af89656..36178bfb4c 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -460,6 +460,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
" \"subversion\": \"/Satoshi:x.x.x/\", (string) the server subversion string\n"
" \"protocolversion\": xxxxx, (numeric) the protocol version\n"
" \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
+ " \"localrelay\": true|false, (bool) true if transaction relay is requested from peers\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
" \"networks\": [ (array) information per network\n"
@@ -494,6 +495,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("subversion", strSubVersion));
obj.push_back(Pair("protocolversion",PROTOCOL_VERSION));
obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
+ obj.push_back(Pair("localrelay", fRelayTxes));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("networks", GetNetworksInfo()));
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index bec7ebe55f..483fe746ca 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -211,7 +211,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
"\nNOTE: By default this function only works sometimes. This is when there is an\n"
"unspent output in the utxo for this transaction. To make it always work,\n"
"you need to maintain a transaction index, using the -txindex command line option or\n"
- "specify the block in which the transaction is included in manually (by blockhash).\n"
+ "specify the block in which the transaction is included manually (by blockhash).\n"
"\nReturn the raw transaction data.\n"
"\nArguments:\n"
"1. \"txids\" (string) A json array of txids to filter\n"
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 0b46d718d1..58a62ee022 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "crypto/aes.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
@@ -16,6 +17,8 @@
#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
+#include <openssl/aes.h>
+#include <openssl/evp.h>
BOOST_FIXTURE_TEST_SUITE(crypto_tests, BasicTestingSetup)
@@ -63,6 +66,127 @@ void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const s
TestVector(CHMAC_SHA512(&key[0], key.size()), ParseHex(hexin), ParseHex(hexout));
}
+void TestAES128(const std::string &hexkey, const std::string &hexin, const std::string &hexout)
+{
+ std::vector<unsigned char> key = ParseHex(hexkey);
+ std::vector<unsigned char> in = ParseHex(hexin);
+ std::vector<unsigned char> correctout = ParseHex(hexout);
+ std::vector<unsigned char> buf, buf2;
+
+ assert(key.size() == 16);
+ assert(in.size() == 16);
+ assert(correctout.size() == 16);
+ AES128Encrypt enc(&key[0]);
+ buf.resize(correctout.size());
+ buf2.resize(correctout.size());
+ enc.Encrypt(&buf[0], &in[0]);
+ BOOST_CHECK_EQUAL(HexStr(buf), HexStr(correctout));
+ AES128Decrypt dec(&key[0]);
+ dec.Decrypt(&buf2[0], &buf[0]);
+ BOOST_CHECK_EQUAL(HexStr(buf2), HexStr(in));
+}
+
+void TestAES256(const std::string &hexkey, const std::string &hexin, const std::string &hexout)
+{
+ std::vector<unsigned char> key = ParseHex(hexkey);
+ std::vector<unsigned char> in = ParseHex(hexin);
+ std::vector<unsigned char> correctout = ParseHex(hexout);
+ std::vector<unsigned char> buf;
+
+ assert(key.size() == 32);
+ assert(in.size() == 16);
+ assert(correctout.size() == 16);
+ AES256Encrypt enc(&key[0]);
+ buf.resize(correctout.size());
+ enc.Encrypt(&buf[0], &in[0]);
+ BOOST_CHECK(buf == correctout);
+ AES256Decrypt dec(&key[0]);
+ dec.Decrypt(&buf[0], &buf[0]);
+ BOOST_CHECK(buf == in);
+}
+
+void TestAES128CBC(const std::string &hexkey, const std::string &hexiv, bool pad, const std::string &hexin, const std::string &hexout)
+{
+ std::vector<unsigned char> key = ParseHex(hexkey);
+ std::vector<unsigned char> iv = ParseHex(hexiv);
+ std::vector<unsigned char> in = ParseHex(hexin);
+ std::vector<unsigned char> correctout = ParseHex(hexout);
+ std::vector<unsigned char> realout(in.size() + AES_BLOCKSIZE);
+
+ // Encrypt the plaintext and verify that it equals the cipher
+ AES128CBCEncrypt enc(&key[0], &iv[0], pad);
+ int size = enc.Encrypt(&in[0], in.size(), &realout[0]);
+ realout.resize(size);
+ BOOST_CHECK(realout.size() == correctout.size());
+ BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout);
+
+ // Decrypt the cipher and verify that it equals the plaintext
+ std::vector<unsigned char> decrypted(correctout.size());
+ AES128CBCDecrypt dec(&key[0], &iv[0], pad);
+ size = dec.Decrypt(&correctout[0], correctout.size(), &decrypted[0]);
+ decrypted.resize(size);
+ BOOST_CHECK(decrypted.size() == in.size());
+ BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin);
+
+ // Encrypt and re-decrypt substrings of the plaintext and verify that they equal each-other
+ for(std::vector<unsigned char>::iterator i(in.begin()); i != in.end(); ++i)
+ {
+ std::vector<unsigned char> sub(i, in.end());
+ std::vector<unsigned char> subout(sub.size() + AES_BLOCKSIZE);
+ int size = enc.Encrypt(&sub[0], sub.size(), &subout[0]);
+ if (size != 0)
+ {
+ subout.resize(size);
+ std::vector<unsigned char> subdecrypted(subout.size());
+ size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]);
+ subdecrypted.resize(size);
+ BOOST_CHECK(decrypted.size() == in.size());
+ BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub));
+ }
+ }
+}
+
+void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad, const std::string &hexin, const std::string &hexout)
+{
+ std::vector<unsigned char> key = ParseHex(hexkey);
+ std::vector<unsigned char> iv = ParseHex(hexiv);
+ std::vector<unsigned char> in = ParseHex(hexin);
+ std::vector<unsigned char> correctout = ParseHex(hexout);
+ std::vector<unsigned char> realout(in.size() + AES_BLOCKSIZE);
+
+ // Encrypt the plaintext and verify that it equals the cipher
+ AES256CBCEncrypt enc(&key[0], &iv[0], pad);
+ int size = enc.Encrypt(&in[0], in.size(), &realout[0]);
+ realout.resize(size);
+ BOOST_CHECK(realout.size() == correctout.size());
+ BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout);
+
+ // Decrypt the cipher and verify that it equals the plaintext
+ std::vector<unsigned char> decrypted(correctout.size());
+ AES256CBCDecrypt dec(&key[0], &iv[0], pad);
+ size = dec.Decrypt(&correctout[0], correctout.size(), &decrypted[0]);
+ decrypted.resize(size);
+ BOOST_CHECK(decrypted.size() == in.size());
+ BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin);
+
+ // Encrypt and re-decrypt substrings of the plaintext and verify that they equal each-other
+ for(std::vector<unsigned char>::iterator i(in.begin()); i != in.end(); ++i)
+ {
+ std::vector<unsigned char> sub(i, in.end());
+ std::vector<unsigned char> subout(sub.size() + AES_BLOCKSIZE);
+ int size = enc.Encrypt(&sub[0], sub.size(), &subout[0]);
+ if (size != 0)
+ {
+ subout.resize(size);
+ std::vector<unsigned char> subdecrypted(subout.size());
+ size = dec.Decrypt(&subout[0], subout.size(), &subdecrypted[0]);
+ subdecrypted.resize(size);
+ BOOST_CHECK(decrypted.size() == in.size());
+ BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub));
+ }
+ }
+}
+
std::string LongTestString(void) {
std::string ret;
for (int i=0; i<200000; i++) {
@@ -248,4 +372,71 @@ BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) {
"b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58");
}
+BOOST_AUTO_TEST_CASE(aes_testvectors) {
+ // AES test vectors from FIPS 197.
+ TestAES128("000102030405060708090a0b0c0d0e0f", "00112233445566778899aabbccddeeff", "69c4e0d86a7b0430d8cdb78070b4c55a");
+ TestAES256("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "00112233445566778899aabbccddeeff", "8ea2b7ca516745bfeafc49904b496089");
+
+ // AES-ECB test vectors from NIST sp800-38a.
+ TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "6bc1bee22e409f96e93d7e117393172a", "3ad77bb40d7a3660a89ecaf32466ef97");
+ TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "ae2d8a571e03ac9c9eb76fac45af8e51", "f5d3d58503b9699de785895a96fdbaaf");
+ TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "30c81c46a35ce411e5fbc1191a0a52ef", "43b1cd7f598ece23881b00e3ed030688");
+ TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "f69f2445df4f9b17ad2b417be66c3710", "7b0c785e27e8ad3f8223207104725dd4");
+ TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "6bc1bee22e409f96e93d7e117393172a", "f3eed1bdb5d2a03c064b5a7e3db181f8");
+ TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "ae2d8a571e03ac9c9eb76fac45af8e51", "591ccb10d410ed26dc5ba74a31362870");
+ TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "30c81c46a35ce411e5fbc1191a0a52ef", "b6ed21b99ca6f4f9f153e7b1beafed1d");
+ TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "f69f2445df4f9b17ad2b417be66c3710", "23304b7a39f9f3ff067d8d8f9e24ecc7");
+}
+
+BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) {
+
+ // NIST AES CBC 128-bit encryption test-vectors
+ TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "000102030405060708090A0B0C0D0E0F", false, \
+ "6bc1bee22e409f96e93d7e117393172a", "7649abac8119b246cee98e9b12e9197d");
+ TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "7649ABAC8119B246CEE98E9B12E9197D", false, \
+ "ae2d8a571e03ac9c9eb76fac45af8e51", "5086cb9b507219ee95db113a917678b2");
+ TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "5086cb9b507219ee95db113a917678b2", false, \
+ "30c81c46a35ce411e5fbc1191a0a52ef", "73bed6b8e3c1743b7116e69e22229516");
+ TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "73bed6b8e3c1743b7116e69e22229516", false, \
+ "f69f2445df4f9b17ad2b417be66c3710", "3ff1caa1681fac09120eca307586e1a7");
+
+ // The same vectors with padding enabled
+ TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "000102030405060708090A0B0C0D0E0F", true, \
+ "6bc1bee22e409f96e93d7e117393172a", "7649abac8119b246cee98e9b12e9197d8964e0b149c10b7b682e6e39aaeb731c");
+ TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "7649ABAC8119B246CEE98E9B12E9197D", true, \
+ "ae2d8a571e03ac9c9eb76fac45af8e51", "5086cb9b507219ee95db113a917678b255e21d7100b988ffec32feeafaf23538");
+ TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "5086cb9b507219ee95db113a917678b2", true, \
+ "30c81c46a35ce411e5fbc1191a0a52ef", "73bed6b8e3c1743b7116e69e22229516f6eccda327bf8e5ec43718b0039adceb");
+ TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "73bed6b8e3c1743b7116e69e22229516", true, \
+ "f69f2445df4f9b17ad2b417be66c3710", "3ff1caa1681fac09120eca307586e1a78cb82807230e1321d3fae00d18cc2012");
+
+ // NIST AES CBC 256-bit encryption test-vectors
+ TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", \
+ "000102030405060708090A0B0C0D0E0F", false, "6bc1bee22e409f96e93d7e117393172a", \
+ "f58c4c04d6e5f1ba779eabfb5f7bfbd6");
+ TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", \
+ "F58C4C04D6E5F1BA779EABFB5F7BFBD6", false, "ae2d8a571e03ac9c9eb76fac45af8e51", \
+ "9cfc4e967edb808d679f777bc6702c7d");
+ TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", \
+ "9CFC4E967EDB808D679F777BC6702C7D", false, "30c81c46a35ce411e5fbc1191a0a52ef",
+ "39f23369a9d9bacfa530e26304231461");
+ TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", \
+ "39F23369A9D9BACFA530E26304231461", false, "f69f2445df4f9b17ad2b417be66c3710", \
+ "b2eb05e2c39be9fcda6c19078c6a9d1b");
+
+ // The same vectors with padding enabled
+ TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", \
+ "000102030405060708090A0B0C0D0E0F", true, "6bc1bee22e409f96e93d7e117393172a", \
+ "f58c4c04d6e5f1ba779eabfb5f7bfbd6485a5c81519cf378fa36d42b8547edc0");
+ TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", \
+ "F58C4C04D6E5F1BA779EABFB5F7BFBD6", true, "ae2d8a571e03ac9c9eb76fac45af8e51", \
+ "9cfc4e967edb808d679f777bc6702c7d3a3aa5e0213db1a9901f9036cf5102d2");
+ TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", \
+ "9CFC4E967EDB808D679F777BC6702C7D", true, "30c81c46a35ce411e5fbc1191a0a52ef",
+ "39f23369a9d9bacfa530e263042314612f8da707643c90a6f732b3de1d3f5cee");
+ TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", \
+ "39F23369A9D9BACFA530E26304231461", true, "f69f2445df4f9b17ad2b417be66c3710", \
+ "b2eb05e2c39be9fcda6c19078c6a9d1b3f461796d6b0d6b2e0c2a72b4d80e644");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index 757d94b526..0bdac182e0 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -1311,6 +1311,13 @@
"P2SH(P2PK), bad redeemscript"
],
[
+ "0x47 0x30440220781ba4f59a7b207a10db87628bc2168df4d59b844b397d2dbc9a5835fb2f2b7602206ed8fbcc1072fe2dfc5bb25909269e5dc42ffcae7ec2bc81d59692210ff30c2b01 0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x19 0x76a91491b24bf9f5288532960ac687abb035127b1d28a588ac",
+ "HASH160 0x14 0x7f67f0521934a57d3039f77f9f32cf313f3ac74b EQUAL",
+ "P2SH",
+ "OK",
+ "P2SH(P2PKH)"
+],
+[
"0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac",
"HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL",
"",
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 5e9711a4a7..39089f103d 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -427,7 +427,10 @@ BOOST_AUTO_TEST_CASE(script_build)
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
"P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).PushRedeem().DamagePush(10).ScriptError(SCRIPT_ERR_EVAL_FALSE));
-
+
+ tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,
+ "P2SH(P2PKH)", SCRIPT_VERIFY_P2SH, true
+ ).PushSig(keys.key0).Push(keys.pubkey0).PushRedeem());
tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true
).PushSig(keys.key0).DamagePush(10).PushRedeem());
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 04c6fa9625..e43b2ff6c4 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -195,7 +195,6 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
nHashType = test[3].get_int();
sigHashHex = test[4].get_str();
- uint256 sh;
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
stream >> tx;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index aa5df6ca4e..4f17e7f8ca 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -789,15 +789,23 @@ void CTxMemPool::queryHashes(vector<uint256>& vtxid)
std::sort(vtxid.begin(), vtxid.end(), DepthAndScoreComparator(this));
}
-bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
+
+bool CTxMemPool::lookup(uint256 hash, CTransaction& result, int64_t& time) const
{
LOCK(cs);
indexed_transaction_set::const_iterator i = mapTx.find(hash);
if (i == mapTx.end()) return false;
result = i->GetTx();
+ time = i->GetTime();
return true;
}
+bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
+{
+ int64_t time;
+ return CTxMemPool::lookup(hash, result, time);
+}
+
bool CTxMemPool::lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const
{
LOCK(cs);
diff --git a/src/txmempool.h b/src/txmempool.h
index 3e1d387975..75cf0f4c12 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -602,6 +602,7 @@ public:
}
bool lookup(uint256 hash, CTransaction& result) const;
+ bool lookup(uint256 hash, CTransaction& result, int64_t& time) const;
bool lookupFeeRate(const uint256& hash, CFeeRate& feeRate) const;
/** Estimate fee rate needed to get into the next nBlocks
diff --git a/src/util.cpp b/src/util.cpp
index 80f2193016..9a9209c621 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -113,7 +113,7 @@ string strMiscWarning;
bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
bool fLogIPs = DEFAULT_LOGIPS;
-volatile sig_atomic_t fReopenDebugLog = false;
+std::atomic<bool> fReopenDebugLog(false);
CTranslationInterface translationInterface;
/** Init OpenSSL library multithreading support */
diff --git a/src/util.h b/src/util.h
index 88a00d3ca1..ac4b947785 100644
--- a/src/util.h
+++ b/src/util.h
@@ -18,6 +18,7 @@
#include "tinyformat.h"
#include "utiltime.h"
+#include <atomic>
#include <exception>
#include <map>
#include <stdint.h>
@@ -28,10 +29,6 @@
#include <boost/signals2/signal.hpp>
#include <boost/thread/exceptions.hpp>
-#ifndef WIN32
-#include <signal.h>
-#endif
-
static const bool DEFAULT_LOGTIMEMICROS = false;
static const bool DEFAULT_LOGIPS = false;
static const bool DEFAULT_LOGTIMESTAMPS = true;
@@ -54,7 +51,7 @@ extern std::string strMiscWarning;
extern bool fLogTimestamps;
extern bool fLogTimeMicros;
extern bool fLogIPs;
-extern volatile sig_atomic_t fReopenDebugLog;
+extern std::atomic<bool> fReopenDebugLog;
extern CTranslationInterface translationInterface;
extern const char * const BITCOIN_CONF_FILENAME;
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index 95aa4c2593..190f8ecf2a 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -4,6 +4,8 @@
#include "crypter.h"
+#include "crypto/aes.h"
+#include "crypto/sha512.h"
#include "script/script.h"
#include "script/standard.h"
#include "util.h"
@@ -11,8 +13,33 @@
#include <string>
#include <vector>
#include <boost/foreach.hpp>
-#include <openssl/aes.h>
-#include <openssl/evp.h>
+
+int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const
+{
+ // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc
+ // cipher and sha512 message digest. Because sha512's output size (64b) is
+ // greater than the aes256 block size (16b) + aes256 key size (32b),
+ // there's no need to process more than once (D_0).
+
+ if(!count || !key || !iv)
+ return 0;
+
+ unsigned char buf[CSHA512::OUTPUT_SIZE];
+ CSHA512 di;
+
+ di.Write((const unsigned char*)strKeyData.c_str(), strKeyData.size());
+ if(chSalt.size())
+ di.Write(&chSalt[0], chSalt.size());
+ di.Finalize(buf);
+
+ for(int i = 0; i != count - 1; i++)
+ di.Reset().Write(buf, sizeof(buf)).Finalize(buf);
+
+ memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
+ memcpy(iv, buf + WALLET_CRYPTO_KEY_SIZE, WALLET_CRYPTO_IV_SIZE);
+ memory_cleanse(buf, sizeof(buf));
+ return WALLET_CRYPTO_KEY_SIZE;
+}
bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
{
@@ -21,8 +48,7 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v
int i = 0;
if (nDerivationMethod == 0)
- i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
- (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
+ i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, chKey, chIV);
if (i != (int)WALLET_CRYPTO_KEY_SIZE)
{
@@ -37,7 +63,7 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v
bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
{
- if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
+ if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_SIZE)
return false;
memcpy(&chKey[0], &chNewKey[0], sizeof chKey);
@@ -47,57 +73,39 @@ bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigne
return true;
}
-bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext)
+bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
{
if (!fKeySet)
return false;
// max ciphertext len for a n bytes of plaintext is
- // n + AES_BLOCK_SIZE - 1 bytes
- int nLen = vchPlaintext.size();
- int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
- vchCiphertext = std::vector<unsigned char> (nCLen);
-
- EVP_CIPHER_CTX ctx;
+ // n + AES_BLOCKSIZE bytes
+ vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);
- bool fOk = true;
-
- EVP_CIPHER_CTX_init(&ctx);
- if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
- if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
- if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
- EVP_CIPHER_CTX_cleanup(&ctx);
-
- if (!fOk) return false;
+ AES256CBCEncrypt enc(chKey, chIV, true);
+ size_t nLen = enc.Encrypt(&vchPlaintext[0], vchPlaintext.size(), &vchCiphertext[0]);
+ if(nLen < vchPlaintext.size())
+ return false;
+ vchCiphertext.resize(nLen);
- vchCiphertext.resize(nCLen + nFLen);
return true;
}
-bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext)
+bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
{
if (!fKeySet)
return false;
// plaintext will always be equal to or lesser than length of ciphertext
int nLen = vchCiphertext.size();
- int nPLen = nLen, nFLen = 0;
-
- vchPlaintext = CKeyingMaterial(nPLen);
- EVP_CIPHER_CTX ctx;
+ vchPlaintext.resize(nLen);
- bool fOk = true;
-
- EVP_CIPHER_CTX_init(&ctx);
- if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
- if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
- if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
- EVP_CIPHER_CTX_cleanup(&ctx);
-
- if (!fOk) return false;
-
- vchPlaintext.resize(nPLen + nFLen);
+ AES256CBCDecrypt dec(chKey, chIV, true);
+ nLen = dec.Decrypt(&vchCiphertext[0], vchCiphertext.size(), &vchPlaintext[0]);
+ if(nLen == 0)
+ return false;
+ vchPlaintext.resize(nLen);
return true;
}
@@ -105,8 +113,8 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{
CCrypter cKeyCrypter;
- std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
- memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
+ std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
+ memcpy(&chIV[0], &nIV, WALLET_CRYPTO_IV_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
@@ -115,8 +123,8 @@ static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMateri
static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
{
CCrypter cKeyCrypter;
- std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
- memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
+ std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
+ memcpy(&chIV[0], &nIV, WALLET_CRYPTO_IV_SIZE);
if(!cKeyCrypter.SetKey(vMasterKey, chIV))
return false;
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index eb06a7866a..5d0a4a3305 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -13,6 +13,7 @@ class uint256;
const unsigned int WALLET_CRYPTO_KEY_SIZE = 32;
const unsigned int WALLET_CRYPTO_SALT_SIZE = 8;
+const unsigned int WALLET_CRYPTO_IV_SIZE = 16;
/**
* Private key encryption is done based on a CMasterKey,
@@ -66,18 +67,26 @@ public:
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
+namespace wallet_crypto
+{
+ class TestCrypter;
+}
+
/** Encryption/decryption context with key information */
class CCrypter
{
+friend class wallet_crypto::TestCrypter; // for test access to chKey/chIV
private:
unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
- unsigned char chIV[WALLET_CRYPTO_KEY_SIZE];
+ unsigned char chIV[WALLET_CRYPTO_IV_SIZE];
bool fKeySet;
+ int BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const;
+
public:
bool SetKeyFromPassphrase(const SecureString &strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod);
- bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext);
- bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext);
+ bool Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const;
+ bool Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const;
bool SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV);
void CleanKey()
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 27596929f1..b9f086b092 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -673,38 +673,6 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
}
-CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
-{
- CAmount nBalance = 0;
-
- // Tally wallet transactions
- for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
- {
- const CWalletTx& wtx = (*it).second;
- if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
- continue;
-
- CAmount nReceived, nSent, nFee;
- wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
-
- if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
- nBalance += nReceived;
- nBalance -= nSent + nFee;
- }
-
- // Tally internal accounting entries
- nBalance += walletdb.GetAccountCreditDebit(strAccount);
-
- return nBalance;
-}
-
-CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
-{
- CWalletDB walletdb(pwalletMain->strWalletFile);
- return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
-}
-
-
UniValue getbalance(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
@@ -775,7 +743,7 @@ UniValue getbalance(const UniValue& params, bool fHelp)
string strAccount = AccountFromValue(params[0]);
- CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
+ CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, filter);
return ValueFromAmount(nBalance);
}
@@ -923,7 +891,7 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
// Check funds
- CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
+ CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
if (nAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
@@ -1026,7 +994,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
// Check funds
- CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
+ CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
if (totalAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
@@ -1836,7 +1804,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
string strDest = params[0].get_str();
- if (!BackupWallet(*pwalletMain, strDest))
+ if (!pwalletMain->BackupWallet(strDest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
return NullUniValue;
diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp
new file mode 100644
index 0000000000..05387f5f2b
--- /dev/null
+++ b/src/wallet/test/crypto_tests.cpp
@@ -0,0 +1,230 @@
+// Copyright (c) 2014 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 "random.h"
+#include "utilstrencodings.h"
+#include "test/test_bitcoin.h"
+#include "wallet/crypter.h"
+
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+
+BOOST_FIXTURE_TEST_SUITE(wallet_crypto, BasicTestingSetup)
+
+bool OldSetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod, unsigned char* chKey, unsigned char* chIV)
+{
+ if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
+ return false;
+
+ int i = 0;
+ if (nDerivationMethod == 0)
+ i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
+ (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
+
+ if (i != (int)WALLET_CRYPTO_KEY_SIZE)
+ {
+ memory_cleanse(chKey, sizeof(chKey));
+ memory_cleanse(chIV, sizeof(chIV));
+ return false;
+ }
+ return true;
+}
+
+bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext, const unsigned char chKey[32], const unsigned char chIV[16])
+{
+ // max ciphertext len for a n bytes of plaintext is
+ // n + AES_BLOCK_SIZE - 1 bytes
+ int nLen = vchPlaintext.size();
+ int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
+ vchCiphertext = std::vector<unsigned char> (nCLen);
+
+ EVP_CIPHER_CTX ctx;
+
+ bool fOk = true;
+
+ EVP_CIPHER_CTX_init(&ctx);
+ if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
+ if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
+ if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ if (!fOk) return false;
+
+ vchCiphertext.resize(nCLen + nFLen);
+ return true;
+}
+
+bool OldDecrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext, const unsigned char chKey[32], const unsigned char chIV[16])
+{
+ // plaintext will always be equal to or lesser than length of ciphertext
+ int nLen = vchCiphertext.size();
+ int nPLen = nLen, nFLen = 0;
+
+ vchPlaintext = CKeyingMaterial(nPLen);
+
+ EVP_CIPHER_CTX ctx;
+
+ bool fOk = true;
+
+ EVP_CIPHER_CTX_init(&ctx);
+ if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0;
+ if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
+ if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ if (!fOk) return false;
+
+ vchPlaintext.resize(nPLen + nFLen);
+ return true;
+}
+
+class TestCrypter
+{
+public:
+static void TestPassphraseSingle(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds,
+ const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(),
+ const std::vector<unsigned char>& correctIV=std::vector<unsigned char>())
+{
+ unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
+ unsigned char chIV[WALLET_CRYPTO_IV_SIZE];
+
+ CCrypter crypt;
+ crypt.SetKeyFromPassphrase(passphrase, vchSalt, rounds, 0);
+
+ OldSetKeyFromPassphrase(passphrase, vchSalt, rounds, 0, chKey, chIV);
+
+ BOOST_CHECK_MESSAGE(memcmp(chKey, crypt.chKey, sizeof(chKey)) == 0, \
+ HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(crypt.chKey, crypt.chKey + (sizeof crypt.chKey)));
+ BOOST_CHECK_MESSAGE(memcmp(chIV, crypt.chIV, sizeof(chIV)) == 0, \
+ HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(crypt.chIV, crypt.chIV + (sizeof crypt.chIV)));
+
+ if(!correctKey.empty())
+ BOOST_CHECK_MESSAGE(memcmp(chKey, &correctKey[0], sizeof(chKey)) == 0, \
+ HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(correctKey.begin(), correctKey.end()));
+ if(!correctIV.empty())
+ BOOST_CHECK_MESSAGE(memcmp(chIV, &correctIV[0], sizeof(chIV)) == 0,
+ HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(correctIV.begin(), correctIV.end()));
+}
+
+static void TestPassphrase(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds,
+ const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(),
+ const std::vector<unsigned char>& correctIV=std::vector<unsigned char>())
+{
+ TestPassphraseSingle(vchSalt, passphrase, rounds, correctKey, correctIV);
+ for(SecureString::const_iterator i(passphrase.begin()); i != passphrase.end(); ++i)
+ TestPassphraseSingle(vchSalt, SecureString(i, passphrase.end()), rounds);
+}
+
+
+static void TestDecrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchCiphertext, \
+ const std::vector<unsigned char>& vchPlaintext = std::vector<unsigned char>())
+{
+ CKeyingMaterial vchDecrypted1;
+ CKeyingMaterial vchDecrypted2;
+ int result1, result2;
+ result1 = crypt.Decrypt(vchCiphertext, vchDecrypted1);
+ result2 = OldDecrypt(vchCiphertext, vchDecrypted2, crypt.chKey, crypt.chIV);
+ BOOST_CHECK(result1 == result2);
+
+ // These two should be equal. However, OpenSSL 1.0.1j introduced a change
+ // that would zero all padding except for the last byte for failed decrypts.
+ // This behavior was reverted for 1.0.1k.
+ if (vchDecrypted1 != vchDecrypted2 && vchDecrypted1.size() >= AES_BLOCK_SIZE && SSLeay() == 0x100010afL)
+ {
+ for(CKeyingMaterial::iterator it = vchDecrypted1.end() - AES_BLOCK_SIZE; it != vchDecrypted1.end() - 1; it++)
+ *it = 0;
+ }
+
+ BOOST_CHECK_MESSAGE(vchDecrypted1 == vchDecrypted2, HexStr(vchDecrypted1.begin(), vchDecrypted1.end()) + " != " + HexStr(vchDecrypted2.begin(), vchDecrypted2.end()));
+
+ if (vchPlaintext.size())
+ BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted2);
+}
+
+static void TestEncryptSingle(const CCrypter& crypt, const CKeyingMaterial& vchPlaintext,
+ const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>())
+{
+ std::vector<unsigned char> vchCiphertext1;
+ std::vector<unsigned char> vchCiphertext2;
+ int result1 = crypt.Encrypt(vchPlaintext, vchCiphertext1);
+
+ int result2 = OldEncrypt(vchPlaintext, vchCiphertext2, crypt.chKey, crypt.chIV);
+ BOOST_CHECK(result1 == result2);
+ BOOST_CHECK(vchCiphertext1 == vchCiphertext2);
+
+ if (!vchCiphertextCorrect.empty())
+ BOOST_CHECK(vchCiphertext2 == vchCiphertextCorrect);
+
+ const std::vector<unsigned char> vchPlaintext2(vchPlaintext.begin(), vchPlaintext.end());
+
+ if(vchCiphertext1 == vchCiphertext2)
+ TestDecrypt(crypt, vchCiphertext1, vchPlaintext2);
+}
+
+static void TestEncrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchPlaintextIn, \
+ const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>())
+{
+ TestEncryptSingle(crypt, CKeyingMaterial(vchPlaintextIn.begin(), vchPlaintextIn.end()), vchCiphertextCorrect);
+ for(std::vector<unsigned char>::const_iterator i(vchPlaintextIn.begin()); i != vchPlaintextIn.end(); ++i)
+ TestEncryptSingle(crypt, CKeyingMaterial(i, vchPlaintextIn.end()));
+}
+
+};
+
+BOOST_AUTO_TEST_CASE(passphrase) {
+ // These are expensive.
+
+ TestCrypter::TestPassphrase(ParseHex("0000deadbeef0000"), "test", 25000, \
+ ParseHex("fc7aba077ad5f4c3a0988d8daa4810d0d4a0e3bcb53af662998898f33df0556a"), \
+ ParseHex("cf2f2691526dd1aa220896fb8bf7c369"));
+
+ std::string hash(GetRandHash().ToString());
+ std::vector<unsigned char> vchSalt(8);
+ GetRandBytes(&vchSalt[0], vchSalt.size());
+ uint32_t rounds = insecure_rand();
+ if (rounds > 30000)
+ rounds = 30000;
+ TestCrypter::TestPassphrase(vchSalt, SecureString(hash.begin(), hash.end()), rounds);
+}
+
+BOOST_AUTO_TEST_CASE(encrypt) {
+ std::vector<unsigned char> vchSalt = ParseHex("0000deadbeef0000");
+ BOOST_CHECK(vchSalt.size() == WALLET_CRYPTO_SALT_SIZE);
+ CCrypter crypt;
+ crypt.SetKeyFromPassphrase("passphrase", vchSalt, 25000, 0);
+ TestCrypter::TestEncrypt(crypt, ParseHex("22bcade09ac03ff6386914359cfe885cfeb5f77ff0d670f102f619687453b29d"));
+
+ for (int i = 0; i != 100; i++)
+ {
+ uint256 hash(GetRandHash());
+ TestCrypter::TestEncrypt(crypt, std::vector<unsigned char>(hash.begin(), hash.end()));
+ }
+
+}
+
+BOOST_AUTO_TEST_CASE(decrypt) {
+ std::vector<unsigned char> vchSalt = ParseHex("0000deadbeef0000");
+ BOOST_CHECK(vchSalt.size() == WALLET_CRYPTO_SALT_SIZE);
+ CCrypter crypt;
+ crypt.SetKeyFromPassphrase("passphrase", vchSalt, 25000, 0);
+
+ // Some corner cases the came up while testing
+ TestCrypter::TestDecrypt(crypt,ParseHex("795643ce39d736088367822cdc50535ec6f103715e3e48f4f3b1a60a08ef59ca"));
+ TestCrypter::TestDecrypt(crypt,ParseHex("de096f4a8f9bd97db012aa9d90d74de8cdea779c3ee8bc7633d8b5d6da703486"));
+ TestCrypter::TestDecrypt(crypt,ParseHex("32d0a8974e3afd9c6c3ebf4d66aa4e6419f8c173de25947f98cf8b7ace49449c"));
+ TestCrypter::TestDecrypt(crypt,ParseHex("e7c055cca2faa78cb9ac22c9357a90b4778ded9b2cc220a14cea49f931e596ea"));
+ TestCrypter::TestDecrypt(crypt,ParseHex("b88efddd668a6801d19516d6830da4ae9811988ccbaf40df8fbb72f3f4d335fd"));
+ TestCrypter::TestDecrypt(crypt,ParseHex("8cae76aa6a43694e961ebcb28c8ca8f8540b84153d72865e8561ddd93fa7bfa9"));
+
+ for (int i = 0; i != 100; i++)
+ {
+ uint256 hash(GetRandHash());
+ TestCrypter::TestDecrypt(crypt, std::vector<unsigned char>(hash.begin(), hash.end()));
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 6b942e29d7..da0d6f272b 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -509,16 +509,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
return false;
CKeyingMaterial vMasterKey;
- RandAddSeedPerfmon();
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
- GetRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
+ GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
CMasterKey kMasterKey;
- RandAddSeedPerfmon();
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
- GetRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
+ GetStrongRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
@@ -2759,6 +2757,37 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
return ret;
}
+CAmount CWallet::GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter)
+{
+ CWalletDB walletdb(strWalletFile);
+ return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
+}
+
+CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter)
+{
+ CAmount nBalance = 0;
+
+ // Tally wallet transactions
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
+ continue;
+
+ CAmount nReceived, nSent, nFee;
+ wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
+
+ if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
+ nBalance += nReceived;
+ nBalance -= nSent + nFee;
+ }
+
+ // Tally internal accounting entries
+ nBalance += walletdb.GetAccountCreditDebit(strAccount);
+
+ return nBalance;
+}
+
std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
{
LOCK(cs_wallet);
@@ -3116,8 +3145,6 @@ bool CWallet::InitLoadWallet()
if (fFirstRun)
{
// Create new keyUser and set as default key
- RandAddSeedPerfmon();
-
CPubKey newDefaultKey;
if (walletInstance->GetKeyFromPool(newDefaultKey)) {
walletInstance->SetDefaultKey(newDefaultKey);
@@ -3252,6 +3279,46 @@ bool CWallet::ParameterInteraction()
return true;
}
+bool CWallet::BackupWallet(const std::string& strDest)
+{
+ if (!fFileBacked)
+ return false;
+ while (true)
+ {
+ {
+ LOCK(bitdb.cs_db);
+ if (!bitdb.mapFileUseCount.count(strWalletFile) || bitdb.mapFileUseCount[strWalletFile] == 0)
+ {
+ // Flush log data to the dat file
+ bitdb.CloseDb(strWalletFile);
+ bitdb.CheckpointLSN(strWalletFile);
+ bitdb.mapFileUseCount.erase(strWalletFile);
+
+ // Copy wallet file
+ boost::filesystem::path pathSrc = GetDataDir() / strWalletFile;
+ boost::filesystem::path pathDest(strDest);
+ if (boost::filesystem::is_directory(pathDest))
+ pathDest /= strWalletFile;
+
+ try {
+#if BOOST_VERSION >= 104000
+ boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
+#else
+ boost::filesystem::copy_file(pathSrc, pathDest);
+#endif
+ LogPrintf("copied %s to %s\n", strWalletFile, pathDest.string());
+ return true;
+ } catch (const boost::filesystem::filesystem_error& e) {
+ LogPrintf("error copying %s to %s - %s\n", strWalletFile, pathDest.string(), e.what());
+ return false;
+ }
+ }
+ }
+ MilliSleep(100);
+ }
+ return false;
+}
+
CKeyPool::CKeyPool()
{
nTime = GetTime();
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index cc568c3749..b2180a5a26 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -776,6 +776,8 @@ public:
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, CAmount> GetAddressBalances();
+ CAmount GetAccountBalance(const std::string& strAccount, int nMinDepth, const isminefilter& filter);
+ CAmount GetAccountBalance(CWalletDB& walletdb, const std::string& strAccount, int nMinDepth, const isminefilter& filter);
std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
isminetype IsMine(const CTxIn& txin) const;
@@ -883,6 +885,8 @@ public:
/* Wallets parameter interaction */
static bool ParameterInteraction();
+
+ bool BackupWallet(const std::string& strDest);
};
/** A key allocated from the key pool. */
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 48579b2821..b5037c9a65 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -903,46 +903,6 @@ void ThreadFlushWalletDB(const string& strFile)
}
}
-bool BackupWallet(const CWallet& wallet, const string& strDest)
-{
- if (!wallet.fFileBacked)
- return false;
- while (true)
- {
- {
- LOCK(bitdb.cs_db);
- if (!bitdb.mapFileUseCount.count(wallet.strWalletFile) || bitdb.mapFileUseCount[wallet.strWalletFile] == 0)
- {
- // Flush log data to the dat file
- bitdb.CloseDb(wallet.strWalletFile);
- bitdb.CheckpointLSN(wallet.strWalletFile);
- bitdb.mapFileUseCount.erase(wallet.strWalletFile);
-
- // Copy wallet file
- boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile;
- boost::filesystem::path pathDest(strDest);
- if (boost::filesystem::is_directory(pathDest))
- pathDest /= wallet.strWalletFile;
-
- try {
-#if BOOST_VERSION >= 104000
- boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
-#else
- boost::filesystem::copy_file(pathSrc, pathDest);
-#endif
- LogPrintf("copied %s to %s\n", wallet.strWalletFile, pathDest.string());
- return true;
- } catch (const boost::filesystem::filesystem_error& e) {
- LogPrintf("error copying %s to %s - %s\n", wallet.strWalletFile, pathDest.string(), e.what());
- return false;
- }
- }
- }
- MilliSleep(100);
- }
- return false;
-}
-
//
// Try to (very carefully!) recover wallet file if there is a problem.
//
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 5345c0907e..00c10ea70f 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -141,7 +141,6 @@ private:
bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry);
};
-bool BackupWallet(const CWallet& wallet, const std::string& strDest);
void ThreadFlushWalletDB(const std::string& strFile);
#endif // BITCOIN_WALLET_WALLETDB_H