Browse Source

Merge remote-tracking branch 'zcash/master' into dev

# Conflicts:
#	.gitignore
#	README.md
#	src/Makefile.gtest.include
#	src/gtest/test_checkblock.cpp
#	src/init.cpp
#	src/main.cpp
#	src/main.h
#	src/rpcserver.cpp
#	src/test/checkblock_tests.cpp
#	src/util.cpp
metaverse
jl777 8 years ago
parent
commit
3ced93646d
  1. 42
      .github/ISSUE_TEMPLATE.md
  2. 3
      .gitignore
  3. 10
      Makefile.am
  4. 3
      README.md
  5. 0
      build-aux/m4/bitcoin_find_bdb.m4
  6. 4
      configure.ac
  7. 12
      contrib/debian/changelog
  8. 0
      contrib/debian/compat
  9. 12
      contrib/debian/control
  10. 0
      contrib/debian/copyright
  11. 2
      contrib/debian/examples/zcash.conf
  12. 4
      contrib/debian/manpages/zcash-cli.1
  13. 28
      contrib/debian/manpages/zcash-fetch-params.1
  14. 40
      contrib/debian/manpages/zcashd.1
  15. 0
      contrib/debian/postinst
  16. 0
      contrib/debian/postrm
  17. 0
      contrib/debian/preinst
  18. 0
      contrib/debian/prerm
  19. 0
      contrib/debian/rules
  20. 0
      contrib/debian/zcash.examples
  21. 0
      contrib/debian/zcash.install
  22. 0
      contrib/debian/zcash.manpages
  23. 2
      contrib/gitian-descriptors/gitian-linux.yml
  24. 18
      doc/authors.md
  25. 6
      doc/payment-api.md
  26. 75
      doc/release-notes/release-notes-1.0.4.md
  27. 58
      doc/release-notes/release-notes-1.0.5.md
  28. 9
      doc/release-process.md
  29. 1
      qa/pull-tester/rpc-tests.sh
  30. 1
      qa/pull-tester/run-bitcoind-for-test.sh.in
  31. 2
      qa/rpc-tests/wallet.py
  32. 106
      qa/rpc-tests/wallet_1941.py
  33. 8
      qa/rpc-tests/wallet_protectcoinbase.py
  34. 31
      qa/rpc-tests/walletbackup.py
  35. 11
      qa/zcash/performance-measurements.sh
  36. 3
      src/Makefile.am
  37. 8
      src/Makefile.gtest.include
  38. 2
      src/Makefile.test.include
  39. 15
      src/Makefile.zcash.include
  40. 3
      src/asyncrpcoperation.h
  41. 26
      src/bitcoin-cli.cpp
  42. 18
      src/bitcoind.cpp
  43. 2
      src/clientversion.h
  44. 5
      src/gtest/test_checkblock.cpp
  45. 4
      src/gtest/test_keystore.cpp
  46. 6
      src/gtest/test_merkletree.cpp
  47. 61
      src/gtest/test_proofs.cpp
  48. 17
      src/init.cpp
  49. 2
      src/init.h
  50. 47
      src/main.cpp
  51. 16
      src/main.h
  52. 35
      src/metrics.cpp
  53. 2
      src/metrics.h
  54. 5
      src/rpcblockchain.cpp
  55. 2
      src/rpcmining.cpp
  56. 67
      src/rpcprotocol.cpp
  57. 10
      src/rpcprotocol.h
  58. 21
      src/rpcserver.cpp
  59. 4
      src/test/checkblock_tests.cpp
  60. 22
      src/test/rpc_wallet_tests.cpp
  61. 29
      src/test/transaction_tests.cpp
  62. 35
      src/util.cpp
  63. 8
      src/util.h
  64. 16
      src/utilstrencodings.cpp
  65. 1
      src/utilstrencodings.h
  66. 67
      src/wallet/asyncrpcoperation_sendmany.cpp
  67. 6
      src/wallet/asyncrpcoperation_sendmany.h
  68. 244
      src/wallet/gtest/test_wallet.cpp
  69. 0
      src/wallet/gtest/test_wallet_zkeys.cpp
  70. 32
      src/wallet/rpcdump.cpp
  71. 71
      src/wallet/rpcwallet.cpp
  72. 40
      src/wallet/wallet.cpp
  73. 4
      src/wallet/walletdb.cpp
  74. 35
      src/zcash/CreateJoinSplit.cpp
  75. 19
      src/zcash/IncrementalMerkleTree.cpp
  76. 2
      src/zcash/IncrementalMerkleTree.hpp
  77. 4
      src/zcash/Proof.cpp
  78. 21
      src/zcbenchmarks.cpp
  79. 1
      src/zcbenchmarks.h
  80. 16
      zcutil/build-debian-package.sh

42
.github/ISSUE_TEMPLATE.md

