Merge pull request #133 from jl777/dPoW

DPoW
This commit is contained in:
jl777
2017-01-25 15:25:43 +02:00
committed by GitHub
85 changed files with 1318 additions and 359 deletions

42
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -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 vendored
View File

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

View File

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

View File

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

View File

@@ -2,12 +2,12 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60]) AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 1) define(_CLIENT_VERSION_MAJOR, 1)
define(_CLIENT_VERSION_MINOR, 0) define(_CLIENT_VERSION_MINOR, 0)
define(_CLIENT_VERSION_REVISION, 3) define(_CLIENT_VERSION_REVISION, 5)
define(_CLIENT_VERSION_BUILD, 50) 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(_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_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(_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_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_SRCDIR([src/main.cpp])
AC_CONFIG_HEADERS([src/config/bitcoin-config.h]) AC_CONFIG_HEADERS([src/config/bitcoin-config.h])

View File

@@ -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 zcash (1.0.3) jessie; urgency=medium
* 1.0.3 release. * 1.0.3 release.

View File

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

View File

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

View File

@@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. .\" 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 .SH NAME
zcash-cli \- RPC client for the Zcash daemon zcash-cli \- RPC client for the Zcash daemon
.SH DESCRIPTION .SH DESCRIPTION
Zcash RPC client version v1.0.3 Zcash RPC client version v1.0.5
.SS "Usage:" .SS "Usage:"
.TP .TP
zcash\-cli [options] <command> [params] zcash\-cli [options] <command> [params]

View File

@@ -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.

View File

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

View File

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

View File

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

View File

@@ -89,6 +89,10 @@ Asynchronous calls return an OperationStatus object which is a JSON object with
* code : number * code : number
* message: error message * 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. 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. 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`. "Could not find previous JoinSplit anchor" | Try restarting node with `-reindex`.
"Error decrypting output note of previous JoinSplit: __" | "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 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. "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. "Not enough funds to pay miners fee" | Retry with sufficient funds.

View File

@@ -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

View File

@@ -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

View File

@@ -35,7 +35,6 @@ previous release:
README.md README.md
src/clientversion.h src/clientversion.h
configure.ac configure.ac
contrib/DEBIAN/control
contrib/gitian-descriptors/gitian-linux.yml contrib/gitian-descriptors/gitian-linux.yml
Build and commit to update versions, and then perform the following commands: 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. 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) ## 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 ## H. Make and deploy deterministic builds
- Run the [Gitian deterministic build environment](https://github.com/zcash/zcash-gitian) - Run the [Gitian deterministic build environment](https://github.com/zcash/zcash-gitian)

View File

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

View File

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

View File

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

106
qa/rpc-tests/wallet_1941.py Executable file
View File

@@ -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()

View File

@@ -98,6 +98,14 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
else: else:
status = results[0]["status"] status = results[0]["status"]
errorString = results[0]["error"]["message"] 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 break
assert_equal("failed", status) assert_equal("failed", status)
assert_equal("wallet does not allow any change" in errorString, True) assert_equal("wallet does not allow any change" in errorString, True)

View File

@@ -47,8 +47,13 @@ class WalletBackupTest(BitcoinTestFramework):
# This mirrors how the network was setup in the bash test # This mirrors how the network was setup in the bash test
def setup_network(self, split=False): 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 # 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) self.nodes = start_nodes(4, self.options.tmpdir, extra_args)
connect_nodes(self.nodes[0], 3) connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[1], 3) connect_nodes(self.nodes[1], 3)
@@ -122,12 +127,12 @@ class WalletBackupTest(BitcoinTestFramework):
logging.info("Backing up") logging.info("Backing up")
tmpdir = self.options.tmpdir tmpdir = self.options.tmpdir
self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak") self.nodes[0].backupwallet("walletbak")
self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump") self.nodes[0].dumpwallet("walletdump")
self.nodes[1].backupwallet(tmpdir + "/node1/wallet.bak") self.nodes[1].backupwallet("walletbak")
self.nodes[1].dumpwallet(tmpdir + "/node1/wallet.dump") self.nodes[1].dumpwallet("walletdump")
self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak") self.nodes[2].backupwallet("walletbak")
self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump") self.nodes[2].dumpwallet("walletdump")
logging.info("More transactions") logging.info("More transactions")
for i in range(5): for i in range(5):
@@ -159,9 +164,9 @@ class WalletBackupTest(BitcoinTestFramework):
shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate") shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate")
# Restore wallets from backup # Restore wallets from backup
shutil.copyfile(tmpdir + "/node0/wallet.bak", tmpdir + "/node0/regtest/wallet.dat") shutil.copyfile(tmpdir + "/node0/walletbak", tmpdir + "/node0/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallet.dat") shutil.copyfile(tmpdir + "/node1/walletbak", tmpdir + "/node1/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallet.dat") shutil.copyfile(tmpdir + "/node2/walletbak", tmpdir + "/node2/regtest/wallet.dat")
logging.info("Re-starting nodes") logging.info("Re-starting nodes")
self.start_three() self.start_three()
@@ -185,9 +190,9 @@ class WalletBackupTest(BitcoinTestFramework):
assert_equal(self.nodes[1].getbalance(), 0) assert_equal(self.nodes[1].getbalance(), 0)
assert_equal(self.nodes[2].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 0)
self.nodes[0].importwallet(tmpdir + "/node0/wallet.dump") self.nodes[0].importwallet(tmpdir + "/node0/walletdump")
self.nodes[1].importwallet(tmpdir + "/node1/wallet.dump") self.nodes[1].importwallet(tmpdir + "/node1/walletdump")
self.nodes[2].importwallet(tmpdir + "/node2/wallet.dump") self.nodes[2].importwallet(tmpdir + "/node2/walletdump")
sync_blocks(self.nodes) sync_blocks(self.nodes)

View File

@@ -5,7 +5,7 @@ set -e
DATADIR=./benchmark-datadir DATADIR=./benchmark-datadir
function zcash_rpc { 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 { function zcashd_generate {
@@ -15,6 +15,7 @@ function zcashd_generate {
function zcashd_start { function zcashd_start {
rm -rf "$DATADIR" rm -rf "$DATADIR"
mkdir -p "$DATADIR" mkdir -p "$DATADIR"
touch "$DATADIR/zcash.conf"
./src/zcashd -regtest -datadir="$DATADIR" -rpcuser=user -rpcpassword=password -rpcport=5983 -showmetrics=0 & ./src/zcashd -regtest -datadir="$DATADIR" -rpcuser=user -rpcpassword=password -rpcport=5983 -showmetrics=0 &
ZCASHD_PID=$! ZCASHD_PID=$!
} }
@@ -27,6 +28,7 @@ function zcashd_stop {
function zcashd_massif_start { function zcashd_massif_start {
rm -rf "$DATADIR" rm -rf "$DATADIR"
mkdir -p "$DATADIR" mkdir -p "$DATADIR"
touch "$DATADIR/zcash.conf"
rm -f massif.out 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 & 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=$! ZCASHD_PID=$!
@@ -41,6 +43,7 @@ function zcashd_massif_stop {
function zcashd_valgrind_start { function zcashd_valgrind_start {
rm -rf "$DATADIR" rm -rf "$DATADIR"
mkdir -p "$DATADIR" mkdir -p "$DATADIR"
touch "$DATADIR/zcash.conf"
rm -f valgrind.out 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 & 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=$! ZCASHD_PID=$!
@@ -74,7 +77,7 @@ case "$1" in
zcash_rpc zcbenchmark parameterloading 10 zcash_rpc zcbenchmark parameterloading 10
;; ;;
createjoinsplit) createjoinsplit)
zcash_rpc zcbenchmark createjoinsplit 10 zcash_rpc zcbenchmark createjoinsplit 10 "${@:3}"
;; ;;
verifyjoinsplit) verifyjoinsplit)
zcash_rpc zcbenchmark verifyjoinsplit 1000 "\"$RAWJOINSPLIT\"" zcash_rpc zcbenchmark verifyjoinsplit 1000 "\"$RAWJOINSPLIT\""
@@ -111,7 +114,7 @@ case "$1" in
zcash_rpc zcbenchmark parameterloading 1 zcash_rpc zcbenchmark parameterloading 1
;; ;;
createjoinsplit) createjoinsplit)
zcash_rpc zcbenchmark createjoinsplit 1 zcash_rpc zcbenchmark createjoinsplit 1 "${@:3}"
;; ;;
verifyjoinsplit) verifyjoinsplit)
zcash_rpc zcbenchmark verifyjoinsplit 1 "\"$RAWJOINSPLIT\"" zcash_rpc zcbenchmark verifyjoinsplit 1 "\"$RAWJOINSPLIT\""
@@ -146,7 +149,7 @@ case "$1" in
zcash_rpc zcbenchmark parameterloading 1 zcash_rpc zcbenchmark parameterloading 1
;; ;;
createjoinsplit) createjoinsplit)
zcash_rpc zcbenchmark createjoinsplit 1 zcash_rpc zcbenchmark createjoinsplit 1 "${@:3}"
;; ;;
verifyjoinsplit) verifyjoinsplit)
zcash_rpc zcbenchmark verifyjoinsplit 1 "\"$RAWJOINSPLIT\"" zcash_rpc zcbenchmark verifyjoinsplit 1 "\"$RAWJOINSPLIT\""

View File

@@ -59,6 +59,7 @@ LIBZCASH_CONSENSUS=
endif endif
bin_PROGRAMS = bin_PROGRAMS =
noinst_PROGRAMS =
TESTS = TESTS =
if BUILD_BITCOIND if BUILD_BITCOIND
@@ -482,7 +483,7 @@ libzcashconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCO
endif 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 DISTCLEANFILES = obj/build.h

View File

@@ -1,3 +1,4 @@
TESTS += komodo-gtest TESTS += komodo-gtest
bin_PROGRAMS += komodo-gtest bin_PROGRAMS += komodo-gtest
@@ -10,6 +11,13 @@ komodo_gtest_SOURCES = \
gtest/json_test_vectors.h \ gtest/json_test_vectors.h \
# gtest/test_foundersreward.cpp \ # gtest/test_foundersreward.cpp \
gtest/test_wallet_zkeys.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_jsonspirit.cpp \
gtest/test_tautology.cpp \ gtest/test_tautology.cpp \
gtest/test_equihash.cpp \ gtest/test_equihash.cpp \

View File

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

View File

@@ -1,5 +1,6 @@
bin_PROGRAMS += \ noinst_PROGRAMS += \
zcash/GenerateParams zcash/GenerateParams \
zcash/CreateJoinSplit
# tool for generating our public parameters # tool for generating our public parameters
zcash_GenerateParams_SOURCES = zcash/GenerateParams.cpp zcash_GenerateParams_SOURCES = zcash/GenerateParams.cpp
@@ -9,3 +10,13 @@ zcash_GenerateParams_LDADD = \
$(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \ $(LIBBITCOIN_CRYPTO) \
$(LIBZCASH_LIBS) $(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)

View File

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

View File

@@ -87,6 +87,8 @@ static bool AppInitRPC(int argc, char* argv[])
" komodo-cli [options] help <command> " + _("Get help for a command") + "\n"; " komodo-cli [options] help <command> " + _("Get help for a command") + "\n";
strUsage += "\n" + HelpMessageCli(); strUsage += "\n" + HelpMessageCli();
} else {
strUsage += LicenseInfo();
} }
fprintf(stdout, "%s", strUsage.c_str()); 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) 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 // Connect to localhost
bool fUseSSL = GetBoolArg("-rpcssl", false); bool fUseSSL = GetBoolArg("-rpcssl", false);
boost::asio::io_service io_service; boost::asio::io_service io_service;
@@ -131,10 +127,24 @@ Object CallRPC(const string& strMethod, const Array& params)
if (!fConnected) if (!fConnected)
throw CConnectionFailed("couldn't connect to server"); 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 // HTTP basic authentication
string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
map<string, string> mapRequestHeaders; map<string, string> mapRequestHeaders;
mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64; mapRequestHeaders["Authorization"] = string("Basic ") + EncodeBase64(strRPCUserColonPass);
// Send request // Send request
string strRequest = JSONRPCRequest(strMethod, params, 1); string strRequest = JSONRPCRequest(strMethod, params, 1);

View File

@@ -115,6 +115,24 @@ bool AppInit(int argc, char* argv[])
try try
{ {
ReadConfigFile(mapArgs, mapMultiArgs); 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) { } catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what()); fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false; return false;

View File

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

View File

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

View File

@@ -2,7 +2,9 @@
#include "keystore.h" #include "keystore.h"
#include "random.h" #include "random.h"
#ifdef ENABLE_WALLET
#include "wallet/crypter.h" #include "wallet/crypter.h"
#endif
#include "zcash/Address.hpp" #include "zcash/Address.hpp"
TEST(keystore_tests, store_and_retrieve_spending_key) { 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); EXPECT_EQ(ZCNoteDecryption(sk.viewing_key()), decOut);
} }
#ifdef ENABLE_WALLET
class TestCCryptoKeyStore : public CCryptoKeyStore class TestCCryptoKeyStore : public CCryptoKeyStore
{ {
public: 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(addr));
ASSERT_EQ(1, addrs.count(addr2)); ASSERT_EQ(1, addrs.count(addr2));
} }
#endif

View File

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

View File

@@ -22,6 +22,67 @@ typedef libsnark::default_r1cs_ppzksnark_pp::Fqe_type curve_Fq2;
#include "version.h" #include "version.h"
#include "utilstrencodings.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) TEST(proofs, sqrt_zero)
{ {
ASSERT_TRUE(curve_Fq::zero() == curve_Fq::zero().sqrt()); ASSERT_TRUE(curve_Fq::zero() == curve_Fq::zero().sqrt());

View File

@@ -289,6 +289,7 @@ std::string HelpMessage(HelpMessageMode mode)
#endif #endif
} }
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory")); 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("-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("-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)); 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("-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)); 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) if (mode == HMM_BITCOIN_QT)
debugCategories += ", qt"; debugCategories += ", qt";
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " + 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 #ifdef ENABLE_WALLET
strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0)); 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)); strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1));
@@ -460,20 +462,6 @@ std::string HelpMessage(HelpMessageMode mode)
return strUsage; return strUsage;
} }
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" +
FormatParagraph(strprintf(_("Copyright (C) 2015-%i jl777 and SuperNET 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";
}
static void BlockNotifyCallback(const uint256& hashNewTip) static void BlockNotifyCallback(const uint256& hashNewTip)
{ {
std::string strCmd = GetArg("-blocknotify", ""); std::string strCmd = GetArg("-blocknotify", "");
@@ -625,6 +613,17 @@ static void ZC_LoadParams()
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key"; boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.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(); pzcashParams = ZCJoinSplit::Unopened();
LogPrintf("Loading verifying key from %s\n", vk_path.string().c_str()); LogPrintf("Loading verifying key from %s\n", vk_path.string().c_str());

View File

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

View File

@@ -416,7 +416,8 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr
komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen-len+4+3+(scriptbuf[1] == 0x4d),j); komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen-len+4+3+(scriptbuf[1] == 0x4d),j);
} }
} }
} else printf("notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s (%s)\n",notarized,(long long)signedmask,height,*notarizedheightp,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,kmdtxid.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len]); } else if ( height >= KOMODO_MAINNET_START )
printf("notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s (%s)\n",notarized,(long long)signedmask,height,*notarizedheightp,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,kmdtxid.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len]);
} }
else if ( i == 0 && j == 1 && opretlen == 149 ) else if ( i == 0 && j == 1 && opretlen == 149 )
{ {
@@ -425,9 +426,9 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr
} }
else else
{ {
int32_t k; for (k=0; k<scriptlen; k++) //int32_t k; for (k=0; k<scriptlen; k++)
printf("%02x",scriptbuf[k]); // printf("%02x",scriptbuf[k]);
printf(" <- script ht.%d i.%d j.%d value %.8f %s\n",height,i,j,dstr(value),ASSETCHAINS_SYMBOL); //printf(" <- script ht.%d i.%d j.%d value %.8f %s\n",height,i,j,dstr(value),ASSETCHAINS_SYMBOL);
if ( opretlen >= 32*2+4 && strcmp(ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,(char *)&scriptbuf[len+32*2+4]) == 0 ) if ( opretlen >= 32*2+4 && strcmp(ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,(char *)&scriptbuf[len+32*2+4]) == 0 )
{ {
for (k=0; k<32; k++) for (k=0; k<32; k++)
@@ -495,7 +496,8 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
hwmheight = pindex->nHeight; hwmheight = pindex->nHeight;
else else
{ {
printf("%s hwmheight.%d vs pindex->nHeight.%d t.%u reorg.%d\n",ASSETCHAINS_SYMBOL,hwmheight,pindex->nHeight,(uint32_t)pindex->nTime,hwmheight-pindex->nHeight); if ( pindex->nHeight != hwmheight )
printf("%s hwmheight.%d vs pindex->nHeight.%d t.%u reorg.%d\n",ASSETCHAINS_SYMBOL,hwmheight,pindex->nHeight,(uint32_t)pindex->nTime,hwmheight-pindex->nHeight);
komodo_event_rewind(sp,symbol,pindex->nHeight); komodo_event_rewind(sp,symbol,pindex->nHeight);
komodo_stateupdate(pindex->nHeight,0,0,0,zero,0,0,0,0,-pindex->nHeight,pindex->nTime,0,0,0,0); komodo_stateupdate(pindex->nHeight,0,0,0,zero,0,0,0,0,-pindex->nHeight,pindex->nTime,0,0,0,0);
} }
@@ -554,7 +556,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
} }
} }
} }
printf("%s ht.%d txi.%d signedmask.%llx numvins.%d numvouts.%d notarized.%d special.%d isratification.%d\n",ASSETCHAINS_SYMBOL,height,i,(long long)signedmask,numvins,numvouts,notarized,specialtx,isratification); //printf("%s ht.%d txi.%d signedmask.%llx numvins.%d numvouts.%d notarized.%d special.%d isratification.%d\n",ASSETCHAINS_SYMBOL,height,i,(long long)signedmask,numvins,numvouts,notarized,specialtx,isratification);
if ( notarized != 0 && (notarizedheight != 0 || specialtx != 0) ) if ( notarized != 0 && (notarizedheight != 0 || specialtx != 0) )
{ {
if ( isratification != 0 ) if ( isratification != 0 )

View File

@@ -683,7 +683,7 @@ int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 has
return(-1); return(-1);
} }
} else fprintf(stderr,"unexpected error notary_hash %s ht.%d at ht.%d\n",notarized_hash.ToString().c_str(),notarized_height,notary->nHeight); } else fprintf(stderr,"unexpected error notary_hash %s ht.%d at ht.%d\n",notarized_hash.ToString().c_str(),notarized_height,notary->nHeight);
} else if ( notarized_height > 0 && notarized_height != 73880 ) } else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 )
fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->nHeight); fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->nHeight);
return(0); return(0);
} }

View File

@@ -818,7 +818,7 @@ const char *komodo_opreturn(int32_t height,uint64_t value,uint8_t *opretbuf,int3
if ( (pax= komodo_paxmark(height,txids[i],vouts[i],'D',height)) != 0 ) if ( (pax= komodo_paxmark(height,txids[i],vouts[i],'D',height)) != 0 )
komodo_paxdelete(pax); komodo_paxdelete(pax);
} }
} else printf("opreturn none issued?\n"); } //else printf("opreturn none issued?\n");
} }
} }
else if ( opretbuf[0] == 'W' )//&& opretlen >= 38 ) else if ( opretbuf[0] == 'W' )//&& opretlen >= 38 )

View File

@@ -65,7 +65,7 @@ uint64_t komodo_moneysupply(int32_t height)
uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime) uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime)
{ {
int32_t minutes; uint64_t numerator,denominator,interest = 0; int32_t minutes,exception; uint64_t numerator,denominator,interest = 0;
if ( ASSETCHAINS_SYMBOL[0] != 0 ) if ( ASSETCHAINS_SYMBOL[0] != 0 )
return(0); return(0);
if ( komodo_moneysupply(txheight) < MAX_MONEY && nLockTime >= LOCKTIME_THRESHOLD && tiptime != 0 && nLockTime < tiptime && nValue >= 10*COIN ) if ( komodo_moneysupply(txheight) < MAX_MONEY && nLockTime >= LOCKTIME_THRESHOLD && tiptime != 0 && nLockTime < tiptime && nValue >= 10*COIN )
@@ -75,10 +75,39 @@ uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uin
denominator = (((uint64_t)365 * 24 * 60) / minutes); denominator = (((uint64_t)365 * 24 * 60) / minutes);
if ( denominator == 0 ) if ( denominator == 0 )
denominator = 1; // max KOMODO_INTEREST per transfer, do it at least annually! denominator = 1; // max KOMODO_INTEREST per transfer, do it at least annually!
if ( nValue > 25000LL*COIN && txheight > 155949 ) if ( nValue > 25000LL*COIN )
{ {
numerator = (nValue / 20); // assumes 5%! exception = 0;
interest = (numerator / denominator); if ( txheight <= 155949 )
{
if ( (txheight == 116607 && nValue == 2502721100000LL) ||
(txheight == 126891 && nValue == 2879650000000LL) ||
(txheight == 129510 && nValue == 3000000000000LL) ||
(txheight == 141549 && nValue == 3500000000000LL) ||
(txheight == 154473 && nValue == 3983399350000LL) ||
(txheight == 154736 && nValue == 3983406748175LL) ||
(txheight == 155013 && nValue == 3983414006565LL) ||
(txheight == 155492 && nValue == 3983427592291LL) ||
(txheight == 155613 && nValue == 9997409999999797LL) ||
(txheight == 157927 && nValue == 9997410667451072LL) ||
(txheight == 155613 && nValue == 2590000000000LL) ||
(txheight == 155949 && nValue == 4000000000000LL) )
exception = 1;
if ( exception == 0 || nValue == 4000000000000LL )
printf(">>>>>>>>>>>> exception.%d txheight.%d %.8f locktime %u vs tiptime %u <<<<<<<<<\n",exception,txheight,(double)nValue/COIN,nLockTime,tiptime);
}
//if ( nValue == 4000000000000LL )
// printf(">>>>>>>>>>>> exception.%d txheight.%d %.8f locktime %u vs tiptime %u <<<<<<<<<\n",exception,txheight,(double)nValue/COIN,nLockTime,tiptime);
if ( exception == 0 )
{
numerator = (nValue / 20); // assumes 5%!
interest = (numerator / denominator);
}
else
{
numerator = (nValue * KOMODO_INTEREST);
interest = (numerator / denominator) / COIN;
}
} }
else else
{ {

View File

@@ -177,7 +177,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value)
ptr->height = height; ptr->height = height;
ptr->flags = flags | 1; ptr->flags = flags | 1;
portable_mutex_unlock(&KOMODO_KV_mutex); portable_mutex_unlock(&KOMODO_KV_mutex);
} else printf("size mismatch %d vs %d\n",opretlen,coresize); } //else printf("size mismatch %d vs %d\n",opretlen,coresize);
} else printf("insufficient fee %.8f vs %.8f flags.%d keylen.%d valuesize.%d height.%d (%02x %02x %02x) (%02x %02x %02x)\n",(double)fee/COIN,(double)value/COIN,flags,keylen,valuesize,height,key[0],key[1],key[2],valueptr[0],valueptr[1],valueptr[2]); } else printf("insufficient fee %.8f vs %.8f flags.%d keylen.%d valuesize.%d height.%d (%02x %02x %02x) (%02x %02x %02x)\n",(double)fee/COIN,(double)value/COIN,flags,keylen,valuesize,height,key[0],key[1],key[2],valueptr[0],valueptr[1],valueptr[2]);
} }

View File

@@ -860,7 +860,8 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
return nSigOps; 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 // Don't count coinbase transactions because mining skews the count
if (!tx.IsCoinBase()) { if (!tx.IsCoinBase()) {
@@ -871,7 +872,6 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return false; return false;
} else { } else {
// Ensure that zk-SNARKs verify // Ensure that zk-SNARKs verify
auto verifier = libzcash::ProofVerifier::Strict();
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) { if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) {
return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"), return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"),
@@ -1082,9 +1082,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
if (pfMissingInputs) if (pfMissingInputs)
*pfMissingInputs = false; *pfMissingInputs = false;
if (!CheckTransaction(tx, state)) auto verifier = libzcash::ProofVerifier::Strict();
if (!CheckTransaction(tx, state, verifier))
{ {
fprintf(stderr,"AcceptToMemoryPool CheckTransaction failed\n"); fprintf(stderr,"accept failure.0\n");
return error("AcceptToMemoryPool: CheckTransaction failed"); return error("AcceptToMemoryPool: CheckTransaction failed");
} }
// Coinbase is only valid in a block, not as a loose transaction // Coinbase is only valid in a block, not as a loose transaction
@@ -1126,7 +1127,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
{ {
static uint32_t counter; static uint32_t counter;
// Disable replacement feature for now // Disable replacement feature for now
if ( counter++ < 100 ) //if ( counter++ < 100 )
fprintf(stderr,"Disable replacement feature for now\n"); fprintf(stderr,"Disable replacement feature for now\n");
return false; return false;
} }
@@ -1173,13 +1174,16 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// are the actual inputs available? // are the actual inputs available?
if (!view.HaveInputs(tx)) if (!view.HaveInputs(tx))
return state.Invalid(error("AcceptToMemoryPool: inputs already spent"), {
REJECT_DUPLICATE, "bad-txns-inputs-spent"); fprintf(stderr,"accept failure.1\n");
return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),REJECT_DUPLICATE, "bad-txns-inputs-spent");
}
// are the joinsplit's requirements met? // are the joinsplit's requirements met?
if (!view.HaveJoinSplitRequirements(tx)) if (!view.HaveJoinSplitRequirements(tx))
return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"), {
REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met"); fprintf(stderr,"accept failure.2\n");
return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met");
}
// Bring the best block into scope // Bring the best block into scope
view.GetBestBlock(); view.GetBestBlock();
@@ -1193,7 +1197,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Check for non-standard pay-to-script-hash in inputs // Check for non-standard pay-to-script-hash in inputs
if (Params().RequireStandard() && !AreInputsStandard(tx, view)) if (Params().RequireStandard() && !AreInputsStandard(tx, view))
{
fprintf(stderr,"accept failure.3\n");
return error("AcceptToMemoryPool: nonstandard transaction input"); return error("AcceptToMemoryPool: nonstandard transaction input");
}
// Check that the transaction doesn't have an excessive number of // Check that the transaction doesn't have an excessive number of
// sigops, making it impossible to mine. Since the coinbase transaction // sigops, making it impossible to mine. Since the coinbase transaction
@@ -1203,9 +1210,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
unsigned int nSigOps = GetLegacySigOpCount(tx); unsigned int nSigOps = GetLegacySigOpCount(tx);
nSigOps += GetP2SHSigOpCount(tx, view); nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_STANDARD_TX_SIGOPS) if (nSigOps > MAX_STANDARD_TX_SIGOPS)
return state.DoS(0, error("AcceptToMemoryPool: too many sigops %s, %d > %d", {
hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS), fprintf(stderr,"accept failure.4\n");
REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); return state.DoS(0, error("AcceptToMemoryPool: too many sigops %s, %d > %d", hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS),REJECT_NONSTANDARD, "bad-txns-too-many-sigops");
}
CAmount nValueOut = tx.GetValueOut(); CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn-nValueOut; CAmount nFees = nValueIn-nValueOut;
@@ -1221,13 +1229,15 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Don't accept it if it can't get into a block // Don't accept it if it can't get into a block
CAmount txMinFee = GetMinRelayFee(tx, nSize, true); CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
if (fLimitFree && nFees < txMinFee) if (fLimitFree && nFees < txMinFee)
return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d", {
hash.ToString(), nFees, txMinFee), fprintf(stderr,"accept failure.5\n");
REJECT_INSUFFICIENTFEE, "insufficient fee"); return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",hash.ToString(), nFees, txMinFee),REJECT_INSUFFICIENTFEE, "insufficient fee");
}
} }
// Require that free transactions have sufficient priority to be mined in the next block. // Require that free transactions have sufficient priority to be mined in the next block.
if (GetBoolArg("-relaypriority", false) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { if (GetBoolArg("-relaypriority", false) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
fprintf(stderr,"accept failure.6\n");
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
} }
@@ -1249,19 +1259,25 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// -limitfreerelay unit is thousand-bytes-per-minute // -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB // At default rate it would take over a month to fill 1GB
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000) if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
{
fprintf(stderr,"accept failure.7\n");
return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"), REJECT_INSUFFICIENTFEE, "rate limited free transaction"); return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"), REJECT_INSUFFICIENTFEE, "rate limited free transaction");
}
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize; dFreeCount += nSize;
} }
if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000) if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
return error("AcceptToMemoryPool: absurdly high fees %s, %d > %d", {
hash.ToString(), nFees, ::minRelayTxFee.GetFee(nSize) * 10000); fprintf(stderr,"accept failure.8\n");
return error("AcceptToMemoryPool: absurdly high fees %s, %d > %d",hash.ToString(), nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
}
// Check against previous transactions // Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks. // This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus())) if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus()))
{ {
fprintf(stderr,"accept failure.9\n");
return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString()); return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString());
} }
@@ -1276,6 +1292,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// can be exploited as a DoS attack. // can be exploited as a DoS attack.
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus())) if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus()))
{ {
fprintf(stderr,"accept failure.10\n");
return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString());
} }
@@ -1819,6 +1836,7 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks) bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
{ {
if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) { if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) {
fprintf(stderr,"ContextualCheckInputs failure.0\n");
return false; return false;
} }
@@ -1839,9 +1857,10 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
// If prev is coinbase, check that it's matured // If prev is coinbase, check that it's matured
if (coins->IsCoinBase()) { if (coins->IsCoinBase()) {
if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) { if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) {
fprintf(stderr,"ContextualCheckInputs failure.1 i.%d of %d\n",i,(int32_t)tx.vin.size());
return state.Invalid( return state.Invalid(
error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight), error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
} }
} }
} }
@@ -2142,7 +2161,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
// Check it again in case a previous version let a bad block in // 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; return false;
// verify that the view's current state corresponds to the previous block // verify that the view's current state corresponds to the previous block
@@ -2189,7 +2213,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
CBlockUndo blockundo; CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); CCheckQueueControl<CScriptCheck> control(fExpensiveChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
int64_t nTimeStart = GetTimeMicros(); int64_t nTimeStart = GetTimeMicros();
CAmount nFees = 0; CAmount nFees = 0;
@@ -2251,7 +2275,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
nFees += view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime) - tx.GetValueOut(); nFees += view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime) - tx.GetValueOut();
sum += interest; sum += interest;
std::vector<CScriptCheck> vChecks; 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; return false;
control.Add(vChecks); control.Add(vChecks);
} }
@@ -3094,7 +3118,9 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl
} }
int32_t komodo_check_deposit(int32_t height,const CBlock& block); 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. // These are checks that are independent of context.
@@ -3139,7 +3165,7 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat
// Check transactions // Check transactions
BOOST_FOREACH(const CTransaction& tx, block.vtx) BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state)) if (!CheckTransaction(tx, state, verifier))
return error("CheckBlock(): CheckTransaction failed"); return error("CheckBlock(): CheckTransaction failed");
unsigned int nSigOps = 0; unsigned int nSigOps = 0;
@@ -3310,7 +3336,9 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
if (fTooFarAhead) return true; // Block height is too high 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,pindex,block, state, verifier)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
if (state.IsInvalid() && !state.CorruptionPossible()) { if (state.IsInvalid() && !state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID; pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex); setDirtyBlockIndex.insert(pindex);
@@ -3361,11 +3389,12 @@ bool ProcessNewBlock(int32_t height,CValidationState &state, CNode* pfrom, CBloc
{ {
// Preliminary checks // Preliminary checks
bool checked; bool checked;
auto verifier = libzcash::ProofVerifier::Disabled();
if ( chainActive.Tip() != 0 ) if ( chainActive.Tip() != 0 )
komodo_currentheight_set(chainActive.Tip()->nHeight); komodo_currentheight_set(chainActive.Tip()->nHeight);
if ( ASSETCHAINS_SYMBOL[0] == 0 ) if ( ASSETCHAINS_SYMBOL[0] == 0 )
checked = CheckBlock(height!=0?height:komodo_block2height(pblock),0,*pblock, state); checked = CheckBlock(height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier);
else checked = CheckBlock(0,0,*pblock, state); else checked = CheckBlock(0,0,*pblock, state, verifier);
{ {
LOCK(cs_main); LOCK(cs_main);
bool fRequested = MarkBlockAsReceived(pblock->GetHash()); bool fRequested = MarkBlockAsReceived(pblock->GetHash());
@@ -3400,11 +3429,13 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
CBlockIndex indexDummy(block); CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev; indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1; indexDummy.nHeight = pindexPrev->nHeight + 1;
// JoinSplit proofs are verified in ConnectBlock
auto verifier = libzcash::ProofVerifier::Disabled();
// NOTE: CheckBlockHeader is called by CheckBlock // NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, pindexPrev)) if (!ContextualCheckBlockHeader(block, state, pindexPrev))
return false; return false;
if (!CheckBlock(indexDummy.nHeight,0,block, state, fCheckPOW, fCheckMerkleRoot)) if (!CheckBlock(indexDummy.nHeight,0,block, state, verifier, fCheckPOW, fCheckMerkleRoot))
return false; return false;
if (!ContextualCheckBlock(block, state, pindexPrev)) if (!ContextualCheckBlock(block, state, pindexPrev))
return false; return false;
@@ -3725,6 +3756,8 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
CBlockIndex* pindexFailure = NULL; CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0; int nGoodTransactions = 0;
CValidationState state; CValidationState state;
// No need to verify JoinSplits twice
auto verifier = libzcash::ProofVerifier::Disabled();
for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
{ {
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
@@ -3736,7 +3769,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
if (!ReadBlockFromDisk(block, pindex)) if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 1: verify block validity // 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()); return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 2: verify undo validity // check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) { if (nCheckLevel >= 2 && pindex) {

View File

@@ -339,7 +339,7 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight); void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight);
/** Context-independent validity checks */ /** 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); bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state);
/** Check for standard transaction types /** 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); bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
/** Context-independent validity checks */ /** Context-independent validity checks */
bool CheckBlockHeader(int32_t height,CBlockIndex *pindex,const CBlockHeader& blockhdr, CValidationState& state, bool fCheckPOW = 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, bool fCheckPOW = true, bool fCheckMerkleRoot = 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 */ /** Context-dependent validity checks */
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); 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) */ /** 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); 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 AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL); bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,6 +6,7 @@
#include "rpcprotocol.h" #include "rpcprotocol.h"
#include "clientversion.h" #include "clientversion.h"
#include "random.h"
#include "tinyformat.h" #include "tinyformat.h"
#include "util.h" #include "util.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
@@ -13,6 +14,7 @@
#include "version.h" #include "version.h"
#include <stdint.h> #include <stdint.h>
#include <fstream>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
@@ -288,3 +290,68 @@ Object JSONRPCError(int code, const string& message)
error.push_back(Pair("message", message)); error.push_back(Pair("message", message));
return error; 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());
}
}

View File

@@ -14,6 +14,7 @@
#include <boost/iostreams/stream.hpp> #include <boost/iostreams/stream.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#include <boost/filesystem.hpp>
#include "json/json_spirit_reader_template.h" #include "json/json_spirit_reader_template.h"
#include "json/json_spirit_utils.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); 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); 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 #endif // BITCOIN_RPCPROTOCOL_H

View File

@@ -309,7 +309,9 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "kvupdate", &kvupdate, true }, { "blockchain", "kvupdate", &kvupdate, true },
/* Mining */ /* Mining */
#ifdef ENABLE_WALLET
{ "mining", "getblocktemplate", &getblocktemplate, true }, { "mining", "getblocktemplate", &getblocktemplate, true },
#endif
{ "mining", "getmininginfo", &getmininginfo, true }, { "mining", "getmininginfo", &getmininginfo, true },
{ "mining", "getlocalsolps", &getlocalsolps, true }, { "mining", "getlocalsolps", &getlocalsolps, true },
{ "mining", "getnetworksolps", &getnetworksolps, true }, { "mining", "getnetworksolps", &getnetworksolps, true },
@@ -629,10 +631,9 @@ void StartRPCThreads()
strAllowed += subnet.ToString() + " "; strAllowed += subnet.ToString() + " ";
LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed); LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; if (mapArgs["-rpcpassword"] == "")
if (((mapArgs["-rpcpassword"] == "") ||
(mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword())
{ {
/*<<<<<<< HEAD
unsigned char rand_pwd[32]; unsigned char rand_pwd[32];
GetRandBytes(rand_pwd, 32); GetRandBytes(rand_pwd, 32);
uiInterface.ThreadSafeMessageBox(strprintf( uiInterface.ThreadSafeMessageBox(strprintf(
@@ -651,6 +652,18 @@ void StartRPCThreads()
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE); "", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE);
StartShutdown(); StartShutdown();
return; 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); assert(rpc_io_service == NULL);
@@ -817,6 +830,8 @@ void StopRPCThreads()
} }
deadlineTimers.clear(); deadlineTimers.clear();
DeleteAuthCookie();
rpc_io_service->stop(); rpc_io_service->stop();
g_rpcSignals.Stopped(); g_rpcSignals.Stopped();
if (rpc_worker_group != NULL) if (rpc_worker_group != NULL)

View File

@@ -7,6 +7,7 @@
#include "main.h" #include "main.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"
#include "utiltime.h" #include "utiltime.h"
#include "zcash/Proof.hpp"
#include <cstdio> #include <cstdio>
@@ -56,7 +57,8 @@ BOOST_AUTO_TEST_CASE(May15)
// After May 15'th, big blocks are OK: // After May 15'th, big blocks are OK:
forkingBlock.nTime = tMay15; // Invalidates PoW 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); SetMockTime(0);

View File

@@ -358,16 +358,26 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
pwalletMain->GetPaymentAddresses(addrs); pwalletMain->GetPaymentAddresses(addrs);
BOOST_CHECK(addrs.size()==1); 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"), runtime_error);
BOOST_CHECK_THROW(CallRPC("z_exportwallet toomany args"), runtime_error); BOOST_CHECK_THROW(CallRPC("z_exportwallet toomany args"), runtime_error);
BOOST_CHECK_THROW(CallRPC(string("z_exportwallet invalid!*/_chars.txt")), runtime_error);
boost::filesystem::path temp = boost::filesystem::temp_directory_path() /
boost::filesystem::unique_path(); BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string()));
const std::string path = temp.native();
BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + path));
auto addr = paymentAddress.Get(); auto addr = paymentAddress.Get();
libzcash::SpendingKey key; libzcash::SpendingKey key;
@@ -382,7 +392,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked();
ifstream file; 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()); BOOST_CHECK(file.is_open());
bool fVerified = false; bool fVerified = false;
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg()); int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());

View File

@@ -29,6 +29,7 @@
#include "zcash/Note.hpp" #include "zcash/Note.hpp"
#include "zcash/Address.hpp" #include "zcash/Address.hpp"
#include "zcash/Proof.hpp"
using namespace std; using namespace std;
using namespace json_spirit; 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" // 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))); 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; ScriptError err;
BOOST_FOREACH(Value& tv, tests) BOOST_FOREACH(Value& tv, tests)
{ {
@@ -141,7 +143,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
stream >> tx; stream >> tx;
CValidationState state; CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier), strTest);
BOOST_CHECK(state.IsValid()); BOOST_CHECK(state.IsValid());
for (unsigned int i = 0; i < tx.vin.size(); i++) 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" // 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))); 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; ScriptError err;
BOOST_FOREACH(Value& tv, tests) BOOST_FOREACH(Value& tv, tests)
{ {
@@ -217,7 +220,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
stream >> tx; stream >> tx;
CValidationState state; 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++) for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{ {
@@ -246,11 +249,12 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
CMutableTransaction tx; CMutableTransaction tx;
stream >> tx; stream >> tx;
CValidationState state; 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 // Check that duplicate txins fail
tx.vin.push_back(tx.vin[0]); 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) BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
{ {
auto verifier = libzcash::ProofVerifier::Strict();
CMutableTransaction tx; CMutableTransaction tx;
tx.nVersion = 2; tx.nVersion = 2;
{ {
@@ -424,23 +429,23 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
JSDescription *jsdesc = &newTx.vjoinsplit[0]; JSDescription *jsdesc = &newTx.vjoinsplit[0];
jsdesc->vpub_old = -1; jsdesc->vpub_old = -1;
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-negative"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-negative");
jsdesc->vpub_old = MAX_MONEY + 1; 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"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-toolarge");
jsdesc->vpub_old = 0; jsdesc->vpub_old = 0;
jsdesc->vpub_new = -1; jsdesc->vpub_new = -1;
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-negative"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-negative");
jsdesc->vpub_new = MAX_MONEY + 1; 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"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-toolarge");
jsdesc->vpub_new = (MAX_MONEY / 2) + 10; jsdesc->vpub_new = (MAX_MONEY / 2) + 10;
@@ -450,7 +455,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
JSDescription *jsdesc2 = &newTx.vjoinsplit[1]; JSDescription *jsdesc2 = &newTx.vjoinsplit[1];
jsdesc2->vpub_new = (MAX_MONEY / 2) + 10; 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"); 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[0] = GetRandHash();
jsdesc->nullifiers[1] = jsdesc->nullifiers[0]; 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"); BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
jsdesc->nullifiers[1] = GetRandHash(); jsdesc->nullifiers[1] = GetRandHash();
@@ -475,7 +480,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
jsdesc2->nullifiers[0] = GetRandHash(); jsdesc2->nullifiers[0] = GetRandHash();
jsdesc2->nullifiers[1] = jsdesc->nullifiers[0]; 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"); BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
} }
{ {
@@ -494,7 +499,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
CTransaction finalNewTx(newTx); CTransaction finalNewTx(newTx);
BOOST_CHECK(finalNewTx.IsCoinBase()); BOOST_CHECK(finalNewTx.IsCoinBase());
} }
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-joinsplits"); BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-joinsplits");
} }
} }

View File

@@ -501,6 +501,26 @@ const boost::filesystem::path &ZC_GetParamsDir()
return path; 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) const boost::filesystem::path &GetDataDir(bool fNetSpecific)
{ {
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
@@ -556,7 +576,7 @@ void ReadConfigFile(map<string, string>& mapSettingsRet,
{ {
boost::filesystem::ifstream streamConfig(GetConfigFile()); boost::filesystem::ifstream streamConfig(GetConfigFile());
if (!streamConfig.good()) if (!streamConfig.good())
return; // No komodo.conf file is OK throw missing_zcash_conf();
set<string> setOptions; set<string> setOptions;
setOptions.insert("*"); setOptions.insert("*");
@@ -837,3 +857,17 @@ void SetThreadPriority(int nPriority)
#endif // PRIO_THREAD #endif // PRIO_THREAD
#endif // WIN32 #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" +
FormatParagraph(strprintf(_("Copyright (C) 2015-%i jl777 and SuperNET 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";
}

View File

@@ -127,6 +127,10 @@ boost::filesystem::path GetConfigFile();
boost::filesystem::path GetPidFile(); boost::filesystem::path GetPidFile();
void CreatePidFile(const boost::filesystem::path &path, pid_t pid); void CreatePidFile(const boost::filesystem::path &path, pid_t pid);
#endif #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); void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
#ifdef WIN32 #ifdef WIN32
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); 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(); boost::filesystem::path GetTempPath();
void ShrinkDebugFile(); void ShrinkDebugFile();
void runCommand(std::string strCommand); void runCommand(std::string strCommand);
const boost::filesystem::path GetExportDir();
/** Returns licensing information (for -version) */
std::string LicenseInfo();
inline bool IsSwitchChar(char c) inline bool IsSwitchChar(char c)
{ {

View File

@@ -30,6 +30,22 @@ string SanitizeString(const string& str)
return strResult; 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] = 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,-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,

View File

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

View File

@@ -53,8 +53,9 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
std::vector<SendManyRecipient> tOutputs, std::vector<SendManyRecipient> tOutputs,
std::vector<SendManyRecipient> zOutputs, std::vector<SendManyRecipient> zOutputs,
int minDepth, int minDepth,
CAmount fee) : CAmount fee,
fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth), fee_(fee) Value contextInfo) :
fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth), fee_(fee), contextinfo_(contextInfo)
{ {
assert(fee_ > 0); assert(fee_ > 0);
@@ -88,7 +89,7 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
isfromzaddr_ = true; isfromzaddr_ = true;
frompaymentaddress_ = addr; frompaymentaddress_ = addr;
spendingkey_ = key; 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()); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("runtime error: ") + e.what());
} }
} }
@@ -108,17 +109,20 @@ void AsyncRPCOperation_sendmany::main() {
try { try {
success = main_impl(); success = main_impl();
} catch (Object objError) { } catch (const Object& objError) {
int code = find_value(objError, "code").get_int(); int code = find_value(objError, "code").get_int();
std::string message = find_value(objError, "message").get_str(); std::string message = find_value(objError, "message").get_str();
set_error_code(code); set_error_code(code);
set_error_message(message); set_error_message(message);
} catch (runtime_error e) { } catch (const runtime_error& e) {
set_error_code(-1); set_error_code(-1);
set_error_message("runtime error: " + string(e.what())); set_error_message("runtime error: " + string(e.what()));
} catch (logic_error e) { } catch (const logic_error& e) {
set_error_code(-1); set_error_code(-1);
set_error_message("logic error: " + string(e.what())); 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 (...) { } catch (...) {
set_error_code(-2); set_error_code(-2);
set_error_message("unknown error"); set_error_message("unknown error");
@@ -450,13 +454,22 @@ bool AsyncRPCOperation_sendmany::main_impl() {
info.notes.push_back(note); info.notes.push_back(note);
outPoints.push_back(outPoint); outPoints.push_back(outPoint);
int wtxHeight = -1;
LogPrint("zrpc", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s)\n", 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), getId().substr(0, 10),
outPoint.hash.ToString().substr(0, 10), outPoint.hash.ToString().substr(0, 10),
outPoint.js, outPoint.js,
int(outPoint.n), // uint8_t 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) 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())); 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; 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), getId().substr(0, 10),
jso.hash.ToString().substr(0, 10), jso.hash.ToString().substr(0, 10),
jso.js, jso.js,
int(jso.n), // uint8_t 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)); o.push_back(Pair("hex", signedtxn));
set_result(Value(o)); 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; 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);
}

View File

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

View File

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

View File

@@ -430,7 +430,9 @@ Value z_exportwallet(const Array& params, bool fHelp)
"z_exportwallet \"filename\"\n" "z_exportwallet \"filename\"\n"
"\nExports all wallet keys, for taddr and zaddr, in a human-readable format.\n" "\nExports all wallet keys, for taddr and zaddr, in a human-readable format.\n"
"\nArguments:\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" "\nExamples:\n"
+ HelpExampleCli("z_exportwallet", "\"test\"") + HelpExampleCli("z_exportwallet", "\"test\"")
+ HelpExampleRpc("z_exportwallet", "\"test\"") + HelpExampleRpc("z_exportwallet", "\"test\"")
@@ -449,7 +451,9 @@ Value dumpwallet(const Array& params, bool fHelp)
"dumpwallet \"filename\"\n" "dumpwallet \"filename\"\n"
"\nDumps taddr wallet keys in a human-readable format.\n" "\nDumps taddr wallet keys in a human-readable format.\n"
"\nArguments:\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" "\nExamples:\n"
+ HelpExampleCli("dumpwallet", "\"test\"") + HelpExampleCli("dumpwallet", "\"test\"")
+ HelpExampleRpc("dumpwallet", "\"test\"") + HelpExampleRpc("dumpwallet", "\"test\"")
@@ -464,8 +468,24 @@ Value dumpwallet_impl(const Array& params, bool fHelp, bool fDumpZKeys)
EnsureWalletIsUnlocked(); 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; ofstream file;
file.open(params[0].get_str().c_str()); file.open(exportfilepath.string().c_str());
if (!file.is_open()) if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); 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 << "# End of dump\n";
file.close(); 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; 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 // We want to scan for transactions and notes
if (fRescan) { if (fRescan) {
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);

View File

@@ -34,6 +34,8 @@
#include "json/json_spirit_value.h" #include "json/json_spirit_value.h"
#include "asyncrpcqueue.h" #include "asyncrpcqueue.h"
#include <numeric>
using namespace std; using namespace std;
using namespace json_spirit; 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))); entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
if (fLong) if (fLong)
WalletTxToJSON(wtx, entry); WalletTxToJSON(wtx, entry);
entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
ret.push_back(entry); 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)); entry.push_back(Pair("vout", r.vout));
if (fLong) if (fLong)
WalletTxToJSON(wtx, entry); WalletTxToJSON(wtx, entry);
entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
ret.push_back(entry); 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" " \"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" " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
" negative amounts).\n" " negative amounts).\n"
" \"size\": n, (numeric) Transaction size in bytes\n"
" }\n" " }\n"
"]\n" "]\n"
@@ -1998,21 +2003,38 @@ Value backupwallet(const Array& params, bool fHelp)
if (fHelp || params.size() != 1) if (fHelp || params.size() != 1)
throw runtime_error( throw runtime_error(
"backupwallet \"destination\"\n" "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" "\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" "\nExamples:\n"
+ HelpExampleCli("backupwallet", "\"backup.dat\"") + HelpExampleCli("backupwallet", "\"backupdata\"")
+ HelpExampleRpc("backupwallet", "\"backup.dat\"") + HelpExampleRpc("backupwallet", "\"backupdata\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
string strDest = params[0].get_str(); boost::filesystem::path exportdir;
if (!BackupWallet(*pwalletMain, strDest)) 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!"); throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
return Value::null; return exportfilepath.string();
} }
@@ -2612,12 +2634,14 @@ Value listunspent(const Array& params, bool fHelp)
{ {
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
CBlockIndex *tipindex,*pindex = it->second; CBlockIndex *tipindex,*pindex = it->second;
uint64_t interest; uint64_t interest; uint32_t locktime; int32_t txheight;
komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue);
if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 )
{ {
interest = komodo_interest(pindex->nHeight,nValue,out.tx->nLockTime,tipindex->nTime); interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime);
entry.push_back(Pair("interest",ValueFromAmount(interest))); entry.push_back(Pair("interest",ValueFromAmount(interest)));
} }
//fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.Tip(),locktime,txheight,pindex->nHeight);
} }
entry.push_back(Pair("confirmations",out.nDepth)); entry.push_back(Pair("confirmations",out.nDepth));
entry.push_back(Pair("spendable", out.fSpendable)); entry.push_back(Pair("spendable", out.fSpendable));
@@ -2734,7 +2758,15 @@ Value zc_benchmark(const json_spirit::Array& params, bool fHelp)
} else if (benchmarktype == "parameterloading") { } else if (benchmarktype == "parameterloading") {
sample_times.push_back(benchmark_parameter_loading()); sample_times.push_back(benchmark_parameter_loading());
} else if (benchmarktype == "createjoinsplit") { } 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") { } else if (benchmarktype == "verifyjoinsplit") {
sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit)); sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
} else if (benchmarktype == "solveequihash") { } else if (benchmarktype == "solveequihash") {
@@ -3224,7 +3256,7 @@ Value z_listreceivedbyaddress(const Array& params, bool fHelp)
CZCPaymentAddress address(fromaddress); CZCPaymentAddress address(fromaddress);
try { try {
zaddr = address.Get(); zaddr = address.Get();
} catch (std::runtime_error) { } catch (const std::runtime_error&) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr."); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
} }
@@ -3291,7 +3323,7 @@ Value z_getbalance(const Array& params, bool fHelp)
CZCPaymentAddress address(fromaddress); CZCPaymentAddress address(fromaddress);
try { try {
zaddr = address.Get(); 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."); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
} }
if (!pwalletMain->HaveSpendingKey(zaddr)) { if (!pwalletMain->HaveSpendingKey(zaddr)) {
@@ -3443,6 +3475,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; return ret;
} }
@@ -3497,7 +3536,7 @@ Value z_sendmany(const Array& params, bool fHelp)
CZCPaymentAddress address(fromaddress); CZCPaymentAddress address(fromaddress);
try { try {
zaddr = address.Get(); zaddr = address.Get();
} catch (std::runtime_error) { } catch (const std::runtime_error&) {
// invalid // invalid
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr."); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
} }
@@ -3544,7 +3583,7 @@ Value z_sendmany(const Array& params, bool fHelp)
CZCPaymentAddress zaddr(address); CZCPaymentAddress zaddr(address);
zaddr.Get(); zaddr.Get();
isZaddr = true; isZaddr = true;
} catch (std::runtime_error) { } catch (const std::runtime_error&) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address ); throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
} }
} }
@@ -3624,9 +3663,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 // Create operation and add to global queue
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue(); 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); q->addOperation(operation);
AsyncRPCOperationId operationId = operation->getId(); AsyncRPCOperationId operationId = operation->getId();
return operationId; return operationId;

View File

@@ -645,10 +645,14 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) { for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) { for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
CNoteData* nd = &(item.second); CNoteData* nd = &(item.second);
// Check the validity of the cache
assert(nWitnessCacheSize >= nd->witnesses.size());
// Only increment witnesses that are behind the current height // Only increment witnesses that are behind the current height
if (nd->witnessHeight < pindex->nHeight) { 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 // Witnesses being incremented should always be either -1
// (never incremented or decremented) or one below pindex // (never incremented or decremented) or one below pindex
assert((nd->witnessHeight == -1) || assert((nd->witnessHeight == -1) ||
@@ -687,10 +691,11 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) { for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) { for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
CNoteData* nd = &(item.second); CNoteData* nd = &(item.second);
// Check the validity of the cache
assert(nWitnessCacheSize >= nd->witnesses.size());
if (nd->witnessHeight < pindex->nHeight && if (nd->witnessHeight < pindex->nHeight &&
nd->witnesses.size() > 0) { 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); nd->witnesses.front().append(note_commitment);
} }
} }
@@ -699,7 +704,8 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
// If this is our note, witness it // If this is our note, witness it
if (txIsOurs) { if (txIsOurs) {
JSOutPoint jsoutpt {hash, i, j}; 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]); CNoteData* nd = &(mapWallet[hash].mapNoteData[jsoutpt]);
if (nd->witnesses.size() > 0) { if (nd->witnesses.size() > 0) {
// We think this can happen because we write out the // We think this can happen because we write out the
@@ -735,9 +741,10 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
CNoteData* nd = &(item.second); CNoteData* nd = &(item.second);
if (nd->witnessHeight < pindex->nHeight) { if (nd->witnessHeight < pindex->nHeight) {
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 (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) { for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
CNoteData* nd = &(item.second); 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 // Only increment witnesses that are not above the current height
if (nd->witnessHeight <= pindex->nHeight) { 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 // Witnesses being decremented should always be either -1
// (never incremented or decremented) or equal to pindex // (never incremented or decremented) or equal to pindex
assert((nd->witnessHeight == -1) || assert((nd->witnessHeight == -1) ||
@@ -777,7 +786,18 @@ void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex)
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) { for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
CNoteData* nd = &(item.second); CNoteData* nd = &(item.second);
// Check the validity of the cache // 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 ) if ( nWitnessCacheSize <= 0 )
@@ -2185,6 +2205,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
* populate vCoins with vector of available COutputs. * populate vCoins with vector of available COutputs.
*/ */
uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime); uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue);
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, bool fIncludeCoinBase) const void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue, bool fIncludeCoinBase) const
{ {
@@ -2223,14 +2244,20 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
{ {
#ifdef KOMODO_ENABLE_INTEREST #ifdef KOMODO_ENABLE_INTEREST
extern char ASSETCHAINS_SYMBOL[16]; extern char ASSETCHAINS_SYMBOL[16];
uint32_t locktime; int32_t txheight; CBlockIndex *tipindex;
if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.Tip() != 0 && chainActive.Tip()->nHeight >= 60000 ) if ( ASSETCHAINS_SYMBOL[0] == 0 && chainActive.Tip() != 0 && chainActive.Tip()->nHeight >= 60000 )
{ {
if ( pcoin->vout[i].nValue >= 10*COIN ) if ( pcoin->vout[i].nValue >= 10*COIN )
{ {
interest = komodo_interest(chainActive.Tip()->nHeight+1,pcoin->vout[i].nValue,pcoin->nLockTime,chainActive.Tip()->nTime); komodo_accrued_interest(&txheight,&locktime,wtxid,i,0,pcoin->vout[i].nValue);
if ( (tipindex= chainActive.Tip()) != 0 )
{
interest = komodo_interest(txheight,pcoin->vout[i].nValue,locktime,tipindex->nTime);
} else interest = 0;
//interest = komodo_interest(chainActive.Tip()->nHeight+1,pcoin->vout[i].nValue,pcoin->nLockTime,chainActive.Tip()->nTime);
if ( interest != 0 ) if ( interest != 0 )
{ {
//printf("wallet nValueRet %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,chainActive.Tip()->nHeight+1,pcoin->nLockTime,chainActive.Tip()->nTime); //printf("wallet nValueRet %.8f += interest %.8f ht.%d lock.%u/%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,txheight,locktime,pcoin->nLockTime,tipindex->nTime);
//fprintf(stderr,"wallet nValueRet %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,chainActive.Tip()->nHeight+1,pcoin->nLockTime,chainActive.Tip()->nTime); //fprintf(stderr,"wallet nValueRet %.8f += interest %.8f ht.%d lock.%u tip.%u\n",(double)pcoin->vout[i].nValue/COIN,(double)interest/COIN,chainActive.Tip()->nHeight+1,pcoin->nLockTime,chainActive.Tip()->nTime);
//ptr = (uint64_t *)&pcoin->vout[i].nValue; //ptr = (uint64_t *)&pcoin->vout[i].nValue;
//(*ptr) += interest; //(*ptr) += interest;
@@ -2805,7 +2832,8 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
// Broadcast // Broadcast
if (!wtxNew.AcceptToMemoryPool(false)) if (!wtxNew.AcceptToMemoryPool(false))
{ {
// This must not fail. The transaction has already been signed and recorded. fprintf(stderr,"commit failed\n");
// This must not fail. The transaction has already been signed and recorded.
LogPrintf("CommitTransaction(): Error: Transaction not valid\n"); LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
return false; return false;
} }

View File

@@ -14,6 +14,7 @@
#include "util.h" #include "util.h"
#include "utiltime.h" #include "utiltime.h"
#include "wallet/wallet.h" #include "wallet/wallet.h"
#include "zcash/Proof.hpp"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@@ -411,7 +412,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CWalletTx wtx; CWalletTx wtx;
ssValue >> wtx; ssValue >> wtx;
CValidationState state; 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; return false;
// Undo serialize changes in 31600 // Undo serialize changes in 31600

View File

@@ -0,0 +1,36 @@
// 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"
char ASSETCHAINS_SYMBOL[16];
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);
}
}

View File

@@ -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> template<size_t Depth, typename Hash>
void IncrementalMerkleTree<Depth, Hash>::append(Hash obj) { void IncrementalMerkleTree<Depth, Hash>::append(Hash obj) {
if (is_complete(Depth)) { if (is_complete(Depth)) {

View File

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

View File

@@ -163,6 +163,10 @@ curve_G2 CompressedG2::to_libsnark_g2() const
assert(r.is_well_formed()); 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; return r;
} }

View File

@@ -95,6 +95,27 @@ double benchmark_create_joinsplit()
return ret; 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) double benchmark_verify_joinsplit(const JSDescription &joinsplit)
{ {
struct timeval tv_start; struct timeval tv_start;

View File

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

View File

@@ -8,7 +8,7 @@ set -x
BUILD_PATH="/tmp/zcbuild" BUILD_PATH="/tmp/zcbuild"
PACKAGE_NAME="zcash" PACKAGE_NAME="zcash"
SRC_PATH=`pwd` SRC_PATH=`pwd`
SRC_DEB=$SRC_PATH/contrib/DEBIAN SRC_DEB=$SRC_PATH/contrib/debian
umask 022 umask 022
@@ -16,22 +16,20 @@ if [ ! -d $BUILD_PATH ]; then
mkdir $BUILD_PATH mkdir $BUILD_PATH
fi 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" BUILD_DIR="$BUILD_PATH/$PACKAGE_NAME-$PACKAGE_VERSION-amd64"
if [ -d $BUILD_DIR ]; then if [ -d $BUILD_DIR ]; then
rm -R $BUILD_DIR rm -R $BUILD_DIR
fi fi
DEB_CMP=$BUILD_DIR/etc/bash_completion.d
DEB_BIN=$BUILD_DIR/usr/bin 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_DOC=$BUILD_DIR/usr/share/doc/$PACKAGE_NAME
DEB_MAN=$BUILD_DIR/usr/share/man/man1 DEB_MAN=$BUILD_DIR/usr/share/man/man1
mkdir -p $BUILD_DIR/DEBIAN $DEB_CMP $DEB_BIN $DEB_DOC $DEB_MAN mkdir -p $BUILD_DIR/DEBIAN $DEB_CMP $DEB_BIN $DEB_DOC $DEB_MAN
chmod 0755 -R $BUILD_DIR/* chmod 0755 -R $BUILD_DIR/*
# Copy control file
cp $SRC_DEB/control $BUILD_DIR/DEBIAN
# Package maintainer scripts (currently empty) # Package maintainer scripts (currently empty)
#cp $SRC_DEB/postinst $BUILD_DIR/DEBIAN #cp $SRC_DEB/postinst $BUILD_DIR/DEBIAN
#cp $SRC_DEB/postrm $BUILD_DIR/DEBIAN #cp $SRC_DEB/postrm $BUILD_DIR/DEBIAN
@@ -49,6 +47,7 @@ cp -r $SRC_DEB/examples $DEB_DOC
# Copy manpages # Copy manpages
cp $SRC_DEB/manpages/zcashd.1 $DEB_MAN cp $SRC_DEB/manpages/zcashd.1 $DEB_MAN
cp $SRC_DEB/manpages/zcash-cli.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 # Copy bash completion files
cp $SRC_PATH/contrib/bitcoind.bash-completion $DEB_CMP/zcashd cp $SRC_PATH/contrib/bitcoind.bash-completion $DEB_CMP/zcashd
cp $SRC_PATH/contrib/bitcoin-cli.bash-completion $DEB_CMP/zcash-cli 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_DOC/changelog.Debian
gzip --best -n $DEB_MAN/zcashd.1 gzip --best -n $DEB_MAN/zcashd.1
gzip --best -n $DEB_MAN/zcash-cli.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 # Create the Debian package
fakeroot dpkg-deb --build $BUILD_DIR fakeroot dpkg-deb --build $BUILD_DIR