@ -0,0 +1,42 @@
<!--- Remove text and sections that do not apply -->
This issue tracker is only for technical issues related to zcashd.
General Zcash questions and/or support requests and are best directed to the [Zcash Forums](https://forum.z.cash) or [Community Rocket.Chat](https://chat.zcashcommunity.com).
For reporting security vulnerabilities or for sensitive discussions with our security team, please contact [security@z.cash](mailto:security@z.cash). You can use the [GPG key](https://z.cash/gpg-pubkeys/security.asc) (fingerprint: `AF85 0445 546C 18B7 86F9 2C62 88FB 8B86 D8B5 A68C`) to send an encrypted message. The key and fingerprint are duplicated on our [Public Keys page](https://z.cash/support/pubkeys.html).
### Describe the issue
Please provide a general summary of the issue you're experiencing
### Can you reliably reproduce the issue?
#### If so, please list the steps to reproduce below:
1.
2.
3.
### Expected behaviour
Tell us what should happen
### Actual behaviour + errors
Tell us what happens instead including any noticable error output (any messages displayed on-screen when e.g. a crash occurred)
### The version of Zcash you were using:
Run `zcashd --version` to find out
### Machine specs:
- OS name + version:
- CPU:
- RAM:
- Disk size:
- Disk Type (HD/SDD):
- Linux kernel version (uname -a):
- Compiler version (gcc -version):
### Any extra information that might be useful in the debugging process.
This includes the relevant contents of `~/.zcash/debug.log`. You can paste raw text, attach the file directly in the issue or link to the text via a pastebin type site.
Please also include any non-standard things you did during compilation (extra flags, dependency version changes etc.) if applicable.
### Do you have a back up of `~/.zcash` directory and/or take a VM snapshot?
- Backing up / making a copy of the `~/.zcash` directory might help make the problem reproducible. Please redact appropriately.
- Taking a VM snapshot is really helpful for interactively testing fixes

3
.gitignore

@ -11,6 +11,7 @@ src/qt/test/test_bitcoin-qt
# Zcash utilities
src/zcash/GenerateParams
src/zcash/CreateJoinSplit
*zcashTest.pk
*zcashTest.vk
@ -124,3 +125,5 @@ qa/pull-tester/test.*/*
libzcashconsensus.pc
src/fiat/-usd
contrib/debian/files
contrib/debian/substvars

10
Makefile.am

@ -176,6 +176,8 @@ baseline_filtered.info: baseline.info
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
"$(abs_builddir)/src/gtest/*" \
"$(abs_builddir)/src/test/*" \
"$(abs_builddir)/src/wallet/gtest/*" \
"$(abs_builddir)/src/wallet/test/*" \
-o $@
endif
@ -199,6 +201,8 @@ leveldb_baseline_filtered.info: leveldb_baseline.info
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
"$(abs_builddir)/src/gtest/*" \
"$(abs_builddir)/src/test/*" \
"$(abs_builddir)/src/wallet/gtest/*" \
"$(abs_builddir)/src/wallet/test/*" \
-o $@
endif
@ -218,6 +222,8 @@ test_bitcoin_filtered.info: test_bitcoin.info
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/boost/*" \
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gmock/*" \
"$(abs_builddir)/src/test/*" \
"$(abs_builddir)/src/wallet/gtest/*" \
"$(abs_builddir)/src/wallet/test/*" \
-o $@
else
test_bitcoin_filtered.info: test_bitcoin.info
@ -228,6 +234,8 @@ test_bitcoin_filtered.info: test_bitcoin.info
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
"$(abs_builddir)/src/gtest/*" \
"$(abs_builddir)/src/test/*" \
"$(abs_builddir)/src/wallet/gtest/*" \
"$(abs_builddir)/src/wallet/test/*" \
-o $@
endif
@ -255,6 +263,8 @@ block_test_filtered.info: block_test.info
"$(abs_builddir)/depends/x86_64-unknown-linux-gnu/include/gtest/*" \
"$(abs_builddir)/src/gtest/*" \
"$(abs_builddir)/src/test/*" \
"$(abs_builddir)/src/wallet/gtest/*" \
"$(abs_builddir)/src/wallet/test/*" \
-o $@
endif

3
README.md

@ -1,4 +1,7 @@
=======
Zcash 1.0.5
===========
What is Zcash?
--------------

0
build-aux/m4/bitcoin_find_bdb48.m4 → build-aux/m4/bitcoin_find_bdb.m4

4
configure.ac

@ -2,12 +2,12 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 1)
define(_CLIENT_VERSION_MINOR, 0)
define(_CLIENT_VERSION_REVISION, 3)
define(_CLIENT_VERSION_REVISION, 5)
define(_CLIENT_VERSION_BUILD, 50)
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2016)
define(_COPYRIGHT_YEAR, 2017)
AC_INIT([Zcash],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_SUFFIX(_ZC_BUILD_VAL)],[https://github.com/zcash/zcash/issues],[zcash])
AC_CONFIG_SRCDIR([src/main.cpp])
AC_CONFIG_HEADERS([src/config/bitcoin-config.h])

12
contrib/DEBIAN/changelog → contrib/debian/changelog

@ -1,3 +1,15 @@
zcash (1.0.5) jessie; urgency=medium
* 1.0.5 release.
-- Zcash Company <team@z.cash> Thu, 19 Jan 2016 19:23:40 -0700
zcash (1.0.4) jessie; urgency=medium
* 1.0.4 release.
-- Zcash Company <team@z.cash> Thu, 15 Dec 2016 16:46:14 +1300
zcash (1.0.3) jessie; urgency=medium
* 1.0.3 release.

0
contrib/DEBIAN/compat → contrib/debian/compat

12
contrib/DEBIAN/control → contrib/debian/control

@ -3,17 +3,17 @@ Section: utils
Priority: optional
Maintainer: Zcash Company <team@z.cash>
Homepage: https://z.cash
Build-Depends: autoconf, automake, bsdmainutils, build-essential
git, g++-multilib, libc6-dev, libtool
m4, ncurses-dev, pkg-config, python
Build-Depends: autoconf, automake, bsdmainutils, build-essential,
git, g++-multilib, libc6-dev, libtool,
m4, ncurses-dev, pkg-config, python,
unzip, wget, zlib1g-dev
Vcs-Git: https://github.com/zcash/zcash.git
Vcs-Browser: https://github.com/zcash/zcash
Package: zcash
Version: 1.0.3
Architecture: amd64
Depends: libgomp1
Description: An implementation of the "Zerocash" protocol.
Depends: ${shlibs:Depends}
Description: HTTPS for money.
Based on Bitcoin's code, it intends to offer a far higher standard
of privacy and anonymity through a sophisticiated zero-knowledge
proving scheme which preserves confidentiality of transaction metadata.

0
contrib/DEBIAN/copyright → contrib/debian/copyright

2
contrib/DEBIAN/examples/zcash.conf → contrib/debian/examples/zcash.conf

@ -1,4 +1,4 @@
##
##
## zcash.conf configuration file. Lines beginning with # are comments.
##

4
contrib/DEBIAN/manpages/zcash-cli.1 → contrib/debian/manpages/zcash-cli.1

@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH ZCASH-CLI "1" "November 2016" "Zcash RPC client version v1.0.3" "User Commands"
.TH ZCASH-CLI "1" "January 2017" "Zcash RPC client version v1.0.5" "User Commands"
.SH NAME
zcash-cli \- RPC client for the Zcash daemon
.SH DESCRIPTION
Zcash RPC client version v1.0.3
Zcash RPC client version v1.0.5
.SS "Usage:"
.TP
zcash\-cli [options] <command> [params]

28
contrib/debian/manpages/zcash-fetch-params.1

@ -0,0 +1,28 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH ZCASH-FETCH-PARAMS "1" "January 2017" "Zcash - zcash-fetch-params" "User Commands"
.SH NAME
zcash-fetch-params \- Downloads the Zcash network parameters
.SH DESCRIPTION
Zcash \- zcash-fetch\-params
.PP
This script will fetch the Zcash zkSNARK parameters and verify their
integrity with sha256sum.
.PP
If they already exist locally, it will exit now and do nothing else.
.PP
This script will fetch the Zcash zkSNARK parameters and verify their
integrity with sha256sum.
.PP
If they already exist locally, it will exit now and do nothing else.
.SH "SEE ALSO"
The full documentation for
.B Zcash
is maintained as a Texinfo manual. If the
.B info
and
.B Zcash
programs are properly installed at your site, the command
.IP
.B info Zcash
.PP
should give you access to the complete manual.

40
contrib/DEBIAN/manpages/zcashd.1 → contrib/debian/manpages/zcashd.1

@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3.
.TH ZCASHD "1" "November 2016" "Zcash Daemon version v1.0.3" "User Commands"
.TH ZCASHD "1" "January 2017" "Zcash Daemon version v1.0.5" "User Commands"
.SH NAME
zcashd \- Network daemon for interacting with the Zcash blockchain
.SH DESCRIPTION
Zcash Daemon version v1.0.3
Zcash Daemon version v1.0.5
.SS "Usage:"
.TP
zcashd [options]
@ -62,7 +62,7 @@ Keep at most <n> unconnectable transactions in memory (default: 100)
.HP
\fB\-par=\fR<n>
.IP
Set the number of script verification threads (\fB\-8\fR to 16, 0 = auto, <0 =
Set the number of script verification threads (\fB\-4\fR to 16, 0 = auto, <0 =
leave that many cores free, default: 0)
.HP
\fB\-pid=\fR<file>
@ -219,7 +219,7 @@ Fee (in BTC/kB) to add to transactions you send (default: 0.00)
.HP
\fB\-rescan\fR
.IP
Rescan the block chain for missing wallet transactions on startup
Rescan the blockchain for missing wallet transactions on startup
.HP
\fB\-salvagewallet\fR
.IP
@ -271,9 +271,9 @@ Debugging/Testing options:
\fB\-debug=\fR<category>
.IP
Output debugging information (default: 0, supplying <category> is
optional). If <category> is not supplied, output all debugging
information.<category> can be: addrman, alert, bench, coindb, db, lock,
rand, rpc, selectcoins, mempool, net, proxy, prune.
optional). If <category> is not supplied or if <category> = 1, output
all debugging information.<category> can be: addrman, alert, bench,
coindb, db, lock, rand, rpc, selectcoins, mempool, net, proxy, prune.
.HP
\fB\-gen\fR
.IP
@ -303,7 +303,7 @@ Prepend debug output with timestamp (default: 1)
\fB\-minrelaytxfee=\fR<amt>
.IP
Fees (in BTC/Kb) smaller than this are considered zero fee for relaying
(default: 0.00005)
(default: 0.00001)
.HP
\fB\-printtoconsole\fR
.IP
@ -336,12 +336,12 @@ Set minimum block size in bytes (default: 0)
.HP
\fB\-blockmaxsize=\fR<n>
.IP
Set maximum block size in bytes (default: 750000)
Set maximum block size in bytes (default: 2000000)
.HP
\fB\-blockprioritysize=\fR<n>
.IP
Set maximum size of high\-priority/low\-fee transactions in bytes
(default: 50000)
(default: 1000000)
.PP
RPC server options:
.HP
@ -382,10 +382,6 @@ multiple times
\fB\-rpcthreads=\fR<n>
.IP
Set the number of threads to service RPC calls (default: 4)
.HP
\fB\-rpckeepalive\fR
.IP
RPC support for HTTP persistent connections (default: 1)
.PP
RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)
.HP
@ -405,6 +401,22 @@ Server private key (default: server.pem)
.IP
Acceptable ciphers (default:
TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH)
.PP
Metrics Options (only if \fB\-daemon\fR and \fB\-printtoconsole\fR are not set):
.HP
\fB\-showmetrics\fR
.IP
Show metrics on stdout (default: 1 if running in a console, 0 otherwise)
.HP
\fB\-metricsui\fR
.IP
Set to 1 for a persistent metrics screen, 0 for sequential metrics
output (default: 1 if running in a console, 0 otherwise)
.HP
\fB\-metricsrefreshtime\fR
.IP
Number of seconds between metrics refreshes (default: 1 if running in a
console, 600 otherwise)
.SH COPYRIGHT
Copyright \(co 2009\-2016 The Bitcoin Core Developers
.br

0
contrib/DEBIAN/postinst → contrib/debian/postinst

0
contrib/DEBIAN/postrm → contrib/debian/postrm

0
contrib/DEBIAN/preinst → contrib/debian/preinst

0
contrib/DEBIAN/prerm → contrib/debian/prerm

0
contrib/DEBIAN/rules → contrib/debian/rules

0
contrib/DEBIAN/zcash.examples → contrib/debian/zcash.examples

0
contrib/DEBIAN/zcash.install → contrib/debian/zcash.install

0
contrib/DEBIAN/zcash.manpages → contrib/debian/zcash.manpages

2
contrib/gitian-descriptors/gitian-linux.yml

@ -1,5 +1,5 @@
---
name: "zcash-1.0.3"
name: "zcash-1.0.5"
enable_cache: true
distro: "debian"
suites:

18
doc/authors.md

@ -1,22 +1,23 @@
Zcash Contributors
==================
Jack Grigg (269)
Simon Liu (199)
Sean Bowe (168)
Jack Grigg (323)
Simon Liu (220)
Sean Bowe (180)
Taylor Hornby (65)
Daira Hopwood (62)
Kevin Gallagher (38)
Jay Graber (32)
Jay Graber (35)
Wladimir J. van der Laan (10)
Nathan Wilcox (10)
Wladimir J. van der Laan (9)
Pieter Wuille (8)
Cory Fields (7)
Paige Peterson (5)
ITH4Coinomia (4)
David Mercer (4)
4ZEC (4)
lpescher (3)
Patrick Strateman (3)
Paige Peterson (3)
MarcoFalke (3)
Alfie John (3)
aniemerg (2)
@ -27,13 +28,18 @@ kazcw (1)
fanquake (1)
ayleph (1)
Tom Ritter (1)
Scott (1)
S. Matthew English (1)
Philip Kaufmann (1)
Louis Nyffenegger (1)
Lars-Magnus Skog (1)
Jeffrey Walton (1)
Gaurav Rana (1)
Ethan Heilman (1)
Eran Tromer (1)
Christian von Roques (1)
Chirag Davé (1)
Cameron Boehmer (1)
Bryan Stitt (1)
Bitcoin Error Log (1)
Alex (1)

6
doc/payment-api.md

@ -89,6 +89,10 @@ Asynchronous calls return an OperationStatus object which is a JSON object with
* code : number
* message: error message
Depending on the type of asynchronous call, there may be other key-value pairs. For example, a z_sendmany operation will also include the following in an OperationStatus object:
* params : an object containing the parameters to z_sendmany
Currently, as soon as you retrieve the operation status for an operation which has finished, that is it has either succeeded, failed, or been cancelled, the operation and any associated information is removed.
It is currently not possible to cancel operations.
@ -151,7 +155,7 @@ RPC_WALLET_ERROR (-4) | _Unspecified problem with wallet_
----------------------| -------------------------------------
"Could not find previous JoinSplit anchor" | Try restarting node with `-reindex`.
"Error decrypting output note of previous JoinSplit: __" |
"Could not find witness for note commitment" | Try restarting node with `-reindex`.
"Could not find witness for note commitment" | Try restarting node with `-rescan`.
"Witness for note commitment is null" | Missing witness for note commitement.
"Witness for spendable note does not have same anchor as change input" | Invalid anchor for spendable note witness.
"Not enough funds to pay miners fee" | Retry with sufficient funds.

75
doc/release-notes/release-notes-1.0.4.md

@ -0,0 +1,75 @@
Bitcoin Error Log (1):
Edit for grammar: "block chain"
Christian von Roques (1):
bash-completion: Adapt for 0.12 and 0.13
Jack Grigg (32):
Add getlocalsolps and getnetworksolps RPC calls, show them in getmininginfo
Add benchmark for attempting decryption of notes
Add benchmark for incrementing note witnesses
Add -metricsui flag to toggle between persistent screen and rolling metrics
Add -metricsrefreshtime option
Only show metrics by default if stdout is a TTY
Document metrics screen options
Clarify that metrics options are only useful without -daemon and -printtoconsole
Increase length of metrics divider
Write witness caches when writing the best block
Apply miniupnpc patches to enable compilation on Solaris 11
Add an upstream miniupnpc patch revision
Address review comments, tweak strings
Change function names to not clash with Bitcoin, apply to correct binaries
Add bash completion files to Debian package
Always bash-complete the default account
Add Zcash RPC commands to CLI argument completion
Document behaviour of CWallet::SetBestChain
Fix indentation
Generate JS for trydecryptnotes, make number of addresses a variable
Add JS to second block to ensure witnesses are incremented
Skip JoinSplit verification before the last checkpoint
Add a reindex test that fails because of a bug in decrementing witness caches
Make the test pass by fixing the bug!
Only check cache validity for witnesses being incremented or decremented
Fix bug in wallet tests
Extract block-generation wallet test code into a function
Rewrite reindex test to check beyond the max witness cache size
Fix bug in IncrementNoteWitness()
Update payment API docs to recommend -rescan for fixing witness errors
Update version to 1.0.4
Update man pages
Jay Graber (2):
Replace bitcoin with zcash in rpcprotocol.cpp
Gather release notes from previous release to HEAD
Jeffrey Walton (1):
Add porter dev overrides for CC, CXX, MAKE, BUILD, HOST
Scott (1):
Metrics - Don't exclaim unless > 1
Sean Bowe (8):
Isolate verification to a `ProofVerifier` context object that allows verification behavior to be tuned by the caller.
Regression test.
Ensure cache contains valid entry when anchor is popped.
Ensure ProofVerifier cannot be accidentally copied.
Rename Dummy to Disabled.
Add more tests for ProofVerifier.
ASSERT_TRUE -> ASSERT_FALSE
Check that E' points are actually in G2 by ensuring they are of order r.
Simon Liu (8):
Fix stale comment referencing upstream block interval
Add checkpoint at block height 15000
Closes #1857. Fixes bug where tx spending only notes had priority of 0.
Closes #1901. Increase default settings for the max block size when mining and the amount of space available for priority transactions.
Closes #1903. Add fee parameter to z_sendmany.
Fixes #1823. Witness anchors for input notes no longer cross block boundaries.
Increase timeout as laptops on battery power have cpu throttling.
WitnessAnchorData only needs to store one witness per JSOutPoint.
lpescher (3):
Make command line option to show all debugging consistent with similar options
Update documentation to match the #4219 change
Update help message to match the #4219 change

58
doc/release-notes/release-notes-1.0.5.md

@ -0,0 +1,58 @@
Eran Tromer (1):
CreateJoinSplit: add start_profiling() call
Jack Grigg (22):
Extend createjoinsplit to benchmark parallel JoinSplits
Add total number of commitments to getblockchaininfo
Only enable getblocktemplate when wallet is enabled
Only run wallet tests when wallet is enabled
Add a tool for profiling the creation of JoinSplits
Exclude test binaries from make install
Scan the whole chain whenever a z-key is imported
Instruct users to run zcash-fetch-params if network params aren't available
Trigger metrics UI refresh on new messages
Strip out the SECURE flag in metrics UI so message style is detected
Handle newlines in UI messages
Suggest ./zcutil/fetch-params.sh as well
Update debug categories
Rename build-aux/m4/bitcoin_find_bdb48.m4 to remove version
Throw an error if zcash.conf is missing
Show a friendly message explaining why zcashd needs a zcash.conf
Fix gtest ordering broken by #1949
Debian package lint
Generate Debian control file to fix shlibs lint
Create empty zcash.conf during performance measurements
Create empty zcash.conf during coverage checks
Coverage build system tweaks
Jay Graber (1):
Update release process to check in with users who opened resolved issues
Paige Peterson (2):
Create ISSUE_TEMPLATE.md
move template to subdirectory, fix typo, include prompt under describing issue section, include uploading file directly to github ticket as option for sharing logs
Sean Bowe (4):
Add test for IncrementalMerkleTree::size().
Add 'CreateJoinSplit' standalone utility to gitignore.
Add test for z_importkey rescanning from beginning of chain.
Bump version to 1.0.5.
Simon Liu (13):
Fixes #1964 to catch general exception in z_sendmany and catch exceptions as reference-to-const.
Fixes #1967 by adding age of note to z_sendmany logging.
Fixes a bug where the unsigned transaction was logged by z_sendmany after a successful sign and send, meaning that the logged hash fragment would be different from the txid logged by "AddToWallet". This issue occured when sending from transparent addresses, as utxo inputs must be signed. It did not occur when sending from shielded addresses.
Bump COPYRIGHT_YEAR from 2016 to 2017.
Closes #1780. Result of z_getoperationstatus now sorted by creation time of operation
Remove UTF-8 BOM efbbbf from zcash.conf to avoid problems with command line tools
Closes #1097 so zcash-cli now displays license info like zcashd.
Fixes #1497 ZCA-009 by restricting data exporting to user defined folder.
Closes #1957 by adding tx serialization size to listtransactions output.
Fixes #1960: z_getoperationstatus/result now includes operation details.
Update walletbackup.py qa test to use -exportdir option
Add missing header required by std::accumulate
Increase timeout for z_sendmany transaction in wallet.py qa test
Wladimir J. van der Laan (1):
rpc: Implement random-cookie based authentication

9
doc/release-process.md

@ -35,7 +35,6 @@ previous release:
README.md
src/clientversion.h
configure.ac
contrib/DEBIAN/control
contrib/gitian-descriptors/gitian-linux.yml
Build and commit to update versions, and then perform the following commands:
@ -112,8 +111,14 @@ Notify the Zcash DevOps engineer/sysadmin that the release has been tagged. They
Then, verify that nodes can connect to the testnet server, and update the guide on the wiki to ensure the correct hostname is listed in the recommended zcash.conf.
## F. Update the Beta Guide
## F. Update the 1.0 User Guide
## G. Publish the release announcement (blog, zcash-dev, slack)
### G1. Check in with users who opened issues that were resolved in the release
Contact all users who opened `user support` issues that were resolved in the release, and ask them if the release fixes or improves their issue.
## H. Make and deploy deterministic builds
- Run the [Gitian deterministic build environment](https://github.com/zcash/zcash-gitian)

1
qa/pull-tester/rpc-tests.sh

@ -15,6 +15,7 @@ testScripts=(
'wallet_protectcoinbase.py'
'wallet.py'
'wallet_nullifiers.py'
'wallet_1941.py'
'listtransactions.py'
'mempool_resurrect_test.py'
'txn_doublespend.py'

1
qa/pull-tester/run-bitcoind-for-test.sh.in

@ -7,6 +7,7 @@ ZCASH_LOAD_TIMEOUT=500
DATADIR="@abs_top_builddir@/.zcash"
rm -rf "$DATADIR"
mkdir -p "$DATADIR"/regtest
touch "$DATADIR/zcash.conf"
touch "$DATADIR/regtest/debug.log"
tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" &
WAITER=$!

2
qa/rpc-tests/wallet.py

@ -301,7 +301,7 @@ class WalletTest (BitcoinTestFramework):
opids = []
opids.append(myopid)
timeout = 120
timeout = 300
status = None
for x in xrange(1, timeout):
results = self.nodes[2].z_getoperationresult(opids)

106
qa/rpc-tests/wallet_1941.py

@ -0,0 +1,106 @@
#!/usr/bin/env python2
# Copyright (c) 2016 The Zcash developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# This is a regression test for #1941.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from time import *
import sys
starttime = 1388534400
class Wallet1941RegressionTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 1)
# Start nodes with -regtestprotectcoinbase to set fCoinbaseMustBeProtected to true.
def setup_network(self, split=False):
self.nodes = start_nodes(1, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase','-debug=zrpc']] )
self.is_network_split=False
def add_second_node(self):
initialize_datadir(self.options.tmpdir, 1)
self.nodes.append(start_node(1, self.options.tmpdir, extra_args=['-regtestprotectcoinbase','-debug=zrpc']))
self.nodes[1].setmocktime(starttime + 9000)
connect_nodes_bi(self.nodes,0,1)
self.sync_all()
def wait_and_assert_operationid_status(self, myopid, in_status='success', in_errormsg=None):
print('waiting for async operation {}'.format(myopid))
opids = []
opids.append(myopid)
timeout = 300
status = None
errormsg = None
for x in xrange(1, timeout):
results = self.nodes[0].z_getoperationresult(opids)
if len(results)==0:
sleep(1)
else:
status = results[0]["status"]
if status == "failed":
errormsg = results[0]['error']['message']
break
print('...returned status: {}'.format(status))
print('...error msg: {}'.format(errormsg))
assert_equal(in_status, status)
if errormsg is not None:
assert(in_errormsg is not None)
assert_equal(in_errormsg in errormsg, True)
print('...returned error: {}'.format(errormsg))
def run_test (self):
print "Mining blocks..."
self.nodes[0].setmocktime(starttime)
self.nodes[0].generate(101)
mytaddr = self.nodes[0].getnewaddress() # where coins were mined
myzaddr = self.nodes[0].z_getnewaddress()
# Send 10 coins to our zaddr.
recipients = []
recipients.append({"address":myzaddr, "amount":Decimal('10.0') - Decimal('0.0001')})
myopid = self.nodes[0].z_sendmany(mytaddr, recipients)
self.wait_and_assert_operationid_status(myopid)
self.nodes[0].generate(1)
# Ensure the block times of the latest blocks exceed the variability
self.nodes[0].setmocktime(starttime + 3000)
self.nodes[0].generate(1)
self.nodes[0].setmocktime(starttime + 6000)
self.nodes[0].generate(1)
self.nodes[0].setmocktime(starttime + 9000)
self.nodes[0].generate(1)
# Confirm the balance on node 0.
resp = self.nodes[0].z_getbalance(myzaddr)
assert_equal(Decimal(resp), Decimal('10.0') - Decimal('0.0001'))
# Export the key for the zaddr from node 0.
key = self.nodes[0].z_exportkey(myzaddr)
# Start the new wallet
self.add_second_node()
self.nodes[1].getnewaddress()
self.nodes[1].z_getnewaddress()
self.nodes[1].generate(101)
self.sync_all()
# Import the key on node 1.
self.nodes[1].z_importkey(key)
# Confirm that the balance on node 1 is valid now (node 1 must
# have rescanned)
resp = self.nodes[1].z_getbalance(myzaddr)
assert_equal(Decimal(resp), Decimal('10.0') - Decimal('0.0001'))
if __name__ == '__main__':
Wallet1941RegressionTest().main()

8
qa/rpc-tests/wallet_protectcoinbase.py

@ -98,6 +98,14 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
else:
status = results[0]["status"]
errorString = results[0]["error"]["message"]
# Test that the returned status object contains a params field with the operation's input parameters
params =results[0]["params"]
assert_equal(params["fee"], Decimal('0.0001')) # default
assert_equal(params["minconf"], Decimal('1')) # default
assert_equal(params["fromaddress"], mytaddr)
assert_equal(params["amounts"][0]["address"], myzaddr)
assert_equal(params["amounts"][0]["amount"], Decimal('1.23456789'))
break
assert_equal("failed", status)
assert_equal("wallet does not allow any change" in errorString, True)

31
qa/rpc-tests/walletbackup.py

@ -47,8 +47,13 @@ class WalletBackupTest(BitcoinTestFramework):
# This mirrors how the network was setup in the bash test
def setup_network(self, split=False):
# -exportdir option means we must provide a valid path to the destination folder for wallet backups
ed0 = "-exportdir=" + self.options.tmpdir + "/node0"
ed1 = "-exportdir=" + self.options.tmpdir + "/node1"
ed2 = "-exportdir=" + self.options.tmpdir + "/node2"
# nodes 1, 2,3 are spenders, let's give them a keypool=100
extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
extra_args = [["-keypool=100", ed0], ["-keypool=100", ed1], ["-keypool=100", ed2], []]
self.nodes = start_nodes(4, self.options.tmpdir, extra_args)
connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[1], 3)
@ -122,12 +127,12 @@ class WalletBackupTest(BitcoinTestFramework):
logging.info("Backing up")
tmpdir = self.options.tmpdir
self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak")
self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump")
self.nodes[1].backupwallet(tmpdir + "/node1/wallet.bak")
self.nodes[1].dumpwallet(tmpdir + "/node1/wallet.dump")
self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak")
self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump")
self.nodes[0].backupwallet("walletbak")
self.nodes[0].dumpwallet("walletdump")
self.nodes[1].backupwallet("walletbak")
self.nodes[1].dumpwallet("walletdump")
self.nodes[2].backupwallet("walletbak")
self.nodes[2].dumpwallet("walletdump")
logging.info("More transactions")
for i in range(5):
@ -159,9 +164,9 @@ class WalletBackupTest(BitcoinTestFramework):
shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
# Restore wallets from backup
shutil.copyfile(tmpdir + "/node0/wallet.bak", tmpdir + "/node0/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/node0/walletbak", tmpdir + "/node0/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/node1/walletbak", tmpdir + "/node1/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/node2/walletbak", tmpdir + "/node2/regtest/wallet.dat")
logging.info("Re-starting nodes")
self.start_three()
@ -185,9 +190,9 @@ class WalletBackupTest(BitcoinTestFramework):
assert_equal(self.nodes[1].getbalance(), 0)
assert_equal(self.nodes[2].getbalance(), 0)
self.nodes[0].importwallet(tmpdir + "/node0/wallet.dump")
self.nodes[1].importwallet(tmpdir + "/node1/wallet.dump")
self.nodes[2].importwallet(tmpdir + "/node2/wallet.dump")
self.nodes[0].importwallet(tmpdir + "/node0/walletdump")
self.nodes[1].importwallet(tmpdir + "/node1/walletdump")
self.nodes[2].importwallet(tmpdir + "/node2/walletdump")
sync_blocks(self.nodes)

11
qa/zcash/performance-measurements.sh

@ -5,7 +5,7 @@ set -e
DATADIR=./benchmark-datadir
function zcash_rpc {
./src/zcash-cli -rpcwait -rpcuser=user -rpcpassword=password -rpcport=5983 "$@"
./src/zcash-cli -datadir="$DATADIR" -rpcwait -rpcuser=user -rpcpassword=password -rpcport=5983 "$@"
}
function zcashd_generate {
@ -15,6 +15,7 @@ function zcashd_generate {
function zcashd_start {
rm -rf "$DATADIR"
mkdir -p "$DATADIR"
touch "$DATADIR/zcash.conf"
./src/zcashd -regtest -datadir="$DATADIR" -rpcuser=user -rpcpassword=password -rpcport=5983 -showmetrics=0 &
ZCASHD_PID=$!
}
@ -27,6 +28,7 @@ function zcashd_stop {
function zcashd_massif_start {
rm -rf "$DATADIR"
mkdir -p "$DATADIR"
touch "$DATADIR/zcash.conf"
rm -f massif.out
valgrind --tool=massif --time-unit=ms --massif-out-file=massif.out ./src/zcashd -regtest -datadir="$DATADIR" -rpcuser=user -rpcpassword=password -rpcport=5983 -showmetrics=0 &
ZCASHD_PID=$!
@ -41,6 +43,7 @@ function zcashd_massif_stop {
function zcashd_valgrind_start {
rm -rf "$DATADIR"
mkdir -p "$DATADIR"
touch "$DATADIR/zcash.conf"
rm -f valgrind.out
valgrind --leak-check=yes -v --error-limit=no --log-file="valgrind.out" ./src/zcashd -regtest -datadir="$DATADIR" -rpcuser=user -rpcpassword=password -rpcport=5983 -showmetrics=0 &
ZCASHD_PID=$!
@ -74,7 +77,7 @@ case "$1" in
zcash_rpc zcbenchmark parameterloading 10
;;
createjoinsplit)
zcash_rpc zcbenchmark createjoinsplit 10
zcash_rpc zcbenchmark createjoinsplit 10 "${@:3}"
;;
verifyjoinsplit)
zcash_rpc zcbenchmark verifyjoinsplit 1000 "\"$RAWJOINSPLIT\""
@ -111,7 +114,7 @@ case "$1" in
zcash_rpc zcbenchmark parameterloading 1
;;
createjoinsplit)
zcash_rpc zcbenchmark createjoinsplit 1
zcash_rpc zcbenchmark createjoinsplit 1 "${@:3}"
;;
verifyjoinsplit)
zcash_rpc zcbenchmark verifyjoinsplit 1 "\"$RAWJOINSPLIT\""
@ -146,7 +149,7 @@ case "$1" in
zcash_rpc zcbenchmark parameterloading 1
;;
createjoinsplit)
zcash_rpc zcbenchmark createjoinsplit 1
zcash_rpc zcbenchmark createjoinsplit 1 "${@:3}"
;;
verifyjoinsplit)
zcash_rpc zcbenchmark verifyjoinsplit 1 "\"$RAWJOINSPLIT\""

3
src/Makefile.am

@ -59,6 +59,7 @@ LIBZCASH_CONSENSUS=
endif
bin_PROGRAMS =
noinst_PROGRAMS =
TESTS =
if BUILD_BITCOIND
@ -482,7 +483,7 @@ libzcashconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCO
endif
#
CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno
CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno */*.gcno wallet/*/*.gcno
DISTCLEANFILES = obj/build.h

8
src/Makefile.gtest.include

@ -1,3 +1,4 @@
TESTS += komodo-gtest
bin_PROGRAMS += komodo-gtest
@ -10,6 +11,13 @@ komodo_gtest_SOURCES = \
gtest/json_test_vectors.h \
# gtest/test_foundersreward.cpp \
gtest/test_wallet_zkeys.cpp \
# These tests are order-dependent, because they
# depend on global state (see #1539)
if ENABLE_WALLET
zcash_gtest_SOURCES += \
wallet/gtest/test_wallet_zkeys.cpp
endif
zcash_gtest_SOURCES += \
gtest/test_jsonspirit.cpp \
gtest/test_tautology.cpp \
gtest/test_equihash.cpp \

2
src/Makefile.test.include

@ -1,5 +1,5 @@
TESTS += test/test_bitcoin
bin_PROGRAMS += test/test_bitcoin
noinst_PROGRAMS += test/test_bitcoin
TEST_SRCDIR = test
TEST_BINARY=test/test_bitcoin$(EXEEXT)

15
src/Makefile.zcash.include

@ -1,5 +1,6 @@
bin_PROGRAMS += \
zcash/GenerateParams
noinst_PROGRAMS += \
zcash/GenerateParams \
zcash/CreateJoinSplit
# tool for generating our public parameters
zcash_GenerateParams_SOURCES = zcash/GenerateParams.cpp
@ -9,3 +10,13 @@ zcash_GenerateParams_LDADD = \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZCASH_LIBS)
# tool for profiling the creation of joinsplits
zcash_CreateJoinSplit_SOURCES = zcash/CreateJoinSplit.cpp
zcash_CreateJoinSplit_LDADD = \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZCASH) \
$(BOOST_LIBS) \
$(LIBZCASH_LIBS)

3
src/asyncrpcoperation.h

@ -66,7 +66,8 @@ public:
return creation_time_;
}
Value getStatus() const;
// Override this method to add data to the default status object.
virtual Value getStatus() const;
Value getError() const;

26
src/bitcoin-cli.cpp

@ -87,6 +87,8 @@ static bool AppInitRPC(int argc, char* argv[])
" komodo-cli [options] help <command> " + _("Get help for a command") + "\n";
strUsage += "\n" + HelpMessageCli();
} else {
strUsage += LicenseInfo();
}
fprintf(stdout, "%s", strUsage.c_str());
@ -112,12 +114,6 @@ static bool AppInitRPC(int argc, char* argv[])
Object CallRPC(const string& strMethod, const Array& params)
{
if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
throw runtime_error(strprintf(
_("You must set rpcpassword=<password> in the configuration file:\n%s\n"
"If the file does not exist, create it with owner-readable-only file permissions."),
GetConfigFile().string().c_str()));
// Connect to localhost
bool fUseSSL = GetBoolArg("-rpcssl", false);
boost::asio::io_service io_service;
@ -131,10 +127,24 @@ Object CallRPC(const string& strMethod, const Array& params)
if (!fConnected)
throw CConnectionFailed("couldn't connect to server");
// Find credentials to use
std::string strRPCUserColonPass;
if (mapArgs["-rpcpassword"] == "") {
// Try fall back to cookie-based authentication if no password is provided
if (!GetAuthCookie(&strRPCUserColonPass)) {
throw runtime_error(strprintf(
_("You must set rpcpassword=<password> in the configuration file:\n%s\n"
"If the file does not exist, create it with owner-readable-only file permissions."),
GetConfigFile().string().c_str()));
}
} else {
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
}
// HTTP basic authentication
string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
map<string, string> mapRequestHeaders;
mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
mapRequestHeaders["Authorization"] = string("Basic ") + EncodeBase64(strRPCUserColonPass);
// Send request
string strRequest = JSONRPCRequest(strMethod, params, 1);

18
src/bitcoind.cpp

@ -115,6 +115,24 @@ bool AppInit(int argc, char* argv[])
try
{
ReadConfigFile(mapArgs, mapMultiArgs);
} catch (const missing_zcash_conf& e) {
fprintf(stderr,
(_("Before starting zcashd, you need to create a configuration file:\n"
"%s\n"
"It can be completely empty! That indicates you are happy with the default\n"
"configuration of zcashd. But requiring a configuration file to start ensures\n"
"that zcashd won't accidentally compromise your privacy if there was a default\n"
"option you needed to change.\n"
"\n"
"You can look at the example configuration file for suggestions of default\n"
"options that you may want to change. It should be in one of these locations,\n"
"depending on how you installed Zcash:\n") +
_("- Source code: %s\n"
"- .deb package: %s\n")).c_str(),
GetConfigFile().string().c_str(),
"contrib/DEBIAN/examples/zcash.conf",
"/usr/share/doc/zcash/examples/zcash.conf");
return false;
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;

2
src/clientversion.h

@ -16,7 +16,7 @@
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 1
#define CLIENT_VERSION_MINOR 0
#define CLIENT_VERSION_REVISION 3
#define CLIENT_VERSION_REVISION 5
#define CLIENT_VERSION_BUILD 50
//! Set to true for release, false for prerelease or test build

5
src/gtest/test_checkblock.cpp

@ -3,6 +3,7 @@
#include "consensus/validation.h"
#include "main.h"
#include "zcash/Proof.hpp"
class MockCValidationState : public CValidationState {
public:
@ -22,12 +23,14 @@ public:
};
TEST(CheckBlock, VersionTooLow) {
auto verifier = libzcash::ProofVerifier::Strict();
CBlock block;
block.nVersion = 1;
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "version-too-low", false)).Times(1);
EXPECT_FALSE(CheckBlock(0,0,block, state, false, false));
EXPECT_FALSE(CheckBlock(0,0,block, state, verifier, false, false));
}
TEST(ContextualCheckBlock, BadCoinbaseHeight) {

4
src/gtest/test_keystore.cpp

@ -2,7 +2,9 @@
#include "keystore.h"
#include "random.h"
#ifdef ENABLE_WALLET
#include "wallet/crypter.h"
#endif
#include "zcash/Address.hpp"
TEST(keystore_tests, store_and_retrieve_spending_key) {
@ -44,6 +46,7 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) {
EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
}
#ifdef ENABLE_WALLET
class TestCCryptoKeyStore : public CCryptoKeyStore
{
public:
@ -125,3 +128,4 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) {
ASSERT_EQ(1, addrs.count(addr));
ASSERT_EQ(1, addrs.count(addr2));
}
#endif

6
src/gtest/test_merkletree.cpp

@ -79,6 +79,9 @@ void test_tree(
// The tree doesn't have a 'last' element added since it's blank.
ASSERT_THROW(tree.last(), std::runtime_error);
// The tree is empty.
ASSERT_TRUE(tree.size() == 0);
// We need to witness at every single point in the tree, so
// that the consistency of the tree and the merkle paths can
// be checked.
@ -93,6 +96,9 @@ void test_tree(
// Now append a commitment to the tree
tree.append(test_commitment);
// Size incremented by one.
ASSERT_TRUE(tree.size() == i+1);
// Last element added to the tree was `test_commitment`
ASSERT_TRUE(tree.last() == test_commitment);

61
src/gtest/test_proofs.cpp

@ -22,6 +22,67 @@ typedef libsnark::default_r1cs_ppzksnark_pp::Fqe_type curve_Fq2;
#include "version.h"
#include "utilstrencodings.h"
TEST(proofs, g2_subgroup_check)
{
// all G2 elements are order r
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * curve_G2::random_element() == curve_G2::zero());
// but that doesn't mean all elements that satisfy the curve equation are in G2...
curve_G2 p = curve_G2::one();
while (1) {
// This will construct an order r(2q-r) point with high probability
p.X = curve_Fq2::random_element();
try {
p.Y = ((p.X.squared() * p.X) + libsnark::alt_bn128_twist_coeff_b).sqrt();
break;
} catch(...) {}
}
ASSERT_TRUE(p.is_well_formed()); // it's on the curve
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p != curve_G2::zero()); // but not the order r subgroup..
{
// libsnark unfortunately doesn't check, and the pairing will complete
auto e = curve_Fr("149");
auto a = curve_pp::reduced_pairing(curve_G1::one(), p);
auto b = curve_pp::reduced_pairing(e * curve_G1::one(), p);
// though it will not preserve bilinearity
ASSERT_TRUE((a^e) != b);
}
{
// so, our decompression API should not allow you to decompress G2 elements of that form!
CompressedG2 badp(p);
try {
auto newp = badp.to_libsnark_g2<curve_G2>();
FAIL() << "Expected std::runtime_error";
} catch (std::runtime_error const & err) {
EXPECT_EQ(err.what(), std::string("point is not in G2"));
} catch(...) {
FAIL() << "Expected std::runtime_error";
}
}
// educational purposes: showing that E'(Fp2) is of order r(2q-r),
// by multiplying our random point in E' by (2q-r) = (q + q - r) to
// get an element in G2
{
auto p1 = libsnark::alt_bn128_modulus_q * p;
p1 = p1 + p1;
p1 = p1 - (libsnark::alt_bn128_modulus_r * p);
ASSERT_TRUE(p1.is_well_formed());
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p1 == curve_G2::zero());
CompressedG2 goodp(p1);
auto newp = goodp.to_libsnark_g2<curve_G2>();
ASSERT_TRUE(newp == p1);
}
}
TEST(proofs, sqrt_zero)
{
ASSERT_TRUE(curve_Fq::zero() == curve_Fq::zero().sqrt());

17
src/init.cpp

@ -289,6 +289,7 @@ std::string HelpMessage(HelpMessageMode mode)
#endif
}
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
strUsage += HelpMessageOpt("-exportdir=<dir>", _("Specify directory to be used when exporting data"));
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup"));
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
@ -376,11 +377,12 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", 1));
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0));
}
string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net, proxy, prune"; // Don't translate these and qt below
string debugCategories = "addrman, alert, bench, coindb, db, estimatefee, lock, mempool, net, partitioncheck, pow, proxy, prune, "
"rand, reindex, rpc, selectcoins, zrpc, zrpcunsafe"; // Don't translate these and qt below
if (mode == HMM_BITCOIN_QT)
debugCategories += ", qt";
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
_("If <category> is not supplied or if <category> = 1, output all debugging information.") + _("<category> can be:") + " " + debugCategories + ".");
_("If <category> is not supplied or if <category> = 1, output all debugging information.") + " " + _("<category> can be:") + " " + debugCategories + ".");
#ifdef ENABLE_WALLET
strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0));
strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1));
@ -625,6 +627,17 @@ static void ZC_LoadParams()
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
if (!(boost::filesystem::exists(pk_path) && boost::filesystem::exists(vk_path))) {
uiInterface.ThreadSafeMessageBox(strprintf(
_("Cannot find the Zcash network parameters in the following directory:\n"
"%s\n"
"Please run 'zcash-fetch-params' or './zcutil/fetch-params.sh' and then restart."),
ZC_GetParamsDir()),
"", CClientUIInterface::MSG_ERROR);
StartShutdown();
return;
}
pzcashParams = ZCJoinSplit::Unopened();
LogPrintf("Loading verifying key from %s\n", vk_path.string().c_str());

2
src/init.h

@ -34,7 +34,5 @@ enum HelpMessageMode {
/** Help for options shared between UI and daemon (for -help) */
std::string HelpMessage(HelpMessageMode mode);
/** Returns licensing information (for -version) */
std::string LicenseInfo();
#endif // BITCOIN_INIT_H

47
src/main.cpp

@ -860,7 +860,8 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
return nSigOps;
}
bool CheckTransaction(const CTransaction& tx, CValidationState &state)
bool CheckTransaction(const CTransaction& tx, CValidationState &state,
libzcash::ProofVerifier& verifier)
{
// Don't count coinbase transactions because mining skews the count
if (!tx.IsCoinBase()) {
@ -871,7 +872,6 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return false;
} else {
// Ensure that zk-SNARKs verify
auto verifier = libzcash::ProofVerifier::Strict();
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) {
return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"),
@ -1082,11 +1082,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
AssertLockHeld(cs_main);
if (pfMissingInputs)
*pfMissingInputs = false;
if (!CheckTransaction(tx, state))
{
fprintf(stderr,"AcceptToMemoryPool CheckTransaction failed\n");
auto verifier = libzcash::ProofVerifier::Strict();
if (!CheckTransaction(tx, state, verifier))
return error("AcceptToMemoryPool: CheckTransaction failed");
}
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
{
@ -2142,7 +2140,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
const CChainParams& chainparams = Params();
AssertLockHeld(cs_main);
// Check it again in case a previous version let a bad block in
if (!CheckBlock(pindex->nHeight,pindex,block, state, !fJustCheck, !fJustCheck))
bool fExpensiveChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()));
auto verifier = libzcash::ProofVerifier::Strict();
auto disabledVerifier = libzcash::ProofVerifier::Disabled();
// Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in
if (!CheckBlock(pindex->nHeight,pindex,block, state, fExpensiveChecks ? verifier : disabledVerifier, !fJustCheck, !fJustCheck))
return false;
// verify that the view's current state corresponds to the previous block
@ -2161,9 +2164,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return true;
}
<<<<<<< HEAD
bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()));
//if ( KOMODO_TESTNET_EXPIRATION != 0 && pindex->nHeight > KOMODO_TESTNET_EXPIRATION ) // "testnet"
// return(false);
=======
>>>>>>> zcash/master
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
BOOST_FOREACH(const CTransaction& tx, block.vtx) {
@ -2189,7 +2195,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
CCheckQueueControl<CScriptCheck> control(fExpensiveChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
int64_t nTimeStart = GetTimeMicros();
CAmount nFees = 0;
@ -2251,7 +2257,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
nFees += view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime) - tx.GetValueOut();
sum += interest;
std::vector<CScriptCheck> vChecks;
if (!ContextualCheckInputs(tx, state, view, fScriptChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
return false;
control.Add(vChecks);
}
@ -3094,7 +3100,9 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl
}
int32_t komodo_check_deposit(int32_t height,const CBlock& block);
bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot)
bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state,
libzcash::ProofVerifier& verifier,
bool fCheckPOW, bool fCheckMerkleRoot)
{
// These are checks that are independent of context.
@ -3139,7 +3147,7 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat
// Check transactions
BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state))
if (!CheckTransaction(tx, state, verifier))
return error("CheckBlock(): CheckTransaction failed");
unsigned int nSigOps = 0;
@ -3310,7 +3318,9 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
if (fTooFarAhead) return true; // Block height is too high
}
if ((!CheckBlock(pindex->nHeight,pindex,block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
// See method docstring for why this is always disabled
auto verifier = libzcash::ProofVerifier::Disabled();
if ((!CheckBlock(pindex->nHeight,block, state, verifier)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
if (state.IsInvalid() && !state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
@ -3361,11 +3371,12 @@ bool ProcessNewBlock(int32_t height,CValidationState &state, CNode* pfrom, CBloc
{
// Preliminary checks
bool checked;
auto verifier = libzcash::ProofVerifier::Disabled();
if ( chainActive.Tip() != 0 )
komodo_currentheight_set(chainActive.Tip()->nHeight);
if ( ASSETCHAINS_SYMBOL[0] == 0 )
checked = CheckBlock(height!=0?height:komodo_block2height(pblock),0,*pblock, state);
else checked = CheckBlock(0,0,*pblock, state);
checked = CheckBlock(height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier);
else checked = CheckBlock(0,0,*pblock, state, verifier);
{
LOCK(cs_main);
bool fRequested = MarkBlockAsReceived(pblock->GetHash());
@ -3400,11 +3411,13 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1;
// JoinSplit proofs are verified in ConnectBlock
auto verifier = libzcash::ProofVerifier::Disabled();
// NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
return false;
if (!CheckBlock(indexDummy.nHeight,0,block, state, fCheckPOW, fCheckMerkleRoot))
if (!CheckBlock(indexDummy.nHeight,0,block, state, verifier, fCheckPOW, fCheckMerkleRoot))
return false;
if (!ContextualCheckBlock(block, state, pindexPrev))
return false;
@ -3725,6 +3738,8 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0;
CValidationState state;
// No need to verify JoinSplits twice
auto verifier = libzcash::ProofVerifier::Disabled();
for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
{
boost::this_thread::interruption_point();
@ -3736,7 +3751,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 1: verify block validity
if (nCheckLevel >= 1 && !CheckBlock(pindex->nHeight,pindex,block, state))
if (nCheckLevel >= 1 && !CheckBlock(pindex->nHeight,pindex,block, state, verifier))
return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) {

16
src/main.h

@ -339,7 +339,7 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight);
/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier);
bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state);
/** Check for standard transaction types
@ -415,8 +415,10 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
/** Context-independent validity checks */
bool CheckBlockHeader(int32_t height,CBlockIndex *pindex,const CBlockHeader& blockhdr, CValidationState& state, bool fCheckPOW = true);
bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
bool CheckBlockHeader(int32_t height,CBlockIndex *pindex,const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state,
libzcash::ProofVerifier& verifier,
bool fCheckPOW = true, bool fCheckMerkleRoot = true);
/** Context-dependent validity checks */
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev);
@ -425,7 +427,13 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
/**
* Store block on disk.
* JoinSplit proofs are never verified, because:
* - AcceptBlock doesn't perform script checks either.
* - The only caller of AcceptBlock verifies JoinSplit proofs elsewhere.
* If dbp is non-NULL, the file is known to already reside on disk
*/
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);

35
src/metrics.cpp

@ -20,6 +20,7 @@
CCriticalSection cs_metrics;
boost::synchronized_value<int64_t> nNodeStartTime;
boost::synchronized_value<int64_t> nNextRefresh;
AtomicCounter transactionsValidated;
AtomicCounter ehSolverRuns;
AtomicCounter solutionTargetChecks;
@ -60,10 +61,20 @@ double GetLocalSolPS()
return GetLocalSolPS_INTERNAL(GetUptime());
}
void TriggerRefresh()
{
*nNextRefresh = GetTime();
// Ensure that the refresh has started before we return
MilliSleep(200);
}
static bool metrics_ThreadSafeMessageBox(const std::string& message,
const std::string& caption,
unsigned int style)
{
// The SECURE flag has no effect in the metrics UI.
style &= ~CClientUIInterface::SECURE;
std::string strCaption;
// Check for usage of predefined caption
switch (style) {
@ -85,6 +96,9 @@ static bool metrics_ThreadSafeMessageBox(const std::string& message,
if (u->size() > 5) {
u->pop_back();
}
TriggerRefresh();
return false;
}
static void metrics_InitMessage(const std::string& message)
@ -247,8 +261,21 @@ int printMessageBox(size_t cols)
std::cout << _("Messages:") << std::endl;
for (auto it = u->cbegin(); it != u->cend(); ++it) {
std::cout << *it << std::endl;
// Handle wrapped lines
lines += (it->size() / cols);
// Handle newlines and wrapped lines
size_t i = 0;
size_t j = 0;
while (j < it->size()) {
i = it->find('\n', j);
if (i == std::string::npos) {
i = it->size();
} else {
// Newline
lines++;
}
// Wrapped lines
lines += ((i-j) / cols);
j = i + 1;
}
}
std::cout << std::endl;
return lines;
@ -333,8 +360,8 @@ void ThreadShowMetricsScreen()
std::cout << "----------------------------------------" << std::endl;
}
int64_t nWaitEnd = GetTime() + nRefresh;
while (GetTime() < nWaitEnd) {
*nNextRefresh = GetTime() + nRefresh;
while (GetTime() < *nNextRefresh) {
boost::this_thread::interruption_point();
MilliSleep(200);
}

2
src/metrics.h

@ -34,6 +34,8 @@ void TrackMinedBlock(uint256 hash);
void MarkStartTime();
double GetLocalSolPS();
void TriggerRefresh();
void ConnectMetricsScreen();
void ThreadShowMetricsScreen();

5
src/rpcblockchain.cpp

@ -806,6 +806,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
" \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
" \"commitments\": xxxxxx, (numeric) the current number of note commitments in the commitment tree\n"
" \"softforks\": [ (array) status of softforks in progress\n"
" {\n"
" \"id\": \"xxxx\", (string) name of softfork\n"
@ -837,6 +838,10 @@ Value getblockchaininfo(const Array& params, bool fHelp)
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
obj.push_back(Pair("pruned", fPruneMode));
ZCIncrementalMerkleTree tree;
pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), tree);
obj.push_back(Pair("commitments", tree.size()));
const Consensus::Params& consensusParams = Params().GetConsensus();
CBlockIndex* tip = chainActive.Tip();
Array softforks;

2
src/rpcmining.cpp

@ -405,6 +405,7 @@ static Value BIP22ValidationResult(const CValidationState& state)
return "valid?";
}
#ifdef ENABLE_WALLET
Value getblocktemplate(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 1)
@ -697,6 +698,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
return result;
}
#endif
class submitblock_StateCatcher : public CValidationInterface
{

67
src/rpcprotocol.cpp

@ -6,6 +6,7 @@
#include "rpcprotocol.h"
#include "clientversion.h"
#include "random.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
@ -13,6 +14,7 @@
#include "version.h"
#include <stdint.h>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
@ -288,3 +290,68 @@ Object JSONRPCError(int code, const string& message)
error.push_back(Pair("message", message));
return error;
}
/** Username used when cookie authentication is in use (arbitrary, only for
* recognizability in debugging/logging purposes)
*/
static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";
boost::filesystem::path GetAuthCookieFile()
{
boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
if (!path.is_complete()) path = GetDataDir() / path;
return path;
}
bool GenerateAuthCookie(std::string *cookie_out)
{
unsigned char rand_pwd[32];
GetRandBytes(rand_pwd, 32);
std::string cookie = COOKIEAUTH_USER + ":" + EncodeBase64(&rand_pwd[0],32);
/** the umask determines what permissions are used to create this file -
* these are set to 077 in init.cpp unless overridden with -sysperms.
*/
std::ofstream file;
boost::filesystem::path filepath = GetAuthCookieFile();
file.open(filepath.string().c_str());
if (!file.is_open()) {
LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
return false;
}
file << cookie;
file.close();
LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
if (cookie_out)
*cookie_out = cookie;
return true;
}
bool GetAuthCookie(std::string *cookie_out)
{
std::ifstream file;
std::string cookie;
boost::filesystem::path filepath = GetAuthCookieFile();
file.open(filepath.string().c_str());
if (!file.is_open())
return false;
std::getline(file, cookie);
file.close();
if (cookie_out)
*cookie_out = cookie;
return true;
}
void DeleteAuthCookie()
{
try {
boost::filesystem::remove(GetAuthCookieFile());
} catch (const boost::filesystem::filesystem_error& e) {
LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what());
}
}

10
src/rpcprotocol.h

@ -14,6 +14,7 @@
#include <boost/iostreams/stream.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/filesystem.hpp>
#include "json/json_spirit_reader_template.h"
#include "json/json_spirit_utils.h"
@ -165,4 +166,13 @@ json_spirit::Object JSONRPCReplyObj(const json_spirit::Value& result, const json
std::string JSONRPCReply(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id);
json_spirit::Object JSONRPCError(int code, const std::string& message);
/** Get name of RPC authentication cookie file */
boost::filesystem::path GetAuthCookieFile();
/** Generate a new RPC authentication cookie and write it to disk */
bool GenerateAuthCookie(std::string *cookie_out);
/** Read the RPC authentication cookie from disk */
bool GetAuthCookie(std::string *cookie_out);
/** Delete RPC authentication cookie from disk */
void DeleteAuthCookie();
#endif // BITCOIN_RPCPROTOCOL_H

21
src/rpcserver.cpp

@ -309,7 +309,9 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "kvupdate", &kvupdate, true },
/* Mining */
#ifdef ENABLE_WALLET
{ "mining", "getblocktemplate", &getblocktemplate, true },
#endif
{ "mining", "getmininginfo", &getmininginfo, true },
{ "mining", "getlocalsolps", &getlocalsolps, true },
{ "mining", "getnetworksolps", &getnetworksolps, true },
@ -629,10 +631,9 @@ void StartRPCThreads()
strAllowed += subnet.ToString() + " ";
LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
if (((mapArgs["-rpcpassword"] == "") ||
(mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword())
if (mapArgs["-rpcpassword"] == "")
{
/*<<<<<<< HEAD
unsigned char rand_pwd[32];
GetRandBytes(rand_pwd, 32);
uiInterface.ThreadSafeMessageBox(strprintf(
@ -651,6 +652,18 @@ void StartRPCThreads()
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE);
StartShutdown();
return;
=======*/
LogPrintf("No rpcpassword set - using random cookie authentication\n");
if (!GenerateAuthCookie(&strRPCUserColonPass)) {
uiInterface.ThreadSafeMessageBox(
_("Error: A fatal internal error occured, see debug.log for details"), // Same message as AbortNode
"", CClientUIInterface::MSG_ERROR);
StartShutdown();
return;
}
} else {
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
//>>>>>>> zcash/master
}
assert(rpc_io_service == NULL);
@ -817,6 +830,8 @@ void StopRPCThreads()
}
deadlineTimers.clear();
DeleteAuthCookie();
rpc_io_service->stop();
g_rpcSignals.Stopped();
if (rpc_worker_group != NULL)

4
src/test/checkblock_tests.cpp

@ -7,6 +7,7 @@
#include "main.h"
#include "test/test_bitcoin.h"
#include "utiltime.h"
#include "zcash/Proof.hpp"
#include <cstdio>
@ -56,7 +57,8 @@ BOOST_AUTO_TEST_CASE(May15)
// After May 15'th, big blocks are OK:
forkingBlock.nTime = tMay15; // Invalidates PoW
BOOST_CHECK(CheckBlock(0,0,forkingBlock, state, false, false));
auto verifier = libzcash::ProofVerifier::Strict();
BOOST_CHECK(CheckBlock(forkingBlock, state, verifier, false, false));
}
SetMockTime(0);

22
src/test/rpc_wallet_tests.cpp

@ -358,16 +358,26 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==1);
// Set up paths
boost::filesystem::path tmppath = boost::filesystem::temp_directory_path();
boost::filesystem::path tmpfilename = boost::filesystem::unique_path("%%%%%%%%");
boost::filesystem::path exportfilepath = tmppath / tmpfilename;
// export will fail since exportdir is not set
BOOST_CHECK_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string()), runtime_error);
// set exportdir
mapArgs["-exportdir"] = tmppath.native();
// run some tests
BOOST_CHECK_THROW(CallRPC("z_exportwallet"), runtime_error);
BOOST_CHECK_THROW(CallRPC("z_exportwallet toomany args"), runtime_error);
boost::filesystem::path temp = boost::filesystem::temp_directory_path() /
boost::filesystem::unique_path();
const std::string path = temp.native();
BOOST_CHECK_THROW(CallRPC(string("z_exportwallet invalid!*/_chars.txt")), runtime_error);
BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string()));
BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + path));
auto addr = paymentAddress.Get();
libzcash::SpendingKey key;
@ -382,7 +392,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
EnsureWalletIsUnlocked();
ifstream file;
file.open(path.c_str(), std::ios::in | std::ios::ate);
file.open(exportfilepath.string().c_str(), std::ios::in | std::ios::ate);
BOOST_CHECK(file.is_open());
bool fVerified = false;
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());

29
src/test/transaction_tests.cpp

@ -29,6 +29,7 @@
#include "zcash/Note.hpp"
#include "zcash/Address.hpp"
#include "zcash/Proof.hpp"
using namespace std;
using namespace json_spirit;
@ -97,6 +98,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
auto verifier = libzcash::ProofVerifier::Strict();
ScriptError err;
BOOST_FOREACH(Value& tv, tests)
{
@ -141,7 +143,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
stream >> tx;
CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier), strTest);
BOOST_CHECK(state.IsValid());
for (unsigned int i = 0; i < tx.vin.size(); i++)
@ -173,6 +175,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
auto verifier = libzcash::ProofVerifier::Strict();
ScriptError err;
BOOST_FOREACH(Value& tv, tests)
{
@ -217,7 +220,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
stream >> tx;
CValidationState state;
fValid = CheckTransaction(tx, state) && state.IsValid();
fValid = CheckTransaction(tx, state, verifier) && state.IsValid();
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{
@ -246,11 +249,12 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
CMutableTransaction tx;
stream >> tx;
CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid.");
auto verifier = libzcash::ProofVerifier::Strict();
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier) && state.IsValid(), "Simple deserialized transaction should be valid.");
// Check that duplicate txins fail
tx.vin.push_back(tx.vin[0]);
BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state, verifier) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
}
//
@ -373,6 +377,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
{
auto verifier = libzcash::ProofVerifier::Strict();
CMutableTransaction tx;
tx.nVersion = 2;
{
@ -424,23 +429,23 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
JSDescription *jsdesc = &newTx.vjoinsplit[0];
jsdesc->vpub_old = -1;
BOOST_CHECK(!CheckTransaction(newTx, state));
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-negative");
jsdesc->vpub_old = MAX_MONEY + 1;
BOOST_CHECK(!CheckTransaction(newTx, state));
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-toolarge");
jsdesc->vpub_old = 0;
jsdesc->vpub_new = -1;
BOOST_CHECK(!CheckTransaction(newTx, state));
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-negative");
jsdesc->vpub_new = MAX_MONEY + 1;
BOOST_CHECK(!CheckTransaction(newTx, state));
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-toolarge");
jsdesc->vpub_new = (MAX_MONEY / 2) + 10;
@ -450,7 +455,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
JSDescription *jsdesc2 = &newTx.vjoinsplit[1];
jsdesc2->vpub_new = (MAX_MONEY / 2) + 10;
BOOST_CHECK(!CheckTransaction(newTx, state));
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-txintotal-toolarge");
}
{
@ -464,7 +469,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
jsdesc->nullifiers[0] = GetRandHash();
jsdesc->nullifiers[1] = jsdesc->nullifiers[0];
BOOST_CHECK(!CheckTransaction(newTx, state));
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
jsdesc->nullifiers[1] = GetRandHash();
@ -475,7 +480,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
jsdesc2->nullifiers[0] = GetRandHash();
jsdesc2->nullifiers[1] = jsdesc->nullifiers[0];
BOOST_CHECK(!CheckTransaction(newTx, state));
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
}
{
@ -494,7 +499,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
CTransaction finalNewTx(newTx);
BOOST_CHECK(finalNewTx.IsCoinBase());
}
BOOST_CHECK(!CheckTransaction(newTx, state));
BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-joinsplits");
}
}

35
src/util.cpp

@ -501,6 +501,26 @@ const boost::filesystem::path &ZC_GetParamsDir()
return path;
}
// Return the user specified export directory. Create directory if it doesn't exist.
// If user did not set option, return an empty path.
// If there is a filesystem problem, throw an exception.
const boost::filesystem::path GetExportDir()
{
namespace fs = boost::filesystem;
fs::path path;
if (mapArgs.count("-exportdir")) {
path = fs::system_complete(mapArgs["-exportdir"]);
if (fs::exists(path) && !fs::is_directory(path)) {
throw std::runtime_error(strprintf("The -exportdir '%s' already exists and is not a directory", path.string()));
}
if (!fs::exists(path) && !fs::create_directories(path)) {
throw std::runtime_error(strprintf("Failed to create directory at -exportdir '%s'", path.string()));
}
}
return path;
}
const boost::filesystem::path &GetDataDir(bool fNetSpecific)
{
namespace fs = boost::filesystem;
@ -556,7 +576,7 @@ void ReadConfigFile(map<string, string>& mapSettingsRet,
{
boost::filesystem::ifstream streamConfig(GetConfigFile());
if (!streamConfig.good())
return; // No komodo.conf file is OK
throw missing_zcash_conf();
set<string> setOptions;
setOptions.insert("*");
@ -837,3 +857,16 @@ void SetThreadPriority(int nPriority)
#endif // PRIO_THREAD
#endif // WIN32
}
std::string LicenseInfo()
{
return FormatParagraph(strprintf(_("Copyright (C) 2009-%i The Bitcoin Core Developers"), COPYRIGHT_YEAR)) + "\n" +
FormatParagraph(strprintf(_("Copyright (C) 2015-%i The Zcash Developers"), COPYRIGHT_YEAR)) + "\n" +
"\n" +
FormatParagraph(_("This is experimental software.")) + "\n" +
"\n" +
FormatParagraph(_("Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>.")) + "\n" +
"\n" +
FormatParagraph(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.")) +
"\n";
}

8
src/util.h

@ -127,6 +127,10 @@ boost::filesystem::path GetConfigFile();
boost::filesystem::path GetPidFile();
void CreatePidFile(const boost::filesystem::path &path, pid_t pid);
#endif
class missing_zcash_conf : public std::runtime_error {
public:
missing_zcash_conf() : std::runtime_error("Missing komodo.conf") { }
};
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
#ifdef WIN32
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
@ -134,6 +138,10 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
boost::filesystem::path GetTempPath();
void ShrinkDebugFile();
void runCommand(std::string strCommand);
const boost::filesystem::path GetExportDir();
/** Returns licensing information (for -version) */
std::string LicenseInfo();
inline bool IsSwitchChar(char c)
{

16
src/utilstrencodings.cpp

@ -30,6 +30,22 @@ string SanitizeString(const string& str)
return strResult;
}
string SanitizeFilename(const string& str)
{
/**
* safeChars chosen to restrict filename, keeping it simple to avoid cross-platform issues.
* http://stackoverflow.com/a/2306003
*/
static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890");
string strResult;
for (std::string::size_type i = 0; i < str.size(); i++)
{
if (safeChars.find(str[i]) != std::string::npos)
strResult.push_back(str[i]);
}
return strResult;
}
const signed char p_util_hexdigit[256] =
{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,

1
src/utilstrencodings.h

@ -22,6 +22,7 @@
/** This is needed because the foreach macro can't get over the comma in pair<t1, t2> */
#define PAIRTYPE(t1, t2) std::pair<t1, t2>
std::string SanitizeFilename(const std::string& str);
std::string SanitizeString(const std::string& str);
std::vector<unsigned char> ParseHex(const char* psz);
std::vector<unsigned char> ParseHex(const std::string& str);

67
src/wallet/asyncrpcoperation_sendmany.cpp

@ -53,8 +53,9 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
std::vector<SendManyRecipient> tOutputs,
std::vector<SendManyRecipient> zOutputs,
int minDepth,
CAmount fee) :
fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth), fee_(fee)
CAmount fee,
Value contextInfo) :
fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth), fee_(fee), contextinfo_(contextInfo)
{
assert(fee_ > 0);
@ -88,7 +89,7 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
isfromzaddr_ = true;
frompaymentaddress_ = addr;
spendingkey_ = key;
} catch (std::runtime_error e) {
} catch (const std::runtime_error& e) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("runtime error: ") + e.what());
}
}
@ -108,17 +109,20 @@ void AsyncRPCOperation_sendmany::main() {
try {
success = main_impl();
} catch (Object objError) {
} catch (const Object& objError) {
int code = find_value(objError, "code").get_int();
std::string message = find_value(objError, "message").get_str();
set_error_code(code);
set_error_message(message);
} catch (runtime_error e) {
} catch (const runtime_error& e) {
set_error_code(-1);
set_error_message("runtime error: " + string(e.what()));
} catch (logic_error e) {
} catch (const logic_error& e) {
set_error_code(-1);
set_error_message("logic error: " + string(e.what()));
} catch (const exception& e) {
set_error_code(-1);
set_error_message("general exception: " + string(e.what()));
} catch (...) {
set_error_code(-2);
set_error_message("unknown error");
@ -450,13 +454,22 @@ bool AsyncRPCOperation_sendmany::main_impl() {
info.notes.push_back(note);
outPoints.push_back(outPoint);
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s)\n",
int wtxHeight = -1;
int wtxDepth = -1;
{
LOCK2(cs_main, pwalletMain->cs_wallet);
const CWalletTx& wtx = pwalletMain->mapWallet[outPoint.hash];
wtxHeight = mapBlockIndex[wtx.hashBlock]->nHeight;
wtxDepth = wtx.GetDepthInMainChain();
}
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n",
getId().substr(0, 10),
outPoint.hash.ToString().substr(0, 10),
outPoint.js,
int(outPoint.n), // uint8_t
FormatMoney(noteFunds, false)
FormatMoney(noteFunds, false),
wtxHeight,
wtxDepth
);
@ -579,7 +592,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
FormatMoney(plaintext.value, false)
);
} catch (const std::exception e) {
} catch (const std::exception& e) {
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error decrypting output note of previous JoinSplit: %s", e.what()));
}
}
@ -613,12 +626,22 @@ bool AsyncRPCOperation_sendmany::main_impl() {
jsInputValue += noteFunds;
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s)\n",
int wtxHeight = -1;
int wtxDepth = -1;
{
LOCK2(cs_main, pwalletMain->cs_wallet);
const CWalletTx& wtx = pwalletMain->mapWallet[jso.hash];
wtxHeight = mapBlockIndex[wtx.hashBlock]->nHeight;
wtxDepth = wtx.GetDepthInMainChain();
}
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n",
getId().substr(0, 10),
jso.hash.ToString().substr(0, 10),
jso.js,
int(jso.n), // uint8_t
FormatMoney(noteFunds, false)
FormatMoney(noteFunds, false),
wtxHeight,
wtxDepth
);
}
@ -778,6 +801,12 @@ void AsyncRPCOperation_sendmany::sign_send_raw_transaction(Object obj)
o.push_back(Pair("hex", signedtxn));
set_result(Value(o));
}
// Keep the signed transaction so we can hash to the same txid
CDataStream stream(ParseHex(signedtxn), SER_NETWORK, PROTOCOL_VERSION);
CTransaction tx;
stream >> tx;
tx_ = tx;
}
@ -1096,4 +1125,18 @@ boost::array<unsigned char, ZC_MEMO_SIZE> AsyncRPCOperation_sendmany::get_memo_f
return memo;
}
/**
* Override getStatus() to append the operation's input parameters to the default status object.
*/
Value AsyncRPCOperation_sendmany::getStatus() const {
Value v = AsyncRPCOperation::getStatus();
if (contextinfo_.is_null()) {
return v;
}
Object obj = v.get_obj();
obj.push_back(Pair("method", "z_sendmany"));
obj.push_back(Pair("params", contextinfo_ ));
return Value(obj);
}

6
src/wallet/asyncrpcoperation_sendmany.h

@ -50,7 +50,7 @@ struct WitnessAnchorData {
class AsyncRPCOperation_sendmany : public AsyncRPCOperation {
public:
AsyncRPCOperation_sendmany(std::string fromAddress, std::vector<SendManyRecipient> tOutputs, std::vector<SendManyRecipient> zOutputs, int minDepth, CAmount fee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE);
AsyncRPCOperation_sendmany(std::string fromAddress, std::vector<SendManyRecipient> tOutputs, std::vector<SendManyRecipient> zOutputs, int minDepth, CAmount fee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE, Value contextInfo = Value::null);
virtual ~AsyncRPCOperation_sendmany();
// We don't want to be copied or moved around
@ -61,11 +61,15 @@ public:
virtual void main();
virtual Value getStatus() const;
bool testmode = false; // Set to true to disable sending txs and generating proofs
private:
friend class TEST_FRIEND_AsyncRPCOperation_sendmany; // class for unit testing
Value contextinfo_; // optional data to include in return value from getStatus()
CAmount fee_;
int mindepth_;
std::string fromaddress_;

244
src/wallet/gtest/test_wallet.cpp

@ -51,7 +51,7 @@ public:
void IncrementNoteWitnesses(const CBlockIndex* pindex,
const CBlock* pblock,
ZCIncrementalMerkleTree tree) {
ZCIncrementalMerkleTree& tree) {
CWallet::IncrementNoteWitnesses(pindex, pblock, tree);
}
void DecrementNoteWitnesses(const CBlockIndex* pindex) {
@ -82,6 +82,28 @@ CWalletTx GetValidSpend(const libzcash::SpendingKey& sk,
return GetValidSpend(*params, sk, note, value);
}
JSOutPoint CreateValidBlock(TestWallet& wallet,
const libzcash::SpendingKey& sk,
const CBlockIndex& index,
CBlock& block,
ZCIncrementalMerkleTree& tree) {
auto wtx = GetValidReceive(sk, 50, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
mapNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
CNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
wtx.SetNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
block.vtx.push_back(wtx);
wallet.IncrementNoteWitnesses(&index, &block, tree);
return jsoutpt;
}
TEST(wallet_tests, setup_datadir_location_run_as_first_test) {
// Get temporary and unique path for file.
boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
@ -572,27 +594,14 @@ TEST(wallet_tests, cached_witnesses_chain_tip) {
wallet.AddSpendingKey(sk);
{
// First transaction (case tested in _empty_chain)
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
mapNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
CNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
wtx.SetNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
std::vector<JSOutPoint> notes {jsoutpt};
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
// First block (case tested in _empty_chain)
block1.vtx.push_back(wtx);
CBlockIndex index1(block1);
index1.nHeight = 1;
wallet.IncrementNoteWitnesses(&index1, &block1, tree);
auto jsoutpt = CreateValidBlock(wallet, sk, index1, block1, tree);
// Called to fetch anchor
std::vector<JSOutPoint> notes {jsoutpt};
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
wallet.GetNoteWitnesses(notes, witnesses, anchor1);
}
@ -667,47 +676,21 @@ TEST(wallet_tests, CachedWitnessesDecrementFirst) {
wallet.AddSpendingKey(sk);
{
// First transaction (case tested in _empty_chain)
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
mapNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
CNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
wtx.SetNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
// First block (case tested in _empty_chain)
CBlock block1;
block1.vtx.push_back(wtx);
CBlockIndex index1(block1);
index1.nHeight = 1;
wallet.IncrementNoteWitnesses(&index1, &block1, tree);
CreateValidBlock(wallet, sk, index1, block1, tree);
}
{
// Second transaction (case tested in _chain_tip)
auto wtx = GetValidReceive(sk, 50, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
mapNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
CNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
wtx.SetNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
std::vector<JSOutPoint> notes {jsoutpt};
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
// Second block (case tested in _chain_tip)
block2.vtx.push_back(wtx);
index2.nHeight = 2;
wallet.IncrementNoteWitnesses(&index2, &block2, tree);
auto jsoutpt = CreateValidBlock(wallet, sk, index2, block2, tree);
// Called to fetch anchor
std::vector<JSOutPoint> notes {jsoutpt};
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
wallet.GetNoteWitnesses(notes, witnesses, anchor2);
}
@ -753,116 +736,77 @@ TEST(wallet_tests, CachedWitnessesDecrementFirst) {
TEST(wallet_tests, CachedWitnessesCleanIndex) {
TestWallet wallet;
CBlock block1;
CBlock block2;
CBlock block3;
CBlockIndex index1(block1);
CBlockIndex index2(block2);
CBlockIndex index3(block3);
std::vector<CBlock> blocks;
std::vector<CBlockIndex> indices;
std::vector<JSOutPoint> notes;
std::vector<uint256> anchors;
ZCIncrementalMerkleTree tree;
ZCIncrementalMerkleTree riTree = tree;
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
auto sk = libzcash::SpendingKey::random();
wallet.AddSpendingKey(sk);
{
// First transaction (case tested in _empty_chain)
auto wtx = GetValidReceive(sk, 10, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
// Generate a chain
size_t numBlocks = WITNESS_CACHE_SIZE + 10;
blocks.resize(numBlocks);
indices.resize(numBlocks);
for (size_t i = 0; i < numBlocks; i++) {
indices[i].nHeight = i;
auto old = tree.root();
auto jsoutpt = CreateValidBlock(wallet, sk, indices[i], blocks[i], tree);
EXPECT_NE(old, tree.root());
notes.push_back(jsoutpt);
mapNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
CNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
wtx.SetNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
// First block (case tested in _empty_chain)
block1.vtx.push_back(wtx);
index1.nHeight = 1;
wallet.IncrementNoteWitnesses(&index1, &block1, tree);
}
{
// Second transaction (case tested in _chain_tip)
auto wtx = GetValidReceive(sk, 50, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
mapNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
CNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
wtx.SetNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
// Second block (case tested in _chain_tip)
block2.vtx.push_back(wtx);
index2.nHeight = 2;
wallet.IncrementNoteWitnesses(&index2, &block2, tree);
}
{
// Third transaction
auto wtx = GetValidReceive(sk, 20, true);
auto note = GetNote(sk, wtx, 0, 1);
auto nullifier = note.nullifier(sk);
mapNoteData_t noteData;
JSOutPoint jsoutpt {wtx.GetHash(), 0, 1};
CNoteData nd {sk.address(), nullifier};
noteData[jsoutpt] = nd;
wtx.SetNoteData(noteData);
wallet.AddToWallet(wtx, true, NULL);
std::vector<JSOutPoint> notes {jsoutpt};
std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
uint256 anchor3;
// Third block
block3.vtx.push_back(wtx);
index3.nHeight = 3;
wallet.IncrementNoteWitnesses(&index3, &block3, tree);
wallet.GetNoteWitnesses(notes, witnesses, anchor3);
// Now pretend we are reindexing: the chain is cleared, and each block is
// used to increment witnesses again.
wallet.IncrementNoteWitnesses(&index1, &block1, tree);
uint256 anchor3a;
witnesses.clear();
wallet.GetNoteWitnesses(notes, witnesses, anchor3a);
EXPECT_TRUE((bool) witnesses[0]);
// Should equal third anchor because witness cache unaffected
EXPECT_EQ(anchor3, anchor3a);
wallet.IncrementNoteWitnesses(&index2, &block2, tree);
uint256 anchor3b;
witnesses.clear();
wallet.GetNoteWitnesses(notes, witnesses, anchor3b);
EXPECT_TRUE((bool) witnesses[0]);
EXPECT_EQ(anchor3, anchor3b);
// Pretend a reorg happened that was recorded in the block files
wallet.DecrementNoteWitnesses(&index2);
uint256 anchor3c;
witnesses.clear();
wallet.GetNoteWitnesses(notes, witnesses, anchor3c);
EXPECT_TRUE((bool) witnesses[0]);
EXPECT_EQ(anchor3, anchor3c);
wallet.IncrementNoteWitnesses(&index2, &block2, tree);
uint256 anchor3d;
witnesses.clear();
wallet.GetNoteWitnesses(notes, witnesses, anchor3d);
EXPECT_TRUE((bool) witnesses[0]);
EXPECT_EQ(anchor3, anchor3d);
uint256 anchor;
wallet.GetNoteWitnesses(notes, witnesses, anchor);
for (size_t j = 0; j <= i; j++) {
EXPECT_TRUE((bool) witnesses[j]);
}
anchors.push_back(anchor);
}
wallet.IncrementNoteWitnesses(&index3, &block3, tree);
uint256 anchor3e;
// Now pretend we are reindexing: the chain is cleared, and each block is
// used to increment witnesses again.
for (size_t i = 0; i < numBlocks; i++) {
ZCIncrementalMerkleTree riPrevTree {riTree};
wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), riTree);
witnesses.clear();
wallet.GetNoteWitnesses(notes, witnesses, anchor3e);
EXPECT_TRUE((bool) witnesses[0]);
EXPECT_EQ(anchor3, anchor3e);
uint256 anchor;
wallet.GetNoteWitnesses(notes, witnesses, anchor);
for (size_t j = 0; j < numBlocks; j++) {
EXPECT_TRUE((bool) witnesses[j]);
}
// Should equal final anchor because witness cache unaffected
EXPECT_EQ(anchors.back(), anchor);
if ((i == 5) || (i == 50)) {
// Pretend a reorg happened that was recorded in the block files
{
wallet.DecrementNoteWitnesses(&(indices[i]));
witnesses.clear();
uint256 anchor;
wallet.GetNoteWitnesses(notes, witnesses, anchor);
for (size_t j = 0; j < numBlocks; j++) {
EXPECT_TRUE((bool) witnesses[j]);
}
// Should equal final anchor because witness cache unaffected
EXPECT_EQ(anchors.back(), anchor);
}
{
wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), riPrevTree);
witnesses.clear();
uint256 anchor;
wallet.GetNoteWitnesses(notes, witnesses, anchor);
for (size_t j = 0; j < numBlocks; j++) {
EXPECT_TRUE((bool) witnesses[j]);
}
// Should equal final anchor because witness cache unaffected
EXPECT_EQ(anchors.back(), anchor);
}
}
}
}

0
src/gtest/test_wallet_zkeys.cpp → src/wallet/gtest/test_wallet_zkeys.cpp

32
src/wallet/rpcdump.cpp

@ -430,7 +430,9 @@ Value z_exportwallet(const Array& params, bool fHelp)
"z_exportwallet \"filename\"\n"
"\nExports all wallet keys, for taddr and zaddr, in a human-readable format.\n"
"\nArguments:\n"
"1. \"filename\" (string, required) The filename\n"
"1. \"filename\" (string, required) The filename, saved in folder set by zcashd -exportdir option\n"
"\nResult:\n"
"\"path\" (string) The full path of the destination file\n"
"\nExamples:\n"
+ HelpExampleCli("z_exportwallet", "\"test\"")
+ HelpExampleRpc("z_exportwallet", "\"test\"")
@ -449,7 +451,9 @@ Value dumpwallet(const Array& params, bool fHelp)
"dumpwallet \"filename\"\n"
"\nDumps taddr wallet keys in a human-readable format.\n"
"\nArguments:\n"
"1. \"filename\" (string, required) The filename\n"
"1. \"filename\" (string, required) The filename, saved in folder set by zcashd -exportdir option\n"
"\nResult:\n"
"\"path\" (string) The full path of the destination file\n"
"\nExamples:\n"
+ HelpExampleCli("dumpwallet", "\"test\"")
+ HelpExampleRpc("dumpwallet", "\"test\"")
@ -464,8 +468,24 @@ Value dumpwallet_impl(const Array& params, bool fHelp, bool fDumpZKeys)
EnsureWalletIsUnlocked();
boost::filesystem::path exportdir;
try {
exportdir = GetExportDir();
} catch (const std::runtime_error& e) {
throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
}
if (exportdir.empty()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot export wallet until the zcashd -exportdir option has been set");
}
std::string unclean = params[0].get_str();
std::string clean = SanitizeFilename(unclean);
if (clean.compare(unclean) != 0) {
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
}
boost::filesystem::path exportfilepath = exportdir / clean;
ofstream file;
file.open(params[0].get_str().c_str());
file.open(exportfilepath.string().c_str());
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
@ -523,7 +543,8 @@ Value dumpwallet_impl(const Array& params, bool fHelp, bool fDumpZKeys)
file << "# End of dump\n";
file.close();
return Value::null;
return exportfilepath.string();
}
@ -575,6 +596,9 @@ Value z_importkey(const Array& params, bool fHelp)
pwalletMain->mapZKeyMetadata[addr].nCreateTime = 1;
// whenever a key is imported, we need to scan the whole chain
pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
// We want to scan for transactions and notes
if (fRescan) {
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);

71
src/wallet/rpcwallet.cpp

@ -34,6 +34,8 @@
#include "json/json_spirit_value.h"
#include "asyncrpcqueue.h"
#include <numeric>
using namespace std;
using namespace json_spirit;
@ -1557,6 +1559,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
if (fLong)
WalletTxToJSON(wtx, entry);
entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
ret.push_back(entry);
}
}
@ -1593,6 +1596,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
entry.push_back(Pair("vout", r.vout));
if (fLong)
WalletTxToJSON(wtx, entry);
entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
ret.push_back(entry);
}
}
@ -1661,6 +1665,7 @@ Value listtransactions(const Array& params, bool fHelp)
" \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
" from (for receiving funds, positive amounts), or went to (for sending funds,\n"
" negative amounts).\n"
" \"size\": n, (numeric) Transaction size in bytes\n"
" }\n"
"]\n"
@ -1998,21 +2003,38 @@ Value backupwallet(const Array& params, bool fHelp)
if (fHelp || params.size() != 1)
throw runtime_error(
"backupwallet \"destination\"\n"
"\nSafely copies wallet.dat to destination, which can be a directory or a path with filename.\n"
"\nSafely copies wallet.dat to destination filename\n"
"\nArguments:\n"
"1. \"destination\" (string) The destination directory or file\n"
"1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
"\nResult:\n"
"\"path\" (string) The full path of the destination file\n"
"\nExamples:\n"
+ HelpExampleCli("backupwallet", "\"backup.dat\"")
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
+ HelpExampleCli("backupwallet", "\"backupdata\"")
+ HelpExampleRpc("backupwallet", "\"backupdata\"")
);
LOCK2(cs_main, pwalletMain->cs_wallet);
string strDest = params[0].get_str();
if (!BackupWallet(*pwalletMain, strDest))
boost::filesystem::path exportdir;
try {
exportdir = GetExportDir();
} catch (const std::runtime_error& e) {
throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
}
if (exportdir.empty()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
}
std::string unclean = params[0].get_str();
std::string clean = SanitizeFilename(unclean);
if (clean.compare(unclean) != 0) {
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
}
boost::filesystem::path exportfilepath = exportdir / clean;
if (!BackupWallet(*pwalletMain, exportfilepath.string()))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
return Value::null;
return exportfilepath.string();
}
@ -2734,7 +2756,15 @@ Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
} else if (benchmarktype == "parameterloading") {
sample_times.push_back(benchmark_parameter_loading());
} else if (benchmarktype == "createjoinsplit") {
sample_times.push_back(benchmark_create_joinsplit());
if (params.size() < 3) {
sample_times.push_back(benchmark_create_joinsplit());
} else {
int nThreads = params[2].get_int();
std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
// Divide by nThreads^2 to get average seconds per JoinSplit because
// we are running one JoinSplit per thread.
sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
}
} else if (benchmarktype == "verifyjoinsplit") {
sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
} else if (benchmarktype == "solveequihash") {
@ -3224,7 +3254,7 @@ Value z_listreceivedbyaddress(const Array& params, bool fHelp)
CZCPaymentAddress address(fromaddress);
try {
zaddr = address.Get();
} catch (std::runtime_error) {
} catch (const std::runtime_error&) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
}
@ -3291,7 +3321,7 @@ Value z_getbalance(const Array& params, bool fHelp)
CZCPaymentAddress address(fromaddress);
try {
zaddr = address.Get();
} catch (std::runtime_error) {
} catch (const std::runtime_error&) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
}
if (!pwalletMain->HaveSpendingKey(zaddr)) {
@ -3443,6 +3473,13 @@ Value z_getoperationstatus_IMPL(const Array& params, bool fRemoveFinishedOperati
}
}
// sort results chronologically by creation_time
std::sort(ret.begin(), ret.end(), [](Value a, Value b) -> bool {
const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
return t1 < t2;
});
return ret;
}
@ -3497,7 +3534,7 @@ Value z_sendmany(const Array& params, bool fHelp)
CZCPaymentAddress address(fromaddress);
try {
zaddr = address.Get();
} catch (std::runtime_error) {
} catch (const std::runtime_error&) {
// invalid
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
}
@ -3544,7 +3581,7 @@ Value z_sendmany(const Array& params, bool fHelp)
CZCPaymentAddress zaddr(address);
zaddr.Get();
isZaddr = true;
} catch (std::runtime_error) {
} catch (const std::runtime_error&) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
}
}
@ -3624,9 +3661,17 @@ Value z_sendmany(const Array& params, bool fHelp)
}
}
// Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
Object o;
o.push_back(Pair("fromaddress", params[0]));
o.push_back(Pair("amounts", params[1]));
o.push_back(Pair("minconf", nMinDepth));
o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
Value contextInfo = Value(o);
// Create operation and add to global queue
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee) );
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
q->addOperation(operation);
AsyncRPCOperationId operationId = operation->getId();
return operationId;

40
src/wallet/wallet.cpp

@ -645,10 +645,14 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
CNoteData* nd = &(item.second);
// Check the validity of the cache
assert(nWitnessCacheSize >= nd->witnesses.size());
// Only increment witnesses that are behind the current height
if (nd->witnessHeight < pindex->nHeight) {
// Check the validity of the cache
// The only time a note witnessed above the current height
// would be invalid here is during a reindex when blocks
// have been decremented, and we are incrementing the blocks
// immediately after.
assert(nWitnessCacheSize >= nd->witnesses.size());
// Witnesses being incremented should always be either -1
// (never incremented or decremented) or one below pindex
assert((nd->witnessHeight == -1) ||
@ -687,10 +691,11 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
CNoteData* nd = &(item.second);
// Check the validity of the cache
assert(nWitnessCacheSize >= nd->witnesses.size());
if (nd->witnessHeight < pindex->nHeight &&
nd->witnesses.size() > 0) {
// Check the validity of the cache
// See earlier comment about validity.
assert(nWitnessCacheSize >= nd->witnesses.size());
nd->witnesses.front().append(note_commitment);
}
}
@ -699,7 +704,8 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
// If this is our note, witness it
if (txIsOurs) {
JSOutPoint jsoutpt {hash, i, j};
if (mapWallet[hash].mapNoteData.count(jsoutpt)) {
if (mapWallet[hash].mapNoteData.count(jsoutpt) &&
mapWallet[hash].mapNoteData[jsoutpt].witnessHeight < pindex->nHeight) {
CNoteData* nd = &(mapWallet[hash].mapNoteData[jsoutpt]);
if (nd->witnesses.size() > 0) {
// We think this can happen because we write out the
@ -735,9 +741,10 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
CNoteData* nd = &(item.second);
if (nd->witnessHeight < pindex->nHeight) {
nd->witnessHeight = pindex->nHeight;
// Check the validity of the cache
// See earlier comment about validity.
assert(nWitnessCacheSize >= nd->witnesses.size());
}
// Check the validity of the cache
assert(nWitnessCacheSize >= nd->witnesses.size());
}
}
@ -755,10 +762,12 @@ void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex)
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
CNoteData* nd = &(item.second);
// Check the validity of the cache
assert(nWitnessCacheSize >= nd->witnesses.size());
// Only increment witnesses that are not above the current height
if (nd->witnessHeight <= pindex->nHeight) {
// Check the validity of the cache
// See comment below (this would be invalid if there was a
// prior decrement).
assert(nWitnessCacheSize >= nd->witnesses.size());
// Witnesses being decremented should always be either -1
// (never incremented or decremented) or equal to pindex
assert((nd->witnessHeight == -1) ||
@ -777,7 +786,18 @@ void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex)
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
CNoteData* nd = &(item.second);
// Check the validity of the cache
assert(nWitnessCacheSize >= nd->witnesses.size());
// Technically if there are notes witnessed above the current
// height, their cache will now be invalid (relative to the new
// value of nWitnessCacheSize). However, this would only occur
// during a reindex, and by the time the reindex reaches the tip
// of the chain again, the existing witness caches will be valid
// again.
// We don't set nWitnessCacheSize to zero at the start of the
// reindex because the on-disk blocks had already resulted in a
// chain that didn't trigger the assertion below.
if (nd->witnessHeight < pindex->nHeight) {
assert(nWitnessCacheSize >= nd->witnesses.size());
}
}
}
if ( nWitnessCacheSize <= 0 )

4
src/wallet/walletdb.cpp

@ -14,6 +14,7 @@
#include "util.h"
#include "utiltime.h"
#include "wallet/wallet.h"
#include "zcash/Proof.hpp"
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
@ -411,7 +412,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CWalletTx wtx;
ssValue >> wtx;
CValidationState state;
if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))
auto verifier = libzcash::ProofVerifier::Strict();
if (!(CheckTransaction(wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid()))
return false;
// Undo serialize changes in 31600

35
src/zcash/CreateJoinSplit.cpp

@ -0,0 +1,35 @@
// Copyright (c) 2016 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "../util.h"
#include "primitives/transaction.h"
#include "zcash/JoinSplit.hpp"
#include "libsnark/common/profiling.hpp"
using namespace libzcash;
int main(int argc, char **argv)
{
libsnark::start_profiling();
auto p = ZCJoinSplit::Unopened();
p->loadVerifyingKey((ZC_GetParamsDir() / "sprout-verifying.key").string());
p->setProvingKeyPath((ZC_GetParamsDir() / "sprout-proving.key").string());
p->loadProvingKey();
// construct a proof.
for (int i = 0; i < 5; i++) {
uint256 anchor = ZCIncrementalMerkleTree().root();
uint256 pubKeyHash;
JSDescription jsdesc(*p,
pubKeyHash,
anchor,
{JSInput(), JSInput()},
{JSOutput(), JSOutput()},
0,
0);
}
}

19
src/zcash/IncrementalMerkleTree.cpp

@ -81,6 +81,25 @@ Hash IncrementalMerkleTree<Depth, Hash>::last() const {
}
}
template<size_t Depth, typename Hash>
size_t IncrementalMerkleTree<Depth, Hash>::size() const {
size_t ret = 0;
if (left) {
ret++;
}
if (right) {
ret++;
}
// Treat occupation of parents array as a binary number
// (right-shifted by 1)
for (size_t i = 0; i < parents.size(); i++) {
if (parents[i]) {
ret += (1 << (i+1));
}
}
return ret;
}
template<size_t Depth, typename Hash>
void IncrementalMerkleTree<Depth, Hash>::append(Hash obj) {
if (is_complete(Depth)) {

2
src/zcash/IncrementalMerkleTree.hpp

@ -75,6 +75,8 @@ public:
parents.size() * 32; // parents
}
size_t size() const;
void append(Hash obj);
Hash root() const {
return root(Depth, std::deque<Hash>());

4
src/zcash/Proof.cpp

@ -163,6 +163,10 @@ curve_G2 CompressedG2::to_libsnark_g2() const
assert(r.is_well_formed());
if (alt_bn128_modulus_r * r != curve_G2::zero()) {
throw std::runtime_error("point is not in G2");
}
return r;
}

21
src/zcbenchmarks.cpp

@ -95,6 +95,27 @@ double benchmark_create_joinsplit()
return ret;
}
std::vector<double> benchmark_create_joinsplit_threaded(int nThreads)
{
std::vector<double> ret;
std::vector<std::future<double>> tasks;
std::vector<std::thread> threads;
for (int i = 0; i < nThreads; i++) {
std::packaged_task<double(void)> task(&benchmark_create_joinsplit);
tasks.emplace_back(task.get_future());
threads.emplace_back(std::move(task));
}
std::future_status status;
for (auto it = tasks.begin(); it != tasks.end(); it++) {
it->wait();
ret.push_back(it->get());
}
for (auto it = threads.begin(); it != threads.end(); it++) {
it->join();
}
return ret;
}
double benchmark_verify_joinsplit(const JSDescription &joinsplit)
{
struct timeval tv_start;

1
src/zcbenchmarks.h

@ -7,6 +7,7 @@
extern double benchmark_sleep();
extern double benchmark_parameter_loading();
extern double benchmark_create_joinsplit();
extern std::vector<double> benchmark_create_joinsplit_threaded(int nThreads);
extern double benchmark_solve_equihash();
extern std::vector<double> benchmark_solve_equihash_threaded(int nThreads);
extern double benchmark_verify_joinsplit(const JSDescription &joinsplit);

16
zcutil/build-debian-package.sh

@ -8,7 +8,7 @@ set -x
BUILD_PATH="/tmp/zcbuild"
PACKAGE_NAME="zcash"
SRC_PATH=`pwd`
SRC_DEB=$SRC_PATH/contrib/DEBIAN
SRC_DEB=$SRC_PATH/contrib/debian
umask 022
@ -16,22 +16,20 @@ if [ ! -d $BUILD_PATH ]; then
mkdir $BUILD_PATH
fi
PACKAGE_VERSION=$(grep Version $SRC_PATH/contrib/DEBIAN/control | cut -d: -f2 | tr -d ' ')
PACKAGE_VERSION=$($SRC_PATH/src/zcashd --version | grep version | cut -d' ' -f4 | tr -d v)
BUILD_DIR="$BUILD_PATH/$PACKAGE_NAME-$PACKAGE_VERSION-amd64"
if [ -d $BUILD_DIR ]; then
rm -R $BUILD_DIR
fi
DEB_CMP=$BUILD_DIR/etc/bash_completion.d
DEB_BIN=$BUILD_DIR/usr/bin
DEB_CMP=$BUILD_DIR/usr/share/bash-completion/completions
DEB_DOC=$BUILD_DIR/usr/share/doc/$PACKAGE_NAME
DEB_MAN=$BUILD_DIR/usr/share/man/man1
mkdir -p $BUILD_DIR/DEBIAN $DEB_CMP $DEB_BIN $DEB_DOC $DEB_MAN
chmod 0755 -R $BUILD_DIR/*
# Copy control file
cp $SRC_DEB/control $BUILD_DIR/DEBIAN
# Package maintainer scripts (currently empty)
#cp $SRC_DEB/postinst $BUILD_DIR/DEBIAN
#cp $SRC_DEB/postrm $BUILD_DIR/DEBIAN
@ -49,6 +47,7 @@ cp -r $SRC_DEB/examples $DEB_DOC
# Copy manpages
cp $SRC_DEB/manpages/zcashd.1 $DEB_MAN
cp $SRC_DEB/manpages/zcash-cli.1 $DEB_MAN
cp $SRC_DEB/manpages/zcash-fetch-params.1 $DEB_MAN
# Copy bash completion files
cp $SRC_PATH/contrib/bitcoind.bash-completion $DEB_CMP/zcashd
cp $SRC_PATH/contrib/bitcoin-cli.bash-completion $DEB_CMP/zcash-cli
@ -57,6 +56,13 @@ gzip --best -n $DEB_DOC/changelog
gzip --best -n $DEB_DOC/changelog.Debian
gzip --best -n $DEB_MAN/zcashd.1
gzip --best -n $DEB_MAN/zcash-cli.1
gzip --best -n $DEB_MAN/zcash-fetch-params.1
cd $SRC_PATH/contrib
# Create the control file
dpkg-shlibdeps $DEB_BIN/zcashd $DEB_BIN/zcash-cli
dpkg-gencontrol -P$BUILD_DIR
# Create the Debian package
fakeroot dpkg-deb --build $BUILD_DIR

Loading…
Cancel
Save