diff --git a/.gitignore b/.gitignore index 1f2b2537d..01e45a168 100644 --- a/.gitignore +++ b/.gitignore @@ -7,10 +7,6 @@ src/zcash-gtest src/zcash-tx src/test/test_bitcoin -# Zcash utilities -src/zcash/GenerateParams -src/zcash/CreateJoinSplit - *zcashTest.pk *zcashTest.vk diff --git a/COPYING b/COPYING index 02509fbc9..7c046110d 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,7 @@ -Copyright (c) 2016-2018 The Komodo developers -Copyright (c) 2016-2017 The Zcash developers Copyright (c) 2009-2017 The Bitcoin Core developers +Copyright (c) 2009-2018 Bitcoin Developers +Copyright (c) 2016-2017 The Zcash developers +Copyright (c) 2016-2018 The Komodo developers Copyright (c) 2018 The VerusCoin developers Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/README.md b/README.md index 1e365b973..7f400f9f5 100644 --- a/README.md +++ b/README.md @@ -108,13 +108,16 @@ Note that this directory is correct for Linux, not Mac or Windows ./src/komodo-cli help **Zcash is unfinished and highly experimental.** Use at your own risk. -Where do I begin? ------------------ -We have a guide for joining the main Zcash network: -https://github.com/zcash/zcash/wiki/1.0-User-Guide +#### :ledger: Deprecation Policy + +This release is considered deprecated 16 weeks after the release day. There +is an automatic deprecation shutdown feature which will halt the node some +time after this 16 week time period. The automatic feature is based on block +height. #Older Komodo Details The remaining text is from the komodo source we forked when creating VerusCoin/Veruscoin. + **To change modes:** a) backup all privkeys (launch komodod with `-exportdir=` and `dumpwallet`) @@ -124,18 +127,18 @@ d) resume sync till it gets to chaintip For example: ```shell -./komodod -exportdir=/tmp & -./komodo-cli dumpwallet example -./komodo-cli stop -mv ~/.komodo ~/.komodo.old && mkdir ~/.komodo && cp ~/.komodo.old/komodo.conf ~/.komodo.old/peers.dat ~/.komodo -./komodod -exchange -exportdir=/tmp & -./komodo-cli importwallet /tmp/example +./verusd -exportdir=/tmp & +./verus dumpwallet example +./verus stop +mv ~/.komodo/VRSC ~/.komodo/VRSC.old && mkdir ~/.komodo/VRSC && cp ~/.komodo/VRSC.old/VRSC.conf ~/.komodo/VRSC.old/peers.dat ~/.komodo/VRSC +./verusd -exchange -exportdir=/tmp & +./verus importwallet /tmp/example ``` --- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The above copyright notices and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/VRSC_7776 b/VRSC_7776 new file mode 100644 index 000000000..5b272c922 --- /dev/null +++ b/VRSC_7776 @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"VRSC.conf\",\"path\":\"${HOME#"/"}/.komodo/VRSC\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"VRSC\",\"name\":\"VRSC\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"ad8a58e2\",\"p2p\":27485,\"rpc\":27486,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" \ No newline at end of file diff --git a/code_of_conduct.md b/code_of_conduct.md index d8f622351..c4592cc32 100644 --- a/code_of_conduct.md +++ b/code_of_conduct.md @@ -24,7 +24,9 @@ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +threatening, offensive, or harmful. Note that contributors may be volunteers +who do not represent Zcash Company. They are free to express their own +opinions so long as they adhere to these guidelines. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing diff --git a/configure.ac b/configure.ac index eda8fa433..aa0fc1214 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) -define(_CLIENT_VERSION_MAJOR, 1) +define(_CLIENT_VERSION_MAJOR, 2) define(_CLIENT_VERSION_MINOR, 0) -define(_CLIENT_VERSION_REVISION, 15) +define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_BUILD, 50) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) @@ -96,12 +96,6 @@ AC_ARG_ENABLE([mining], [enable_mining=$enableval], [enable_mining=yes]) -AC_ARG_ENABLE([rust], - [AS_HELP_STRING([--enable-rust], - [enable rust (default is yes)])], - [enable_rust=$enableval], - [enable_rust=yes]) - AC_ARG_ENABLE([proton], [AS_HELP_STRING([--disable-proton], [disable Proton (AMQP messaging)])], @@ -238,9 +232,9 @@ AC_ARG_WITH([utils], AC_ARG_WITH([libs], [AS_HELP_STRING([--with-libs], - [build libraries (default=yes)])], + [build libraries (default=no)])], [build_bitcoin_libs=$withval], - [build_bitcoin_libs=yes]) + [build_bitcoin_libs=no]) AC_ARG_WITH([daemon], [AS_HELP_STRING([--with-daemon], @@ -772,15 +766,20 @@ fi #AC_CHECK_HEADER([libsnark/gadgetlib1/gadget.hpp],,AC_MSG_ERROR(libsnark headers missing)) #AC_CHECK_LIB([snark],[main],LIBSNARK_LIBS=-lsnark, [AC_MSG_ERROR(libsnark missing)], [-lgmpxx]) -RUST_LIBS="" -if test x$enable_rust != xno; then - RUST_LIBS="-lrustzcash" -fi +RUST_LIBS="-lrustzcash" +case $host in + *mingw*) + ;; + *) + RUST_LIBS="$RUST_LIBS -ldl" + ;; +esac dnl Check for OpenMP support AX_OPENMP( [AC_DEFINE(HAVE_OPENMP, 1, [Define if OpenMP is enabled]) AM_CONDITIONAL([HAVE_OPENMP], [true]) + CPPFLAGS="$CPPFLAGS -DMULTICORE" CXXFLAGS="$CXXFLAGS $OPENMP_CXXFLAGS"], [AC_MSG_WARN([OpenMP not supported, disabling multithreading]) AC_DEFINE(HAVE_OPENMP, 0, [Define if OpenMP is enabled]) @@ -799,7 +798,7 @@ AX_CHECK_COMPILE_FLAG([-fwrapv],[CXXFLAGS="$CXXFLAGS -fwrapv"]) AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing],[CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"]) AX_CHECK_COMPILE_FLAG([-Wno-builtin-declaration-mismatch],[CXXFLAGS="$CXXFLAGS -Wno-builtin-declaration-mismatch"],,[[$CXXFLAG_WERROR]]) -LIBZCASH_LIBS="-lgmp -lgmpxx -lboost_system -lcrypto -lsodium $RUST_LIBS" +LIBZCASH_LIBS="-lgmp -lgmpxx $BOOST_SYSTEM_LIB -lcrypto -lsodium $RUST_LIBS" AC_MSG_CHECKING([whether to build bitcoind]) AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes]) @@ -859,16 +858,6 @@ else AC_MSG_RESULT(no) fi -dnl enable rust -AC_MSG_CHECKING([if rust should be enabled]) -if test x$enable_rust != xno; then - AC_MSG_RESULT(yes) - AC_DEFINE(ENABLE_RUST, 1, [Define to 1 to enable Rust language dependent functions]) - -else - AC_MSG_RESULT(no) -fi - AM_CONDITIONAL([ENABLE_ZMQ], [test "x$use_zmq" = "xyes"]) AM_CONDITIONAL([ENABLE_PROTON], [test "x$use_proton" = "xyes"]) @@ -898,7 +887,6 @@ AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) AM_CONDITIONAL([ENABLE_MINING],[test x$enable_mining = xyes]) -AM_CONDITIONAL([ENABLE_RUST],[test x$enable_rust = xyes]) AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) @@ -991,7 +979,6 @@ esac echo echo "Options used to compile and link:" echo " with wallet = $enable_wallet" -echo " with rust = $enable_rust" echo " with proton = $use_proton" echo " with zmq = $use_zmq" echo " with test = $use_tests" diff --git a/contrib/ci-workers/README.md b/contrib/ci-workers/README.md index 37f7ad833..8ce9dc764 100644 --- a/contrib/ci-workers/README.md +++ b/contrib/ci-workers/README.md @@ -5,29 +5,29 @@ installation for use as a Buildbot worker in Zcash's CI. # Criteria for Adding Workers -a. Don't add workers until users complain about a problem on a platform - that doesn't yet have workers or if we anticipate many users will use - a platform, we may pre-emptively add an unsupported worker for it. +a. Don't add workers until users complain about a problem on a platform that + doesn't yet have workers. However, if we anticipate many users will use a + platform, we may pre-emptively add an unsupported worker for it. b. Prioritize the platforms that seem to have the most users. -c. When adding workers start by adding workers for the "most common" - variant of any distro, then if users later encounter problems with a - sub-variant, we can consider adding new workers at that point. - Example: add Ubuntu Desktop before Xubuntu, on the assumption the - former has a larger population base. +c. When adding workers, start by adding workers for the "most common" variant of + any distro. Then if users later encounter problems with a sub-variant, we can + consider adding new workers at that point. Example: add Ubuntu Desktop before + Xubuntu, on the assumption the former has a larger population base, and the + latter only materially differs in the GUI. # Setting up a latent worker on Amazon EC2 -- Add a regular (non-latent) worker to the master.cfg for dev-ci.z.cash, and - deploy the changes. +1. Add a regular (non-latent) worker to the master.cfg for dev-ci.z.cash, and + deploy the changes. - This enables the Ansible playbook to run to completion, ending in the worker connecting to the master. -- Start a basic EC2 instance using the template AMI for the target OS. +2. Start a basic EC2 instance using the template AMI for the target OS. - Choose the smallest instance size, it won't be used for building Zcash. -- Figure out which user to log into the instance with. +3. Figure out which user to log into the instance with. - E.g. for the Ubuntu template, use "ubuntu" instead of "root" - If you get an Ansible error later with a message like "Failed to connect to the host via ssh: Received message too long 1349281121\r\n", that means the @@ -35,28 +35,28 @@ c. When adding workers start by adding workers for the "most common" Ansible protocol is balking. Try manually logging in with the same credentials to diagnose. -- Create `inventory/hosts` containing the following: +4. Create `inventory/hosts` containing the following: [zcash-ci-worker-unix] some-name ansible_host= ansible_ssh_user= -- Run `ansible-playbook -e buildbot_worker_host_template=templates/host.ec2.j2 -i inventory/hosts unix.yml`, - passing in the worker's Buildbot name and password. +5. Run `ansible-playbook -e buildbot_worker_host_template=templates/host.ec2.j2 -i inventory/hosts unix.yml`, + passing in the worker's Buildbot name and password. - After a successful run, the worker should be connected to dev-ci.z.cash and visible in its worker list. -- Create an AMI from the instance. This is the worker AMI to put into the - master.cfg for dev-ci.z.cash. +6. Create an AMI from the instance. This is the worker AMI to put into the + master.cfg for dev-ci.z.cash. - 16 GB of storage should be sufficient. -- SSH into the instance, and edit the worker config to connect to ci.z.cash. +7. SSH into the instance, and edit the worker config to connect to ci.z.cash. -- Create an AMI from the instance. This is the worker AMI to put into the - master.cfg for ci.z.cash. +8. Create an AMI from the instance. This is the worker AMI to put into the + master.cfg for ci.z.cash. - 16 GB of storage should be sufficient. -- Delete the instance (it is no longer needed). +9. Delete the instance (it is no longer needed). -- Edit the master.cfg to turn the new worker into a latent (using the new AMI - IDs), add it to the appropriate worker groups, set up new builders etc. +10. Edit the master.cfg to turn the new worker into a latent (using the new AMI + IDs), add it to the appropriate worker groups, set up new builders etc. - Deploy this via the normal PR review process. diff --git a/contrib/ci-workers/files/bashrc b/contrib/ci-workers/files/bashrc new file mode 100644 index 000000000..aaad18b92 --- /dev/null +++ b/contrib/ci-workers/files/bashrc @@ -0,0 +1,2 @@ +export PATH=$HOME/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +export EDITOR=vim diff --git a/contrib/ci-workers/tasks/install-brew.yml b/contrib/ci-workers/tasks/install-brew.yml new file mode 100644 index 000000000..5faedad0b --- /dev/null +++ b/contrib/ci-workers/tasks/install-brew.yml @@ -0,0 +1,10 @@ +--- +- name: Check if brew is installed + stat: + path: /usr/local/bin/brew + register: brew_check + +- name: Fail if brew is unavailable + fail: + msg: 'brew is not installed! Please install Homebrew: https://docs.brew.sh/Installation.html' + when: not brew_check.stat.exists diff --git a/contrib/ci-workers/templates/buildbot-worker.plist.j2 b/contrib/ci-workers/templates/buildbot-worker.plist.j2 new file mode 100644 index 000000000..225c73b8a --- /dev/null +++ b/contrib/ci-workers/templates/buildbot-worker.plist.j2 @@ -0,0 +1,23 @@ + + + + + Label + net.buildbot.worker + ProgramArguments + + {{ buildbot_worker_dir }}/venv/bin/buildbot-worker + start + {{ buildbot_worker_name }} + + WorkingDirectory + {{ buildbot_worker_dir }} + UserName + {{ buildbot_worker_user }} + KeepAlive + + NetworkState + + + + diff --git a/contrib/ci-workers/templates/buildbot-worker.service.j2 b/contrib/ci-workers/templates/buildbot-worker.service.j2 index ffe497bcf..625323be6 100644 --- a/contrib/ci-workers/templates/buildbot-worker.service.j2 +++ b/contrib/ci-workers/templates/buildbot-worker.service.j2 @@ -5,11 +5,11 @@ After=network.target [Service] Type=forking -PIDFile=/home/{{ buildbot_worker_user }}/{{ buildbot_worker_name }}/twistd.pid -WorkingDirectory=/home/{{ buildbot_worker_user }} -ExecStart={{ pip_bin_dir }}/buildbot-worker start {{ buildbot_worker_name }} -ExecReload={{ pip_bin_dir }}/buildbot-worker restart {{ buildbot_worker_name }} -ExecStop={{ pip_bin_dir }}/buildbot-worker stop {{ buildbot_worker_name }} +PIDFile={{ buildbot_worker_dir }}/{{ buildbot_worker_name }}/twistd.pid +WorkingDirectory={{ buildbot_worker_dir }} +ExecStart={{ buildbot_worker_dir }}/venv/bin/buildbot-worker start {{ buildbot_worker_name }} +ExecReload={{ buildbot_worker_dir }}/venv/bin/buildbot-worker restart {{ buildbot_worker_name }} +ExecStop={{ buildbot_worker_dir }}/venv/bin/buildbot-worker stop {{ buildbot_worker_name }} Restart=always User={{ buildbot_worker_user }} diff --git a/contrib/ci-workers/templates/host.j2 b/contrib/ci-workers/templates/host.j2 index 3a5abb0c2..65c4cb709 100644 --- a/contrib/ci-workers/templates/host.j2 +++ b/contrib/ci-workers/templates/host.j2 @@ -1,3 +1,3 @@ OS: {{ ansible_distribution }} {{ ansible_distribution_version }} Memory: {{ ansible_memtotal_mb }} MB -CPU: {{ ansible_processor[1] }} +CPU: {{ ansible_processor if ansible_processor is string else ansible_processor[1] }} ({{ ansible_processor_cores }} cores) diff --git a/contrib/ci-workers/unix.yml b/contrib/ci-workers/unix.yml index 6e6cc49c4..cbb693401 100644 --- a/contrib/ci-workers/unix.yml +++ b/contrib/ci-workers/unix.yml @@ -50,6 +50,7 @@ - name: Gathering Facts setup: + tags: deps - name: Fail if Python is the wrong version fail: @@ -66,34 +67,44 @@ - "vars/{{ ansible_distribution }}.yml" - "vars/{{ ansible_os_family }}.yml" skip: true + tags: deps - name: Collate dependencies set_fact: package_deps: "{{ buildbot_deps + fetch_deps + conf_deps + build_deps + link_deps + dist_deps }}" python_modules: "{{ buildbot_modules + rpc_test_modules }}" + tags: deps + + - name: Install Homebrew [MacOSX] + include: tasks/install-brew.yml + when: ansible_distribution == 'MacOSX' + tags: deps - name: Update rolling release [Arch Linux] pacman: update_cache: yes upgrade: yes when: ansible_distribution == 'Archlinux' + tags: deps - name: Install required packages package: name: "{{ item }}" state: present with_items: "{{ package_deps }}" + become_user: "{{ ansible_ssh_user if ansible_distribution == 'MacOSX' else 'root' }}" + tags: deps - - name: Install pip [CentOS] + - name: Install pip [CentOS, MacOSX] include: tasks/install-pip.yml - when: ansible_distribution == 'CentOS' + when: ansible_distribution in ['CentOS', 'MacOSX'] - - name: Install required Python modules + - name: Install required Python system modules pip: name: "{{ item }}" state: latest - with_items: "{{ python_modules }}" - notify: restart buildbot-worker + executable: "{{ '/usr/local/bin/pip' if ansible_distribution == 'MacOSX' else omit }}" + with_items: "{{ system_modules }}" - name: Set up the Buildbot worker user user: @@ -102,9 +113,28 @@ shell: /bin/bash state: present + - name: Get absolute path to Buildbot worker home directory + command: echo ~ + register: homedir + become_user: "{{ buildbot_worker_user }}" + + - name: Save absolute path to Buildbot worker home directory + set_fact: + buildbot_worker_dir: "{{ homedir.stdout }}" + + - name: Install required Python modules + pip: + name: "{{ item }}" + state: latest + virtualenv: "~{{ buildbot_worker_user }}/venv" + virtualenv_command: "{{ '/usr/local/bin/virtualenv' if ansible_distribution == 'MacOSX' else omit }}" + with_items: "{{ python_modules }}" + become_user: "{{ buildbot_worker_user }}" + notify: restart buildbot-worker + - name: Create Buildbot worker command: > - buildbot-worker create-worker ~/{{ buildbot_worker_name }} + ~{{ buildbot_worker_user }}/venv/bin/buildbot-worker create-worker ~/{{ buildbot_worker_name }} {{ buildbot_master_host }}:{{ buildbot_master_port }} {{ buildbot_worker_name|quote }} {{ buildbot_worker_password|quote }} args: @@ -116,7 +146,7 @@ content: "{{ buildbot_worker_admin }}" dest: "~{{ buildbot_worker_user }}/{{ buildbot_worker_name }}/info/admin" owner: "{{ buildbot_worker_user }}" - group: "{{ buildbot_worker_user }}" + group: "{{ omit if ansible_distribution == 'MacOSX' else buildbot_worker_user }}" mode: "0644" - name: Set host details for Buildbot worker @@ -124,7 +154,15 @@ src: "{{ buildbot_worker_host_template }}" dest: "~{{ buildbot_worker_user }}/{{ buildbot_worker_name }}/info/host" owner: "{{ buildbot_worker_user }}" - group: "{{ buildbot_worker_user }}" + group: "{{ omit if ansible_distribution == 'MacOSX' else buildbot_worker_user }}" + mode: "0644" + + - name: Install custom bashrc for virtualenv + copy: + src: bashrc + dest: "~{{ buildbot_worker_user }}/.bashrc" + owner: "{{ buildbot_worker_user }}" + group: "{{ omit if ansible_distribution == 'MacOSX' else buildbot_worker_user }}" mode: "0644" - name: Copy Buildbot worker systemd service unit @@ -134,13 +172,32 @@ owner: root group: root mode: "0644" + when: ansible_distribution != 'MacOSX' notify: reload systemd - - name: Start Buildbot worker. + - name: Copy Buildbot worker launchd service unit + template: + src: templates/buildbot-worker.plist.j2 + dest: "/Library/LaunchDaemons/net.buildbot.worker.plist" + owner: root + group: wheel + mode: "0644" + when: ansible_distribution == 'MacOSX' + + - name: Start Buildbot worker service: name: buildbot-worker state: started enabled: yes + when: ansible_distribution != 'MacOSX' + + - name: Load Buildbot worker service [MacOSX] + command: launchctl load /Library/LaunchDaemons/net.buildbot.worker.plist + when: ansible_distribution == 'MacOSX' + + - name: Start Buildbot worker [MacOSX] + command: launchctl start net.buildbot.worker + when: ansible_distribution == 'MacOSX' handlers: - name: restart buildbot-worker diff --git a/contrib/ci-workers/vars/Archlinux.yml b/contrib/ci-workers/vars/Archlinux.yml index ac4a44e5b..50e5577c3 100644 --- a/contrib/ci-workers/vars/Archlinux.yml +++ b/contrib/ci-workers/vars/Archlinux.yml @@ -2,6 +2,6 @@ buildbot_deps: - python2-pip build_deps: + - cmake - multilib/gcc - make -pip_bin_dir: /usr/bin diff --git a/contrib/ci-workers/vars/CentOS.yml b/contrib/ci-workers/vars/CentOS.yml index 7e09b0717..f577af5c0 100644 --- a/contrib/ci-workers/vars/CentOS.yml +++ b/contrib/ci-workers/vars/CentOS.yml @@ -2,6 +2,7 @@ buildbot_deps: [] # Empty to remove python-pip build_deps: - bzip2 + - cmake - gcc - gcc-c++ - make @@ -10,4 +11,3 @@ dist_deps: - pkgconfig # Required until b556beda264308e040f8d88aca4f2f386a0183d9 is pulled in - python-devel - redhat-rpm-config -pip_bin_dir: /usr/bin diff --git a/contrib/ci-workers/vars/Debian.yml b/contrib/ci-workers/vars/Debian.yml index 992224721..b6a46f0cd 100644 --- a/contrib/ci-workers/vars/Debian.yml +++ b/contrib/ci-workers/vars/Debian.yml @@ -1,6 +1,6 @@ --- build_deps: - build-essential # Depends on g++, libc6-dev, make + - cmake dist_deps: - - pkg-config # Required until b556beda264308e040f8d88aca4f2f386a0183d9 is pulled in - python-dev diff --git a/contrib/ci-workers/vars/Fedora.yml b/contrib/ci-workers/vars/Fedora.yml index 1c6b0e0f3..2a7351c69 100644 --- a/contrib/ci-workers/vars/Fedora.yml +++ b/contrib/ci-workers/vars/Fedora.yml @@ -1,5 +1,6 @@ --- build_deps: + - cmake - gcc - gcc-c++ - make diff --git a/contrib/ci-workers/vars/FreeBSD.yml b/contrib/ci-workers/vars/FreeBSD.yml index 65909d71d..4b1f01997 100644 --- a/contrib/ci-workers/vars/FreeBSD.yml +++ b/contrib/ci-workers/vars/FreeBSD.yml @@ -2,6 +2,7 @@ buildbot_deps: - py27-pip build_deps: + - cmake - gcc - gmake dist_deps: diff --git a/contrib/ci-workers/vars/MacOSX.yml b/contrib/ci-workers/vars/MacOSX.yml new file mode 100644 index 000000000..80b1ae608 --- /dev/null +++ b/contrib/ci-workers/vars/MacOSX.yml @@ -0,0 +1,6 @@ +--- +buildbot_deps: + - coreutils # For gnproc etc. +# Most are already installed +build_deps: + - cmake diff --git a/contrib/ci-workers/vars/Ubuntu.yml b/contrib/ci-workers/vars/Ubuntu.yml index 4acca499b..0d0f584b4 100644 --- a/contrib/ci-workers/vars/Ubuntu.yml +++ b/contrib/ci-workers/vars/Ubuntu.yml @@ -1,5 +1,4 @@ --- build_deps: - build-essential # Depends on g++, libc6-dev, make -dist_deps: - - pkg-config # Required until b556beda264308e040f8d88aca4f2f386a0183d9 is pulled in + - cmake diff --git a/contrib/ci-workers/vars/default.yml b/contrib/ci-workers/vars/default.yml index 38c5afc8e..a0b0da9e6 100644 --- a/contrib/ci-workers/vars/default.yml +++ b/contrib/ci-workers/vars/default.yml @@ -7,6 +7,7 @@ buildbot_deps: # Dependencies required to download files fetch_deps: + - curl # For depends/ - git - wget # For zcutil/fetch-params.sh @@ -15,9 +16,11 @@ conf_deps: - autoconf - automake - m4 + - pkg-config # Dependencies required to compile Zcash build_deps: + - cmake - g++ - gcc - make @@ -34,6 +37,10 @@ grind_deps: - lcov - valgrind +# Python modules required on the system +system_modules: + - virtualenv + # Python modules required for a Zcash Buildbot worker buildbot_modules: - pip # Needs to be updated first so Buildbot installs @@ -44,6 +51,3 @@ buildbot_modules: rpc_test_modules: - pyblake2 - pyzmq - -# Environment variables -pip_bin_dir: /usr/local/bin diff --git a/contrib/debian/changelog b/contrib/debian/changelog index c0b1d157f..504660f57 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,57 @@ +zcash (2.0.0) stable; urgency=medium + + * 2.0.0 release. + + -- Zcash Company Wed, 15 Aug 2018 17:57:50 -0700 + +zcash (2.0.0~rc1) stable; urgency=medium + + * 2.0.0-rc1 release. + + -- Zcash Company Thu, 09 Aug 2018 16:56:56 +0000 + +zcash (1.1.2) stable; urgency=medium + + * 1.1.2 release. + + -- Zcash Company Sun, 01 Jul 2018 20:12:33 -0700 + +zcash (1.1.2~rc1) stable; urgency=medium + + * 1.1.2-rc1 release. + + -- Zcash Company Fri, 22 Jun 2018 17:03:41 -0700 + +zcash (1.1.1) stable; urgency=medium + + * 1.1.1 release. + + -- Zcash Company Fri, 25 May 2018 15:49:34 +1200 + +zcash (1.1.1~rc2) stable; urgency=medium + + * 1.1.1-rc2 release. + + -- Zcash Company Wed, 23 May 2018 09:28:50 -0700 + +zcash (1.1.1~rc1) stable; urgency=medium + + * 1.1.1-rc1 release. + + -- Zcash Company Sat, 19 May 2018 10:16:14 +1200 + +zcash (1.1.0) stable; urgency=medium + + * 1.1.0 release. + + -- Zcash Company Wed, 11 Apr 2018 20:15:29 -0600 + +zcash (1.1.0~rc1) stable; urgency=medium + + * 1.1.0-rc1 release. + + -- Zcash Company Thu, 05 Apr 2018 03:26:17 +0100 + zcash (1.0.15) stable; urgency=medium * 1.0.15 release. diff --git a/contrib/debian/copyright b/contrib/debian/copyright index 3fbaa848b..7b0f72fce 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -4,8 +4,9 @@ Upstream-Contact: Zcash Company Source: https://github.com/zcash/zcash Files: * -Copyright: 2016-2017, The Zcash developers - 2009-2017, Bitcoin Core developers +Copyright: 2016-2018, The Zcash developers + 2009-2018, Bitcoin Core developers + 2009-2018, Bitcoin Developers License: Expat Comment: The Bitcoin Core developers encompasses the current developers listed on bitcoin.org, as well as the numerous contributors to the project. diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index bee8f3cc1..43c825bde 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/env python ''' Perform basic ELF security checks on a series of executables. Exit status will be 0 if successful, and the program will be silent. @@ -6,6 +6,7 @@ Otherwise the exit status will be 1 and it will log which executables failed whi Needs `readelf` (for ELF) and `objdump` (for PE). ''' from __future__ import division,print_function,unicode_literals +import struct import subprocess import sys import os @@ -171,6 +172,8 @@ CHECKS = { ('DYNAMIC_BASE', check_PE_DYNAMIC_BASE), ('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA), ('NX', check_PE_NX) +], +'MachO64': [ ] } @@ -181,6 +184,8 @@ def identify_executable(executable): return 'PE' elif magic.startswith(b'\x7fELF'): return 'ELF' + elif struct.unpack('I', magic)[0] == 0xFEEDFACF: + return 'MachO64' return None if __name__ == '__main__': diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index 900a80dcf..52b48ef74 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/env python # Copyright (c) 2014 Wladimir J. van der Laan # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py index fed7626aa..324b7bcd8 100755 --- a/contrib/devtools/test-security-check.py +++ b/contrib/devtools/test-security-check.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/env python2 ''' Test script for security-check.py ''' diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index de9e405e1..101df0c2f 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "zcash-1.0.15" +name: "zcash-2.0.0" enable_cache: true distro: "debian" suites: @@ -124,7 +124,8 @@ script: | find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig find ${DISTNAME}/bin -type f -executable -exec objcopy --only-keep-debug {} {}.dbg \; -exec strip -s {} \; -exec objcopy --add-gnu-debuglink={}.dbg {} \; - find ${DISTNAME}/lib -type f -exec objcopy --only-keep-debug {} {}.dbg \; -exec strip -s {} \; -exec objcopy --add-gnu-debuglink={}.dbg {} \; + # Commented out while we don't build any libraries + #find ${DISTNAME}/lib -type f -exec objcopy --only-keep-debug {} {}.dbg \; -exec strip -s {} \; -exec objcopy --add-gnu-debuglink={}.dbg {} \; find ${DISTNAME} -not -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz find ${DISTNAME} -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}-debug.tar.gz cd ../../ diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index b08bd9c3b..44fc4e356 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -150,7 +150,8 @@ script: | find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig find ${DISTNAME}/bin -type f -executable -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; - find ${DISTNAME}/lib -type f -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; + # Commented out while we don't build any libraries + #find ${DISTNAME}/lib -type f -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; find ${DISTNAME} -not -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}.zip find ${DISTNAME} -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}-debug.zip cd ../../ diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py index 0f6fde2a6..8badb4b31 100755 --- a/contrib/linearize/linearize-data.py +++ b/contrib/linearize/linearize-data.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # linearize-data.py: Construct a linear, no-fork version of the chain. # diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py index bed9cc307..7e9cf8898 100755 --- a/contrib/linearize/linearize-hashes.py +++ b/contrib/linearize/linearize-hashes.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # linearize-hashes.py: List blocks in a linear, no-fork version of the chain. # diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index 4e23bb111..c6a2ce636 100755 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -1,5 +1,5 @@ -#!/usr/bin/python -# Copyright (c) 2014 Wladmir J. van der Laan +#!/usr/bin/env python +# Copyright (c) 2014 Wladimir J. van der Laan # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' diff --git a/depends/Makefile b/depends/Makefile index 472d87885..e58dd510f 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -14,6 +14,7 @@ BASEDIR = $(CURDIR) HASH_LENGTH:=11 DOWNLOAD_CONNECT_TIMEOUT:=10 DOWNLOAD_RETRIES:=3 +CRATE_REGISTRY:=vendored-sources host:=$(BUILD) ifneq ($(HOST),) @@ -72,15 +73,14 @@ include builders/$(build_os).mk include builders/default.mk include packages/packages.mk -rust_packages_$(NO_RUST) = $(rust_packages) wallet_packages_$(NO_WALLET) = $(wallet_packages) proton_packages_$(NO_PROTON) = $(proton_packages) -packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(rust_packages_) $(proton_packages_) $(wallet_packages_) +packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(rust_packages) $(proton_packages_) $(wallet_packages_) native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) all_packages = $(packages) $(native_packages) -meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk +meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk cargo-checksum.sh $(host_arch)_$(host_os)_native_toolchain?=$($(host_os)_native_toolchain) diff --git a/depends/cargo-checksum.sh b/depends/cargo-checksum.sh new file mode 100755 index 000000000..535cc0bfd --- /dev/null +++ b/depends/cargo-checksum.sh @@ -0,0 +1,13 @@ +echo "{\"files\":{$( +find . -type f | # Get list of file paths +grep -v $1 | # Exclude Makefile hashes +grep -v '[.]stamp_' | # Exclude Makefile stamps +sed 's|^[.]/||' | # Remove leading ./ +sort | # Sort (for uniformity) +xargs $2 | # Get SHA256 hashes (assumes standard 'H(A) A' format) +awk -v OFS='":"' '{print $2, $1}' | # 'H(A) A' -> 'A":"H(A)' +sed 's|^|"|' | # 'A":"H(A)' -> '"A":"H(A)' +sed 's|$|"|' | # '"A":"H(A)' -> '"A":"H(A)"' +tr '\n' ',' | # Concatenate lines with commas +sed 's|,$||' # Remove any trailing comma (to fit JSON spec) +)},\"package\":$3}" > .cargo-checksum.json diff --git a/depends/funcs.mk b/depends/funcs.mk index df305a74a..3d89de8a7 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -30,6 +30,21 @@ define fetch_file rm -rf $$($(1)_download_dir) )) endef +define generate_crate_checksum +$(BASEDIR)/cargo-checksum.sh "$($(1)_file_name)" "$(build_SHA256SUM)" "\"$($(1)_sha256_hash)\"" +endef + +define generate_unpackaged_crate_checksum +$(BASEDIR)/cargo-checksum.sh "$($(1)_file_name)" "$(build_SHA256SUM)" "null" +endef + +define vendor_crate_source +mkdir -p $($(1)_staging_prefix_dir)/$(CRATE_REGISTRY) && \ +cp -r $($(1)_extract_dir) $($(1)_staging_prefix_dir)/$(CRATE_REGISTRY)/$($(1)_crate_name) && \ +cd $($(1)_staging_prefix_dir)/$(CRATE_REGISTRY)/$($(1)_crate_versioned_name) && \ +rm -r `basename $($(1)_patch_dir)` .stamp_* .$($(1)_file_name).hash +endef + define int_get_build_recipe_hash $(eval $(1)_all_file_checksums:=$(shell $(build_SHA256SUM) $(meta_depends) packages/$(1).mk $(addprefix $(PATCHES_PATH)/$(1)/,$($(1)_patches)) | cut -d" " -f1)) $(eval $(1)_recipe_hash:=$(shell echo -n "$($(1)_all_file_checksums)" | $(build_SHA256SUM) | cut -d" " -f1)) diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 5eaeddc26..d01e8b5a3 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -8,7 +8,7 @@ darwin_CXX=g++-6 -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysro darwin_CFLAGS=-pipe darwin_CXXFLAGS=$(darwin_CFLAGS) -darwin_release_CFLAGS=-O2 +darwin_release_CFLAGS=-O1 darwin_release_CXXFLAGS=$(darwin_release_CFLAGS) darwin_debug_CFLAGS=-O1 diff --git a/depends/hosts/mingw32.mk b/depends/hosts/mingw32.mk index 65ab1702b..b217bfdb5 100644 --- a/depends/hosts/mingw32.mk +++ b/depends/hosts/mingw32.mk @@ -3,7 +3,7 @@ mingw32_CXX=x86_64-w64-mingw32-g++-posix mingw32_CFLAGS=-pipe -std=c11 mingw32_CXXFLAGS=$(mingw32_CFLAGS) -std=c++11 -mingw32_release_CFLAGS=-O2 +mingw32_release_CFLAGS=-O1 mingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS) mingw32_debug_CFLAGS=-O1 diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index 3ff5a7bd9..404d94c51 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -1,6 +1,6 @@ package=bdb $(package)_version=6.2.23 -$(package)_download_path=http://download.oracle.com/berkeley-db +$(package)_download_path=https://download.oracle.com/berkeley-db $(package)_file_name=db-$($(package)_version).tar.gz $(package)_sha256_hash=47612c8991aa9ac2f6be721267c8d3cdccf5ac83105df8e50809daea24e95dc7 $(package)_build_subdir=build_unix @@ -13,6 +13,7 @@ $(package)_cxxflags=-std=c++11 endef define $(package)_preprocess_cmds + sed -i.old 's/WinIoCtl.h/winioctl.h/g' src/dbinc/win_db.h && \ sed -i.old 's/__atomic_compare_exchange\\(/__atomic_compare_exchange_db(/' src/dbinc/atomic.h && \ sed -i.old 's/atomic_init/atomic_init_db/' src/dbinc/atomic.h src/mp/mp_region.c src/mp/mp_mvcc.c src/mp/mp_fget.c src/mutex/mut_method.c src/mutex/mut_tas.c endef diff --git a/depends/packages/crate_aes.mk b/depends/packages/crate_aes.mk new file mode 100644 index 000000000..e53d72679 --- /dev/null +++ b/depends/packages/crate_aes.mk @@ -0,0 +1,15 @@ +package=crate_aes +$(package)_crate_name=aes +$(package)_version=0.2.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=e6fb1737cdc8da3db76e90ca817a194249a38fcb500c2e6ecec39b29448aa873 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_aes_soft.mk b/depends/packages/crate_aes_soft.mk new file mode 100644 index 000000000..bd5a9b585 --- /dev/null +++ b/depends/packages/crate_aes_soft.mk @@ -0,0 +1,15 @@ +package=crate_aes_soft +$(package)_crate_name=aes-soft +$(package)_version=0.2.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_aesni.mk b/depends/packages/crate_aesni.mk new file mode 100644 index 000000000..6f93d155f --- /dev/null +++ b/depends/packages/crate_aesni.mk @@ -0,0 +1,15 @@ +package=crate_aesni +$(package)_crate_name=aesni +$(package)_version=0.4.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=f2838c142db62c0c6aea0a24054c46d35488532fdaea0f51dbeba430f0985df5 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_arrayvec.mk b/depends/packages/crate_arrayvec.mk new file mode 100644 index 000000000..7de373351 --- /dev/null +++ b/depends/packages/crate_arrayvec.mk @@ -0,0 +1,15 @@ +package=crate_arrayvec +$(package)_crate_name=arrayvec +$(package)_version=0.4.7 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_bellman.mk b/depends/packages/crate_bellman.mk new file mode 100644 index 000000000..5c7d904ca --- /dev/null +++ b/depends/packages/crate_bellman.mk @@ -0,0 +1,15 @@ +package=crate_bellman +$(package)_crate_name=bellman +$(package)_version=0.1.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=eae372472c7ea8f7c8fc6a62f7d5535db8302de7f1aafda2e13a97c4830d3bcf +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_bit_vec.mk b/depends/packages/crate_bit_vec.mk new file mode 100644 index 000000000..40575088e --- /dev/null +++ b/depends/packages/crate_bit_vec.mk @@ -0,0 +1,15 @@ +package=crate_bit_vec +$(package)_crate_name=bit-vec +$(package)_version=0.4.4 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_bitflags.mk b/depends/packages/crate_bitflags.mk new file mode 100644 index 000000000..844ec37e8 --- /dev/null +++ b/depends/packages/crate_bitflags.mk @@ -0,0 +1,15 @@ +package=crate_bitflags +$(package)_crate_name=bitflags +$(package)_version=1.0.1 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_blake2_rfc.mk b/depends/packages/crate_blake2_rfc.mk new file mode 100644 index 000000000..73ef7edde --- /dev/null +++ b/depends/packages/crate_blake2_rfc.mk @@ -0,0 +1,16 @@ +package=crate_blake2_rfc +$(package)_crate_name=blake2-rfc +$(package)_download_path=https://github.com/gtank/$($(package)_crate_name)/archive/ +$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz +$(package)_download_file=$($(package)_git_commit).tar.gz +$(package)_sha256_hash=8a873cc41f02e669e8071ab5919931dd4263f050becf0c19820b0497c07b0ca3 +$(package)_git_commit=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_unpackaged_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_block_cipher_trait.mk b/depends/packages/crate_block_cipher_trait.mk new file mode 100644 index 000000000..a2ef96576 --- /dev/null +++ b/depends/packages/crate_block_cipher_trait.mk @@ -0,0 +1,15 @@ +package=crate_block_cipher_trait +$(package)_crate_name=block-cipher-trait +$(package)_version=0.5.3 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_byte_tools.mk b/depends/packages/crate_byte_tools.mk new file mode 100644 index 000000000..03edeeb70 --- /dev/null +++ b/depends/packages/crate_byte_tools.mk @@ -0,0 +1,15 @@ +package=crate_byte_tools +$(package)_crate_name=byte-tools +$(package)_version=0.2.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_byteorder.mk b/depends/packages/crate_byteorder.mk new file mode 100644 index 000000000..0df286920 --- /dev/null +++ b/depends/packages/crate_byteorder.mk @@ -0,0 +1,15 @@ +package=crate_byteorder +$(package)_crate_name=byteorder +$(package)_version=1.2.2 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_constant_time_eq.mk b/depends/packages/crate_constant_time_eq.mk new file mode 100644 index 000000000..b782dfb22 --- /dev/null +++ b/depends/packages/crate_constant_time_eq.mk @@ -0,0 +1,15 @@ +package=crate_constant_time_eq +$(package)_crate_name=constant_time_eq +$(package)_version=0.1.3 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_crossbeam.mk b/depends/packages/crate_crossbeam.mk new file mode 100644 index 000000000..3b31aa53b --- /dev/null +++ b/depends/packages/crate_crossbeam.mk @@ -0,0 +1,15 @@ +package=crate_crossbeam +$(package)_crate_name=crossbeam +$(package)_version=0.3.2 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_digest.mk b/depends/packages/crate_digest.mk new file mode 100644 index 000000000..029ccd7bd --- /dev/null +++ b/depends/packages/crate_digest.mk @@ -0,0 +1,15 @@ +package=crate_digest +$(package)_crate_name=digest +$(package)_version=0.7.2 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_fpe.mk b/depends/packages/crate_fpe.mk new file mode 100644 index 000000000..ba6e344ac --- /dev/null +++ b/depends/packages/crate_fpe.mk @@ -0,0 +1,15 @@ +package=crate_fpe +$(package)_crate_name=fpe +$(package)_version=0.1.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_fuchsia_zircon.mk b/depends/packages/crate_fuchsia_zircon.mk new file mode 100644 index 000000000..f8e10aa55 --- /dev/null +++ b/depends/packages/crate_fuchsia_zircon.mk @@ -0,0 +1,15 @@ +package=crate_fuchsia_zircon +$(package)_crate_name=fuchsia-zircon +$(package)_version=0.3.3 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_fuchsia_zircon_sys.mk b/depends/packages/crate_fuchsia_zircon_sys.mk new file mode 100644 index 000000000..bc978bbb2 --- /dev/null +++ b/depends/packages/crate_fuchsia_zircon_sys.mk @@ -0,0 +1,15 @@ +package=crate_fuchsia_zircon_sys +$(package)_crate_name=fuchsia-zircon-sys +$(package)_version=0.3.3 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_futures.mk b/depends/packages/crate_futures.mk new file mode 100644 index 000000000..3e0e6f990 --- /dev/null +++ b/depends/packages/crate_futures.mk @@ -0,0 +1,15 @@ +package=crate_futures +$(package)_crate_name=futures +$(package)_version=0.1.21 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_futures_cpupool.mk b/depends/packages/crate_futures_cpupool.mk new file mode 100644 index 000000000..0ff2069ed --- /dev/null +++ b/depends/packages/crate_futures_cpupool.mk @@ -0,0 +1,15 @@ +package=crate_futures_cpupool +$(package)_crate_name=futures-cpupool +$(package)_version=0.1.8 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_generic_array.mk b/depends/packages/crate_generic_array.mk new file mode 100644 index 000000000..ab4a566ee --- /dev/null +++ b/depends/packages/crate_generic_array.mk @@ -0,0 +1,15 @@ +package=crate_generic_array +$(package)_crate_name=generic-array +$(package)_version=0.9.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_lazy_static.mk b/depends/packages/crate_lazy_static.mk new file mode 100644 index 000000000..208dc1dad --- /dev/null +++ b/depends/packages/crate_lazy_static.mk @@ -0,0 +1,15 @@ +package=crate_lazy_static +$(package)_crate_name=lazy_static +$(package)_version=1.0.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_libc.mk b/depends/packages/crate_libc.mk new file mode 100644 index 000000000..2e1a2c074 --- /dev/null +++ b/depends/packages/crate_libc.mk @@ -0,0 +1,15 @@ +package=crate_libc +$(package)_crate_name=libc +$(package)_version=0.2.40 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_nodrop.mk b/depends/packages/crate_nodrop.mk new file mode 100644 index 000000000..1997574c0 --- /dev/null +++ b/depends/packages/crate_nodrop.mk @@ -0,0 +1,15 @@ +package=crate_nodrop +$(package)_crate_name=nodrop +$(package)_version=0.1.12 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_num_bigint.mk b/depends/packages/crate_num_bigint.mk new file mode 100644 index 000000000..bc1ff4a32 --- /dev/null +++ b/depends/packages/crate_num_bigint.mk @@ -0,0 +1,15 @@ +package=crate_num_bigint +$(package)_crate_name=num-bigint +$(package)_version=0.2.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=3eceac7784c5dc97c2d6edf30259b4e153e6e2b42b3c85e9a6e9f45d06caef6e +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_num_cpus.mk b/depends/packages/crate_num_cpus.mk new file mode 100644 index 000000000..fdaebe4db --- /dev/null +++ b/depends/packages/crate_num_cpus.mk @@ -0,0 +1,15 @@ +package=crate_num_cpus +$(package)_crate_name=num_cpus +$(package)_version=1.8.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_num_integer.mk b/depends/packages/crate_num_integer.mk new file mode 100644 index 000000000..ea479e8e7 --- /dev/null +++ b/depends/packages/crate_num_integer.mk @@ -0,0 +1,15 @@ +package=crate_num_integer +$(package)_crate_name=num-integer +$(package)_version=0.1.39 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_num_traits.mk b/depends/packages/crate_num_traits.mk new file mode 100644 index 000000000..f0ffbe5a1 --- /dev/null +++ b/depends/packages/crate_num_traits.mk @@ -0,0 +1,15 @@ +package=crate_num_traits +$(package)_crate_name=num-traits +$(package)_version=0.2.5 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_opaque_debug.mk b/depends/packages/crate_opaque_debug.mk new file mode 100644 index 000000000..7d7a5e914 --- /dev/null +++ b/depends/packages/crate_opaque_debug.mk @@ -0,0 +1,15 @@ +package=crate_opaque_debug +$(package)_crate_name=opaque-debug +$(package)_version=0.1.1 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_pairing.mk b/depends/packages/crate_pairing.mk new file mode 100644 index 000000000..c81e23bed --- /dev/null +++ b/depends/packages/crate_pairing.mk @@ -0,0 +1,15 @@ +package=crate_pairing +$(package)_crate_name=pairing +$(package)_version=0.14.2 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=ceda21136251c6d5a422d3d798d8ac22515a6e8d3521bb60c59a8349d36d0d57 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_rand.mk b/depends/packages/crate_rand.mk new file mode 100644 index 000000000..16fb81753 --- /dev/null +++ b/depends/packages/crate_rand.mk @@ -0,0 +1,15 @@ +package=crate_rand +$(package)_crate_name=rand +$(package)_version=0.4.2 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_sapling_crypto.mk b/depends/packages/crate_sapling_crypto.mk new file mode 100644 index 000000000..2da5e2406 --- /dev/null +++ b/depends/packages/crate_sapling_crypto.mk @@ -0,0 +1,16 @@ +package=crate_sapling_crypto +$(package)_crate_name=sapling-crypto +$(package)_download_path=https://github.com/zcash-hackworks/$($(package)_crate_name)/archive/ +$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz +$(package)_download_file=$($(package)_git_commit).tar.gz +$(package)_sha256_hash=ae3a122b1f1ce97b4e80e0e8542e19aa1516e99e6c72875688c886af1a881558 +$(package)_git_commit=21084bde2019c04bd34208e63c3560fe2c02fb0e +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_unpackaged_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_stream_cipher.mk b/depends/packages/crate_stream_cipher.mk new file mode 100644 index 000000000..6429a6179 --- /dev/null +++ b/depends/packages/crate_stream_cipher.mk @@ -0,0 +1,15 @@ +package=crate_stream_cipher +$(package)_crate_name=stream-cipher +$(package)_version=0.1.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=ac49bc6cb2847200d18bfb738ce89448570f4aa1c34ac0348db6205ee69a0777 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_typenum.mk b/depends/packages/crate_typenum.mk new file mode 100644 index 000000000..bc5a235a8 --- /dev/null +++ b/depends/packages/crate_typenum.mk @@ -0,0 +1,15 @@ +package=crate_typenum +$(package)_crate_name=typenum +$(package)_version=1.10.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_winapi.mk b/depends/packages/crate_winapi.mk new file mode 100644 index 000000000..6aafb0251 --- /dev/null +++ b/depends/packages/crate_winapi.mk @@ -0,0 +1,15 @@ +package=crate_winapi +$(package)_crate_name=winapi +$(package)_version=0.3.4 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_winapi_i686_pc_windows_gnu.mk b/depends/packages/crate_winapi_i686_pc_windows_gnu.mk new file mode 100644 index 000000000..ff8c5e76f --- /dev/null +++ b/depends/packages/crate_winapi_i686_pc_windows_gnu.mk @@ -0,0 +1,15 @@ +package=crate_winapi_i686_pc_windows_gnu +$(package)_crate_name=winapi-i686-pc-windows-gnu +$(package)_version=0.4.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_winapi_x86_64_pc_windows_gnu.mk b/depends/packages/crate_winapi_x86_64_pc_windows_gnu.mk new file mode 100644 index 000000000..725baf00f --- /dev/null +++ b/depends/packages/crate_winapi_x86_64_pc_windows_gnu.mk @@ -0,0 +1,15 @@ +package=crate_winapi_x86_64_pc_windows_gnu +$(package)_crate_name=winapi-x86_64-pc-windows-gnu +$(package)_version=0.4.0 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/crate_zip32.mk b/depends/packages/crate_zip32.mk new file mode 100644 index 000000000..e47f1fb94 --- /dev/null +++ b/depends/packages/crate_zip32.mk @@ -0,0 +1,16 @@ +package=crate_zip32 +$(package)_crate_name=zip32 +$(package)_download_path=https://github.com/zcash-hackworks/$($(package)_crate_name)/archive/ +$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz +$(package)_download_file=$($(package)_git_commit).tar.gz +$(package)_sha256_hash=b0b011ea96524f0d918a44c7ab8a3dec6270879d1ff03d7dbda6c676d25caa7e +$(package)_git_commit=176470ef41583b5bd0bd749bd1b61d417aa8ec79 +$(package)_crate_versioned_name=$($(package)_crate_name) + +define $(package)_preprocess_cmds + $(call generate_unpackaged_crate_checksum,$(package)) +endef + +define $(package)_stage_cmds + $(call vendor_crate_source,$(package)) +endef diff --git a/depends/packages/googletest.mk b/depends/packages/googletest.mk index 409c83a1b..00ee3f23b 100644 --- a/depends/packages/googletest.mk +++ b/depends/packages/googletest.mk @@ -5,6 +5,11 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_download_file=release-$($(package)_version).tar.gz $(package)_sha256_hash=58a6f4277ca2bc8565222b3bbd58a177609e9c488e8a72649359ba51450db7d8 +define $(package)_set_vars +$(package)_cxxflags+=-std=c++11 +$(package)_cxxflags_linux=-fPIC +endef + ifeq ($(build_os),darwin) define $(package)_set_vars $(package)_build_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" CXX="$($(package)_cxx)" CXXFLAGS="$($(package)_cxxflags)" @@ -19,9 +24,10 @@ define $(package)_build_cmds endef else $(package)_install=install + define $(package)_build_cmds - $(MAKE) -C googlemock/make CXXFLAGS=-fPIC gmock.a && \ - $(MAKE) -C googletest/make CXXFLAGS=-fPIC gtest.a + $(MAKE) -C googlemock/make CC="$($(package)_cc)" CXX="$($(package)_cxx)" AR="$($(package)_ar)" CXXFLAGS="$($(package)_cxxflags)" gmock.a && \ + $(MAKE) -C googletest/make CC="$($(package)_cc)" CXX="$($(package)_cxx)" AR="$($(package)_ar)" CXXFLAGS="$($(package)_cxxflags)" gtest.a endef endif diff --git a/depends/packages/librustzcash.mk b/depends/packages/librustzcash.mk index 689082f8f..d520eff60 100644 --- a/depends/packages/librustzcash.mk +++ b/depends/packages/librustzcash.mk @@ -3,9 +3,26 @@ $(package)_version=0.1 $(package)_download_path=https://github.com/zcash/$(package)/archive $(package)_file_name=$(package)-$($(package)_git_commit).tar.gz $(package)_download_file=$($(package)_git_commit).tar.gz -$(package)_sha256_hash=a5760a90d4a1045c8944204f29fa2a3cf2f800afee400f88bf89bbfe2cce1279 -$(package)_git_commit=91348647a86201a9482ad4ad68398152dc3d635e -$(package)_dependencies=rust +$(package)_sha256_hash=e9a488a8bbecf7fb237a32dadd65133211ef61616d44cf55609e029837a41004 +$(package)_git_commit=f5e5cb24e1bd756a02fc4a3fd2b824238ccd15ad +$(package)_dependencies=rust $(rust_crates) +$(package)_patches=cargo.config + +ifeq ($(host_os),mingw32) +$(package)_library_file=target/x86_64-pc-windows-gnu/release/rustzcash.lib +else +$(package)_library_file=target/release/librustzcash.a +endif + +define $(package)_set_vars +$(package)_build_opts=--frozen --release +$(package)_build_opts_mingw32=--target=x86_64-pc-windows-gnu +endef + +define $(package)_preprocess_cmds + mkdir .cargo && \ + cat $($(package)_patch_dir)/cargo.config | sed 's|CRATE_REGISTRY|$(host_prefix)/$(CRATE_REGISTRY)|' > .cargo/config +endef ifeq ($(host_os),mingw32) define $(package)_build_cmds @@ -13,7 +30,7 @@ define $(package)_build_cmds endef else define $(package)_build_cmds - cargo build --release + cargo build $($(package)_build_opts) endef endif @@ -28,7 +45,7 @@ else define $(package)_stage_cmds mkdir $($(package)_staging_dir)$(host_prefix)/lib/ && \ mkdir $($(package)_staging_dir)$(host_prefix)/include/ && \ - cp target/release/librustzcash.a $($(package)_staging_dir)$(host_prefix)/lib/ && \ + cp $($(package)_library_file) $($(package)_staging_dir)$(host_prefix)/lib/ && \ cp include/librustzcash.h $($(package)_staging_dir)$(host_prefix)/include/ endef endif diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index f80cd6d25..dec8ecef6 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -1,8 +1,8 @@ package=openssl -$(package)_version=1.1.0d +$(package)_version=1.1.0h $(package)_download_path=https://www.openssl.org/source $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=7d5ebb9e89756545c156ff9c13cf2aa6214193b010a468a3bc789c3c28fe60df +$(package)_sha256_hash=5835626cde9e99656585fc7aaa2302a73a7e1340bf8c14fd635a62c66802a517 define $(package)_set_vars $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 9174db320..a2225f72a 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -7,12 +7,52 @@ else zcash_packages := libgmp libsodium endif +rust_crates := \ + crate_aes \ + crate_aesni \ + crate_aes_soft \ + crate_arrayvec \ + crate_bellman \ + crate_bitflags \ + crate_bit_vec \ + crate_blake2_rfc \ + crate_block_cipher_trait \ + crate_byte_tools \ + crate_byteorder \ + crate_constant_time_eq \ + crate_crossbeam \ + crate_digest \ + crate_fpe \ + crate_fuchsia_zircon \ + crate_fuchsia_zircon_sys \ + crate_futures_cpupool \ + crate_futures \ + crate_generic_array \ + crate_lazy_static \ + crate_libc \ + crate_nodrop \ + crate_num_bigint \ + crate_num_cpus \ + crate_num_integer \ + crate_num_traits \ + crate_opaque_debug \ + crate_pairing \ + crate_rand \ + crate_sapling_crypto \ + crate_stream_cipher \ + crate_typenum \ + crate_winapi_i686_pc_windows_gnu \ + crate_winapi \ + crate_winapi_x86_64_pc_windows_gnu \ + crate_zip32 +rust_packages := rust $(rust_crates) librustzcash +native_packages := native_ccache + +wallet_packages=bdb + ifeq ($(host_os),linux) packages := boost openssl libevent zeromq $(zcash_packages) googletest #googlemock else packages := boost openssl libevent zeromq $(zcash_packages) libcurl googletest #googlemock endif -native_packages := native_ccache - -wallet_packages=bdb diff --git a/depends/packages/rust.mk b/depends/packages/rust.mk index 2e3f0b204..a08ac2747 100644 --- a/depends/packages/rust.mk +++ b/depends/packages/rust.mk @@ -1,17 +1,52 @@ package=rust -$(package)_version=1.16.0 +$(package)_version=1.28.0 $(package)_download_path=https://static.rust-lang.org/dist + +$(package)_file_name_linux=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz +$(package)_sha256_hash_linux=2a1390340db1d24a9498036884e6b2748e9b4b057fc5219694e298bdaa37b810 +$(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz +$(package)_sha256_hash_darwin=5d7a70ed4701fe9410041c1eea025c95cad97e5b3d8acc46426f9ac4f9f02393 +$(package)_file_name_mingw32=rust-$($(package)_version)-x86_64-pc-windows-gnu.tar.gz +$(package)_sha256_hash_mingw32=55c07426f791c51c8a2b6934b35784175c4abb4e03f123f3e847109c4dc1ad8b + ifeq ($(build_os),darwin) -$(package)_file_name=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz -$(package)_sha256_hash=2d08259ee038d3a2c77a93f1a31fc59e7a1d6d1bbfcba3dba3c8213b2e5d1926 +$(package)_file_name=$($(package)_file_name_darwin) +$(package)_sha256_hash=$($(package)_sha256_hash_darwin) else ifeq ($(host_os),mingw32) -$(package)_file_name=rust-$($(package)_version)-i686-unknown-linux-gnu.tar.gz -$(package)_sha256_hash=b5859161ebb182d3b75fa14a5741e5de87b088146fb0ef4a30f3b2439c6179c5 +$(package)_file_name=$($(package)_file_name_mingw32) +$(package)_sha256_hash=$($(package)_sha256_hash_mingw32) else -$(package)_file_name=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz -$(package)_sha256_hash=48621912c242753ba37cad5145df375eeba41c81079df46f93ffb4896542e8fd +$(package)_file_name=$($(package)_file_name_linux) +$(package)_sha256_hash=$($(package)_sha256_hash_linux) endif +ifeq ($(host_os),mingw32) +$(package)_build_subdir=buildos +$(package)_extra_sources = $($(package)_file_name_$(build_os)) + +define $(package)_fetch_cmds +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_file_name_$(build_os)),$($(package)_file_name_$(build_os)),$($(package)_sha256_hash_$(build_os))) +endef + +define $(package)_extract_cmds + mkdir -p $($(package)_extract_dir) && \ + echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_sha256_hash_$(build_os)) $($(package)_source_dir)/$($(package)_file_name_$(build_os))" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + mkdir mingw32 && \ + tar --strip-components=1 -xf $($(package)_source) -C mingw32 && \ + mkdir buildos && \ + tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_file_name_$(build_os)) -C buildos +endef + +define $(package)_stage_cmds + ./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig && \ + cp -r ../mingw32/rust-std-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu $($(package)_staging_dir)$(host_prefix)/native/lib/rustlib +endef +else + define $(package)_stage_cmds ./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig endef +endif diff --git a/depends/patches/boost/deprecated_auto_ptr.patch b/depends/patches/boost/deprecated_auto_ptr.patch deleted file mode 100644 index 5ec38e271..000000000 --- a/depends/patches/boost/deprecated_auto_ptr.patch +++ /dev/null @@ -1,30 +0,0 @@ ---- boost_1_62_0-orig/boost/spirit/home/classic/core/non_terminal/impl/grammar.ipp 2016-09-29 14:03:47.317997658 +1300 -+++ boost_1_62_0/boost/spirit/home/classic/core/non_terminal/impl/grammar.ipp 2016-09-29 14:07:41.308726372 +1300 -@@ -13,10 +13,16 @@ - - #if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) - #include -+#include - #include - #include - #include // for std::auto_ptr - #include -+ -+#if defined( BOOST_SP_DISABLE_DEPRECATED ) -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -+#endif - #endif - - #ifdef BOOST_SPIRIT_THREADSAFE -@@ -370,4 +376,10 @@ - - }} // namespace boost::spirit - -+#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) -+#if defined( BOOST_SP_DISABLE_DEPRECATED ) -+#pragma GCC diagnostic pop -+#endif -+#endif -+ - #endif diff --git a/depends/patches/boost/include_poll.patch b/depends/patches/boost/include_poll.patch deleted file mode 100644 index b7e544b5f..000000000 --- a/depends/patches/boost/include_poll.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- boost_1_62_0-orig/boost/asio/detail/socket_types.hpp 2016-09-21 15:33:21.000000000 +0100 -+++ boost_1_62_0/boost/asio/detail/socket_types.hpp 2016-10-18 03:08:41.712254217 +0100 -@@ -58,7 +58,7 @@ - #else - # include - # if !defined(__SYMBIAN32__) --# include -+# include - # endif - # include - # include diff --git a/depends/patches/librustzcash/cargo.config b/depends/patches/librustzcash/cargo.config new file mode 100644 index 000000000..a0252d1c6 --- /dev/null +++ b/depends/patches/librustzcash/cargo.config @@ -0,0 +1,23 @@ +[source.crates-io] +replace-with = "vendored-sources" + +[source."https://github.com/gtank/blake2-rfc"] +git = "https://github.com/gtank/blake2-rfc" +rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" +replace-with = "vendored-sources" + +[source."https://github.com/zcash-hackworks/sapling-crypto"] +git = "https://github.com/zcash-hackworks/sapling-crypto" +rev = "21084bde2019c04bd34208e63c3560fe2c02fb0e" +replace-with = "vendored-sources" + +[source."https://github.com/zcash-hackworks/zip32"] +git = "https://github.com/zcash-hackworks/zip32" +rev = "176470ef41583b5bd0bd749bd1b61d417aa8ec79" +replace-with = "vendored-sources" + +[source.vendored-sources] +directory = "CRATE_REGISTRY" + +[target.x86_64-pc-windows-gnu] +linker = "x86_64-w64-mingw32-gcc" diff --git a/doc/Doxyfile b/doc/Doxyfile index a423a7e9f..84154e6ec 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -870,7 +870,7 @@ HTML_FILE_EXTENSION = .html # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. -# It is adviced to generate a default header using "doxygen -w html +# It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when diff --git a/doc/authors.md b/doc/authors.md index 8f249b1c0..e4dfec076 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -1,64 +1,80 @@ Zcash Contributors ================== -Jack Grigg (601) -Simon Liu (297) -Sean Bowe (193) -Daira Hopwood (102) -Wladimir J. van der Laan (71) +Jack Grigg (760) +Simon Liu (352) +Sean Bowe (263) +Daira Hopwood (110) +Jay Graber (84) +Wladimir J. van der Laan (81) Taylor Hornby (65) -Jay Graber (61) Nathan Wilcox (56) -Jonas Schnelli (49) +Jonas Schnelli (55) +Pieter Wuille (50) Kevin Gallagher (38) -Cory Fields (30) -Pieter Wuille (24) +Eirik Ogilvie-Wigley (36) +Cory Fields (35) syd (15) +Matt Corallo (13) +Paige Peterson (10) +MarcoFalke (10) nomnombtc (9) -Paige Peterson (9) -Matt Corallo (9) +Jonathan "Duke" Leto (9) +kozyilmaz (8) fanquake (8) -MarcoFalke (7) +Jeff Garzik (7) +Gregory Maxwell (7) +Ariel Gabizon (7) Luke Dashjr (6) +Larry Ruane (6) +Daniel Cousens (6) +Pavel Janík (5) +Karl-Johan Alm (5) Johnathan Corgan (5) -Gregory Maxwell (5) -Ariel Gabizon (5) -kozyilmaz (4) Philip Kaufmann (4) Peter Todd (4) Patrick Strateman (4) -Karl-Johan Alm (4) +João Barbosa (4) Jorge Timón (4) -Jeff Garzik (4) +Duke Leto (4) David Mercer (4) -Daniel Cousens (4) lpescher (3) Suhas Daftuar (3) -Pavel Janík (3) -João Barbosa (3) +Per Grön (3) +Patick Strateman (3) +Jason Davies (3) +James O'Beirne (3) +Daniel Kraft (3) Ariel (3) Alfie John (3) str4d (2) +rofl0r (2) paveljanik (2) +mruddy (2) kpcyrd (2) +ca333 (2) aniemerg (2) +UdjinM6 (2) Scott (2) Robert C. Seacord (2) -Per Grön (2) +Pejvan (2) +Pavol Rusnak (2) Pavel Vasin (2) +Matthew King (2) +Kaz Wesley (2) Joe Turgeon (2) -Jason Davies (2) Jack Gavigan (2) ITH4Coinomia (2) Gavin Andresen (2) -Daniel Kraft (2) +Brad Miller (2) Bjorn Hjortsberg (2) Amgad Abdelhafez (2) +Alex Morcos (2) zathras-crypto (1) unsystemizer (1) practicalswift (1) -mruddy (1) mrbandrews (1) +mdr0id (1) kazcw (1) jc (1) isle2983 (1) @@ -69,10 +85,16 @@ daniel (1) calebogden (1) ayleph (1) Tom Ritter (1) +Tom Harding (1) Stephen (1) S. Matthew English (1) Ross Nicoll (1) +Richard Littauer (1) René Nyffenegger (1) +R E Broadley (1) +Puru (1) +Peter Pratscher (1) +Pedro Branco (1) Paul Georgiou (1) Paragon Initiative Enterprises, LLC (1) Nicolas DORIER (1) @@ -84,10 +106,11 @@ Mark Friedenbach (1) Marius Kjærstad (1) Louis Nyffenegger (1) Leo Arias (1) +Lauda (1) Lars-Magnus Skog (1) Kevin Pan (1) -Jonathan "Duke" Leto (1) Jonas Nick (1) +Jeremy Rubin (1) Jeffrey Walton (1) Ian Kelling (1) Gaurav Rana (1) @@ -95,9 +118,12 @@ Forrest Voight (1) Florian Schmaus (1) Ethan Heilman (1) Eran Tromer (1) -Duke Leto (1) +Dimitris Apostolou (1) +David Llop (1) Christian von Roques (1) Chirag Davé (1) +Charlie OKeefe (1) +Charlie O'Keefe (1) Casey Rodarmor (1) Cameron Boehmer (1) Bryan Stitt (1) @@ -109,7 +135,6 @@ Ashley Holman (1) Anthony Towns (1) Allan Niemerg (1) Alex van der Peet (1) -Alex Morcos (1) Alex (1) Adam Weiss (1) Adam Brown (1) diff --git a/doc/bips.md b/doc/bips.md new file mode 100644 index 000000000..14c7e372f --- /dev/null +++ b/doc/bips.md @@ -0,0 +1,4 @@ +BIPs that are implemented by Zcash (up-to-date up to **v1.1.0**): + +* Numerous historic BIPs were present in **v1.0.0** at launch; see [the protocol spec](https://github.com/zcash/zips/blob/master/protocol/protocol.pdf) for details. +* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, but only enforced for peer versions `>=170004` as of **v1.1.0** ([PR #2814](https://github.com/zcash/zcash/pull/2814)). diff --git a/doc/imgs/logo.png b/doc/imgs/logo.png new file mode 100644 index 000000000..cf47e69fd Binary files /dev/null and b/doc/imgs/logo.png differ diff --git a/doc/imgs/zcashd_screen.gif b/doc/imgs/zcashd_screen.gif new file mode 100644 index 000000000..2eebc1cba Binary files /dev/null and b/doc/imgs/zcashd_screen.gif differ diff --git a/doc/imgs/zcashd_screenshot.png b/doc/imgs/zcashd_screenshot.png new file mode 100644 index 000000000..cdb8a20b8 Binary files /dev/null and b/doc/imgs/zcashd_screenshot.png differ diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index a30af6fe6..d961e3fa6 100644 --- a/doc/man/zcash-cli.1 +++ b/doc/man/zcash-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-CLI "1" "February 2018" "zcash-cli v1.0.15" "User Commands" +.TH ZCASH-CLI "1" "August 2018" "zcash-cli v2.0.0" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v1.0.15 +zcash-cli \- manual page for zcash-cli v2.0.0 .SH DESCRIPTION -Zcash RPC client version v1.0.15 +Zcash RPC client version v2.0.0 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . @@ -65,6 +65,11 @@ Password for JSON\-RPC connections .IP Timeout in seconds during HTTP requests, or 0 for no timeout. (default: 900) +.HP +\fB\-stdin\fR +.IP +Read extra arguments from standard input, one per line until EOF/Ctrl\-D +(recommended for sensitive information such as passphrases) .SH COPYRIGHT In order to ensure you are adequately protecting your privacy when using Zcash, diff --git a/doc/man/zcash-tx.1 b/doc/man/zcash-tx.1 index f5830e6de..f284e0daa 100644 --- a/doc/man/zcash-tx.1 +++ b/doc/man/zcash-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASH-TX "1" "February 2018" "zcash-tx v1.0.15" "User Commands" +.TH ZCASH-TX "1" "August 2018" "zcash-tx v2.0.0" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v1.0.15 +zcash-tx \- manual page for zcash-tx v2.0.0 .SH DESCRIPTION -Zcash zcash\-tx utility version v1.0.15 +Zcash zcash\-tx utility version v2.0.0 .SS "Usage:" .TP zcash\-tx [options] [commands] @@ -48,7 +48,7 @@ delout=N .IP Delete output N from TX .IP -in=TXID:VOUT +in=TXID:VOUT(:SEQUENCE_NUMBER) .IP Add input to TX .IP diff --git a/doc/man/zcashd.1 b/doc/man/zcashd.1 index eaef634c0..2a1daa2a5 100644 --- a/doc/man/zcashd.1 +++ b/doc/man/zcashd.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.3. -.TH ZCASHD "1" "February 2018" "zcashd v1.0.15" "User Commands" +.TH ZCASHD "1" "August 2018" "zcashd v2.0.0" "User Commands" .SH NAME -zcashd \- manual page for zcashd v1.0.15 +zcashd \- manual page for zcashd v2.0.0 .SH DESCRIPTION -Zcash Daemon version v1.0.15 +Zcash Daemon version v2.0.0 .PP In order to ensure you are adequately protecting your privacy when using Zcash, please see . @@ -51,11 +51,6 @@ Run in the background as a daemon and accept commands .IP Specify data directory .HP -\fB\-disabledeprecation=\fR -.IP -Disable block\-height node deprecation and automatic shutdown (example: -\fB\-disabledeprecation\fR=\fI\,1\/\fR.0.15) -.HP \fB\-exportdir=\fR .IP Specify directory to be used when exporting data @@ -74,12 +69,13 @@ Keep at most unconnectable transactions in memory (default: 100) .HP \fB\-mempooltxinputlimit=\fR .IP -Set the maximum number of transparent inputs in a transaction that the -mempool will accept (default: 0 = no limit applied) +[DEPRECATED FROM OVERWINTER] Set the maximum number of transparent +inputs in a transaction that the mempool will accept (default: 0 = no +limit applied) .HP \fB\-par=\fR .IP -Set the number of script verification threads (\fB\-2\fR to 16, 0 = auto, <0 = +Set the number of script verification threads (\fB\-4\fR to 16, 0 = auto, <0 = leave that many cores free, default: 0) .HP \fB\-pid=\fR @@ -187,6 +183,11 @@ Only connect to nodes in network (ipv4, ipv6 or onion) .IP Relay non\-P2SH multisig (default: 1) .HP +\fB\-peerbloomfilters\fR +.IP +Support filtering of blocks and transaction with Bloom filters (default: +1) +.HP \fB\-port=\fR .IP Listen for connections on (default: 8233 or testnet: 18233) diff --git a/doc/payment-api.md b/doc/payment-api.md index 14732adba..a9be9d08a 100644 --- a/doc/payment-api.md +++ b/doc/payment-api.md @@ -29,10 +29,10 @@ Optional parameters are denoted in [square brackets]. RPC calls by category: * Accounting: z_getbalance, z_gettotalbalance -* Addresses : z_getnewaddress, z_listaddresses, z_validateaddress +* Addresses : z_getnewaddress, z_listaddresses, z_validateaddress, z_exportviewingkey, z_importviewingkey * Keys : z_exportkey, z_importkey, z_exportwallet, z_importwallet * Operation: z_getoperationresult, z_getoperationstatus, z_listoperationids -* Payment : z_listreceivedbyaddress, z_sendmany, z_shieldcoinbase +* Payment : z_listreceivedbyaddress, z_listunspent, z_sendmany, z_shieldcoinbase RPC parameter conventions: @@ -55,7 +55,7 @@ Command | Parameters | Description --- | --- | --- z_getnewaddress | | Return a new zaddr for sending and receiving payments. The spending key for this zaddr will be added to the node’s wallet.

Output:
zN68D8hSs3... z_listaddresses | | Returns a list of all the zaddrs in this node’s wallet for which you have a spending key.

Output:
{ [“z123…”, “z456...”, “z789...”] } -z_validateaddress | zaddr | Return information about a given zaddr.

Output:
{"isvalid" : true,
"address" : "zcWsmq...",
"payingkey" : "f5bb3c...",
"transmissionkey" : "7a58c7...",
"ismine" : true} +z_validateaddress | zaddr | Return information about a given zaddr.

Output:
{"isvalid" : true,
"address" : "zcWsmq...",
"type" : "sprout",
"payingkey" : "f5bb3c...",
"transmissionkey" : "7a58c7...",
"ismine" : true} ### Key Management @@ -64,13 +64,17 @@ Command | Parameters | Description z_exportkey | zaddr | _Requires an unlocked wallet or an unencrypted wallet._

Return a zkey for a given zaddr belonging to the node’s wallet.

The key will be returned as a string formatted using Base58Check as described in the Zcash protocol spec.

Output:AKWUAkypwQjhZ6LLNaMuuuLcmZ6gt5UFyo8m3jGutvALmwZKLdR5 z_importkey | zkey [rescan=true] | _Wallet must be unlocked._

Add a zkey as returned by z_exportkey to a node's wallet.

The key should be formatted using Base58Check as described in the Zcash protocol spec.

Set rescan to true (the default) to rescan the entire local block database for transactions affecting any address or pubkey script in the wallet (including transactions affecting the newly-added address for this spending key). z_exportwallet | filename | _Requires an unlocked wallet or an unencrypted wallet._

Creates or overwrites a file with taddr private keys and zaddr private keys in a human-readable format.

Filename is the file in which the wallet dump will be placed. May be prefaced by an absolute file path. An existing file with that name will be overwritten.

No value is returned but a JSON-RPC error will be reported if a failure occurred. -z_importwallet | filename | _Requires an unlocked wallet or an unencrypted wallet._

Imports private keys from a file in wallet export file format (see z_exportwallet). These keys will be added to the keys currently in the wallet. This call may need to rescan all or parts of the block chain for transactions affecting the newly-added keys, which may take several minutes.

Filename is the file to import. The path is relative to komodod’s working directory.

No value is returned but a JSON-RPC error will be reported if a failure occurred. +z_importwallet | filename | _Requires an unlocked wallet or an unencrypted wallet._

Imports private keys from a file in wallet export file format (see z_exportwallet). These keys will be added to the keys currently in the wallet. This call may need to rescan all or parts of the block chain for transactions affecting the newly-added keys, which may take several minutes.

Filename is the file to import. The path is relative to verusd’s working directory.

No value is returned but a JSON-RPC error will be reported if a failure occurred. +z_exportviewingkey | zaddr | Reveals the viewing key corresponding to 'zaddr'. Then the z_importviewingkey can be used with this output. +z_importviewingkey | vkey [rescan=whenkeyisnew] [startHeight=0] | Adds a viewing key (as returned by z_exportviewingkey) to your wallet. + ### Payment Command | Parameters | Description --- | --- | --- z_listreceivedbyaddress
| zaddr [minconf=1] | Return a list of amounts received by a zaddr belonging to the node’s wallet.

Optionally set the minimum number of confirmations which a received amount must have in order to be included in the result. Use 0 to count unconfirmed transactions.

Output:
[{
“txid”: “4a0f…”,
“amount”: 0.54,
“memo”:”F0FF…”,}, {...}, {...}
] +z_listunspent | [minconf=1] [maxconf=9999999] [includeWatchonly=false] [zaddrs] | Returns array of unspent shielded notes with between minconf and maxconf (inclusive) confirmations.

Optionally filter to only include notes sent to specified addresses.

When minconf is 0, unspent notes with zero confirmations are returned, even though they are not immediately spendable.

Results are an array of Objects, each of which has: {txid, jsindex, jsoutindex, confirmations, address, amount, memo} z_sendmany
| fromaddress amounts [minconf=1] [fee=0.0001] | _This is an Asynchronous RPC call_

Send funds from an address to multiple outputs. The address can be either a taddr or a zaddr.

Amounts is a list containing key/value pairs corresponding to the addresses and amount to pay. Each output address can be in taddr or zaddr format.

When sending to a zaddr, you also have the option of attaching a memo in hexadecimal format.

**NOTE:**When sending coinbase funds to a zaddr, the node's wallet does not allow any change. Put another way, spending a partial amount of a coinbase utxo is not allowed. This is not a consensus rule but a local wallet rule due to the current implementation of z_sendmany. In future, this rule may be removed.

Example of Outputs parameter:
[{“address”:”t123…”, “amount”:0.005},
,{“address”:”z010…”,”amount”:0.03, “memo”:”f508af…”}]

Optionally set the minimum number of confirmations which a private or transparent transaction must have in order to be used as an input. When sending from a zaddr, minconf must be greater than zero.

Optionally set a transaction fee, which by default is 0.0001 ZEC.

Any transparent change will be sent to a new transparent address. Any private change will be sent back to the zaddr being used as the source of funds.

Returns an operationid. You use the operationid value with z_getoperationstatus and z_getoperationresult to obtain the result of sending funds, which if successful, will be a txid. z_shieldcoinbase
| fromaddress toaddress [fee=0.0001] [limit=50] | _This is an Asynchronous RPC call_

Shield transparent coinbase funds by sending to a shielded z address. Utxos selected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent` can be used to return a list of locked utxos.

The number of coinbase utxos selected for shielding can be set with the limit parameter, which has a default value of 50. If the parameter is set to 0, the number of utxos selected is limited by the `-mempooltxinputlimit` option. Any limit is constrained by a consensus rule defining a maximum transaction size of 100000 bytes.

The from address is a taddr or "*" for all taddrs belonging to the wallet. The to address is a zaddr. The default fee is 0.0001.

Returns an object containing an operationid which can be used with z_getoperationstatus and z_getoperationresult, along with key-value pairs regarding how many utxos are being shielded in this transaction and what remains to be shielded. diff --git a/doc/release-notes.md b/doc/release-notes.md index a29094b51..6cdd058ac 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,3 +4,16 @@ release-notes at release time) Notable changes =============== +Hierarchical Deterministic Key Generation for Sapling +----------------------------------------------------- +All Sapling addresses will use hierarchical deterministic key generation +according to ZIP 32 (keypath m/32'/133'/k' on mainnet). Transparent and +Sprout addresses will still use traditional key generation. + +Backups of HD wallets, regardless of when they have been created, can +therefore be used to re-generate all possible Sapling private keys, even the +ones which haven't already been generated during the time of the backup. +Regular backups are still necessary, however, in order to ensure that +transparent and Sprout addresses are not lost. + +[Pull request](https://github.com/zcash/zcash/pull/3492), [ZIP 32](https://github.com/zcash/zips/blob/master/zip-0032.mediawiki) diff --git a/doc/release-notes/release-notes-1.1.0-rc1.md b/doc/release-notes/release-notes-1.1.0-rc1.md new file mode 100644 index 000000000..a769b97cf --- /dev/null +++ b/doc/release-notes/release-notes-1.1.0-rc1.md @@ -0,0 +1,180 @@ +Notable changes +=============== + +`-mempooltxinputlimit` deprecation +---------------------------------- + +The configuration option `-mempooltxinputlimit` was added in release 1.0.10 as a +short-term fix for the quadratic hashing problem inherited from Bitcoin. At the +time, transactions with many inputs were causing performance issues for miners. +Since then, several performance improvements have been merged from the Bitcoin +Core codebase that significantly reduce these issues. + +The Overwinter network upgrade includes changes that solve the quadratic hashing +problem, and so `-mempooltxinputlimit` will no longer be needed - a transaction +with 1000 inputs will take just as long to validate as 10 transactions with 100 +inputs each. Starting from this release, `-mempooltxinputlimit` will be enforced +before the Overwinter activation height is reached, but will be ignored once +Overwinter activates. The option will be removed entirely in a future release +after Overwinter has activated. + +`NODE_BLOOM` service bit +------------------------ + +Support for the `NODE_BLOOM` service bit, as described in [BIP +111](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki), has been +added to the P2P protocol code. + +BIP 111 defines a service bit to allow peers to advertise that they support +Bloom filters (such as used by SPV clients) explicitly. It also bumps the protocol +version to allow peers to identify old nodes which allow Bloom filtering of the +connection despite lacking the new service bit. + +In this version, it is only enforced for peers that send protocol versions +`>=170004`. For the next major version it is planned that this restriction will be +removed. It is recommended to update SPV clients to check for the `NODE_BLOOM` +service bit for nodes that report version 170004 or newer. + +Changelog +========= + +Brad Miller (2): + Clean up + Implement note locking for z_mergetoaddress + +Charlie O'Keefe (1): + Add filename and sha256 hash for windows rust package + +Daira Hopwood (5): + Squashed commit of the following: + pyflakes cleanups to RPC tests after Overwinter PRs. + Add support for Overwinter v3 transactions to mininode framework. + Test that receiving an expired transaction does not increase the peer's ban score. + Don't increase banscore if the transaction only just expired. + +Daniel Kraft (1): + trivial: use constants for db keys + +Jack Grigg (43): + Add environment variable for setting ./configure flags in zcutil/build.sh + Add configure flags for enabling ASan/UBSan and TSan + Split declaration and definition of SPROUT_BRANCH_ID constant + Add link to Overwinter info page + Notify users about auto-senescence via -alertnotify + test: Move wait_and_assert_operationid_status debug output before asserts + Don't require RELRO and BIND_NOW for Darwin + Only set multicore flags if OpenMP is available + Revert "remove -mt suffix from boost libraries built by depends" + Use correct Boost::System linker flag for libzcash + depends: Remove -mt suffix from Boost libraries + snark: Remove -mt suffix from Boost library + cleanup: Ensure code is pyflakes-clean for CI + Ignore -mempooltxinputlimit once Overwinter activates + depends: Explicitly download and vendor Rust dependencies + Make Rust compilation mandatory + Optimise serialization of MerklePath, avoiding ambiguity of std::vector + Use uint64_t instead of size_t for serialized indices into tx.vjoinsplit + Move explicit instantiation of IncrementalMerkleTree::emptyroots into header + libsnark: Don't set -static on Darwin + Set PLATFORM flag when compiling libsnark + Add base case to CurrentEpoch() + Cast ZCIncrementalMerkleTree::size() to uint64_t before passing to UniValue + rpcwallet.cpp: Cast size_t to uint64_t before passing to UniValue + wallet: Cast size_t to uint64_t before passing to UniValue + Test calling z_mergetoaddress to merge notes while a note merge is ongoing + depends: Fix regex bugs in cargo-checksum.sh + Fix z_importviewingkey startHeight parameter + Add RPC test of RewindBlockIndex + When rewinding, remove insufficiently-validated blocks + Adjust deprecation message to work in both UI and -alertnotify + Refactor Zcash changes to CCoinsViewDB + Update blockchain.py RPC test for Zcash + Update CBlockTreeDB::EraseBatchSync for dbwrapper refactor + Fix typo + test: Check return value of snprintf + test: Add missing Overwinter fields to mininode's CTransaction + Add RPC test for -enforcenodebloom + Fix NODE_BLOOM documentation errors + Move bloom filter filtering logic back into command "switch" + Update -enforcenodebloom RPC test with filterclear vs filteradd + make-release.py: Versioning changes for 1.1.0-rc1. + make-release.py: Updated manpages for 1.1.0-rc1. + +James O'Beirne (3): + Refactor leveldbwrapper + Minor bugfixes + Add tests for gettxoutsetinfo, CLevelDBBatch, CLevelDBIterator + +Jason Davies (1): + Fix typo in comment: should link to issue #1359. + +Jay Graber (1): + Set ban score for expired txs to 0 + +Jeff Garzik (3): + leveldbwrapper: Remove unused .Prev(), .SeekToLast() methods + leveldbwrapper symbol rename: Remove "Level" from class, etc. names + leveldbwrapper file rename to dbwrapper.* + +Jonathan "Duke" Leto (7): + Fix references to Bitcoin in RPC tests readme + This library seems to not be used at all and all comments mentioning it are ghosts + Update awkward wording about blocks as per @daira + Regtest mining does have a founders reward, a single address t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg + Fix outdated comment about starting balance of nodes + Return JoinSplit and JoinSplitOutput indexes in z_listreceivedbyaddress + Add tests for new JoinSplit keys returned by z_listreceivedbyaddress + +Lauda (1): + [Trivial] Grammar and typo correction + +Matt Corallo (3): + Add test for dbwrapper iterators with same-prefix keys. + Add NODE_BLOOM service bit and bump protocol version + Don't do mempool lookups for "mempool" command without a filter + +Patick Strateman (3): + Move bloom filter filtering logic outside of command "switch" (giant if/else). + Add enforcenodebloom option. + Document both the peerbloomfilters and enforcenodebloom options. + +Pavel Janík (1): + Do not shadow members in dbwrapper + +Pieter Wuille (2): + Encapsulate CLevelDB iterators cleanly + Fix chainstate serialized_size computation + +R E Broadley (1): + Allow filterclear messages for enabling TX relay only. + +Simon Liu (13): + Code clean up. Remove use of X macro. + Enable mempool logging in tx expiry QA test. + Closes #3084. Log txid when removing expired txs from mempool. + Add qa test for cache invalidation bug found in v1.0.0 to v1.0.3. + Remove local function wait_and_assert_operationid_status which is now defined in the test framework for shared usage. + Update boost to 1.66.0 + Part of #2966, extending Sprout tests to other epochs. + Update boost package URL to match official download url on boost.org + Closes #3110. Ensure user can see error message about absurdly high fees. + Closes #2910. Add z_listunspent RPC call. + Upgrade OpenSSL to 1.1.0h + Use range based for loop + Bump MIT Licence copyright header. + +Wladimir J. van der Laan (6): + dbwrapper: Pass parent CDBWrapper into CDBBatch and CDBIterator + dbwrapper: Move `HandleError` to `dbwrapper_private` + chain: Add assertion in case of missing records in index db + test: Add more thorough test for dbwrapper iterators + test: Replace remaining sprintf with snprintf + doc: update release-notes and bips.md for BIP111 + +kozyilmaz (1): + Fix test/gtest bugs caught by latest macOS clang + +rofl0r (2): + fix build error due to usage of obsolete boost_system-mt + remove -mt suffix from boost libraries built by depends + diff --git a/doc/release-notes/release-notes-1.1.0.md b/doc/release-notes/release-notes-1.1.0.md new file mode 100644 index 000000000..37f803e6f --- /dev/null +++ b/doc/release-notes/release-notes-1.1.0.md @@ -0,0 +1,193 @@ +Notable changes +=============== + +Overwinter network upgrade +-------------------------- + +The activation height for the Overwinter network upgrade on mainnet is included +in this release. Overwinter will activate on mainnet at height 347500, which is +expected to be mined on the 25th of June 2018. Please upgrade to this release, +or any subsequent release, in order to follow the Overwinter network upgrade. + +`-mempooltxinputlimit` deprecation +---------------------------------- + +The configuration option `-mempooltxinputlimit` was added in release 1.0.10 as a +short-term fix for the quadratic hashing problem inherited from Bitcoin. At the +time, transactions with many inputs were causing performance issues for miners. +Since then, several performance improvements have been merged from the Bitcoin +Core codebase that significantly reduce these issues. + +The Overwinter network upgrade includes changes that solve the quadratic hashing +problem, and so `-mempooltxinputlimit` will no longer be needed - a transaction +with 1000 inputs will take just as long to validate as 10 transactions with 100 +inputs each. Starting from this release, `-mempooltxinputlimit` will be enforced +before the Overwinter activation height is reached, but will be ignored once +Overwinter activates. The option will be removed entirely in a future release +after Overwinter has activated. + +`NODE_BLOOM` service bit +------------------------ + +Support for the `NODE_BLOOM` service bit, as described in [BIP +111](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki), has been +added to the P2P protocol code. + +BIP 111 defines a service bit to allow peers to advertise that they support +Bloom filters (such as used by SPV clients) explicitly. It also bumps the protocol +version to allow peers to identify old nodes which allow Bloom filtering of the +connection despite lacking the new service bit. + +In this version, it is only enforced for peers that send protocol versions +`>=170004`. For the next major version it is planned that this restriction will be +removed. It is recommended to update SPV clients to check for the `NODE_BLOOM` +service bit for nodes that report version 170004 or newer. + +Changelog +========= + +Brad Miller (2): + Clean up + Implement note locking for z_mergetoaddress + +Charlie O'Keefe (1): + Add filename and sha256 hash for windows rust package + +Daira Hopwood (5): + Squashed commit of the following: + pyflakes cleanups to RPC tests after Overwinter PRs. + Add support for Overwinter v3 transactions to mininode framework. + Test that receiving an expired transaction does not increase the peer's ban score. + Don't increase banscore if the transaction only just expired. + +Daniel Kraft (1): + trivial: use constants for db keys + +Jack Grigg (47): + Add environment variable for setting ./configure flags in zcutil/build.sh + Add configure flags for enabling ASan/UBSan and TSan + Split declaration and definition of SPROUT_BRANCH_ID constant + Add link to Overwinter info page + Notify users about auto-senescence via -alertnotify + test: Move wait_and_assert_operationid_status debug output before asserts + Don't require RELRO and BIND_NOW for Darwin + Only set multicore flags if OpenMP is available + Revert "remove -mt suffix from boost libraries built by depends" + Use correct Boost::System linker flag for libzcash + depends: Remove -mt suffix from Boost libraries + snark: Remove -mt suffix from Boost library + cleanup: Ensure code is pyflakes-clean for CI + Ignore -mempooltxinputlimit once Overwinter activates + depends: Explicitly download and vendor Rust dependencies + Make Rust compilation mandatory + Optimise serialization of MerklePath, avoiding ambiguity of std::vector + Use uint64_t instead of size_t for serialized indices into tx.vjoinsplit + Move explicit instantiation of IncrementalMerkleTree::emptyroots into header + libsnark: Don't set -static on Darwin + Set PLATFORM flag when compiling libsnark + Add base case to CurrentEpoch() + Cast ZCIncrementalMerkleTree::size() to uint64_t before passing to UniValue + rpcwallet.cpp: Cast size_t to uint64_t before passing to UniValue + wallet: Cast size_t to uint64_t before passing to UniValue + Test calling z_mergetoaddress to merge notes while a note merge is ongoing + depends: Fix regex bugs in cargo-checksum.sh + Fix z_importviewingkey startHeight parameter + Add RPC test of RewindBlockIndex + When rewinding, remove insufficiently-validated blocks + Adjust deprecation message to work in both UI and -alertnotify + Refactor Zcash changes to CCoinsViewDB + Update blockchain.py RPC test for Zcash + Update CBlockTreeDB::EraseBatchSync for dbwrapper refactor + Fix typo + test: Check return value of snprintf + test: Add missing Overwinter fields to mininode's CTransaction + Add RPC test for -enforcenodebloom + Fix NODE_BLOOM documentation errors + Move bloom filter filtering logic back into command "switch" + Update -enforcenodebloom RPC test with filterclear vs filteradd + make-release.py: Versioning changes for 1.1.0-rc1. + make-release.py: Updated manpages for 1.1.0-rc1. + make-release.py: Updated release notes and changelog for 1.1.0-rc1. + Set Overwinter protocol version to 170005 + make-release.py: Versioning changes for 1.1.0. + make-release.py: Updated manpages for 1.1.0. + +James O'Beirne (3): + Refactor leveldbwrapper + Minor bugfixes + Add tests for gettxoutsetinfo, CLevelDBBatch, CLevelDBIterator + +Jason Davies (1): + Fix typo in comment: should link to issue #1359. + +Jay Graber (1): + Set ban score for expired txs to 0 + +Jeff Garzik (3): + leveldbwrapper: Remove unused .Prev(), .SeekToLast() methods + leveldbwrapper symbol rename: Remove "Level" from class, etc. names + leveldbwrapper file rename to dbwrapper.* + +Jonathan "Duke" Leto (7): + Fix references to Bitcoin in RPC tests readme + This library seems to not be used at all and all comments mentioning it are ghosts + Update awkward wording about blocks as per @daira + Regtest mining does have a founders reward, a single address t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg + Fix outdated comment about starting balance of nodes + Return JoinSplit and JoinSplitOutput indexes in z_listreceivedbyaddress + Add tests for new JoinSplit keys returned by z_listreceivedbyaddress + +Lauda (1): + [Trivial] Grammar and typo correction + +Matt Corallo (3): + Add test for dbwrapper iterators with same-prefix keys. + Add NODE_BLOOM service bit and bump protocol version + Don't do mempool lookups for "mempool" command without a filter + +Patick Strateman (3): + Move bloom filter filtering logic outside of command "switch" (giant if/else). + Add enforcenodebloom option. + Document both the peerbloomfilters and enforcenodebloom options. + +Pavel Janík (1): + Do not shadow members in dbwrapper + +Pieter Wuille (2): + Encapsulate CLevelDB iterators cleanly + Fix chainstate serialized_size computation + +R E Broadley (1): + Allow filterclear messages for enabling TX relay only. + +Simon Liu (14): + Code clean up. Remove use of X macro. + Enable mempool logging in tx expiry QA test. + Closes #3084. Log txid when removing expired txs from mempool. + Add qa test for cache invalidation bug found in v1.0.0 to v1.0.3. + Remove local function wait_and_assert_operationid_status which is now defined in the test framework for shared usage. + Update boost to 1.66.0 + Part of #2966, extending Sprout tests to other epochs. + Update boost package URL to match official download url on boost.org + Closes #3110. Ensure user can see error message about absurdly high fees. + Closes #2910. Add z_listunspent RPC call. + Upgrade OpenSSL to 1.1.0h + Use range based for loop + Bump MIT Licence copyright header. + Fix test to check for sanitized string from alertnotify. + +Wladimir J. van der Laan (6): + dbwrapper: Pass parent CDBWrapper into CDBBatch and CDBIterator + dbwrapper: Move `HandleError` to `dbwrapper_private` + chain: Add assertion in case of missing records in index db + test: Add more thorough test for dbwrapper iterators + test: Replace remaining sprintf with snprintf + doc: update release-notes and bips.md for BIP111 + +kozyilmaz (1): + Fix test/gtest bugs caught by latest macOS clang + +rofl0r (2): + fix build error due to usage of obsolete boost_system-mt + remove -mt suffix from boost libraries built by depends + diff --git a/doc/release-notes/release-notes-1.1.1-rc1.md b/doc/release-notes/release-notes-1.1.1-rc1.md new file mode 100644 index 000000000..bc209efc7 --- /dev/null +++ b/doc/release-notes/release-notes-1.1.1-rc1.md @@ -0,0 +1,286 @@ +Notable changes +=============== + +zcash-cli: arguments privacy +---------------------------- + +The RPC command line client gained a new argument, `-stdin` +to read extra arguments from standard input, one per line until EOF/Ctrl-D. +For example: + + $ src/zcash-cli -stdin walletpassphrase + mysecretcode + 120 + ^D (Ctrl-D) + +It is recommended to use this for sensitive information such as private keys, as +command-line arguments can usually be read from the process table by any user on +the system. + +Asm representations of scriptSig signatures now contain SIGHASH type decodes +---------------------------------------------------------------------------- + +The `asm` property of each scriptSig now contains the decoded signature hash +type for each signature that provides a valid defined hash type. + +The following items contain assembly representations of scriptSig signatures +and are affected by this change: + +- RPC `getrawtransaction` +- RPC `decoderawtransaction` +- REST `/rest/tx/` (JSON format) +- REST `/rest/block/` (JSON format when including extended tx details) +- `zcash-tx -json` + +For example, the `scriptSig.asm` property of a transaction input that +previously showed an assembly representation of: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001 + +now shows as: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090[ALL] + +Note that the output of the RPC `decodescript` did not change because it is +configured specifically to process scriptPubKey and not scriptSig scripts. + +Changelog +========= + +Cory Fields (4): + serialization: teach serializers variadics + build: univalue subdir build fixups + don't throw std::bad_alloc when out of memory. Instead, terminate immediately + prevector: assert successful allocation + +Daira Hopwood (1): + Use https: for BDB backup download URL. + +David Llop (1): + Update Payment API + +Eirik Ogilvie-Wigley (7): + Clarify help text of dumpprivkey + Add sapling nullifier set + Add enum for nullifier type + Add sapling nullifiers to db and mempool + Rename nullifier caches and maps to indicate sprout nullifiers + Make sure transactions have non-empty outputs + Coinbase transactions can not have shielded spend or output + +Jack Grigg (50): + Disable building libzcashconsensus by default + depends: Upgrade Rust to 1.26.0-beta.3 + depends: Add support for unpackaged Rust crates + depends: Update to latest librustzcash with sapling-crypto dependencies + Add Sapling to upgrade list + Add static asserts to ensure CONTINUE_EXECUTION doesn't collide + [Bitcoin-Tx] Adjust util-test test cases for Zcash + Handle usage of prevector for CScript in Zcash-specific code + GetSerializeSize changes in Zcash-specific code + Remove nType and nVersion from Zcash-specific code + Adjust consensus rules to require v4 transactions from Sapling activation + Implement basic Sapling v4 transaction parser + Add Sapling v4 transactions to IsStandard + Pass transaction header into correct SignatureHash serialization level + Remove now-unshadowed serialization lines that do nothing + Implement SpendDescription and OutputDescription datastructures + Add a constant for Overwinter's transaction version + Return result of boost::apply_visitor + Improve best-effort logging before termination on OOM + Attempt to log before terminating if prevector allocation fails + Fix -Wstring-plus-int warning on clang + Update mempool_nu_activation RPC test to exercise both Overwinter and Sapling + Use CBitcoinAddress wrappers in Zcash-specific code + Change JSOutPoint constructor to have js argument be uint64_t + Update CreateNewContextualCMutableTransaction to create Sapling transactions + Expire Overwinter transactions before the Sapling activation height + Remove obsolete CreateJoinSplit and GenerateParams binaries + Add missing include guard + Raise 100kB transaction size limit from Sapling activation + Benchmark the largest valid Sapling transaction in validatelargetx + Rename MAX_TX_SIZE to MAX_TX_SIZE_AFTER_SAPLING + Rework z_sendmany z-address recipient limit + Add test of Sapling transaction size boundary + Update tests for CreateNewContextualCMutableTransaction changes + wallet: Change IsLockedNote to take a JSOutPoint + wallet: Make some arguments const that can be + Implement Sapling signature hash (ZIP 243) + Update sighash tests + Introduce wrappers around CZCPaymentAddress + Introduce wrappers around CZCSpendingKey + Introduce wrappers around CZCViewingKey + Implement {Encode,Decode}PaymentAddress etc. without CZCEncoding + Add key_io includes to Zcash-specific code + Add valueBalance to value balances, and enforce its consensus rules + Track net value entering and exiting the Sapling circuit + Add contextual comment for GetValueOut() and GetShieldedValueIn() + Use boost::variant to represent shielded addresses and keys + Correctly serialize Groth16 JSDescription for verifyjoinsplit benchmark + make-release.py: Versioning changes for 1.1.1-rc1. + make-release.py: Updated manpages for 1.1.1-rc1. + +Jay Graber (1): + Add test for dependent txs to mempool_tx_expiry.py + +Jeremy Rubin (1): + Fix subscript[0] in base58.cpp + +Jonas Schnelli (4): + [RPC] createrawtransaction: add option to set the sequence number per input + [bitcoin-tx] allow to set nSequence number over the in= command + [Bitcoin-Tx] Add tests for sequence number support + add bip32 pubkey serialization + +João Barbosa (1): + Remove unused GetKeyID and IsScript methods from CBitcoinAddress + +Karl-Johan Alm (1): + Removed using namespace std from bitcoin-cli/-tx and added std:: in appropriate places. + +Kaz Wesley (1): + CBase58Data::SetString: cleanse the full vector + +Larry Ruane (1): + fix qa/zcash/full_test_suite.py pathname + +MarcoFalke (3): + [uacomment] Sanitize per BIP-0014 + [rpcwallet] Don't use floating point + [test] Remove unused code + +Matt Corallo (1): + Add COMPACTSIZE wrapper similar to VARINT for serialization + +Pavel Janík (1): + [WIP] Remove unused statement in serialization + +Pavol Rusnak (2): + implement uacomment config parameter which can add comments to user agent as per BIP-0014 + limit total length of user agent comments + +Pedro Branco (1): + Prevent multiple calls to ExtractDestination + +Per Grön (1): + Make some globals static that can be + +Peter Pratscher (1): + Backported Bitcoin PR #8704 to optionally return full tx details in the getblock rpc call + +Pieter Wuille (22): + Prevector type + Remove unused ReadVersion and WriteVersion + Make streams' read and write return void + Make nType and nVersion private and sometimes const + Make GetSerializeSize a wrapper on top of CSizeComputer + Get rid of nType and nVersion + Avoid -Wshadow errors + Make CSerAction's ForRead() constexpr + Add optimized CSizeComputer serializers + Use fixed preallocation instead of costly GetSerializeSize + Add serialization for unique_ptr and shared_ptr + Add deserializing constructors to CTransaction and CMutableTransaction + Avoid unaligned access in crypto i/o + Fix some empty vector references + Introduce wrappers around CBitcoinAddress + Move CBitcoinAddress to base58.cpp + Implement {Encode,Decode}Destination without CBitcoinAddress + Import Bech32 C++ reference code & tests + Convert base58_tests from type/payload to scriptPubKey comparison + Replace CBitcoinSecret with {Encode,Decode}Secret + Stop using CBase58Data for ext keys + Split key_io (address/key encodings) off from base58 + +Puru (1): + bitcoin-cli.cpp: Use symbolic constant for exit code + +Sean Bowe (49): + Switch to latest librustzcash + Invoke the merkle_hash API in librustzcash via test suite. + Link with -ldl + Update librustzcash hash + Load Sapling testnet parameters into memory. + Update librustzcash hash + Check that duplicate Sapling nullifiers don't exist within a transaction. + Abstract `uncommitted` and depth personalization for IncrementalMerkleTree. + Add implementation of Sapling merkle tree + Add regression tests and test vectors for Sapling merkle tree + Rename NullifierType to ShieldedType. + Specifically describe anchors as Sprout anchors. + Rename hashAnchor to hashSproutAnchor. + Rename hashReserved to hashSaplingAnchorEnd. + Add primitive implementation of GetSaplingAnchorEnd. + Rename DB_ANCHOR to DB_SPROUT_ANCHOR. + Rename GetAnchorAt to GetSproutAnchorAt. + Rename PushAnchor to PushSproutAnchor. + Introduce support for GetBestAnchor(SAPLING). + Generalize the PopAnchor implementation behavior. + Generalize the PushAnchor implementation behavior. + Remove underscores from gtest test names. + Rename hashSaplingAnchorEnd to hashFinalSaplingRoot to match spec. + Rename hashSproutAnchorEnd to hashFinalSproutRoot to be consistent. + Add support for Sapling anchors in coins/txdb. + Add support for PopAnchor(.., SPROUT/SAPLING) + Add `PushSaplingAnchor` + Add consensus support for Sapling merkle trees. + Add support for Sapling anchor checks in mempool consistency checks. + Calculate the correct hashFinalSaplingRoot in the miner. + Adjust tests to handle Sapling anchor cache + Evict transactions with obsolete anchors from the mempool + Fix outdated comment + Fix broken error messages. + Fix miner tests + Update sapling-crypto and librustzcash + Swap bit endianness of test vectors + Remove unnecessary IsCoinbase() check. Coinbases are guaranteed to have empty vjoinsplit. + Refactor so that dataToBeSigned can be used later in the function for other purposes. + Update to latest librustzcash + Check Sapling Spend/Output proofs and signatures. + Integrate Groth16 verification and proving. + Update librustzcash again + Adjust tests and benchmarks + Switch Rust to 1.26 Stable. + Update librustzcash + Update Sapling testnet parameters + Update merkle tree and pedersen hash tests to account for new encoding + Change txdb prefixes for sapling and avoid writing unnecessary information. + +Simon Liu (14): + Part of #2966, extending Sprout tests to other epochs. + Closes #3134 - Least Authority Issue E + Refactoring: libzcash::Note is now a subclass of libzcash::BaseNote. + Refactoring: Rename class libzcash::Note to libzcash::SproutNote. + Refactoring: SproutNote member variable value moved to BaseNote. + Add virtual destructor to SproutNote and BaseNote + Remove unused SproutNote variables. + Refactoring: rename NotePlaintext --> SproutNotePlaintext + Create class hierarchy for SproutNotePlaintext. + Move memo member varible from SproutNotePlaintext to BaseNotePlaintext. + Tweaks to d0a1d83 to complete backport of Bitcoin PR #8704 + Closes #3178 by adding verbosity level improvements to getblock RPC. + Fix undefined behaviour, calling memcpy with NULL pointer. + Closes #3250. Memo getter should return by reference, not by value. + +Tom Harding (1): + Add optional locktime to createrawtransaction + +UdjinM6 (2): + Fix exit codes: + Every main()/exit() should return/use one of EXIT_ codes instead of magic numbers + +Wladimir J. van der Laan (2): + rpc: Input-from-stdin mode for bitcoin-cli + doc: mention bitcoin-cli -stdin in release notes + +ca333 (2): + [fix] proton download path + update proton.mk + +kozyilmaz (2): + [macOS] added curl method for param download + [macOS] use shlock instead of flock in fetch-params + +mruddy (1): + Resolve issue bitcoin/bitcoin#3166. + diff --git a/doc/release-notes/release-notes-1.1.1-rc2.md b/doc/release-notes/release-notes-1.1.1-rc2.md new file mode 100644 index 000000000..5d10ede47 --- /dev/null +++ b/doc/release-notes/release-notes-1.1.1-rc2.md @@ -0,0 +1,290 @@ +Notable changes +=============== + +zcash-cli: arguments privacy +---------------------------- + +The RPC command line client gained a new argument, `-stdin` +to read extra arguments from standard input, one per line until EOF/Ctrl-D. +For example: + + $ src/zcash-cli -stdin walletpassphrase + mysecretcode + 120 + ^D (Ctrl-D) + +It is recommended to use this for sensitive information such as private keys, as +command-line arguments can usually be read from the process table by any user on +the system. + +Asm representations of scriptSig signatures now contain SIGHASH type decodes +---------------------------------------------------------------------------- + +The `asm` property of each scriptSig now contains the decoded signature hash +type for each signature that provides a valid defined hash type. + +The following items contain assembly representations of scriptSig signatures +and are affected by this change: + +- RPC `getrawtransaction` +- RPC `decoderawtransaction` +- REST `/rest/tx/` (JSON format) +- REST `/rest/block/` (JSON format when including extended tx details) +- `zcash-tx -json` + +For example, the `scriptSig.asm` property of a transaction input that +previously showed an assembly representation of: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001 + +now shows as: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090[ALL] + +Note that the output of the RPC `decodescript` did not change because it is +configured specifically to process scriptPubKey and not scriptSig scripts. + +Changelog +========= + +Cory Fields (4): + serialization: teach serializers variadics + build: univalue subdir build fixups + don't throw std::bad_alloc when out of memory. Instead, terminate immediately + prevector: assert successful allocation + +Daira Hopwood (1): + Use https: for BDB backup download URL. + +David Llop (1): + Update Payment API + +Eirik Ogilvie-Wigley (7): + Clarify help text of dumpprivkey + Add sapling nullifier set + Add enum for nullifier type + Add sapling nullifiers to db and mempool + Rename nullifier caches and maps to indicate sprout nullifiers + Make sure transactions have non-empty outputs + Coinbase transactions can not have shielded spend or output + +Jack Grigg (52): + Disable building libzcashconsensus by default + depends: Upgrade Rust to 1.26.0-beta.3 + depends: Add support for unpackaged Rust crates + depends: Update to latest librustzcash with sapling-crypto dependencies + Add Sapling to upgrade list + Add static asserts to ensure CONTINUE_EXECUTION doesn't collide + [Bitcoin-Tx] Adjust util-test test cases for Zcash + Handle usage of prevector for CScript in Zcash-specific code + GetSerializeSize changes in Zcash-specific code + Remove nType and nVersion from Zcash-specific code + Adjust consensus rules to require v4 transactions from Sapling activation + Implement basic Sapling v4 transaction parser + Add Sapling v4 transactions to IsStandard + Pass transaction header into correct SignatureHash serialization level + Remove now-unshadowed serialization lines that do nothing + Implement SpendDescription and OutputDescription datastructures + Add a constant for Overwinter's transaction version + Return result of boost::apply_visitor + Improve best-effort logging before termination on OOM + Attempt to log before terminating if prevector allocation fails + Fix -Wstring-plus-int warning on clang + Update mempool_nu_activation RPC test to exercise both Overwinter and Sapling + Use CBitcoinAddress wrappers in Zcash-specific code + Change JSOutPoint constructor to have js argument be uint64_t + Update CreateNewContextualCMutableTransaction to create Sapling transactions + Expire Overwinter transactions before the Sapling activation height + Remove obsolete CreateJoinSplit and GenerateParams binaries + Add missing include guard + Raise 100kB transaction size limit from Sapling activation + Benchmark the largest valid Sapling transaction in validatelargetx + Rename MAX_TX_SIZE to MAX_TX_SIZE_AFTER_SAPLING + Rework z_sendmany z-address recipient limit + Add test of Sapling transaction size boundary + Update tests for CreateNewContextualCMutableTransaction changes + wallet: Change IsLockedNote to take a JSOutPoint + wallet: Make some arguments const that can be + Implement Sapling signature hash (ZIP 243) + Update sighash tests + Introduce wrappers around CZCPaymentAddress + Introduce wrappers around CZCSpendingKey + Introduce wrappers around CZCViewingKey + Implement {Encode,Decode}PaymentAddress etc. without CZCEncoding + Add key_io includes to Zcash-specific code + Add valueBalance to value balances, and enforce its consensus rules + Track net value entering and exiting the Sapling circuit + Add contextual comment for GetValueOut() and GetShieldedValueIn() + Use boost::variant to represent shielded addresses and keys + Correctly serialize Groth16 JSDescription for verifyjoinsplit benchmark + make-release.py: Versioning changes for 1.1.1-rc1. + make-release.py: Updated manpages for 1.1.1-rc1. + make-release.py: Updated release notes and changelog for 1.1.1-rc1. + Comment out Gitian library handling while we don't build any libraries + +Jay Graber (1): + Add test for dependent txs to mempool_tx_expiry.py + +Jeremy Rubin (1): + Fix subscript[0] in base58.cpp + +Jonas Schnelli (4): + [RPC] createrawtransaction: add option to set the sequence number per input + [bitcoin-tx] allow to set nSequence number over the in= command + [Bitcoin-Tx] Add tests for sequence number support + add bip32 pubkey serialization + +João Barbosa (1): + Remove unused GetKeyID and IsScript methods from CBitcoinAddress + +Karl-Johan Alm (1): + Removed using namespace std from bitcoin-cli/-tx and added std:: in appropriate places. + +Kaz Wesley (1): + CBase58Data::SetString: cleanse the full vector + +Larry Ruane (1): + fix qa/zcash/full_test_suite.py pathname + +MarcoFalke (3): + [uacomment] Sanitize per BIP-0014 + [rpcwallet] Don't use floating point + [test] Remove unused code + +Matt Corallo (1): + Add COMPACTSIZE wrapper similar to VARINT for serialization + +Pavel Janík (1): + [WIP] Remove unused statement in serialization + +Pavol Rusnak (2): + implement uacomment config parameter which can add comments to user agent as per BIP-0014 + limit total length of user agent comments + +Pedro Branco (1): + Prevent multiple calls to ExtractDestination + +Per Grön (1): + Make some globals static that can be + +Peter Pratscher (1): + Backported Bitcoin PR #8704 to optionally return full tx details in the getblock rpc call + +Pieter Wuille (22): + Prevector type + Remove unused ReadVersion and WriteVersion + Make streams' read and write return void + Make nType and nVersion private and sometimes const + Make GetSerializeSize a wrapper on top of CSizeComputer + Get rid of nType and nVersion + Avoid -Wshadow errors + Make CSerAction's ForRead() constexpr + Add optimized CSizeComputer serializers + Use fixed preallocation instead of costly GetSerializeSize + Add serialization for unique_ptr and shared_ptr + Add deserializing constructors to CTransaction and CMutableTransaction + Avoid unaligned access in crypto i/o + Fix some empty vector references + Introduce wrappers around CBitcoinAddress + Move CBitcoinAddress to base58.cpp + Implement {Encode,Decode}Destination without CBitcoinAddress + Import Bech32 C++ reference code & tests + Convert base58_tests from type/payload to scriptPubKey comparison + Replace CBitcoinSecret with {Encode,Decode}Secret + Stop using CBase58Data for ext keys + Split key_io (address/key encodings) off from base58 + +Puru (1): + bitcoin-cli.cpp: Use symbolic constant for exit code + +Sean Bowe (49): + Switch to latest librustzcash + Invoke the merkle_hash API in librustzcash via test suite. + Link with -ldl + Update librustzcash hash + Load Sapling testnet parameters into memory. + Update librustzcash hash + Check that duplicate Sapling nullifiers don't exist within a transaction. + Abstract `uncommitted` and depth personalization for IncrementalMerkleTree. + Add implementation of Sapling merkle tree + Add regression tests and test vectors for Sapling merkle tree + Rename NullifierType to ShieldedType. + Specifically describe anchors as Sprout anchors. + Rename hashAnchor to hashSproutAnchor. + Rename hashReserved to hashSaplingAnchorEnd. + Add primitive implementation of GetSaplingAnchorEnd. + Rename DB_ANCHOR to DB_SPROUT_ANCHOR. + Rename GetAnchorAt to GetSproutAnchorAt. + Rename PushAnchor to PushSproutAnchor. + Introduce support for GetBestAnchor(SAPLING). + Generalize the PopAnchor implementation behavior. + Generalize the PushAnchor implementation behavior. + Remove underscores from gtest test names. + Rename hashSaplingAnchorEnd to hashFinalSaplingRoot to match spec. + Rename hashSproutAnchorEnd to hashFinalSproutRoot to be consistent. + Add support for Sapling anchors in coins/txdb. + Add support for PopAnchor(.., SPROUT/SAPLING) + Add `PushSaplingAnchor` + Add consensus support for Sapling merkle trees. + Add support for Sapling anchor checks in mempool consistency checks. + Calculate the correct hashFinalSaplingRoot in the miner. + Adjust tests to handle Sapling anchor cache + Evict transactions with obsolete anchors from the mempool + Fix outdated comment + Fix broken error messages. + Fix miner tests + Update sapling-crypto and librustzcash + Swap bit endianness of test vectors + Remove unnecessary IsCoinbase() check. Coinbases are guaranteed to have empty vjoinsplit. + Refactor so that dataToBeSigned can be used later in the function for other purposes. + Update to latest librustzcash + Check Sapling Spend/Output proofs and signatures. + Integrate Groth16 verification and proving. + Update librustzcash again + Adjust tests and benchmarks + Switch Rust to 1.26 Stable. + Update librustzcash + Update Sapling testnet parameters + Update merkle tree and pedersen hash tests to account for new encoding + Change txdb prefixes for sapling and avoid writing unnecessary information. + +Simon Liu (16): + Part of #2966, extending Sprout tests to other epochs. + Closes #3134 - Least Authority Issue E + Refactoring: libzcash::Note is now a subclass of libzcash::BaseNote. + Refactoring: Rename class libzcash::Note to libzcash::SproutNote. + Refactoring: SproutNote member variable value moved to BaseNote. + Add virtual destructor to SproutNote and BaseNote + Remove unused SproutNote variables. + Refactoring: rename NotePlaintext --> SproutNotePlaintext + Create class hierarchy for SproutNotePlaintext. + Move memo member varible from SproutNotePlaintext to BaseNotePlaintext. + Tweaks to d0a1d83 to complete backport of Bitcoin PR #8704 + Closes #3178 by adding verbosity level improvements to getblock RPC. + Fix undefined behaviour, calling memcpy with NULL pointer. + Closes #3250. Memo getter should return by reference, not by value. + make-release.py: Versioning changes for 1.1.1-rc2. + make-release.py: Updated manpages for 1.1.1-rc2. + +Tom Harding (1): + Add optional locktime to createrawtransaction + +UdjinM6 (2): + Fix exit codes: + Every main()/exit() should return/use one of EXIT_ codes instead of magic numbers + +Wladimir J. van der Laan (2): + rpc: Input-from-stdin mode for bitcoin-cli + doc: mention bitcoin-cli -stdin in release notes + +ca333 (2): + [fix] proton download path + update proton.mk + +kozyilmaz (2): + [macOS] added curl method for param download + [macOS] use shlock instead of flock in fetch-params + +mruddy (1): + Resolve issue bitcoin/bitcoin#3166. + diff --git a/doc/release-notes/release-notes-1.1.1.md b/doc/release-notes/release-notes-1.1.1.md new file mode 100644 index 000000000..90adec943 --- /dev/null +++ b/doc/release-notes/release-notes-1.1.1.md @@ -0,0 +1,336 @@ +Notable changes +=============== + +Sapling network upgrade +----------------------- + +The consensus code preparations for the Sapling network upgrade, as described +in [ZIP 243](https://github.com/zcash/zips/blob/master/zip-0243.rst) and the +[Sapling spec](https://github.com/zcash/zips/blob/master/protocol/sapling.pdf) +are finished and included in this release. Sapling support in the wallet and +RPC is ongoing, and is expected to land in master over the next few weeks. + +The [Sapling MPC](https://blog.z.cash/announcing-the-sapling-mpc/) is currently +working on producing the final Sapling parameters. In the meantime, Sapling will +activate on testnet with dummy Sapling parameters at height 252500. This +activation will be temporary, and the testnet will be rolled back by version +2.0.0 so that both mainnet and testnet will be using the same parameters. +Users who want to continue testing Overwinter should continue to run version +1.1.0 on testnet, and then upgrade to 2.0.0 (which will be released after +Overwinter activates). + +Sapling can also be activated at a specific height in regtest mode by +setting the config options `-nuparams=5ba81b19:HEIGHT -nuparams=76b809bb:HEIGHT`. +These config options will change when the testnet is rolled back for 2.0.0 +(because the branch ID for Sapling will change, due to us following the safe +upgrade conventions we introduced in Overwinter). + +Users running testnet or regtest nodes will need to run +`./zcutil/fetch-params.sh --testnet` (for users building from source) or +`zcash-fetch-params --testnet` (for binary / Debian users). + +As a reminder, because the Sapling activation height is not yet specified for +mainnet, version 1.1.1 will behave similarly as other pre-Sapling releases even +after a future activation of Sapling on the network. Upgrading from 1.1.1 will +be required in order to follow the Sapling network upgrade on mainnet. + +Sapling transaction format +-------------------------- + +Once Sapling has activated, transactions must use the new v4 format (including +coinbase transactions). All RPC methods that create new transactions (such as +`createrawtransaction` and `getblocktemplate`) will create v4 transactions once +the Sapling activation height has been reached. + +zcash-cli: arguments privacy +---------------------------- + +The RPC command line client gained a new argument, `-stdin` +to read extra arguments from standard input, one per line until EOF/Ctrl-D. +For example: + + $ src/zcash-cli -stdin walletpassphrase + mysecretcode + 120 + ^D (Ctrl-D) + +It is recommended to use this for sensitive information such as private keys, as +command-line arguments can usually be read from the process table by any user on +the system. + +Asm representations of scriptSig signatures now contain SIGHASH type decodes +---------------------------------------------------------------------------- + +The `asm` property of each scriptSig now contains the decoded signature hash +type for each signature that provides a valid defined hash type. + +The following items contain assembly representations of scriptSig signatures +and are affected by this change: + +- RPC `getrawtransaction` +- RPC `decoderawtransaction` +- REST `/rest/tx/` (JSON format) +- REST `/rest/block/` (JSON format when including extended tx details) +- `zcash-tx -json` + +For example, the `scriptSig.asm` property of a transaction input that +previously showed an assembly representation of: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001 + +now shows as: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090[ALL] + +Note that the output of the RPC `decodescript` did not change because it is +configured specifically to process scriptPubKey and not scriptSig scripts. + +Changelog +========= + +Cory Fields (4): + serialization: teach serializers variadics + build: univalue subdir build fixups + don't throw std::bad_alloc when out of memory. Instead, terminate immediately + prevector: assert successful allocation + +Daira Hopwood (1): + Use https: for BDB backup download URL. + +David Llop (1): + Update Payment API + +Eirik Ogilvie-Wigley (7): + Clarify help text of dumpprivkey + Add sapling nullifier set + Add enum for nullifier type + Add sapling nullifiers to db and mempool + Rename nullifier caches and maps to indicate sprout nullifiers + Make sure transactions have non-empty outputs + Coinbase transactions can not have shielded spend or output + +Jack Grigg (55): + Disable building libzcashconsensus by default + depends: Upgrade Rust to 1.26.0-beta.3 + depends: Add support for unpackaged Rust crates + depends: Update to latest librustzcash with sapling-crypto dependencies + Add Sapling to upgrade list + Add static asserts to ensure CONTINUE_EXECUTION doesn't collide + [Bitcoin-Tx] Adjust util-test test cases for Zcash + Handle usage of prevector for CScript in Zcash-specific code + GetSerializeSize changes in Zcash-specific code + Remove nType and nVersion from Zcash-specific code + Adjust consensus rules to require v4 transactions from Sapling activation + Implement basic Sapling v4 transaction parser + Add Sapling v4 transactions to IsStandard + Pass transaction header into correct SignatureHash serialization level + Remove now-unshadowed serialization lines that do nothing + Implement SpendDescription and OutputDescription datastructures + Add a constant for Overwinter's transaction version + Return result of boost::apply_visitor + Improve best-effort logging before termination on OOM + Attempt to log before terminating if prevector allocation fails + Fix -Wstring-plus-int warning on clang + Update mempool_nu_activation RPC test to exercise both Overwinter and Sapling + Use CBitcoinAddress wrappers in Zcash-specific code + Change JSOutPoint constructor to have js argument be uint64_t + Update CreateNewContextualCMutableTransaction to create Sapling transactions + Expire Overwinter transactions before the Sapling activation height + Remove obsolete CreateJoinSplit and GenerateParams binaries + Add missing include guard + Raise 100kB transaction size limit from Sapling activation + Benchmark the largest valid Sapling transaction in validatelargetx + Rename MAX_TX_SIZE to MAX_TX_SIZE_AFTER_SAPLING + Rework z_sendmany z-address recipient limit + Add test of Sapling transaction size boundary + Update tests for CreateNewContextualCMutableTransaction changes + wallet: Change IsLockedNote to take a JSOutPoint + wallet: Make some arguments const that can be + Implement Sapling signature hash (ZIP 243) + Update sighash tests + Introduce wrappers around CZCPaymentAddress + Introduce wrappers around CZCSpendingKey + Introduce wrappers around CZCViewingKey + Implement {Encode,Decode}PaymentAddress etc. without CZCEncoding + Add key_io includes to Zcash-specific code + Add valueBalance to value balances, and enforce its consensus rules + Track net value entering and exiting the Sapling circuit + Add contextual comment for GetValueOut() and GetShieldedValueIn() + Use boost::variant to represent shielded addresses and keys + Correctly serialize Groth16 JSDescription for verifyjoinsplit benchmark + make-release.py: Versioning changes for 1.1.1-rc1. + make-release.py: Updated manpages for 1.1.1-rc1. + make-release.py: Updated release notes and changelog for 1.1.1-rc1. + Comment out Gitian library handling while we don't build any libraries + Add Sapling details to release notes + make-release.py: Versioning changes for 1.1.1. + make-release.py: Updated manpages for 1.1.1. + +Jay Graber (1): + Add test for dependent txs to mempool_tx_expiry.py + +Jeremy Rubin (1): + Fix subscript[0] in base58.cpp + +Jonas Schnelli (4): + [RPC] createrawtransaction: add option to set the sequence number per input + [bitcoin-tx] allow to set nSequence number over the in= command + [Bitcoin-Tx] Add tests for sequence number support + add bip32 pubkey serialization + +João Barbosa (1): + Remove unused GetKeyID and IsScript methods from CBitcoinAddress + +Karl-Johan Alm (1): + Removed using namespace std from bitcoin-cli/-tx and added std:: in appropriate places. + +Kaz Wesley (1): + CBase58Data::SetString: cleanse the full vector + +Larry Ruane (1): + fix qa/zcash/full_test_suite.py pathname + +MarcoFalke (3): + [uacomment] Sanitize per BIP-0014 + [rpcwallet] Don't use floating point + [test] Remove unused code + +Matt Corallo (1): + Add COMPACTSIZE wrapper similar to VARINT for serialization + +Pavel Janík (1): + [WIP] Remove unused statement in serialization + +Pavol Rusnak (2): + implement uacomment config parameter which can add comments to user agent as per BIP-0014 + limit total length of user agent comments + +Pedro Branco (1): + Prevent multiple calls to ExtractDestination + +Per Grön (1): + Make some globals static that can be + +Peter Pratscher (1): + Backported Bitcoin PR #8704 to optionally return full tx details in the getblock rpc call + +Pieter Wuille (22): + Prevector type + Remove unused ReadVersion and WriteVersion + Make streams' read and write return void + Make nType and nVersion private and sometimes const + Make GetSerializeSize a wrapper on top of CSizeComputer + Get rid of nType and nVersion + Avoid -Wshadow errors + Make CSerAction's ForRead() constexpr + Add optimized CSizeComputer serializers + Use fixed preallocation instead of costly GetSerializeSize + Add serialization for unique_ptr and shared_ptr + Add deserializing constructors to CTransaction and CMutableTransaction + Avoid unaligned access in crypto i/o + Fix some empty vector references + Introduce wrappers around CBitcoinAddress + Move CBitcoinAddress to base58.cpp + Implement {Encode,Decode}Destination without CBitcoinAddress + Import Bech32 C++ reference code & tests + Convert base58_tests from type/payload to scriptPubKey comparison + Replace CBitcoinSecret with {Encode,Decode}Secret + Stop using CBase58Data for ext keys + Split key_io (address/key encodings) off from base58 + +Puru (1): + bitcoin-cli.cpp: Use symbolic constant for exit code + +Sean Bowe (49): + Switch to latest librustzcash + Invoke the merkle_hash API in librustzcash via test suite. + Link with -ldl + Update librustzcash hash + Load Sapling testnet parameters into memory. + Update librustzcash hash + Check that duplicate Sapling nullifiers don't exist within a transaction. + Abstract `uncommitted` and depth personalization for IncrementalMerkleTree. + Add implementation of Sapling merkle tree + Add regression tests and test vectors for Sapling merkle tree + Rename NullifierType to ShieldedType. + Specifically describe anchors as Sprout anchors. + Rename hashAnchor to hashSproutAnchor. + Rename hashReserved to hashSaplingAnchorEnd. + Add primitive implementation of GetSaplingAnchorEnd. + Rename DB_ANCHOR to DB_SPROUT_ANCHOR. + Rename GetAnchorAt to GetSproutAnchorAt. + Rename PushAnchor to PushSproutAnchor. + Introduce support for GetBestAnchor(SAPLING). + Generalize the PopAnchor implementation behavior. + Generalize the PushAnchor implementation behavior. + Remove underscores from gtest test names. + Rename hashSaplingAnchorEnd to hashFinalSaplingRoot to match spec. + Rename hashSproutAnchorEnd to hashFinalSproutRoot to be consistent. + Add support for Sapling anchors in coins/txdb. + Add support for PopAnchor(.., SPROUT/SAPLING) + Add `PushSaplingAnchor` + Add consensus support for Sapling merkle trees. + Add support for Sapling anchor checks in mempool consistency checks. + Calculate the correct hashFinalSaplingRoot in the miner. + Adjust tests to handle Sapling anchor cache + Evict transactions with obsolete anchors from the mempool + Fix outdated comment + Fix broken error messages. + Fix miner tests + Update sapling-crypto and librustzcash + Swap bit endianness of test vectors + Remove unnecessary IsCoinbase() check. Coinbases are guaranteed to have empty vjoinsplit. + Refactor so that dataToBeSigned can be used later in the function for other purposes. + Update to latest librustzcash + Check Sapling Spend/Output proofs and signatures. + Integrate Groth16 verification and proving. + Update librustzcash again + Adjust tests and benchmarks + Switch Rust to 1.26 Stable. + Update librustzcash + Update Sapling testnet parameters + Update merkle tree and pedersen hash tests to account for new encoding + Change txdb prefixes for sapling and avoid writing unnecessary information. + +Simon Liu (18): + Part of #2966, extending Sprout tests to other epochs. + Closes #3134 - Least Authority Issue E + Refactoring: libzcash::Note is now a subclass of libzcash::BaseNote. + Refactoring: Rename class libzcash::Note to libzcash::SproutNote. + Refactoring: SproutNote member variable value moved to BaseNote. + Add virtual destructor to SproutNote and BaseNote + Remove unused SproutNote variables. + Refactoring: rename NotePlaintext --> SproutNotePlaintext + Create class hierarchy for SproutNotePlaintext. + Move memo member varible from SproutNotePlaintext to BaseNotePlaintext. + Tweaks to d0a1d83 to complete backport of Bitcoin PR #8704 + Closes #3178 by adding verbosity level improvements to getblock RPC. + Fix undefined behaviour, calling memcpy with NULL pointer. + Closes #3250. Memo getter should return by reference, not by value. + make-release.py: Versioning changes for 1.1.1-rc2. + make-release.py: Updated manpages for 1.1.1-rc2. + make-release.py: Updated release notes and changelog for 1.1.1-rc2. + Closes #3301. Non-void function should not have empty definition. + +Tom Harding (1): + Add optional locktime to createrawtransaction + +UdjinM6 (2): + Fix exit codes: + Every main()/exit() should return/use one of EXIT_ codes instead of magic numbers + +Wladimir J. van der Laan (2): + rpc: Input-from-stdin mode for bitcoin-cli + doc: mention bitcoin-cli -stdin in release notes + +ca333 (2): + [fix] proton download path + update proton.mk + +kozyilmaz (2): + [macOS] added curl method for param download + [macOS] use shlock instead of flock in fetch-params + +mruddy (1): + Resolve issue bitcoin/bitcoin#3166. + diff --git a/doc/release-notes/release-notes-1.1.2-rc1.md b/doc/release-notes/release-notes-1.1.2-rc1.md new file mode 100644 index 000000000..91fdafd5a --- /dev/null +++ b/doc/release-notes/release-notes-1.1.2-rc1.md @@ -0,0 +1,96 @@ +Notable changes +=============== + +`-disabledeprecation` removal +----------------------------- + +In release 1.0.9 we implemented automatic deprecation of `zcashd` software +versions made by the Zcash Company. The configuration option +`-disabledeprecation` was added as a way for users to specifically choose to +stay on a particular software version. However, it incorrectly implied that +deprecated releases would still be supported. + +This release removes the `-disabledeprecation` option, so that `zcashd` software +versions made by the Zcash Company will always shut down in accordance with the +defined deprecation policy (currently 16 weeks after release). Users who wish to +use a different policy must now specifically choose to either: + +- edit and compile the source code themselves, or +- obtain a software version from someone else who has done so (and obtain + support from them). + +Either way, it is much clearer that the software they are running is not +supported by the Zcash Company. + +Changelog +========= + +Ariel Gabizon (1): + Improve/Fix variable names + +Daira Hopwood (1): + Update code_of_conduct.md + +Eirik Ogilvie-Wigley (5): + Add tests for sapling anchors + Add hashFinalSaplingRoot to getblocktemplate + Fix parsing parameters in getnetworksolps + Add BOOST_TEST_CONTEXT to distinguish sprout v. sapling + Rename typename + +Jack Grigg (16): + Replace boost::array with std::array + Add MacOS support to no-dot-so test + Whitespace cleanup + chainparams: Add Sapling Bech32 HRPs + ConvertBits() - convert from one power-of-2 number base to another. + Fix bech32::Encode() error handling + Implement encoding and decoding of Sapling keys and addresses + Add Mach-O 64-bit detection to security-check.py + Fix cached_witnesses_empty_chain test failure on MacOS + Skip ELF-only sec-hard checks on non-ELF binaries + Remove config option -disabledeprecation + Add release notes for -disabledeprecation removal + Add comment about size calculations for converted serialized keys + Add examples of ConvertBits transformation + Use CChainParams::Bech32HRP() in zs_address_test + Add hashFinalSaplingRoot to getblockheader and getblock output + +Jay Graber (8): + Add Sapling key classes to wallet, with new librustzcash APIs + Change librustzcash dependency hash to work for new Sapling classes + Update librustzcash dependency, address comments + Minimal sapling key test + Fix default_address() + s/SaplingInViewingKey/SaplingIncomingViewingKey + Make diversifier functions return option + Add json test vectors for Sapling key components. + +Jonathan "Duke" Leto (1): + Clarify help that signmessage only works on taddrs + +Larry Ruane (1): + (rpc-test) accurately account for fee without rounding error + +Matthew King (2): + Use portable #! in python scripts (/usr/bin/env) + Favour python over python2 as per PR #7723 + +Paige Peterson (1): + include note about volunteers in CoC + +Pieter Wuille (2): + Generalize ConvertBits + Simplify Base32 and Base64 conversions + +Simon Liu (9): + Part of #3277. Add comment about deprecated txdb prefixes. + Remove now redundant Rust call to librustzcash_xor. + Add SaplingNote class and test_sapling_note unit test. + Refactor and replace factory method random() with constructor. + Return optional for Sapling commitments and nullifiers. + Closes #3328. Send alert to put non-Overwinter nodes into safe mode. + Fix pyflakes error in test zkey_import_export. + make-release.py: Versioning changes for 1.1.2-rc1. + make-release.py: Updated manpages for 1.1.2-rc1. + diff --git a/doc/release-notes/release-notes-1.1.2.md b/doc/release-notes/release-notes-1.1.2.md new file mode 100644 index 000000000..9041c1bb2 --- /dev/null +++ b/doc/release-notes/release-notes-1.1.2.md @@ -0,0 +1,99 @@ +Notable changes +=============== + +`-disabledeprecation` removal +----------------------------- + +In release 1.0.9 we implemented automatic deprecation of `zcashd` software +versions made by the Zcash Company. The configuration option +`-disabledeprecation` was added as a way for users to specifically choose to +stay on a particular software version. However, it incorrectly implied that +deprecated releases would still be supported. + +This release removes the `-disabledeprecation` option, so that `zcashd` software +versions made by the Zcash Company will always shut down in accordance with the +defined deprecation policy (currently 16 weeks after release). Users who wish to +use a different policy must now specifically choose to either: + +- edit and compile the source code themselves, or +- obtain a software version from someone else who has done so (and obtain + support from them). + +Either way, it is much clearer that the software they are running is not +supported by the Zcash Company. + +Changelog +========= + +Ariel Gabizon (1): + Improve/Fix variable names + +Daira Hopwood (1): + Update code_of_conduct.md + +Eirik Ogilvie-Wigley (5): + Add tests for sapling anchors + Add hashFinalSaplingRoot to getblocktemplate + Fix parsing parameters in getnetworksolps + Add BOOST_TEST_CONTEXT to distinguish sprout v. sapling + Rename typename + +Jack Grigg (16): + Replace boost::array with std::array + Add MacOS support to no-dot-so test + Whitespace cleanup + chainparams: Add Sapling Bech32 HRPs + ConvertBits() - convert from one power-of-2 number base to another. + Fix bech32::Encode() error handling + Implement encoding and decoding of Sapling keys and addresses + Add Mach-O 64-bit detection to security-check.py + Fix cached_witnesses_empty_chain test failure on MacOS + Skip ELF-only sec-hard checks on non-ELF binaries + Remove config option -disabledeprecation + Add release notes for -disabledeprecation removal + Add comment about size calculations for converted serialized keys + Add examples of ConvertBits transformation + Use CChainParams::Bech32HRP() in zs_address_test + Add hashFinalSaplingRoot to getblockheader and getblock output + +Jay Graber (8): + Add Sapling key classes to wallet, with new librustzcash APIs + Change librustzcash dependency hash to work for new Sapling classes + Update librustzcash dependency, address comments + Minimal sapling key test + Fix default_address() + s/SaplingInViewingKey/SaplingIncomingViewingKey + Make diversifier functions return option + Add json test vectors for Sapling key components. + +Jonathan "Duke" Leto (1): + Clarify help that signmessage only works on taddrs + +Larry Ruane (1): + (rpc-test) accurately account for fee without rounding error + +Matthew King (2): + Use portable #! in python scripts (/usr/bin/env) + Favour python over python2 as per PR #7723 + +Paige Peterson (1): + include note about volunteers in CoC + +Pieter Wuille (2): + Generalize ConvertBits + Simplify Base32 and Base64 conversions + +Simon Liu (12): + Part of #3277. Add comment about deprecated txdb prefixes. + Remove now redundant Rust call to librustzcash_xor. + Add SaplingNote class and test_sapling_note unit test. + Refactor and replace factory method random() with constructor. + Return optional for Sapling commitments and nullifiers. + Closes #3328. Send alert to put non-Overwinter nodes into safe mode. + Fix pyflakes error in test zkey_import_export. + make-release.py: Versioning changes for 1.1.2-rc1. + make-release.py: Updated manpages for 1.1.2-rc1. + make-release.py: Updated release notes and changelog for 1.1.2-rc1. + make-release.py: Versioning changes for 1.1.2. + make-release.py: Updated manpages for 1.1.2. + diff --git a/doc/release-notes/release-notes-2.0.0-rc1.md b/doc/release-notes/release-notes-2.0.0-rc1.md new file mode 100644 index 000000000..9033a31a6 --- /dev/null +++ b/doc/release-notes/release-notes-2.0.0-rc1.md @@ -0,0 +1,176 @@ +Changelog +========= + +Alex Morcos (1): + Output line to debug.log when IsInitialBlockDownload latches to false + +Ariel Gabizon (1): + Extend Joinsplit tests to Groth + +Charlie OKeefe (1): + Remove extra slash from lockfile path + +Cory Fields (1): + crypter: shuffle Makefile so that crypto can be used by the wallet + +Daira Hopwood (1): + Support testnet rollback. + +Daniel Cousens (2): + move rpc* to rpc/ + rpc: update inline comments to refer to new file paths + +Dimitris Apostolou (1): + Fix typos + +Duke Leto (3): + Fix absurd fee bug reported in #3281, with tests + Update comment as per @arielgabizon + Improve error message + +Eirik Ogilvie-Wigley (24): + Add more options when asserting in RPC tests + Add change indicator for notes + Fix test broken by change indicator + Rename note data to include sprout + Remove redundant curly braces + Consolidate for loops + Add out point for sapling note data + Add sapling note data and map + Decrement sapling note witnesses + Clear sapling witness cache + Extract method for copying previous witnesses + Extract methods for incrementing witnesses + Extract method for incrementing witness heights + Pass sapling merkle tree when incrementing witnesses + Increment sapling note witnesses + Rename sprout specific methods + Remove extra indentation + Add getter and setter for sapling note data and update tests + Add parameter for version in GetValidReceive + Rename Merkle Trees to include sprout or sapling + Rename Witnesses to include sprout or sapling + Rename test objects to include sprout or sapling + Only include the change field if we have a spending key + Fix assertion and comment + +Gregory Maxwell (2): + IBD check uses minimumchain work instead of checkpoints. + IsInitialBlockDownload no longer uses header-only timestamps. + +Jack Grigg (38): + Add some more checkpoints, up to the 1.1.0 release + Add Sapling support to z_validateaddress + Update payment-api.md with type field of z_validateaddress + Alter SaplingNote::nullifier() to take a SaplingFullViewingKey + Expose note position in IncrementalMerkleWitness + TransactionBuilder with support for creating Sapling-only transactions + TransactionBuilder: Check that all anchors in a transaction are identical + Formatting + test: Move ECC_Start() call into src/gtest/main.cpp + TransactionBuilder: Add support for transparent inputs and outputs + TransactionBuilder: Add change output to transaction + TransactionBuilder: Make fee configurable + Rename xsk to expsk + Implement CKeyStore::GetSaplingPaymentAddresses() + Raise the 90-character limit on Bech32 encodings + Add Sapling support to z_getnewaddress and z_listaddresses + Fix block hash for checkpoint at height 270000 + Formatting + test: Deduplicate logic in wallet_addresses RPC test + test: Another assert in wallet_zkeys_tests.store_and_load_sapling_zkeys + test: Fix permissions of wallet_addresses + test: Update rpc_wallet_z_importexport to account for Sapling changes + Rename DecryptSpendingKey -> DecryptSproutSpendingKey + Rename CryptedSpendingKeyMap -> CryptedSproutSpendingKeyMap + Add Sapling decryption check to CCryptoKeyStore::Unlock() + Check for unencrypted Sapling keys in CCryptoKeyStore::SetCrypted() + Remove outdated comment + Add CWallet::AddCryptedSaplingSpendingKey() hook + Pass SaplingPaymentAddress to store through the CKeyStore + Rename SpendingKeyMap -> SproutSpendingKeyMap + Rename Serialized*Size -> SerializedSprout*Size + Rename *ViewingKey* -> *SproutViewingKey* + Formatting nits + Rename *SpendingKey -> *SproutSpendingKey + chainparams: Add BIP 44 coin type (as registered in SLIP 44) + Upgrade Rust to 1.28.0 stable + Adjust Makefile so that common can be used by the wallet + Move RewindBlockIndex log message inside rewindLength check + +Jay Graber (13): + Add Sapling Add/Have/Get to keystore + Add SaplingIncomingViewingKeys map, SaplingFullViewingKey methods + Add StoreAndRetrieveSaplingSpendingKey test + Change default_address to return SaplingPaymentAddr and not boost::optional + Add crypted keystore sapling add key + Discard sk if ivk == 0 + Add Sapling support to z_exportkey + Add Sapling support to z_importkey + Add Sapling to rpc_wallet_z_importexport test + Refactor into visitors and throw errors for invalid key or address. + Take expiryheight as param to createrawtransaction + Add Sapling have/get sk crypter overrides + Add Sapling keys to CCryptoKeyStore::EncryptKeys + +Jonas Schnelli (2): + [RPC, Wallet] Move RPC dispatch table registration to wallet/ code + Fix test_bitcoin circular dependency issue + +Kaz Wesley (1): + IsInitialBlockDownload: usually avoid locking + +Larry Ruane (4): + Disable libsnark debug logging in Boost tests + add extra help how to enable experimental features + Add call to sync_all() after (z_sendmany, wait) + don't ban peers when loading pre-overwinter blocks + +Pejvan (2): + Update README.md + Update README.md + +Richard Littauer (1): + docs(LICENSE): update license year to 2018 + +Sean Bowe (18): + Update librustzcash + Implementation of Sapling in-band secret distribution. + Swap types in OutputDescription to use new NoteEncryption interfaces. + Prevent nonce reuse in Sapling note encryption API. + Add get_esk() function to Sapling note encryption. + Minor edits + Decryption and tests of note/outgoing encryption. + Update librustzcash and sapling-crypto. + Fix bug in return value. + Ensure sum of valueBalance and all vpub_new's does not exceed MAX_MONEY inside of CheckTransactionWithoutProofVerification. + Move `extern params` to beginning of `test_checktransaction`. + Relocate ECC_Start() to avoid test failures. + Don't call ECC_Start/ECC_Stop outside the test harness. + Make changes to gtest ECC behavior suggested by @str4d. + Check the hash of the (Sapling+) zk-SNARK parameters during initialization. + Switch to use the official Sapling parameters. + make-release.py: Versioning changes for 2.0.0-rc1. + make-release.py: Updated manpages for 2.0.0-rc1. + +Simon Liu (9): + Add encryption of SaplingNotePlaintext and SaplingOutgoingPlaintext classes. + Update and fix per review comments, the test for absurd fee. + Minor update to address nits in review. + Implement Sapling note decryption using full viewing key. + Rename AttemptSaplingEncDecryptionUsingFullViewingKey and use function overloading. + Only check for a valid Sapling anchor after Sapling activation. + Clean up for rebase: rename mapNoteData to mapSproutNoteData. + Clean up help messages for RPC createrawtransaction. + Add tests for expiryheight parameter of RPC createrawtransaction. + +Wladimir J. van der Laan (2): + Make max tip age an option instead of chainparam + rpc: Register calls where they are defined + +kozyilmaz (1): + Add -Wl,-pie linker option for macOS and use it instead of -pie + +mdr0id (1): + Fix minor references to auto-senescence in code + diff --git a/doc/release-notes/release-notes-2.0.0.md b/doc/release-notes/release-notes-2.0.0.md new file mode 100644 index 000000000..7dcbf5d6a --- /dev/null +++ b/doc/release-notes/release-notes-2.0.0.md @@ -0,0 +1,199 @@ +Notable changes +=============== + +Sapling network upgrade +----------------------- + +The activation height for the Sapling network upgrade on mainnet is included +in this release. Sapling will activate on mainnet at height 419200, which is +expected to be mined on the 28th of October 2018. Please upgrade to this release, +or any subsequent release, in order to follow the Sapling network upgrade. + +The testnet is being rolled back in this release to Overwinter. Sapling will +activate on testnet at height 280000. Please update your testnet nodes before +then. + +Changelog +========= + +Alex Morcos (1): + Output line to debug.log when IsInitialBlockDownload latches to false + +Ariel Gabizon (1): + Extend Joinsplit tests to Groth + +Charlie OKeefe (1): + Remove extra slash from lockfile path + +Cory Fields (1): + crypter: shuffle Makefile so that crypto can be used by the wallet + +Daira Hopwood (1): + Support testnet rollback. + +Daniel Cousens (2): + move rpc* to rpc/ + rpc: update inline comments to refer to new file paths + +Dimitris Apostolou (1): + Fix typos + +Duke Leto (3): + Fix absurd fee bug reported in #3281, with tests + Update comment as per @arielgabizon + Improve error message + +Eirik Ogilvie-Wigley (24): + Add more options when asserting in RPC tests + Add change indicator for notes + Fix test broken by change indicator + Rename note data to include sprout + Remove redundant curly braces + Consolidate for loops + Add out point for sapling note data + Add sapling note data and map + Decrement sapling note witnesses + Clear sapling witness cache + Extract method for copying previous witnesses + Extract methods for incrementing witnesses + Extract method for incrementing witness heights + Pass sapling merkle tree when incrementing witnesses + Increment sapling note witnesses + Rename sprout specific methods + Remove extra indentation + Add getter and setter for sapling note data and update tests + Add parameter for version in GetValidReceive + Rename Merkle Trees to include sprout or sapling + Rename Witnesses to include sprout or sapling + Rename test objects to include sprout or sapling + Only include the change field if we have a spending key + Fix assertion and comment + +Gregory Maxwell (2): + IBD check uses minimumchain work instead of checkpoints. + IsInitialBlockDownload no longer uses header-only timestamps. + +Jack Grigg (41): + Add some more checkpoints, up to the 1.1.0 release + Add Sapling support to z_validateaddress + Update payment-api.md with type field of z_validateaddress + Alter SaplingNote::nullifier() to take a SaplingFullViewingKey + Expose note position in IncrementalMerkleWitness + TransactionBuilder with support for creating Sapling-only transactions + TransactionBuilder: Check that all anchors in a transaction are identical + Formatting + test: Move ECC_Start() call into src/gtest/main.cpp + TransactionBuilder: Add support for transparent inputs and outputs + TransactionBuilder: Add change output to transaction + TransactionBuilder: Make fee configurable + Rename xsk to expsk + Implement CKeyStore::GetSaplingPaymentAddresses() + Raise the 90-character limit on Bech32 encodings + Add Sapling support to z_getnewaddress and z_listaddresses + Fix block hash for checkpoint at height 270000 + Formatting + test: Deduplicate logic in wallet_addresses RPC test + test: Another assert in wallet_zkeys_tests.store_and_load_sapling_zkeys + test: Fix permissions of wallet_addresses + test: Update rpc_wallet_z_importexport to account for Sapling changes + Rename DecryptSpendingKey -> DecryptSproutSpendingKey + Rename CryptedSpendingKeyMap -> CryptedSproutSpendingKeyMap + Add Sapling decryption check to CCryptoKeyStore::Unlock() + Check for unencrypted Sapling keys in CCryptoKeyStore::SetCrypted() + Remove outdated comment + Add CWallet::AddCryptedSaplingSpendingKey() hook + Pass SaplingPaymentAddress to store through the CKeyStore + Rename SpendingKeyMap -> SproutSpendingKeyMap + Rename Serialized*Size -> SerializedSprout*Size + Rename *ViewingKey* -> *SproutViewingKey* + Formatting nits + Rename *SpendingKey -> *SproutSpendingKey + chainparams: Add BIP 44 coin type (as registered in SLIP 44) + Upgrade Rust to 1.28.0 stable + Adjust Makefile so that common can be used by the wallet + Move RewindBlockIndex log message inside rewindLength check + test: gtest for Sapling encoding and decoding + test: Use regtest in key_tests/zs_address_test + Disable Sapling features on mainnet + +Jay Graber (13): + Add Sapling Add/Have/Get to keystore + Add SaplingIncomingViewingKeys map, SaplingFullViewingKey methods + Add StoreAndRetrieveSaplingSpendingKey test + Change default_address to return SaplingPaymentAddr and not boost::optional + Add crypted keystore sapling add key + Discard sk if ivk == 0 + Add Sapling support to z_exportkey + Add Sapling support to z_importkey + Add Sapling to rpc_wallet_z_importexport test + Refactor into visitors and throw errors for invalid key or address. + Take expiryheight as param to createrawtransaction + Add Sapling have/get sk crypter overrides + Add Sapling keys to CCryptoKeyStore::EncryptKeys + +Jonas Schnelli (2): + [RPC, Wallet] Move RPC dispatch table registration to wallet/ code + Fix test_bitcoin circular dependency issue + +Kaz Wesley (1): + IsInitialBlockDownload: usually avoid locking + +Larry Ruane (4): + Disable libsnark debug logging in Boost tests + add extra help how to enable experimental features + Add call to sync_all() after (z_sendmany, wait) + don't ban peers when loading pre-overwinter blocks + +Pejvan (2): + Update README.md + Update README.md + +Richard Littauer (1): + docs(LICENSE): update license year to 2018 + +Sean Bowe (21): + Update librustzcash + Implementation of Sapling in-band secret distribution. + Swap types in OutputDescription to use new NoteEncryption interfaces. + Prevent nonce reuse in Sapling note encryption API. + Add get_esk() function to Sapling note encryption. + Minor edits + Decryption and tests of note/outgoing encryption. + Update librustzcash and sapling-crypto. + Fix bug in return value. + Ensure sum of valueBalance and all vpub_new's does not exceed MAX_MONEY inside of CheckTransactionWithoutProofVerification. + Move `extern params` to beginning of `test_checktransaction`. + Relocate ECC_Start() to avoid test failures. + Don't call ECC_Start/ECC_Stop outside the test harness. + Make changes to gtest ECC behavior suggested by @str4d. + Check the hash of the (Sapling+) zk-SNARK parameters during initialization. + Switch to use the official Sapling parameters. + make-release.py: Versioning changes for 2.0.0-rc1. + make-release.py: Updated manpages for 2.0.0-rc1. + make-release.py: Updated release notes and changelog for 2.0.0-rc1. + Always write the empty root down as the best root, since we may roll back. + Sapling mainnet activation height + +Simon Liu (11): + Add encryption of SaplingNotePlaintext and SaplingOutgoingPlaintext classes. + Update and fix per review comments, the test for absurd fee. + Minor update to address nits in review. + Implement Sapling note decryption using full viewing key. + Rename AttemptSaplingEncDecryptionUsingFullViewingKey and use function overloading. + Only check for a valid Sapling anchor after Sapling activation. + Clean up for rebase: rename mapNoteData to mapSproutNoteData. + Clean up help messages for RPC createrawtransaction. + Add tests for expiryheight parameter of RPC createrawtransaction. + make-release.py: Versioning changes for 2.0.0. + make-release.py: Updated manpages for 2.0.0. + +Wladimir J. van der Laan (2): + Make max tip age an option instead of chainparam + rpc: Register calls where they are defined + +kozyilmaz (1): + Add -Wl,-pie linker option for macOS and use it instead of -pie + +mdr0id (1): + Fix minor references to auto-senescence in code + diff --git a/doc/release-process.md b/doc/release-process.md index 93a8e8362..cde355287 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -24,6 +24,8 @@ Check that there are no surprising performance regressions: Ensure that new performance metrics appear on that site. +Update `src/chainparams.cpp` nMinimumChainWork with information from the getblockchaininfo rpc. + ### Protocol Safety Checks: If this release changes the behavior of the protocol or fixes a serious diff --git a/doc/unit-tests.md b/doc/unit-tests.md index 97dcd701e..9410b4407 100644 --- a/doc/unit-tests.md +++ b/doc/unit-tests.md @@ -6,7 +6,7 @@ and tests weren't explicitly disabled. There are two scripts for running tests: -* ``qa/zcash/full-test-suite.sh``, to run the main test suite +* ``qa/zcash/full_test_suite.py``, to run the main test suite * ``qa/pull-tester/rpc-tests.sh``, to run the RPC tests. The main test suite uses two different testing frameworks. Tests using the Boost diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index fb4ff99a7..83e4049d6 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -16,13 +16,16 @@ testScripts=( 'prioritisetransaction.py' 'wallet_treestate.py' 'wallet_anchorfork.py' + 'wallet_changeindicator.py' 'wallet_protectcoinbase.py' 'wallet_shieldcoinbase.py' 'wallet_mergetoaddress.py' 'wallet.py' 'wallet_overwintertx.py' - 'wallet_nullifiers.py' +# 'wallet_nullifiers.py' 'wallet_1941.py' + 'wallet_addresses.py' + 'wallet_sapling.py' 'listtransactions.py' 'mempool_resurrect_test.py' 'txn_doublespend.py' @@ -39,7 +42,7 @@ testScripts=( 'zapwallettxes.py' 'proxy_test.py' 'merkle_blocks.py' - 'fundrawtransaction.py' +# 'fundrawtransaction.py' 'signrawtransactions.py' 'walletbackup.py' 'key_import_export.py' @@ -49,6 +52,7 @@ testScripts=( 'timestampindex.py' 'spentindex.py' 'decodescript.py' + 'blockchain.py' 'disablewallet.py' 'zcjoinsplit.py' 'zcjoinsplitdoublespend.py' @@ -58,6 +62,9 @@ testScripts=( 'bip65-cltv-p2p.py' 'bipdersig-p2p.py' 'overwinter_peer_management.py' + 'rewind_index.py' + 'p2p_txexpiry_dos.py' + 'p2p_node_bloom.py' ); testScriptsExt=( 'getblocktemplate_longpoll.py' diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py new file mode 100755 index 000000000..c37db8b84 --- /dev/null +++ b/qa/rpc-tests/blockchain.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test RPC calls related to blockchain state. Tests correspond to code in +# rpc/blockchain.cpp. +# + +import decimal + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + initialize_chain, + assert_equal, + start_nodes, + connect_nodes_bi, +) + +class BlockchainTest(BitcoinTestFramework): + """ + Test blockchain-related RPC calls: + + - gettxoutsetinfo + + """ + + def setup_chain(self): + print("Initializing test directory " + self.options.tmpdir) + initialize_chain(self.options.tmpdir) + + def setup_network(self, split=False): + self.nodes = start_nodes(2, self.options.tmpdir) + connect_nodes_bi(self.nodes, 0, 1) + self.is_network_split = False + self.sync_all() + + def run_test(self): + node = self.nodes[0] + res = node.gettxoutsetinfo() + + assert_equal(res[u'total_amount'], decimal.Decimal('2181.25000000')) # 150*12.5 + 49*6.25 + assert_equal(res[u'transactions'], 200) + assert_equal(res[u'height'], 200) + assert_equal(res[u'txouts'], 349) # 150*2 + 49 + assert_equal(res[u'bytes_serialized'], 14951), # 32*199 + 48*90 + 49*60 + 27*49 + assert_equal(len(res[u'bestblock']), 64) + assert_equal(len(res[u'hash_serialized']), 64) + + +if __name__ == '__main__': + BlockchainTest().main() diff --git a/qa/rpc-tests/decodescript.py b/qa/rpc-tests/decodescript.py index 89364a840..293fd0ebb 100755 --- a/qa/rpc-tests/decodescript.py +++ b/qa/rpc-tests/decodescript.py @@ -6,6 +6,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, initialize_chain_clean, \ start_nodes +from test_framework.mininode import CTransaction +from binascii import hexlify, unhexlify +from cStringIO import StringIO class DecodeScriptTest(BitcoinTestFramework): @@ -109,10 +112,77 @@ class DecodeScriptTest(BitcoinTestFramework): rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac') assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_NOP2 OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm']) + def decoderawtransaction_asm_sighashtype(self): + """Tests decoding scripts via RPC command "decoderawtransaction". + + This test is in with the "decodescript" tests because they are testing the same "asm" script decodes. + """ + + # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output + tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm']) + + # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs. + # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc + # verify that we have not altered scriptPubKey decoding. + tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid']) + assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm']) + assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) + assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) + txSave = CTransaction() + txSave.deserialize(StringIO(unhexlify(tx))) + + # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type + tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm']) + + # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks + tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) + assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) + + # some more full transaction tests of varying specific scriptSigs. used instead of + # tests in decodescript_script_sig because the decodescript RPC is specifically + # for working on scriptPubKeys (argh!). + push_signature = hexlify(txSave.vin[0].scriptSig)[2:(0x48*2+4)] + signature = push_signature[2:] + der_signature = signature[:-2] + signature_sighash_decoded = der_signature + '[ALL]' + signature_2 = der_signature + '82' + push_signature_2 = '48' + signature_2 + signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]' + + # 1) P2PK scriptSig + txSave.vin[0].scriptSig = unhexlify(push_signature) + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) + + # make sure that the sighash decodes come out correctly for a more complex / lesser used case. + txSave.vin[0].scriptSig = unhexlify(push_signature_2) + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) + + # 2) multisig scriptSig + txSave.vin[0].scriptSig = unhexlify('00' + push_signature + push_signature_2) + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) + + # 3) test a scriptSig that contains more than push operations. + # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it. + txSave.vin[0].scriptSig = unhexlify('6a143011020701010101010101020601010101010101') + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + print(hexlify('636174')) + assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm']) + def run_test(self): self.decodescript_script_sig() self.decodescript_script_pub_key() + self.decoderawtransaction_asm_sighashtype() if __name__ == '__main__': DecodeScriptTest().main() - diff --git a/qa/rpc-tests/getblocktemplate.py b/qa/rpc-tests/getblocktemplate.py index 82082afa9..af050110e 100755 --- a/qa/rpc-tests/getblocktemplate.py +++ b/qa/rpc-tests/getblocktemplate.py @@ -4,8 +4,8 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import initialize_chain_clean, start_nodes, \ - connect_nodes_bi +from test_framework.util import assert_equal, connect_nodes_bi, \ + initialize_chain_clean, start_nodes class GetBlockTemplateTest(BitcoinTestFramework): @@ -49,11 +49,16 @@ class GetBlockTemplateTest(BitcoinTestFramework): # Test 5: General checks tmpl = node.getblocktemplate() - assert(len(tmpl['noncerange']) == 16) + assert_equal(16, len(tmpl['noncerange'])) # Test 6: coinbasetxn checks assert('foundersreward' in tmpl['coinbasetxn']) assert(tmpl['coinbasetxn']['required']) + # Test 7: hashFinalSaplingRoot checks + assert('finalsaplingroothash' in tmpl) + finalsaplingroothash = '3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb' + assert_equal(finalsaplingroothash, tmpl['finalsaplingroothash']) + if __name__ == '__main__': GetBlockTemplateTest().main() diff --git a/qa/rpc-tests/mempool_nu_activation.py b/qa/rpc-tests/mempool_nu_activation.py index f54095660..28b5e8865 100755 --- a/qa/rpc-tests/mempool_nu_activation.py +++ b/qa/rpc-tests/mempool_nu_activation.py @@ -15,7 +15,10 @@ class MempoolUpgradeActivationTest(BitcoinTestFramework): alert_filename = None # Set by setup_network def setup_network(self): - args = ["-checkmempool", "-debug=mempool", "-blockmaxsize=4000", "-nuparams=5ba81b19:200"] + args = ["-checkmempool", "-debug=mempool", "-blockmaxsize=4000", + "-nuparams=5ba81b19:200", # Overwinter + "-nuparams=76b809bb:210", # Sapling + ] self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, args)) self.nodes.append(start_node(1, self.options.tmpdir, args)) @@ -44,76 +47,100 @@ class MempoolUpgradeActivationTest(BitcoinTestFramework): print wait_and_assert_operationid_status(self.nodes[1], myopid) self.sync_all() - # Mine block 198. After this, the mempool expects - # block 199, which is the last Sprout block. - self.nodes[0].generate(1) + # Mempool checks for activation of upgrade Y at height H on base X + def nu_activation_checks(): + # Mine block H - 2. After this, the mempool expects + # block H - 1, which is the last X block. + self.nodes[0].generate(1) + self.sync_all() + + # Mempool should be empty. + assert_equal(set(self.nodes[0].getrawmempool()), set()) + + # Check node 0 shielded balance + assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) + + # Fill the mempool with twice as many transactions as can fit into blocks + node0_taddr = self.nodes[0].getnewaddress() + x_txids = [] + while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000: + x_txids.append(self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001'))) + self.sync_all() + + # Spends should be in the mempool + x_mempool = set(self.nodes[0].getrawmempool()) + assert_equal(x_mempool, set(x_txids)) + + # Mine block H - 1. After this, the mempool expects + # block H, which is the first Y block. + self.nodes[0].generate(1) + self.sync_all() + + # mempool should be empty. + assert_equal(set(self.nodes[0].getrawmempool()), set()) + + # Block H - 1 should contain a subset of the original mempool + # (with all other transactions having been dropped) + block_txids = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['tx'] + assert(len(block_txids) < len(x_txids)) + for txid in block_txids[1:]: # Exclude coinbase + assert(txid in x_txids) + + # Create some transparent Y transactions + y_txids = [self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10)] + self.sync_all() + + # Create a shielded Y transaction + recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}] + myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0')) + shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) + assert(shielded != None) + y_txids.append(shielded) + self.sync_all() + + # Spends should be in the mempool + assert_equal(set(self.nodes[0].getrawmempool()), set(y_txids)) + + # Node 0 note should be unspendable + assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0')) + + # Invalidate block H - 1. + block_hm1 = self.nodes[0].getbestblockhash() + self.nodes[0].invalidateblock(block_hm1) + + # BUG: Ideally, the mempool should now only contain the transactions + # that were in block H - 1, the Y transactions having been dropped. + # However, because chainActive is not updated until after the transactions + # in the disconnected block have been re-added to the mempool, the height + # seen by AcceptToMemoryPool is one greater than it should be. This causes + # the block H - 1 transactions to be validated against the Y rules, + # and rejected because they (obviously) fail. + #assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:])) + assert_equal(set(self.nodes[0].getrawmempool()), set()) + + # Node 0 note should be spendable again + assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) + + # Reconsider block H - 1. + self.nodes[0].reconsiderblock(block_hm1) + + # Mine blocks on node 1, so that the Y transactions in its mempool + # will be cleared. + self.nodes[1].generate(6) + self.sync_all() + + print('Testing Sprout -> Overwinter activation boundary') + # Current height = 197 + nu_activation_checks() + # Current height = 205 + + self.nodes[0].generate(2) self.sync_all() - # Mempool should be empty. - assert_equal(set(self.nodes[0].getrawmempool()), set()) - - # Check node 0 shielded balance - assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) - - # Fill the mempool with twice as many transactions as can fit into blocks - node0_taddr = self.nodes[0].getnewaddress() - sprout_txids = [] - while self.nodes[1].getmempoolinfo()['bytes'] < 2 * 4000: - sprout_txids.append(self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001'))) - self.sync_all() - - # Spends should be in the mempool - sprout_mempool = set(self.nodes[0].getrawmempool()) - assert_equal(sprout_mempool, set(sprout_txids)) - - # Mine block 199. After this, the mempool expects - # block 200, which is the first Overwinter block. - self.nodes[0].generate(1) - self.sync_all() - - # mempool should be empty. - assert_equal(set(self.nodes[0].getrawmempool()), set()) - - # Block 199 should contain a subset of the original mempool - # (with all other transactions having been dropped) - block_txids = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['tx'] - assert(len(block_txids) < len(sprout_txids)) - for txid in block_txids[1:]: # Exclude coinbase - assert(txid in sprout_txids) - - # Create some transparent Overwinter transactions - overwinter_txids = [self.nodes[1].sendtoaddress(node0_taddr, Decimal('0.001')) for i in range(10)] - self.sync_all() - - # Create a shielded Overwinter transaction - recipients = [{'address': node0_taddr, 'amount': Decimal('10')}] - myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients, 1, Decimal('0')) - shielded = wait_and_assert_operationid_status(self.nodes[0], myopid) - assert(shielded != None) - overwinter_txids.append(shielded) - self.sync_all() - - # Spends should be in the mempool - assert_equal(set(self.nodes[0].getrawmempool()), set(overwinter_txids)) - - # Node 0 note should be unspendable - assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('0')) - - # Invalidate block 199. - self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - - # BUG: Ideally, the mempool should now only contain the transactions - # that were in block 199, the Overwinter transactions having been dropped. - # However, because chainActive is not updated until after the transactions - # in the disconnected block have been re-added to the mempool, the height - # seen by AcceptToMemoryPool is one greater than it should be. This causes - # the block 199 transactions to be validated against the Overwinter rules, - # and rejected because they (obviously) fail. - #assert_equal(set(self.nodes[0].getrawmempool()), set(block_txids[1:])) - assert_equal(set(self.nodes[0].getrawmempool()), set()) - - # Node 0 note should be spendable again - assert_equal(self.nodes[0].z_getbalance(node0_zaddr), Decimal('10')) + print('Testing Overwinter -> Sapling activation boundary') + # Current height = 207 + nu_activation_checks() + # Current height = 215 if __name__ == '__main__': MempoolUpgradeActivationTest().main() diff --git a/qa/rpc-tests/mempool_tx_expiry.py b/qa/rpc-tests/mempool_tx_expiry.py index 9edf156d2..b5ee4bd2a 100755 --- a/qa/rpc-tests/mempool_tx_expiry.py +++ b/qa/rpc-tests/mempool_tx_expiry.py @@ -20,9 +20,9 @@ class MempoolTxExpiryTest(BitcoinTestFramework): return start_nodes(4, self.options.tmpdir, [["-nuparams=5ba81b19:205", "-txexpirydelta=4", "-debug=mempool"]] * 4) # Test before, at, and after expiry block - # TODO: Test case of dependent txs in reorgs # chain is at block height 199 when run_test executes def run_test(self): + alice = self.nodes[0].getnewaddress() z_alice = self.nodes[0].z_getnewaddress() bob = self.nodes[2].getnewaddress() z_bob = self.nodes[2].z_getnewaddress() @@ -36,6 +36,42 @@ class MempoolTxExpiryTest(BitcoinTestFramework): self.nodes[0].generate(6) self.sync_all() + print "Splitting network..." + self.split_network() + + # When Overwinter is activated, test dependent txs + firstTx = self.nodes[0].sendtoaddress(alice, 0.1) + firstTxInfo = self.nodes[0].getrawtransaction(firstTx, 1) + print "First tx expiry height:", firstTxInfo['expiryheight'] + # Mine first transaction + self.nodes[0].generate(1) + for outpoint in firstTxInfo['vout']: + if outpoint['value'] == Decimal('0.10000000'): + vout = outpoint + break + inputs = [{'txid': firstTx, 'vout': vout['n'], 'scriptPubKey': vout['scriptPubKey']['hex']}] + outputs = {alice: 0.1} + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + rawTxSigned = self.nodes[0].signrawtransaction(rawTx) + assert(rawTxSigned['complete']) + secondTx = self.nodes[0].sendrawtransaction(rawTxSigned['hex']) + secondTxInfo = self.nodes[0].getrawtransaction(secondTx, 1) + print "Second tx expiry height:", secondTxInfo['expiryheight'] + # Mine second, dependent transaction + self.nodes[0].generate(1) + print "Mine 6 competing blocks on Node 2..." + blocks = self.nodes[2].generate(6) + print "Connect nodes to force a reorg" + connect_nodes_bi(self.nodes,0,2) + self.is_network_split = False + print "Syncing blocks" + sync_blocks(self.nodes) + print "Ensure that both txs are dropped from mempool of node 0" + print "Blockheight node 0:", self.nodes[0].getblockchaininfo()['blocks'] + print "Blockheight node 2:", self.nodes[2].getblockchaininfo()['blocks'] + assert_equal(set(self.nodes[0].getrawmempool()), set()) + assert_equal(set(self.nodes[2].getrawmempool()), set()) + ## Shield one of Alice's coinbase funds to her zaddr res = self.nodes[0].z_shieldcoinbase("*", z_alice, 0.0001, 1) wait_and_assert_operationid_status(self.nodes[0], res['opid']) @@ -51,6 +87,7 @@ class MempoolTxExpiryTest(BitcoinTestFramework): self.split_network() # Create transactions + blockheight = self.nodes[0].getblockchaininfo()['blocks'] zsendamount = Decimal('1.0') - Decimal('0.0001') recipients = [] recipients.append({"address": z_bob, "amount": zsendamount}) @@ -61,7 +98,7 @@ class MempoolTxExpiryTest(BitcoinTestFramework): rawtx = self.nodes[0].getrawtransaction(persist_transparent, 1) assert_equal(rawtx["version"], 3) assert_equal(rawtx["overwintered"], True) - assert_equal(rawtx["expiryheight"], 212) + assert_equal(rawtx["expiryheight"], blockheight + 5) print "Blockheight at persist_transparent & persist_shielded creation:", self.nodes[0].getblockchaininfo()['blocks'] print "Expiryheight of persist_transparent:", rawtx['expiryheight'] # Verify shielded transaction is version 3 intended for Overwinter branch @@ -69,7 +106,7 @@ class MempoolTxExpiryTest(BitcoinTestFramework): print "Expiryheight of persist_shielded", rawtx['expiryheight'] assert_equal(rawtx["version"], 3) assert_equal(rawtx["overwintered"], True) - assert_equal(rawtx["expiryheight"], 212) + assert_equal(rawtx["expiryheight"], blockheight + 5) print "\n Blockheight advances to less than expiry block height. After reorg, txs should persist in mempool" assert(persist_transparent in self.nodes[0].getrawmempool()) diff --git a/qa/rpc-tests/mempool_tx_input_limit.py b/qa/rpc-tests/mempool_tx_input_limit.py index c48d73be0..201b82998 100755 --- a/qa/rpc-tests/mempool_tx_input_limit.py +++ b/qa/rpc-tests/mempool_tx_input_limit.py @@ -17,7 +17,7 @@ class MempoolTxInputLimitTest(BitcoinTestFramework): alert_filename = None # Set by setup_network def setup_network(self): - args = ["-checkmempool", "-debug=mempool", "-mempooltxinputlimit=2"] + args = ["-checkmempool", "-debug=mempool", "-mempooltxinputlimit=2", "-nuparams=5ba81b19:110"] self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, args)) self.nodes.append(start_node(1, self.options.tmpdir, args)) @@ -100,6 +100,7 @@ class MempoolTxInputLimitTest(BitcoinTestFramework): myopid = self.nodes[0].z_sendmany(node0_zaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid) + self.sync_all() self.nodes[1].generate(1) self.sync_all() @@ -120,5 +121,31 @@ class MempoolTxInputLimitTest(BitcoinTestFramework): # Spend should be in the mempool assert_equal(set(self.nodes[1].getrawmempool()), set([ spend_taddr_id2 ])) + # Mine three blocks + self.nodes[1].generate(3) + self.sync_all() + # The next block to be mined, 109, is the last Sprout block + bci = self.nodes[0].getblockchaininfo() + assert_equal(bci['consensus']['chaintip'], '00000000') + assert_equal(bci['consensus']['nextblock'], '00000000') + + # z_sendmany should be limited by -mempooltxinputlimit + recipients = [] + recipients.append({"address":node0_zaddr, "amount":Decimal('30.0')-Decimal('0.0001')}) # utxo amount less fee + myopid = self.nodes[0].z_sendmany(node0_taddr, recipients) + wait_and_assert_operationid_status(self.nodes[0], myopid, 'failed', 'Too many transparent inputs 3 > limit 2') + + # Mine one block + self.nodes[1].generate(1) + self.sync_all() + # The next block to be mined, 110, is the first Overwinter block + bci = self.nodes[0].getblockchaininfo() + assert_equal(bci['consensus']['chaintip'], '00000000') + assert_equal(bci['consensus']['nextblock'], '5ba81b19') + + # z_sendmany should no longer be limited by -mempooltxinputlimit + myopid = self.nodes[0].z_sendmany(node0_taddr, recipients) + wait_and_assert_operationid_status(self.nodes[0], myopid) + if __name__ == '__main__': MempoolTxInputLimitTest().main() diff --git a/qa/rpc-tests/merkle_blocks.py b/qa/rpc-tests/merkle_blocks.py index 2c0fcd203..13b98e140 100755 --- a/qa/rpc-tests/merkle_blocks.py +++ b/qa/rpc-tests/merkle_blocks.py @@ -7,6 +7,7 @@ # Test merkleblock fetch/validation # +import string from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_raises, \ @@ -86,5 +87,13 @@ class MerkleBlockTest(BitcoinTestFramework): # ...or if we have a -txindex assert_equal(self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof([txid_spent])), [txid_spent]) + # Quick test of getblock using blockhash and different levels of verbosity + result = self.nodes[0].getblock(blockhash, 2) + coinbase_txid = result["tx"][0]["txid"] + result = self.nodes[0].getblock(blockhash, 1) + assert_equal(coinbase_txid, result["tx"][0]) # verbosity 1 only lists txids + result = self.nodes[0].getblock(blockhash, 0) + assert(c in string.hexdigits for c in result) # verbosity 0 returns raw hex + if __name__ == '__main__': MerkleBlockTest().main() diff --git a/qa/rpc-tests/overwinter_peer_management.py b/qa/rpc-tests/overwinter_peer_management.py index 6c59e47ba..a5017b8b0 100755 --- a/qa/rpc-tests/overwinter_peer_management.py +++ b/qa/rpc-tests/overwinter_peer_management.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. from test_framework.mininode import NodeConn, NodeConnCB, NetworkThread, \ - msg_ping, MY_VERSION, OVERWINTER_PROTO_VERSION + msg_ping, SPROUT_PROTO_VERSION, OVERWINTER_PROTO_VERSION from test_framework.test_framework import BitcoinTestFramework from test_framework.util import initialize_chain_clean, start_nodes, \ p2p_port, assert_equal @@ -55,8 +55,10 @@ class OverwinterPeerManagementTest(BitcoinTestFramework): # Launch 10 Sprout and 10 Overwinter mininodes nodes = [] for x in xrange(10): - nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", False)) - nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", True)) + nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], + test, "regtest", SPROUT_PROTO_VERSION)) + nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], + test, "regtest", OVERWINTER_PROTO_VERSION)) # Start up network handling in another thread NetworkThread().start() @@ -68,7 +70,7 @@ class OverwinterPeerManagementTest(BitcoinTestFramework): # Verify mininodes are still connected to zcashd node peerinfo = self.nodes[0].getpeerinfo() versions = [x["version"] for x in peerinfo] - assert_equal(10, versions.count(MY_VERSION)) + assert_equal(10, versions.count(SPROUT_PROTO_VERSION)) assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION)) # Overwinter consensus rules activate at block height 10 @@ -86,19 +88,19 @@ class OverwinterPeerManagementTest(BitcoinTestFramework): # Verify Sprout mininodes have been dropped and Overwinter mininodes are still connected. peerinfo = self.nodes[0].getpeerinfo() versions = [x["version"] for x in peerinfo] - assert_equal(0, versions.count(MY_VERSION)) + assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION)) # Extend the Overwinter chain with another block. self.nodes[0].generate(1) # Connect a new Overwinter mininode to the zcashd node, which is accepted. - nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", True)) + nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", OVERWINTER_PROTO_VERSION)) time.sleep(3) assert_equal(11, len(self.nodes[0].getpeerinfo())) # Try to connect a new Sprout mininode to the zcashd node, which is rejected. - sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", False) + sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SPROUT_PROTO_VERSION) nodes.append(sprout) time.sleep(3) assert("Version must be 170003 or greater" in str(sprout.rejectMessage)) @@ -106,7 +108,7 @@ class OverwinterPeerManagementTest(BitcoinTestFramework): # Verify that only Overwinter mininodes are connected. peerinfo = self.nodes[0].getpeerinfo() versions = [x["version"] for x in peerinfo] - assert_equal(0, versions.count(MY_VERSION)) + assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) assert_equal(11, versions.count(OVERWINTER_PROTO_VERSION)) for node in nodes: diff --git a/qa/rpc-tests/p2p_node_bloom.py b/qa/rpc-tests/p2p_node_bloom.py new file mode 100755 index 000000000..18476a981 --- /dev/null +++ b/qa/rpc-tests/p2p_node_bloom.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.mininode import NodeConn, NodeConnCB, NetworkThread, \ + msg_filteradd, msg_filterclear, mininode_lock, SPROUT_PROTO_VERSION +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import initialize_chain_clean, start_nodes, \ + p2p_port, assert_equal + +import time + + +class TestNode(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.create_callback_map() + self.connection = None + + def add_connection(self, conn): + self.connection = conn + + # Spin until verack message is received from the node. + # We use this to signal that our test can begin. This + # is called from the testing thread, so it needs to acquire + # the global lock. + def wait_for_verack(self): + while True: + with mininode_lock: + if self.verack_received: + return + time.sleep(0.05) + + # Wrapper for the NodeConn's send_message function + def send_message(self, message): + self.connection.send_message(message) + + def on_close(self, conn): + pass + + def on_reject(self, conn, message): + conn.rejectMessage = message + + +class NodeBloomTest(BitcoinTestFramework): + + def setup_chain(self): + print "Initializing test directory "+self.options.tmpdir + initialize_chain_clean(self.options.tmpdir, 2) + + def setup_network(self): + self.nodes = start_nodes(2, self.options.tmpdir, + extra_args=[['-nopeerbloomfilters', '-enforcenodebloom'], []]) + + def run_test(self): + nobf_node = TestNode() + bf_node = TestNode() + + connections = [] + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], nobf_node)) + connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], bf_node)) + nobf_node.add_connection(connections[0]) + bf_node.add_connection(connections[1]) + + # Start up network handling in another thread + NetworkThread().start() + + nobf_node.wait_for_verack() + bf_node.wait_for_verack() + + # Verify mininodes are connected to zcashd nodes + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(1, versions.count(SPROUT_PROTO_VERSION)) + peerinfo = self.nodes[1].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(1, versions.count(SPROUT_PROTO_VERSION)) + + # Mininodes send filterclear message to zcashd node. + nobf_node.send_message(msg_filterclear()) + bf_node.send_message(msg_filterclear()) + + time.sleep(3) + + # Verify mininodes are still connected to zcashd nodes + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(1, versions.count(SPROUT_PROTO_VERSION)) + peerinfo = self.nodes[1].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(1, versions.count(SPROUT_PROTO_VERSION)) + + # Mininodes send filteradd message to zcashd node. + nobf_node.send_message(msg_filteradd()) + bf_node.send_message(msg_filteradd()) + + time.sleep(3) + + # Verify NoBF mininode has been dropped, and BF mininode is still connected. + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) + peerinfo = self.nodes[1].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(1, versions.count(SPROUT_PROTO_VERSION)) + + [ c.disconnect_node() for c in connections ] + +if __name__ == '__main__': + NodeBloomTest().main() diff --git a/qa/rpc-tests/p2p_txexpiry_dos.py b/qa/rpc-tests/p2p_txexpiry_dos.py new file mode 100755 index 000000000..ec970435a --- /dev/null +++ b/qa/rpc-tests/p2p_txexpiry_dos.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.mininode import NodeConn, NodeConnCB, NetworkThread, \ + CTransaction, msg_tx, mininode_lock, OVERWINTER_PROTO_VERSION +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import initialize_chain_clean, start_nodes, \ + p2p_port, assert_equal + +import time, cStringIO +from binascii import hexlify, unhexlify + + +class TestNode(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.create_callback_map() + self.connection = None + + def add_connection(self, conn): + self.connection = conn + + # Spin until verack message is received from the node. + # We use this to signal that our test can begin. This + # is called from the testing thread, so it needs to acquire + # the global lock. + def wait_for_verack(self): + while True: + with mininode_lock: + if self.verack_received: + return + time.sleep(0.05) + + # Wrapper for the NodeConn's send_message function + def send_message(self, message): + self.connection.send_message(message) + + def on_close(self, conn): + pass + + def on_reject(self, conn, message): + conn.rejectMessage = message + + +class TxExpiryDoSTest(BitcoinTestFramework): + + def setup_chain(self): + print "Initializing test directory "+self.options.tmpdir + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self): + self.nodes = start_nodes(1, self.options.tmpdir, + extra_args=[['-nuparams=5ba81b19:10']]) + + def create_transaction(self, node, coinbase, to_address, amount, txModifier=None): + from_txid = node.getblock(coinbase)['tx'][0] + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + tx = CTransaction() + + if txModifier: + f = cStringIO.StringIO(unhexlify(rawtx)) + tx.deserialize(f) + txModifier(tx) + rawtx = hexlify(tx.serialize()) + + signresult = node.signrawtransaction(rawtx) + f = cStringIO.StringIO(unhexlify(signresult['hex'])) + tx.deserialize(f) + return tx + + def run_test(self): + test_node = TestNode() + + connections = [] + connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], + test_node, "regtest", OVERWINTER_PROTO_VERSION)) + test_node.add_connection(connections[0]) + + # Start up network handling in another thread + NetworkThread().start() + + test_node.wait_for_verack() + + # Verify mininodes are connected to zcashd nodes + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(1, versions.count(OVERWINTER_PROTO_VERSION)) + assert_equal(0, peerinfo[0]["banscore"]) + + self.coinbase_blocks = self.nodes[0].generate(1) + self.nodes[0].generate(100) + self.nodeaddress = self.nodes[0].getnewaddress() + + # Mininodes send transaction to zcashd node. + def setExpiryHeight(tx): + tx.nExpiryHeight = 101 + + spendtx = self.create_transaction(self.nodes[0], + self.coinbase_blocks[0], + self.nodeaddress, 1.0, + txModifier=setExpiryHeight) + test_node.send_message(msg_tx(spendtx)) + + time.sleep(3) + + # Verify test mininode has not been dropped + # and still has a banscore of 0. + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(1, versions.count(OVERWINTER_PROTO_VERSION)) + assert_equal(0, peerinfo[0]["banscore"]) + + # Mine a block and resend the transaction + self.nodes[0].generate(1) + test_node.send_message(msg_tx(spendtx)) + + time.sleep(3) + + # Verify test mininode has not been dropped + # but has a banscore of 10. + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(1, versions.count(OVERWINTER_PROTO_VERSION)) + assert_equal(10, peerinfo[0]["banscore"]) + + [ c.disconnect_node() for c in connections ] + +if __name__ == '__main__': + TxExpiryDoSTest().main() diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py index dc919f028..182f87f08 100755 --- a/qa/rpc-tests/rawtransactions.py +++ b/qa/rpc-tests/rawtransactions.py @@ -145,5 +145,11 @@ class RawTransactionsTest(BitcoinTestFramework): self.sync_all() assert_equal(self.nodes[0].getbalance(), bal+Decimal('10.00000000')+Decimal('2.19900000')) #block reward + tx + inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}] + outputs = { self.nodes[0].getnewaddress() : 1 } + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + decrawtx= self.nodes[0].decoderawtransaction(rawtx) + assert_equal(decrawtx['vin'][0]['sequence'], 1000) + if __name__ == '__main__': RawTransactionsTest().main() diff --git a/qa/rpc-tests/rewind_index.py b/qa/rpc-tests/rewind_index.py new file mode 100755 index 000000000..8c5c606df --- /dev/null +++ b/qa/rpc-tests/rewind_index.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, initialize_chain_clean, \ + start_nodes, start_node, connect_nodes_bi, bitcoind_processes + +import time + + +class RewindBlockIndexTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 3) + + def setup_network(self, split=False): + # Node 0 - Overwinter, then Sprout, then Overwinter again + # Node 1 - Sprout + # Node 2 - Overwinter + self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-nuparams=5ba81b19:10'], [], ['-nuparams=5ba81b19:10']]) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + self.is_network_split=False + self.sync_all() + + def run_test (self): + # Bring all nodes to just before the activation block + print("Mining blocks...") + self.nodes[0].generate(8) + block9 = self.nodes[0].generate(1)[0] + self.sync_all() + + assert_equal(self.nodes[0].getbestblockhash(), block9) + assert_equal(self.nodes[1].getbestblockhash(), block9) + + print("Mining diverging blocks") + block10s = self.nodes[1].generate(1)[0] + block10o = self.nodes[2].generate(1)[0] + self.sync_all() + + assert_equal(self.nodes[0].getbestblockhash(), block10o) + assert_equal(self.nodes[1].getbestblockhash(), block10s) + assert_equal(self.nodes[2].getbestblockhash(), block10o) + + # Restart node 0 using Sprout instead of Overwinter + print("Switching node 0 from Overwinter to Sprout") + self.nodes[0].stop() + bitcoind_processes[0].wait() + self.nodes[0] = start_node(0,self.options.tmpdir) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + + # Assume node 1 will send block10s to node 0 quickly + # (if we used self.sync_all() here and there was a bug, the test would hang) + time.sleep(2) + + # Node 0 has rewound and is now on the Sprout chain + assert_equal(self.nodes[0].getblockcount(), 10) + assert_equal(self.nodes[0].getbestblockhash(), block10s) + + # Restart node 0 using Overwinter instead of Sprout + print("Switching node 0 from Sprout to Overwinter") + self.nodes[0].stop() + bitcoind_processes[0].wait() + self.nodes[0] = start_node(0,self.options.tmpdir, extra_args=['-nuparams=5ba81b19:10']) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + + # Assume node 2 will send block10o to node 0 quickly + # (if we used self.sync_all() here and there was a bug, the test would hang) + time.sleep(2) + + # Node 0 has rewound and is now on the Overwinter chain again + assert_equal(self.nodes[0].getblockcount(), 10) + assert_equal(self.nodes[0].getbestblockhash(), block10o) + + +if __name__ == '__main__': + RewindBlockIndexTest().main() diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index 3c9821259..39b634a5e 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -41,9 +41,11 @@ from .equihash import ( OVERWINTER_PROTO_VERSION = 170003 BIP0031_VERSION = 60000 -MY_VERSION = 170002 # past bip-31 for ping/pong +SPROUT_PROTO_VERSION = 170002 # past bip-31 for ping/pong MY_SUBVERSION = "/python-mininode-tester:0.0.1/" +OVERWINTER_VERSION_GROUP_ID = 0x03C48270 + MAX_INV_SZ = 50000 @@ -328,7 +330,7 @@ class CInv(object): class CBlockLocator(object): def __init__(self): - self.nVersion = MY_VERSION + self.nVersion = SPROUT_PROTO_VERSION self.vHave = [] def deserialize(self, f): @@ -565,20 +567,26 @@ class CTxOut(object): class CTransaction(object): def __init__(self, tx=None): if tx is None: + self.fOverwintered = False self.nVersion = 1 + self.nVersionGroupId = 0 self.vin = [] self.vout = [] self.nLockTime = 0 + self.nExpiryHeight = 0 self.vjoinsplit = [] self.joinSplitPubKey = None self.joinSplitSig = None self.sha256 = None self.hash = None else: + self.fOverwintered = tx.fOverwintered self.nVersion = tx.nVersion + self.nVersionGroupId = tx.nVersionGroupId self.vin = copy.deepcopy(tx.vin) self.vout = copy.deepcopy(tx.vout) self.nLockTime = tx.nLockTime + self.nExpiryHeight = tx.nExpiryHeight self.vjoinsplit = copy.deepcopy(tx.vjoinsplit) self.joinSplitPubKey = tx.joinSplitPubKey self.joinSplitSig = tx.joinSplitSig @@ -586,24 +594,46 @@ class CTransaction(object): self.hash = None def deserialize(self, f): - self.nVersion = struct.unpack("> 31) + self.nVersion = header & 0x7FFFFFFF + self.nVersionGroupId = (struct.unpack("= 2: self.vjoinsplit = deser_vector(f, JSDescription) if len(self.vjoinsplit) > 0: self.joinSplitPubKey = deser_uint256(f) self.joinSplitSig = f.read(64) + self.sha256 = None self.hash = None def serialize(self): + header = (int(self.fOverwintered)<<31) | self.nVersion + isOverwinterV3 = (self.fOverwintered and + self.nVersionGroupId == OVERWINTER_VERSION_GROUP_ID and + self.nVersion == 3) + r = "" - r += struct.pack("= 2: r += ser_vector(self.vjoinsplit) if len(self.vjoinsplit) > 0: @@ -628,8 +658,10 @@ class CTransaction(object): return True def __repr__(self): - r = "CTransaction(nVersion=%i vin=%s vout=%s nLockTime=%i" \ - % (self.nVersion, repr(self.vin), repr(self.vout), self.nLockTime) + r = ("CTransaction(fOverwintered=%r nVersion=%i nVersionGroupId=0x%08x " + "vin=%s vout=%s nLockTime=%i nExpiryHeight=%i" + % (self.fOverwintered, self.nVersion, self.nVersionGroupId, + repr(self.vin), repr(self.vout), self.nLockTime, self.nExpiryHeight)) if self.nVersion >= 2: r += " vjoinsplit=%s" % repr(self.vjoinsplit) if len(self.vjoinsplit) > 0: @@ -869,12 +901,8 @@ class CAlert(object): class msg_version(object): command = "version" - def __init__(self, overwintered=False): - if overwintered: - self.nVersion = OVERWINTER_PROTO_VERSION - else: - self.nVersion = MY_VERSION - + def __init__(self, protocol_version=SPROUT_PROTO_VERSION): + self.nVersion = protocol_version self.nServices = 1 self.nTime = time.time() self.addrTo = CAddress() @@ -1231,6 +1259,38 @@ class msg_reject(object): % (self.message, self.code, self.reason, self.data) +class msg_filteradd(object): + command = "filteradd" + + def __init__(self): + self.data = "" + + def deserialize(self, f): + self.data = deser_string(f) + + def serialize(self): + return ser_string(self.data) + + def __repr__(self): + return "msg_filteradd(data=%s)" % (repr(self.data)) + + +class msg_filterclear(object): + command = "filterclear" + + def __init__(self): + pass + + def deserialize(self, f): + pass + + def serialize(self): + return "" + + def __repr__(self): + return "msg_filterclear()" + + # This is what a callback should look like for NodeConn # Reimplement the on_* functions to provide handling for events class NodeConnCB(object): @@ -1270,7 +1330,7 @@ class NodeConnCB(object): def on_version(self, conn, message): if message.nVersion >= 209: conn.send_message(msg_verack()) - conn.ver_send = min(MY_VERSION, message.nVersion) + conn.ver_send = min(SPROUT_PROTO_VERSION, message.nVersion) if message.nVersion < 209: conn.ver_recv = conn.ver_send @@ -1331,7 +1391,7 @@ class NodeConn(asyncore.dispatcher): "regtest": "\xaa\xe8\x3f\x5f" # regtest } - def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", overwintered=False): + def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", protocol_version=SPROUT_PROTO_VERSION): asyncore.dispatcher.__init__(self, map=mininode_socket_map) self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport)) self.dstaddr = dstaddr @@ -1348,7 +1408,7 @@ class NodeConn(asyncore.dispatcher): self.disconnect = False # stuff version msg into sendbuf - vt = msg_version(overwintered) + vt = msg_version(protocol_version) vt.addrTo.ip = self.dstaddr vt.addrTo.port = self.dstport vt.addrFrom.ip = "0.0.0.0" diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 5cb0d1b10..043a31266 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -389,9 +389,18 @@ def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants): return (txid, signresult["hex"], fee) -def assert_equal(thing1, thing2): - if thing1 != thing2: - raise AssertionError("%s != %s"%(str(thing1),str(thing2))) +def assert_equal(expected, actual, message = ""): + if expected != actual: + if message: + message = "%s; " % message + raise AssertionError("%sexpected: <%s> but was: <%s>" % (message, str(expected), str(actual))) + +def assert_true(condition, message = ""): + if not condition: + raise AssertionError(message) + +def assert_false(condition, message = ""): + assert_true(not condition, message) def assert_greater_than(thing1, thing2): if thing1 <= thing2: @@ -427,12 +436,12 @@ def wait_and_assert_operationid_status(node, myopid, in_status='success', in_err elif status == "success": txid = results[0]['result']['txid'] break - assert_equal(in_status, status) - if errormsg is not None: - assert(in_errormsg is not None) - assert_equal(in_errormsg in errormsg, True) if os.getenv("PYTHON_DEBUG", ""): print('...returned status: {}'.format(status)) if errormsg is not None: print('...returned error: {}'.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) return txid diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 12dfac0e4..642590b81 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -89,6 +89,26 @@ class WalletTest (BitcoinTestFramework): assert_equal(len(node2utxos), 2) assert_equal(sum(int(uxto["generated"] is True) for uxto in node2utxos), 0) + # Catch an attempt to send a transaction with an absurdly high fee. + # Send 1.0 from an utxo of value 10.0 but don't specify a change output, so then + # the change of 9.0 becomes the fee, which is greater than estimated fee of 0.0019. + inputs = [] + outputs = {} + for utxo in node2utxos: + if utxo["amount"] == Decimal("10.0"): + break + assert_equal(utxo["amount"], Decimal("10.0")) + inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]}) + outputs[self.nodes[2].getnewaddress("")] = Decimal("1.0") + raw_tx = self.nodes[2].createrawtransaction(inputs, outputs) + signed_tx = self.nodes[2].signrawtransaction(raw_tx) + try: + self.nodes[2].sendrawtransaction(signed_tx["hex"]) + except JSONRPCException,e: + errorString = e.error['message'] + assert("absurdly high fees" in errorString) + assert("900000000 > 190000" in errorString) + # create both transactions txns_to_send = [] for utxo in node0utxos: @@ -443,6 +463,62 @@ class WalletTest (BitcoinTestFramework): assert_equal("not an integer" in errorString, True); + myzaddr = self.nodes[0].z_getnewaddress() + recipients = [ {"address": myzaddr, "amount": Decimal('0.0') } ] + errorString = '' + + # Make sure that amount=0 transactions can use the default fee + # without triggering "absurd fee" errors + try: + myopid = self.nodes[0].z_sendmany(myzaddr, recipients) + assert(myopid) + except JSONRPCException,e: + errorString = e.error['message'] + print errorString + assert(False) + + # This fee is larger than the default fee and since amount=0 + # it should trigger error + fee = Decimal('0.1') + recipients = [ {"address": myzaddr, "amount": Decimal('0.0') } ] + minconf = 1 + errorString = '' + + try: + myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee) + except JSONRPCException,e: + errorString = e.error['message'] + assert('Small transaction amount' in errorString) + + # This fee is less than default and greater than amount, but still valid + fee = Decimal('0.0000001') + recipients = [ {"address": myzaddr, "amount": Decimal('0.00000001') } ] + minconf = 1 + errorString = '' + + try: + myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee) + assert(myopid) + except JSONRPCException,e: + errorString = e.error['message'] + print errorString + assert(False) + + # Make sure amount=0, fee=0 transaction are valid to add to mempool + # though miners decide whether to add to a block + fee = Decimal('0.0') + minconf = 1 + recipients = [ {"address": myzaddr, "amount": Decimal('0.0') } ] + errorString = '' + + try: + myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee) + assert(myopid) + except JSONRPCException,e: + errorString = e.error['message'] + print errorString + assert(False) + if __name__ == '__main__': WalletTest ().main () diff --git a/qa/rpc-tests/wallet_addresses.py b/qa/rpc-tests/wallet_addresses.py new file mode 100755 index 000000000..0b9669972 --- /dev/null +++ b/qa/rpc-tests/wallet_addresses.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, start_nodes + +# Test wallet address behaviour across network upgradesa\ +class WalletAddressesTest(BitcoinTestFramework): + + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir, [[ + '-nuparams=5ba81b19:202', # Overwinter + '-nuparams=76b809bb:204', # Sapling + ]] * 4) + + def run_test(self): + def addr_checks(default_type): + # Check default type, as well as explicit types + types_and_addresses = [ + (default_type, self.nodes[0].z_getnewaddress()), + ('sprout', self.nodes[0].z_getnewaddress('sprout')), + ('sapling', self.nodes[0].z_getnewaddress('sapling')), + ] + + all_addresses = self.nodes[0].z_listaddresses() + + for addr_type, addr in types_and_addresses: + res = self.nodes[0].z_validateaddress(addr) + assert(res['isvalid']) + assert(res['ismine']) + assert_equal(res['type'], addr_type) + assert(addr in all_addresses) + + # Sanity-check the test harness + assert_equal(self.nodes[0].getblockcount(), 200) + + # Current height = 200 -> Sprout + # Default address type is Sprout + print "Testing height 200 (Sprout)" + addr_checks('sprout') + + self.nodes[0].generate(1) + self.sync_all() + + # Current height = 201 -> Sprout + # Default address type is Sprout + print "Testing height 201 (Sprout)" + addr_checks('sprout') + + self.nodes[0].generate(1) + self.sync_all() + + # Current height = 202 -> Overwinter + # Default address type is Sprout + print "Testing height 202 (Overwinter)" + addr_checks('sprout') + + self.nodes[0].generate(1) + self.sync_all() + + # Current height = 203 -> Overwinter + # Default address type is Sprout + print "Testing height 203 (Overwinter)" + addr_checks('sprout') + + self.nodes[0].generate(1) + self.sync_all() + + # Current height = 204 -> Sapling + # Default address type is Sprout + print "Testing height 204 (Sapling)" + addr_checks('sprout') + +if __name__ == '__main__': + WalletAddressesTest().main() diff --git a/qa/rpc-tests/wallet_anchorfork.py b/qa/rpc-tests/wallet_anchorfork.py index a4df66daf..0e2d19385 100755 --- a/qa/rpc-tests/wallet_anchorfork.py +++ b/qa/rpc-tests/wallet_anchorfork.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. from test_framework.test_framework import BitcoinTestFramework -from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ start_nodes, stop_nodes, connect_nodes_bi, \ wait_and_assert_operationid_status, wait_bitcoinds diff --git a/qa/rpc-tests/wallet_changeindicator.py b/qa/rpc-tests/wallet_changeindicator.py new file mode 100755 index 000000000..d26381064 --- /dev/null +++ b/qa/rpc-tests/wallet_changeindicator.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_true, assert_false, wait_and_assert_operationid_status + +from decimal import Decimal + +class WalletChangeIndicatorTest (BitcoinTestFramework): + # Helper Methods + def generate_and_sync(self): + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + # Tests + def run_test(self): + taddr = self.nodes[1].getnewaddress() + zaddr1 = self.nodes[1].z_getnewaddress() + zaddr2 = self.nodes[1].z_getnewaddress() + + self.nodes[0].sendtoaddress(taddr, Decimal('1.0')) + self.generate_and_sync() + + # Send 1 ZEC to a zaddr + wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(taddr, [{'address': zaddr1, 'amount': 1.0, 'memo': 'c0ffee01'}], 1, 0)) + self.generate_and_sync() + + # Check that we have received 1 note which is not change + receivedbyaddress = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) + listunspent = self.nodes[1].z_listunspent() + assert_equal(1, len(receivedbyaddress), "Should have received 1 note") + assert_false(receivedbyaddress[0]['change'], "Note should not be change") + assert_equal(1, len(listunspent), "Should have 1 unspent note") + assert_false(listunspent[0]['change'], "Unspent note should not be change") + + # Generate some change + wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(zaddr1, [{'address': zaddr2, 'amount': 0.6, 'memo': 'c0ffee02'}], 1, 0)) + self.generate_and_sync() + + # Check zaddr1 received + sortedreceived1 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr1, 0), key = lambda received: received['amount']) + assert_equal(2, len(sortedreceived1), "zaddr1 Should have received 2 notes") + assert_equal(Decimal('0.4'), sortedreceived1[0]['amount']) + assert_true(sortedreceived1[0]['change'], "Note valued at 0.4 should be change") + assert_equal(Decimal('1.0'), sortedreceived1[1]['amount']) + assert_false(sortedreceived1[1]['change'], "Note valued at 1.0 should not be change") + # Check zaddr2 received + sortedreceived2 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr2, 0), key = lambda received: received['amount']) + assert_equal(1, len(sortedreceived2), "zaddr2 Should have received 1 notes") + assert_equal(Decimal('0.6'), sortedreceived2[0]['amount']) + assert_false(sortedreceived2[0]['change'], "Note valued at 0.6 should not be change") + # Check unspent + sortedunspent = sorted(self.nodes[1].z_listunspent(), key = lambda received: received['amount']) + assert_equal(2, len(sortedunspent), "Should have 2 unspent notes") + assert_equal(Decimal('0.4'), sortedunspent[0]['amount']) + assert_true(sortedunspent[0]['change'], "Unspent note valued at 0.4 should be change") + assert_equal(Decimal('0.6'), sortedunspent[1]['amount']) + assert_false(sortedunspent[1]['change'], "Unspent note valued at 0.6 should not be change") + + # Give node 0 a viewing key + viewing_key = self.nodes[1].z_exportviewingkey(zaddr1) + self.nodes[0].z_importviewingkey(viewing_key) + received_node0 = self.nodes[0].z_listreceivedbyaddress(zaddr1, 0) + assert_equal(2, len(received_node0)) + unspent_node0 = self.nodes[0].z_listunspent(1, 9999999, True) + assert_equal(2, len(unspent_node0)) + # node 0 only has a viewing key so does not see the change field + assert_false('change' in received_node0[0]) + assert_false('change' in received_node0[1]) + assert_false('change' in unspent_node0[0]) + assert_false('change' in unspent_node0[1]) + +if __name__ == '__main__': + WalletChangeIndicatorTest().main() diff --git a/qa/rpc-tests/wallet_nullifiers.py b/qa/rpc-tests/wallet_nullifiers.py index 207631efb..72e26fab8 100755 --- a/qa/rpc-tests/wallet_nullifiers.py +++ b/qa/rpc-tests/wallet_nullifiers.py @@ -5,7 +5,7 @@ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, start_node, \ +from test_framework.util import assert_equal, assert_true, start_node, \ start_nodes, connect_nodes_bi, bitcoind_processes import time @@ -188,10 +188,24 @@ class WalletNullifiersTest (BitcoinTestFramework): assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False) assert_equal(myzaddr in self.nodes[3].z_listaddresses(True), True) - # Node 3 should see the same received notes as node 2 - assert_equal( - self.nodes[2].z_listreceivedbyaddress(myzaddr), - self.nodes[3].z_listreceivedbyaddress(myzaddr)) + # Node 3 should see the same received notes as node 2; however, + # some of the notes were change for node 2 but not for node 3. + # Aside from that the recieved notes should be the same. So, + # group by txid and then check that all properties aside from + # change are equal. + node2Received = dict([r['txid'], r] for r in self.nodes[2].z_listreceivedbyaddress(myzaddr)) + node3Received = dict([r['txid'], r] for r in self.nodes[3].z_listreceivedbyaddress(myzaddr)) + assert_equal(len(node2Received), len(node2Received)) + for txid in node2Received: + received2 = node2Received[txid] + received3 = node3Received[txid] + # the change field will be omitted for received3, but all other fields should be shared + assert_true(len(received2) >= len(received3)) + for key in received2: + # check all the properties except for change + if key != 'change': + assert_equal(received2[key], received3[key]) + # Node 3's balances should be unchanged without explicitly requesting # to include watch-only balances diff --git a/qa/rpc-tests/wallet_overwintertx.py b/qa/rpc-tests/wallet_overwintertx.py index 61932fece..d77a114db 100755 --- a/qa/rpc-tests/wallet_overwintertx.py +++ b/qa/rpc-tests/wallet_overwintertx.py @@ -6,6 +6,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, initialize_chain_clean, \ start_nodes, connect_nodes_bi, wait_and_assert_operationid_status +from test_framework.authproxy import JSONRPCException from decimal import Decimal @@ -46,6 +47,13 @@ class WalletOverwinterTxTest (BitcoinTestFramework): assert_equal(bci['consensus']['nextblock'], '00000000') assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending') + # Cannot use the expiryheight parameter of createrawtransaction if Overwinter is not active in the next block + try: + self.nodes[0].createrawtransaction([], {}, 0, 99) + except JSONRPCException,e: + errorString = e.error['message'] + assert_equal("Invalid parameter, expiryheight can only be used if Overwinter is active when the transaction is mined" in errorString, True) + # Node 0 sends transparent funds to Node 2 tsendamount = Decimal('1.0') txid_transparent = self.nodes[0].sendtoaddress(taddr2, tsendamount) @@ -92,6 +100,24 @@ class WalletOverwinterTxTest (BitcoinTestFramework): assert_equal(bci['consensus']['nextblock'], '5ba81b19') assert_equal(bci['upgrades']['5ba81b19']['status'], 'pending') + # Test using expiryheight parameter of createrawtransaction when Overwinter is active in the next block + errorString = "" + try: + self.nodes[0].createrawtransaction([], {}, 0, 499999999) + except JSONRPCException,e: + errorString = e.error['message'] + assert_equal("", errorString) + try: + self.nodes[0].createrawtransaction([], {}, 0, -1) + except JSONRPCException,e: + errorString = e.error['message'] + assert_equal("Invalid parameter, expiryheight must be nonnegative and less than 500000000" in errorString, True) + try: + self.nodes[0].createrawtransaction([], {}, 0, 500000000) + except JSONRPCException,e: + errorString = e.error['message'] + assert_equal("Invalid parameter, expiryheight must be nonnegative and less than 500000000" in errorString, True) + # Node 0 sends transparent funds to Node 3 tsendamount = Decimal('1.0') txid_transparent = self.nodes[0].sendtoaddress(taddr3, tsendamount) diff --git a/qa/rpc-tests/wallet_protectcoinbase.py b/qa/rpc-tests/wallet_protectcoinbase.py index afe851a16..a27896df7 100755 --- a/qa/rpc-tests/wallet_protectcoinbase.py +++ b/qa/rpc-tests/wallet_protectcoinbase.py @@ -8,7 +8,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.mininode import COIN from test_framework.util import assert_equal, initialize_chain_clean, \ - start_nodes, connect_nodes_bi, stop_node, wait_and_assert_operationid_status + start_nodes, connect_nodes_bi, wait_and_assert_operationid_status import sys import time @@ -96,8 +96,6 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework): break assert_equal("failed", status) assert_equal("no UTXOs found for taddr from address" in errorString, True) - stop_node(self.nodes[3], 3) - self.nodes.pop() # This send will fail because our wallet does not allow any change when protecting a coinbase utxo, # as it's currently not possible to specify a change address in z_sendmany. @@ -129,6 +127,10 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework): assert_equal("failed", status) assert_equal("wallet does not allow any change" in errorString, True) + # Add viewing key for myzaddr to Node 3 + myviewingkey = self.nodes[0].z_exportviewingkey(myzaddr) + self.nodes[3].z_importviewingkey(myviewingkey, "no") + # This send will succeed. We send two coinbase utxos totalling 20.0 less a fee of 0.00010000, with no change. shieldvalue = Decimal('20.0') - Decimal('0.0001') recipients = [] @@ -136,9 +138,43 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework): myopid = self.nodes[0].z_sendmany(mytaddr, recipients) mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) self.sync_all() + + # Verify that z_listunspent can return a note that has zero confirmations + results = self.nodes[0].z_listunspent() + assert(len(results) == 0) + results = self.nodes[0].z_listunspent(0) # set minconf to zero + assert(len(results) == 1) + assert_equal(results[0]["address"], myzaddr) + assert_equal(results[0]["amount"], shieldvalue) + assert_equal(results[0]["confirmations"], 0) + + # Mine the tx self.nodes[1].generate(1) self.sync_all() + # Verify that z_listunspent returns one note which has been confirmed + results = self.nodes[0].z_listunspent() + assert(len(results) == 1) + assert_equal(results[0]["address"], myzaddr) + assert_equal(results[0]["amount"], shieldvalue) + assert_equal(results[0]["confirmations"], 1) + assert_equal(results[0]["spendable"], True) + + # Verify that z_listunspent returns note for watchonly address on node 3. + results = self.nodes[3].z_listunspent(1, 999, True) + assert(len(results) == 1) + assert_equal(results[0]["address"], myzaddr) + assert_equal(results[0]["amount"], shieldvalue) + assert_equal(results[0]["confirmations"], 1) + assert_equal(results[0]["spendable"], False) + + # Verify that z_listunspent returns error when address spending key from node 0 is not available in wallet of node 1. + try: + results = self.nodes[1].z_listunspent(1, 999, False, [myzaddr]) + except JSONRPCException as e: + errorString = e.error['message'] + assert_equal("Invalid parameter, spending key for address does not belong to wallet" in errorString, True) + # Verify that debug=zrpcunsafe logs params, and that full txid is associated with opid logpath = self.options.tmpdir+"/node0/regtest/debug.log" logcounter = 0 @@ -226,7 +262,7 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework): myopid = self.nodes[0].z_sendmany(mytaddr, recipients) wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient transparent funds, have 10.00, need 10000.0001") myopid = self.nodes[0].z_sendmany(myzaddr, recipients) - wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient protected funds, have 9.9998, need 10000.0001") + wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Insufficient shielded funds, have 9.9998, need 10000.0001") # Send will fail because of insufficient funds unless sender uses coinbase utxos try: @@ -333,13 +369,22 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework): self.nodes[1].generate(1) self.sync_all() - # check balances + # check balances and unspent notes resp = self.nodes[2].z_gettotalbalance() assert_equal(Decimal(resp["private"]), send_amount) + + notes = self.nodes[2].z_listunspent() + sum_of_notes = sum([note["amount"] for note in notes]) + assert_equal(Decimal(resp["private"]), sum_of_notes) + resp = self.nodes[0].z_getbalance(myzaddr) assert_equal(Decimal(resp), zbalance - custom_fee - send_amount) sproutvalue -= custom_fee check_value_pool(self.nodes[0], 'sprout', sproutvalue) + notes = self.nodes[0].z_listunspent(1, 99999, False, [myzaddr]) + sum_of_notes = sum([note["amount"] for note in notes]) + assert_equal(Decimal(resp), sum_of_notes) + if __name__ == '__main__': WalletProtectCoinbaseTest().main() diff --git a/qa/rpc-tests/wallet_sapling.py b/qa/rpc-tests/wallet_sapling.py new file mode 100755 index 000000000..517869820 --- /dev/null +++ b/qa/rpc-tests/wallet_sapling.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + start_nodes, + wait_and_assert_operationid_status, +) + +from decimal import Decimal + +# Test wallet behaviour with Sapling addresses +class WalletSaplingTest(BitcoinTestFramework): + + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir, [[ + '-nuparams=5ba81b19:201', # Overwinter + '-nuparams=76b809bb:201', # Sapling + ]] * 4) + + def run_test(self): + # Sanity-check the test harness + assert_equal(self.nodes[0].getblockcount(), 200) + + # Activate Sapling + self.nodes[2].generate(1) + self.sync_all() + + taddr0 = self.nodes[0].getnewaddress() + # Skip over the address containing node 1's coinbase + self.nodes[1].getnewaddress() + taddr1 = self.nodes[1].getnewaddress() + saplingAddr0 = self.nodes[0].z_getnewaddress('sapling') + saplingAddr1 = self.nodes[1].z_getnewaddress('sapling') + + # Verify addresses + assert(saplingAddr0 in self.nodes[0].z_listaddresses()) + assert(saplingAddr1 in self.nodes[1].z_listaddresses()) + assert_equal(self.nodes[0].z_validateaddress(saplingAddr0)['type'], 'sapling') + assert_equal(self.nodes[0].z_validateaddress(saplingAddr1)['type'], 'sapling') + + # Verify balance + assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('0')) + assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('0')) + assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0')) + + # Node 0 shields some funds + # taddr -> Sapling + # -> taddr (change) + recipients = [] + recipients.append({"address": saplingAddr0, "amount": Decimal('20')}) + myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) + wait_and_assert_operationid_status(self.nodes[0], myopid) + + self.sync_all() + self.nodes[2].generate(1) + self.sync_all() + + # Verify balance + assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('20')) + assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('0')) + assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0')) + + # Node 0 sends some shielded funds to node 1 + # Sapling -> Sapling + # -> Sapling (change) + recipients = [] + recipients.append({"address": saplingAddr1, "amount": Decimal('15')}) + myopid = self.nodes[0].z_sendmany(saplingAddr0, recipients, 1, 0) + wait_and_assert_operationid_status(self.nodes[0], myopid) + + self.sync_all() + self.nodes[2].generate(1) + self.sync_all() + + # Verify balance + assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('5')) + assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('15')) + assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('0')) + + # Node 1 sends some shielded funds to node 0, as well as unshielding + # Sapling -> Sapling + # -> taddr + # -> Sapling (change) + recipients = [] + recipients.append({"address": saplingAddr0, "amount": Decimal('5')}) + recipients.append({"address": taddr1, "amount": Decimal('5')}) + myopid = self.nodes[1].z_sendmany(saplingAddr1, recipients, 1, 0) + wait_and_assert_operationid_status(self.nodes[1], myopid) + + self.sync_all() + self.nodes[2].generate(1) + self.sync_all() + + # Verify balance + assert_equal(self.nodes[0].z_getbalance(saplingAddr0), Decimal('10')) + assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal('5')) + assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal('5')) + +if __name__ == '__main__': + WalletSaplingTest().main() diff --git a/qa/rpc-tests/zkey_import_export.py b/qa/rpc-tests/zkey_import_export.py index 323debe31..dc35937df 100755 --- a/qa/rpc-tests/zkey_import_export.py +++ b/qa/rpc-tests/zkey_import_export.py @@ -9,11 +9,10 @@ from test_framework.util import assert_equal, assert_greater_than, start_nodes,\ initialize_chain_clean, connect_nodes_bi, wait_and_assert_operationid_status import logging -import time -import math logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO) +fee = Decimal('0.0001') # constant (but can be changed within reason) class ZkeyImportExportTest (BitcoinTestFramework): @@ -22,7 +21,7 @@ class ZkeyImportExportTest (BitcoinTestFramework): initialize_chain_clean(self.options.tmpdir, 5) def setup_network(self, split=False): - self.nodes = start_nodes(5, self.options.tmpdir ) + self.nodes = start_nodes(5, self.options.tmpdir) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) @@ -34,19 +33,16 @@ class ZkeyImportExportTest (BitcoinTestFramework): def run_test(self): [alice, bob, charlie, david, miner] = self.nodes + # the sender loses 'amount' plus fee; to_addr receives exactly 'amount' def z_send(from_node, from_addr, to_addr, amount): - opid = from_node.z_sendmany(from_addr, [{"address": to_addr, "amount": Decimal(amount)}]) + global fee + opid = from_node.z_sendmany(from_addr, + [{"address": to_addr, "amount": Decimal(amount)}], 1, fee) wait_and_assert_operationid_status(from_node, opid) self.sync_all() miner.generate(1) self.sync_all() - def z_getbalance(node, zaddr): - bal = node.z_getbalance(zaddr) - # Ignore fees for sake of comparison - round_balance = math.ceil(bal*100)/100 - return round_balance - def verify_utxos(node, amts, zaddr): amts.sort(reverse=True) txs = node.z_listreceivedbyaddress(zaddr) @@ -60,6 +56,12 @@ class ZkeyImportExportTest (BitcoinTestFramework): try: assert_equal(amts, [tx["amount"] for tx in txs]) + for tx in txs: + # make sure JoinSplit keys exist and have valid values + assert_equal("jsindex" in tx, True) + assert_equal("jsoutindex" in tx, True) + assert_greater_than(tx["jsindex"], -1) + assert_greater_than(tx["jsoutindex"], -1) except AssertionError: logging.error( 'Expected amounts: %r; txs: %r', @@ -107,27 +109,27 @@ class ZkeyImportExportTest (BitcoinTestFramework): z_send(alice, alice_zaddr, bob_zaddr, amount) logging.info("Exporting privkey from bob...") - privkey = bob.z_exportkey(bob_zaddr) + bob_privkey = bob.z_exportkey(bob_zaddr) logging.info("Sending post-export txns...") for amount in amounts[2:4]: z_send(alice, alice_zaddr, bob_zaddr, amount) - print("Bob amounts:", amounts[:4]) verify_utxos(bob, amounts[:4], bob_zaddr) # verify_utxos(charlie, []) - logging.info("Importing privkey into charlie...") + logging.info("Importing bob_privkey into charlie...") # z_importkey rescan defaults to "whenkeyisnew", so should rescan here - charlie.z_importkey(privkey) + charlie.z_importkey(bob_privkey) ipk_zaddr = find_imported_key(charlie, bob_zaddr) # z_importkey should have rescanned for new key, so this should pass: verify_utxos(charlie, amounts[:4], ipk_zaddr) # Verify idempotent behavior: - charlie.z_importkey(privkey) + charlie.z_importkey(bob_privkey) ipk_zaddr2 = find_imported_key(charlie, bob_zaddr) + assert_equal(ipk_zaddr, ipk_zaddr2) # amounts should be unchanged verify_utxos(charlie, amounts[:4], ipk_zaddr2) @@ -140,22 +142,26 @@ class ZkeyImportExportTest (BitcoinTestFramework): verify_utxos(charlie, amounts, ipk_zaddr) verify_utxos(charlie, amounts, ipk_zaddr2) + # keep track of the fees incurred by bob (his sends) + bob_fee = Decimal(0) + # Try to reproduce zombie balance reported in #1936 # At generated zaddr, receive ZEC, and send ZEC back out. bob -> alice for amount in amounts[:2]: print("Sending amount from bob to alice: ", amount) z_send(bob, bob_zaddr, alice_zaddr, amount) + bob_fee += fee - balance = float(sum(amounts) - sum(amounts[:2])) - assert_equal(z_getbalance(bob, bob_zaddr), balance) + bob_balance = sum(amounts[2:]) - bob_fee + assert_equal(bob.z_getbalance(bob_zaddr), bob_balance) # z_import onto new node "david" (blockchain rescan, default or True?) - david.z_importkey(privkey) + david.z_importkey(bob_privkey) d_ipk_zaddr = find_imported_key(david, bob_zaddr) # Check if amt bob spent is deducted for charlie and david - assert_equal(z_getbalance(charlie, ipk_zaddr), balance) - assert_equal(z_getbalance(david, d_ipk_zaddr), balance) + assert_equal(charlie.z_getbalance(ipk_zaddr), bob_balance) + assert_equal(david.z_getbalance(d_ipk_zaddr), bob_balance) if __name__ == '__main__': ZkeyImportExportTest().main() diff --git a/qa/zcash/create_benchmark_archive.py b/qa/zcash/create_benchmark_archive.py index 67ad5b101..84bd236de 100644 --- a/qa/zcash/create_benchmark_archive.py +++ b/qa/zcash/create_benchmark_archive.py @@ -5,7 +5,6 @@ import plyvel import progressbar import os import stat -import struct import subprocess import sys import tarfile diff --git a/qa/zcash/full_test_suite.py b/qa/zcash/full_test_suite.py index d8a076420..0e8605cc3 100755 --- a/qa/zcash/full_test_suite.py +++ b/qa/zcash/full_test_suite.py @@ -4,6 +4,7 @@ # import argparse +from glob import glob import os import re import subprocess @@ -62,12 +63,18 @@ def check_security_hardening(): # PIE, RELRO, Canary, and NX are tested by make check-security. ret &= subprocess.call(['make', '-C', repofile('src'), 'check-security']) == 0 + # The remaining checks are only for ELF binaries + # Assume that if zcashd is an ELF binary, they all are + with open(repofile('src/zcashd'), 'rb') as f: + magic = f.read(4) + if not magic.startswith(b'\x7fELF'): + return ret + ret &= test_rpath_runpath('src/zcashd') ret &= test_rpath_runpath('src/zcash-cli') ret &= test_rpath_runpath('src/zcash-gtest') ret &= test_rpath_runpath('src/zcash-tx') ret &= test_rpath_runpath('src/test/test_bitcoin') - ret &= test_rpath_runpath('src/zcash/GenerateParams') # NOTE: checksec.sh does not reliably determine whether FORTIFY_SOURCE # is enabled for the entire binary. See issue #915. @@ -76,16 +83,18 @@ def check_security_hardening(): ret &= test_fortify_source('src/zcash-gtest') ret &= test_fortify_source('src/zcash-tx') ret &= test_fortify_source('src/test/test_bitcoin') - ret &= test_fortify_source('src/zcash/GenerateParams') return ret def ensure_no_dot_so_in_depends(): - arch_dir = os.path.join( - REPOROOT, - 'depends', - 'x86_64-unknown-linux-gnu', - ) + depends_dir = os.path.join(REPOROOT, 'depends') + arch_dir = os.path.join(depends_dir, 'x86_64-unknown-linux-gnu') + if not os.path.isdir(arch_dir): + # Not Linux, try MacOS + arch_dirs = glob(os.path.join(depends_dir, 'x86_64-apple-darwin*')) + if arch_dirs: + # Just try the first one; there will only be on in CI + arch_dir = arch_dirs[0] exit_code = 0 @@ -99,7 +108,7 @@ def ensure_no_dot_so_in_depends(): exit_code = 1 else: exit_code = 2 - print "arch-specific build dir not present: {}".format(arch_dir) + print "arch-specific build dir not present" print "Did you build the ./depends tree?" print "Are you on a currently unsupported architecture?" diff --git a/src/Makefile.am b/src/Makefile.am index 4d68a24c9..fd02d4732 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,7 @@ DIST_SUBDIRS = secp256k1 univalue cryptoconditions AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(SAN_LDFLAGS) $(HARDENED_LDFLAGS) AM_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) $(ERROR_CXXFLAGS) AM_CPPFLAGS = $(HARDENED_CPPFLAGS) +EXTRA_LIBRARIES = if EMBEDDED_LEVELDB LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include @@ -20,7 +21,7 @@ $(LIBLEVELDB) $(LIBMEMENV): endif BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config -BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) +BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/include @@ -34,7 +35,7 @@ endif if TARGET_DARWIN LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl else -LIBBITCOIN_SERVER=libbitcoin_server.a +LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl endif LIBBITCOIN_WALLET=libbitcoin_wallet.a @@ -48,57 +49,68 @@ LIBSECP256K1=secp256k1/libsecp256k1.la LIBCRYPTOCONDITIONS=cryptoconditions/libcryptoconditions_core.la LIBSNARK=snark/libsnark.a LIBUNIVALUE=univalue/libunivalue.la -LIBZCASH=libzcash.a -lcurl +LIBZCASH=libzcash.a + +if ENABLE_ZMQ +LIBBITCOIN_ZMQ=libbitcoin_zmq.a +endif +if ENABLE_PROTON +LIBBITCOIN_PROTON=libbitcoin_proton.a +endif +if BUILD_BITCOIN_LIBS +LIBZCASH_CONSENSUS=libzcashconsensus.la +endif +if ENABLE_WALLET +LIBBITCOIN_WALLET=libbitcoin_wallet.a +endif $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=x86-64 -g " -LIBSNARK_CXXFLAGS = -fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 -fstack-protector-all +LIBSNARK_CXXFLAGS = $(AM_CXXFLAGS) $(PIC_FLAGS) -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1 -fstack-protector-all LIBSNARK_CONFIG_FLAGS = CURVE=ALT_BN128 NO_PROCPS=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT NO_COPY_DEPINST=1 NO_COMPILE_LIBGTEST=1 if HAVE_OPENMP LIBSNARK_CONFIG_FLAGS += MULTICORE=1 endif +if TARGET_DARWIN +LIBSNARK_CONFIG_FLAGS += PLATFORM=darwin +endif $(LIBSNARK): $(wildcard snark/src/*) - $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64 -g " + $(AM_V_at) CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" libsnark-tests: $(wildcard snark/src/*) - $(AM_V_at) CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64 -g " + $(AM_V_at) CC="$(CC)" CXX="$(CXX)" AR="$(AR)" CXXFLAGS="$(LIBSNARK_CXXFLAGS)" $(MAKE) $(AM_MAKEFLAGS) -C snark/ check DEPINST="$(LIBSNARK_DEPINST)" $(LIBSNARK_CONFIG_FLAGS) OPTFLAGS="-O2 -march=x86-64" $(LIBUNIVALUE): $(wildcard univalue/lib/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/ OPTFLAGS="-O2 -march=x86-64 -g " + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=x86-64 -g " $(LIBCRYPTOCONDITIONS): $(wildcard cryptoconditions/src/*) $(wildcard cryptoconditions/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) OPTFLAGS="-O2 -march=x86-64 -g " # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: -EXTRA_LIBRARIES = \ - crypto/libbitcoin_crypto.a \ - crypto/libverus_crypto.a \ - crypto/libverus_portable_crypto.a \ - libbitcoin_util.a \ - libbitcoin_common.a \ - libbitcoin_server.a \ - libbitcoin_cli.a \ +EXTRA_LIBRARIES += \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBVERUS_CRYPTO) \ + $(LIBVERUS_PORTABLE_CRYPTO) \ + $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_CLI) \ libzcash.a if ENABLE_WALLET BITCOIN_INCLUDES += $(BDB_CPPFLAGS) -EXTRA_LIBRARIES += libbitcoin_wallet.a +EXTRA_LIBRARIES += $(LIBBITCOIN_WALLET) endif if ENABLE_ZMQ -EXTRA_LIBRARIES += libbitcoin_zmq.a +EXTRA_LIBRARIES += $(LIBBITCOIN_ZMQ) endif if ENABLE_PROTON -EXTRA_LIBRARIES += libbitcoin_proton.a +EXTRA_LIBRARIES += $(LIBBITCOIN_PROTON) endif -if BUILD_BITCOIN_LIBS -lib_LTLIBRARIES = libzcashconsensus.la -LIBZCASH_CONSENSUS=libzcashconsensus.la -else -LIBZCASH_CONSENSUS= -endif +lib_LTLIBRARIES = $(LIBZCASH_CONSENSUS) bin_PROGRAMS = noinst_PROGRAMS = @@ -125,7 +137,8 @@ LIBZCASH_H = \ zcash/prf.h \ zcash/Proof.hpp \ zcash/util.h \ - zcash/Zcash.h + zcash/Zcash.h \ + zcash/zip32.h .PHONY: FORCE collate-libsnark check-symbols check-security # bitcoin core # @@ -144,6 +157,7 @@ BITCOIN_CORE_H = \ asyncrpcoperation.h \ asyncrpcqueue.h \ base58.h \ + bech32.h \ bloom.h \ cc/eval.h \ chain.h \ @@ -175,8 +189,9 @@ BITCOIN_CORE_H = \ httpserver.h \ init.h \ key.h \ + key_io.h \ keystore.h \ - leveldbwrapper.h \ + dbwrapper.h \ limitedmap.h \ main.h \ memusage.h \ @@ -191,6 +206,7 @@ BITCOIN_CORE_H = \ paymentdisclosuredb.h \ policy/fees.h \ pow.h \ + prevector.h \ primitives/block.h \ primitives/transaction.h \ primitives/nonce.h \ @@ -198,9 +214,10 @@ BITCOIN_CORE_H = \ pubkey.h \ random.h \ reverselock.h \ - rpcclient.h \ - rpcprotocol.h \ - rpcserver.h \ + rpc/client.h \ + rpc/protocol.h \ + rpc/server.h \ + rpc/register.h \ scheduler.h \ script/interpreter.h \ script/script.h \ @@ -220,6 +237,7 @@ BITCOIN_CORE_H = \ timedata.h \ tinyformat.h \ torcontrol.h \ + transaction_builder.h \ txdb.h \ txmempool.h \ ui_interface.h \ @@ -237,6 +255,7 @@ BITCOIN_CORE_H = \ wallet/asyncrpcoperation_shieldcoinbase.h \ wallet/crypter.h \ wallet/db.h \ + wallet/rpcwallet.h \ wallet/wallet.h \ wallet/wallet_ismine.h \ wallet/walletdb.h \ @@ -297,10 +316,10 @@ libbitcoin_server_a_SOURCES = \ httprpc.cpp \ httpserver.cpp \ init.cpp \ - leveldbwrapper.cpp \ + dbwrapper.cpp \ main.cpp \ merkleblock.cpp \ - metrics.cpp \ + metrics.h \ miner.cpp \ net.cpp \ noui.cpp \ @@ -310,14 +329,15 @@ libbitcoin_server_a_SOURCES = \ policy/fees.cpp \ pow.cpp \ rest.cpp \ - rpcblockchain.cpp \ - rpccrosschain.cpp \ - rpcmining.cpp \ - rpcmisc.cpp \ - rpcnet.cpp \ - rpcrawtransaction.cpp \ - rpcserver.cpp \ + rpc/blockchain.cpp \ + rpc/crosschain.cpp \ + rpc/mining.cpp \ + rpc/misc.cpp \ + rpc/net.cpp \ + rpc/rawtransaction.cpp \ + rpc/server.cpp \ script/serverchecker.cpp \ + script/sigcache.cpp \ timedata.cpp \ torcontrol.cpp \ txdb.cpp \ @@ -327,8 +347,6 @@ libbitcoin_server_a_SOURCES = \ $(LIBZCASH_H) if ENABLE_ZMQ -LIBBITCOIN_ZMQ=libbitcoin_zmq.a - libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(ZMQ_CFLAGS) libbitcoin_zmq_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_zmq_a_SOURCES = \ @@ -338,8 +356,6 @@ libbitcoin_zmq_a_SOURCES = \ endif if ENABLE_PROTON -LIBBITCOIN_PROTON=libbitcoin_proton.a - libbitcoin_proton_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_proton_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_proton_a_SOURCES = \ @@ -363,6 +379,7 @@ libbitcoin_wallet_a_SOURCES = \ wallet/db.cpp \ paymentdisclosure.cpp \ paymentdisclosuredb.cpp \ + transaction_builder.cpp \ wallet/rpcdisclosure.cpp \ wallet/rpcdump.cpp \ cc/CCassetstx.cpp \ @@ -371,6 +388,7 @@ libbitcoin_wallet_a_SOURCES = \ wallet/wallet.cpp \ wallet/wallet_ismine.cpp \ wallet/walletdb.cpp \ + zcash/zip32.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) @@ -432,6 +450,7 @@ libbitcoin_common_a_SOURCES = \ amount.cpp \ arith_uint256.cpp \ base58.cpp \ + bech32.cpp \ chainparams.cpp \ coins.cpp \ compressor.cpp \ @@ -445,8 +464,10 @@ libbitcoin_common_a_SOURCES = \ hash.cpp \ importcoin.cpp \ key.cpp \ + key_io.cpp \ keystore.cpp \ netbase.cpp \ + metrics.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ primitives/nonce.cpp \ @@ -461,6 +482,7 @@ libbitcoin_common_a_SOURCES = \ script/sign.cpp \ script/standard.cpp \ veruslaunch.cpp \ + transaction_builder.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) @@ -470,23 +492,23 @@ libbitcoin_common_a_SOURCES = \ libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ - support/pagelocker.cpp \ - chainparamsbase.cpp \ - clientversion.cpp \ - compat/glibc_sanity.cpp \ - compat/glibcxx_sanity.cpp \ - compat/strnlen.cpp \ - random.cpp \ - rpcprotocol.cpp \ - support/cleanse.cpp \ - sync.cpp \ - uint256.cpp \ - util.cpp \ - utilmoneystr.cpp \ - utilstrencodings.cpp \ - utiltime.cpp \ - $(BITCOIN_CORE_H) \ - $(LIBZCASH_H) + support/pagelocker.cpp \ + chainparamsbase.cpp \ + clientversion.cpp \ + compat/glibc_sanity.cpp \ + compat/glibcxx_sanity.cpp \ + compat/strnlen.cpp \ + random.cpp \ + rpc/protocol.cpp \ + support/cleanse.cpp \ + sync.cpp \ + uint256.cpp \ + util.cpp \ + utilmoneystr.cpp \ + utilstrencodings.cpp \ + utiltime.cpp \ + $(BITCOIN_CORE_H) \ + $(LIBZCASH_H) if GLIBC_BACK_COMPAT libbitcoin_util_a_SOURCES += compat/glibc_compat.cpp @@ -496,9 +518,9 @@ endif libbitcoin_cli_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_cli_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_cli_a_SOURCES = \ - rpcclient.cpp \ - $(BITCOIN_CORE_H) \ - $(LIBZCASH_H) + rpc/client.cpp \ + $(BITCOIN_CORE_H) \ + $(LIBZCASH_H) nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h # @@ -518,6 +540,8 @@ komodod_LDADD = \ $(LIBBITCOIN_COMMON) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_ZMQ) \ + $(LIBBITCOIN_PROTON) \ $(LIBBITCOIN_CRYPTO) \ $(LIBVERUS_CRYPTO) \ $(LIBVERUS_PORTABLE_CRYPTO) \ @@ -528,12 +552,8 @@ komodod_LDADD = \ $(LIBSECP256K1) \ $(LIBCRYPTOCONDITIONS) -if ENABLE_ZMQ -komodod_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) -endif - if ENABLE_WALLET -komodod_LDADD += libbitcoin_wallet.a +komodod_LDADD += $(LIBBITCOIN_WALLET) endif komodod_LDADD += \ @@ -543,6 +563,8 @@ komodod_LDADD += \ $(CRYPTO_LIBS) \ $(EVENT_PTHREADS_LIBS) \ $(EVENT_LIBS) \ + $(ZMQ_LIBS) \ + $(PROTON_LIBS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBVERUS_CRYPTO) \ $(LIBVERUS_PORTABLE_CRYPTO) \ @@ -639,6 +661,7 @@ libzcash_a_SOURCES = \ zcash/Note.cpp \ zcash/prf.cpp \ zcash/util.cpp \ + zcash/zip32.cpp \ zcash/circuit/commitment.tcc \ zcash/circuit/gadget.tcc \ zcash/circuit/merkle.tcc \ @@ -648,6 +671,10 @@ libzcash_a_SOURCES = \ libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) $(HARDENED_CXXFLAGS) $(HARDENED_LDFLAGS) -pipe $(SAN_LDFLAGS) -O1 -g -Wstack-protector $(SAN_CXXFLAGS) -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES) +#libzcash_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +#libzcash_a_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +#libzcash_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMONTGOMERY_OUTPUT + libzcash_a_CXXFLAGS = $(SAN_CXXFLAGS) $(HARDENED_CXXFLAGS) -fwrapv -fno-strict-aliasing libzcash_a_LDFLAGS = $(SAN_LDFLAGS) $(HARDENED_LDFLAGS) libzcash_a_CPPFLAGS += -DMONTGOMERY_OUTPUT @@ -694,6 +721,7 @@ clean-local: -$(MAKE) -C leveldb clean -$(MAKE) -C secp256k1 clean -$(MAKE) -C snark clean + -$(MAKE) -C univalue clean rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno -rm -f config.h @@ -726,5 +754,3 @@ include Makefile.ktest.include #include Makefile.test.include #include Makefile.gtest.include endif - -include Makefile.zcash.include diff --git a/src/Makefile.gtest.include b/src/Makefile.gtest.include index b424fd41f..ec3a4a12e 100644 --- a/src/Makefile.gtest.include +++ b/src/Makefile.gtest.include @@ -23,6 +23,7 @@ zcash_gtest_SOURCES += \ gtest/test_equihash.cpp \ gtest/test_httprpc.cpp \ gtest/test_joinsplit.cpp \ + gtest/test_keys.cpp \ gtest/test_keystore.cpp \ gtest/test_noteencryption.cpp \ gtest/test_mempool.cpp \ @@ -32,7 +33,9 @@ zcash_gtest_SOURCES += \ gtest/test_pow.cpp \ gtest/test_random.cpp \ gtest/test_rpc.cpp \ + gtest/test_sapling_note.cpp \ gtest/test_transaction.cpp \ + gtest/test_transaction_builder.cpp \ gtest/test_upgrades.cpp \ gtest/test_validation.cpp \ gtest/test_circuit.cpp \ @@ -40,7 +43,9 @@ zcash_gtest_SOURCES += \ gtest/test_libzcash_utils.cpp \ gtest/test_proofs.cpp \ gtest/test_paymentdisclosure.cpp \ - gtest/test_checkblock.cpp + gtest/test_pedersen_hash.cpp \ + gtest/test_checkblock.cpp \ + gtest/test_zip32.cpp if ENABLE_WALLET zcash_gtest_SOURCES += \ wallet/gtest/test_wallet.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 2769e120c..1f9f9ac1e 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -20,78 +20,89 @@ EXTRA_DIST += \ test/data/wallet.dat JSON_TEST_FILES = \ - test/data/script_valid.json \ - test/data/base58_keys_valid.json \ - test/data/base58_encode_decode.json \ - test/data/base58_keys_invalid.json \ - test/data/script_invalid.json \ - test/data/tx_invalid.json \ - test/data/tx_valid.json \ - test/data/sighash.json \ - test/data/merkle_roots.json \ - test/data/merkle_roots_empty.json \ - test/data/merkle_serialization.json \ - test/data/merkle_witness_serialization.json \ - test/data/merkle_path.json \ - test/data/merkle_commitments.json \ - test/data/g1_compressed.json \ - test/data/g2_compressed.json + test/data/script_valid.json \ + test/data/base58_keys_valid.json \ + test/data/base58_encode_decode.json \ + test/data/base58_keys_invalid.json \ + test/data/script_invalid.json \ + test/data/tx_invalid.json \ + test/data/tx_valid.json \ + test/data/sighash.json \ + test/data/merkle_roots.json \ + test/data/merkle_roots_empty.json \ + test/data/merkle_serialization.json \ + test/data/merkle_witness_serialization.json \ + test/data/merkle_path.json \ + test/data/merkle_commitments.json \ + test/data/merkle_roots_sapling.json \ + test/data/merkle_roots_empty_sapling.json \ + test/data/merkle_serialization_sapling.json \ + test/data/merkle_witness_serialization_sapling.json \ + test/data/merkle_path_sapling.json \ + test/data/merkle_commitments_sapling.json \ + test/data/g1_compressed.json \ + test/data/g2_compressed.json \ + test/data/sapling_key_components.json RAW_TEST_FILES = test/data/alertTests.raw GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) BITCOIN_TESTS =\ - test/arith_uint256_tests.cpp \ - test/bignum.h \ - test/addrman_tests.cpp \ - test/allocator_tests.cpp \ - test/base32_tests.cpp \ - test/base58_tests.cpp \ - test/base64_tests.cpp \ - test/bip32_tests.cpp \ - test/bloom_tests.cpp \ - test/checkblock_tests.cpp \ - test/Checkpoints_tests.cpp \ - test/coins_tests.cpp \ - test/compress_tests.cpp \ - test/crypto_tests.cpp \ - test/DoS_tests.cpp \ - test/equihash_tests.cpp \ - test/getarg_tests.cpp \ - test/hash_tests.cpp \ - test/key_tests.cpp \ - test/main_tests.cpp \ - test/mempool_tests.cpp \ - test/miner_tests.cpp \ - test/mruset_tests.cpp \ - test/multisig_tests.cpp \ - test/netbase_tests.cpp \ - test/pmt_tests.cpp \ - test/policyestimator_tests.cpp \ - test/pow_tests.cpp \ - test/raii_event_tests.cpp \ - test/reverselock_tests.cpp \ - test/rpc_tests.cpp \ - test/sanity_tests.cpp \ - test/scheduler_tests.cpp \ - test/script_P2SH_tests.cpp \ - test/script_P2PKH_tests.cpp \ - test/script_tests.cpp \ - test/scriptnum_tests.cpp \ - test/serialize_tests.cpp \ - test/sighash_tests.cpp \ - test/sigopcount_tests.cpp \ - test/skiplist_tests.cpp \ - test/test_bitcoin.cpp \ - test/test_bitcoin.h \ - test/timedata_tests.cpp \ - test/torcontrol_tests.cpp \ - test/transaction_tests.cpp \ - test/uint256_tests.cpp \ - test/univalue_tests.cpp \ - test/util_tests.cpp \ - test/sha256compress_tests.cpp + test/arith_uint256_tests.cpp \ + test/bignum.h \ + test/addrman_tests.cpp \ + test/alert_tests.cpp \ + test/allocator_tests.cpp \ + test/base32_tests.cpp \ + test/base58_tests.cpp \ + test/base64_tests.cpp \ + test/bech32_tests.cpp \ + test/bip32_tests.cpp \ + test/bloom_tests.cpp \ + test/checkblock_tests.cpp \ + test/Checkpoints_tests.cpp \ + test/coins_tests.cpp \ + test/compress_tests.cpp \ + test/convertbits_tests.cpp \ + test/crypto_tests.cpp \ + test/DoS_tests.cpp \ + test/equihash_tests.cpp \ + test/getarg_tests.cpp \ + test/hash_tests.cpp \ + test/key_tests.cpp \ + test/dbwrapper_tests.cpp \ + test/main_tests.cpp \ + test/mempool_tests.cpp \ + test/miner_tests.cpp \ + test/mruset_tests.cpp \ + test/multisig_tests.cpp \ + test/netbase_tests.cpp \ + test/pmt_tests.cpp \ + test/policyestimator_tests.cpp \ + test/pow_tests.cpp \ + test/prevector_tests.cpp \ + test/raii_event_tests.cpp \ + test/reverselock_tests.cpp \ + test/rpc_tests.cpp \ + test/sanity_tests.cpp \ + test/scheduler_tests.cpp \ + test/script_P2SH_tests.cpp \ + test/script_tests.cpp \ + test/scriptnum_tests.cpp \ + test/serialize_tests.cpp \ + test/sighash_tests.cpp \ + test/sigopcount_tests.cpp \ + test/skiplist_tests.cpp \ + test/test_bitcoin.cpp \ + test/test_bitcoin.h \ + test/timedata_tests.cpp \ + test/torcontrol_tests.cpp \ + test/transaction_tests.cpp \ + test/uint256_tests.cpp \ + test/univalue_tests.cpp \ + test/util_tests.cpp \ + test/sha256compress_tests.cpp if ENABLE_WALLET BITCOIN_TESTS += \ @@ -108,6 +119,9 @@ test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif +test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \ + $(LIBLEVELDB) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) +test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_bitcoin_LDADD += $(LIBZCASH_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(LIBZCASH) $(LIBSNARK) $(LIBZCASH_LIBS) test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static diff --git a/src/addrman.h b/src/addrman.h index 0483e8bdb..5c77a4fdb 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -54,7 +54,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(*(CAddress*)this); READWRITE(source); READWRITE(nLastSuccess); @@ -279,7 +279,7 @@ public: * very little in common. */ template - void Serialize(Stream &s, int nType, int nVersionDummy) const + void Serialize(Stream &s) const { LOCK(cs); @@ -329,7 +329,7 @@ public: } template - void Unserialize(Stream& s, int nType, int nVersionDummy) + void Unserialize(Stream& s) { LOCK(cs); @@ -434,11 +434,6 @@ public: Check(); } - unsigned int GetSerializeSize(int nType, int nVersion) const - { - return (CSizeComputer(nType, nVersion) << *this).size(); - } - void Clear() { std::vector().swap(vRandom); diff --git a/src/alert.h b/src/alert.h index 76d8d916e..4e3b88775 100644 --- a/src/alert.h +++ b/src/alert.h @@ -49,9 +49,8 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); - nVersion = this->nVersion; READWRITE(nRelayUntil); READWRITE(nExpiration); READWRITE(nID); @@ -87,7 +86,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vchMsg); READWRITE(vchSig); } diff --git a/src/amount.h b/src/amount.h index 9b62f7663..7423fdaa1 100644 --- a/src/amount.h +++ b/src/amount.h @@ -58,7 +58,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nSatoshisPerK); } }; diff --git a/src/asyncrpcoperation.cpp b/src/asyncrpcoperation.cpp index f32e8d716..ff5c4cb9f 100644 --- a/src/asyncrpcoperation.cpp +++ b/src/asyncrpcoperation.cpp @@ -16,7 +16,7 @@ using namespace std; static boost::uuids::random_generator uuidgen; -std::map OperationStatusMap = { +static std::map OperationStatusMap = { {OperationStatus::READY, "queued"}, {OperationStatus::EXECUTING, "executing"}, {OperationStatus::CANCELLED, "cancelled"}, diff --git a/src/base58.cpp b/src/base58.cpp index b85803569..50697fb9e 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -4,15 +4,12 @@ #include "base58.h" -#include "hash.h" -#include "uint256.h" - -#include "version.h" -#include "streams.h" +#include +#include #include -#include #include +#include #include #include #include @@ -104,7 +101,7 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) std::string EncodeBase58(const std::vector& vch) { - return EncodeBase58(&vch[0], &vch[0] + vch.size()); + return EncodeBase58(vch.data(), vch.data() + vch.size()); } bool DecodeBase58(const std::string& str, std::vector& vchRet) @@ -143,6 +140,7 @@ bool DecodeBase58Check(const std::string& str, std::vector& vchRe return DecodeBase58Check(str.c_str(), vchRet); } + CBase58Data::CBase58Data() { vchVersion.clear(); @@ -381,27 +379,3 @@ DATA_TYPE CZCEncoding::Get() const ss >> ret; return ret; } - -// Explicit instantiations for libzcash::PaymentAddress -template bool CZCEncoding::Set(const libzcash::PaymentAddress& addr); -template libzcash::PaymentAddress CZCEncoding::Get() const; - -// Explicit instantiations for libzcash::ViewingKey -template bool CZCEncoding::Set(const libzcash::ViewingKey& vk); -template libzcash::ViewingKey CZCEncoding::Get() const; - -// Explicit instantiations for libzcash::SpendingKey -template bool CZCEncoding::Set(const libzcash::SpendingKey& sk); -template libzcash::SpendingKey CZCEncoding::Get() const; diff --git a/src/base58.h b/src/base58.h index 4e8b2c3ce..1f9002e0f 100644 --- a/src/base58.h +++ b/src/base58.h @@ -58,13 +58,13 @@ std::string EncodeBase58Check(const std::vector& vchIn); * Decode a base58-encoded string (psz) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful */ -inline bool DecodeBase58Check(const char* psz, std::vector& vchRet); +bool DecodeBase58Check(const char* psz, std::vector& vchRet); /** * Decode a base58-encoded string (str) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful */ -inline bool DecodeBase58Check(const std::string& str, std::vector& vchRet); +bool DecodeBase58Check(const std::string& str, std::vector& vchRet); /** * Base class for all base58-encoded data @@ -107,39 +107,6 @@ public: DATA_TYPE Get() const; }; -class CZCPaymentAddress : public CZCEncoding { -protected: - std::string PrependName(const std::string& s) const { return "payment address" + s; } - -public: - CZCPaymentAddress() {} - - CZCPaymentAddress(const std::string& strAddress) { SetString(strAddress.c_str(), 2); } - CZCPaymentAddress(const libzcash::PaymentAddress& addr) { Set(addr); } -}; - -class CZCViewingKey : public CZCEncoding { -protected: - std::string PrependName(const std::string& s) const { return "viewing key" + s; } - -public: - CZCViewingKey() {} - - CZCViewingKey(const std::string& strViewingKey) { SetString(strViewingKey.c_str(), 3); } - CZCViewingKey(const libzcash::ViewingKey& vk) { Set(vk); } -}; - -class CZCSpendingKey : public CZCEncoding { -protected: - std::string PrependName(const std::string& s) const { return "spending key" + s; } - -public: - CZCSpendingKey() {} - - CZCSpendingKey(const std::string& strAddress) { SetString(strAddress.c_str(), 2); } - CZCSpendingKey(const libzcash::SpendingKey& addr) { Set(addr); } -}; - /** base58-encoded Bitcoin addresses. * Public-key-hash-addresses have version 0 (or 111 testnet). * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. diff --git a/src/bech32.cpp b/src/bech32.cpp new file mode 100644 index 000000000..78c35b976 --- /dev/null +++ b/src/bech32.cpp @@ -0,0 +1,194 @@ +// Copyright (c) 2017 Pieter Wuille +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bech32.h" + +namespace +{ + +typedef std::vector data; + +/** The Bech32 character set for encoding. */ +const char* CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +/** The Bech32 character set for decoding. */ +const int8_t CHARSET_REV[128] = { + -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, + 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 +}; + +/** Concatenate two byte arrays. */ +data Cat(data x, const data& y) +{ + x.insert(x.end(), y.begin(), y.end()); + return x; +} + +/** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to + * make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher + * bits correspond to earlier values. */ +uint32_t PolyMod(const data& v) +{ + // The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an + // implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) = + // 1*x^5 + v0*x^4 + v1*x^3 + v2*x^2 + v3*x + v4. The implicit 1 guarantees that + // [v0,v1,v2,...] has a distinct checksum from [0,v0,v1,v2,...]. + + // The output is a 30-bit integer whose 5-bit groups are the coefficients of the remainder of + // v(x) mod g(x), where g(x) is the Bech32 generator, + // x^6 + {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18}. g(x) is chosen in such a way + // that the resulting code is a BCH code, guaranteeing detection of up to 3 errors within a + // window of 1023 characters. Among the various possible BCH codes, one was selected to in + // fact guarantee detection of up to 4 errors within a window of 89 characters. + + // Note that the coefficients are elements of GF(32), here represented as decimal numbers + // between {}. In this finite field, addition is just XOR of the corresponding numbers. For + // example, {27} + {13} = {27 ^ 13} = {22}. Multiplication is more complicated, and requires + // treating the bits of values themselves as coefficients of a polynomial over a smaller field, + // GF(2), and multiplying those polynomials mod a^5 + a^3 + 1. For example, {5} * {26} = + // (a^2 + 1) * (a^4 + a^3 + a) = (a^4 + a^3 + a) * a^2 + (a^4 + a^3 + a) = a^6 + a^5 + a^4 + a + // = a^3 + 1 (mod a^5 + a^3 + 1) = {9}. + + // During the course of the loop below, `c` contains the bitpacked coefficients of the + // polynomial constructed from just the values of v that were processed so far, mod g(x). In + // the above example, `c` initially corresponds to 1 mod (x), and after processing 2 inputs of + // v, it corresponds to x^2 + v0*x + v1 mod g(x). As 1 mod g(x) = 1, that is the starting value + // for `c`. + uint32_t c = 1; + for (auto v_i : v) { + // We want to update `c` to correspond to a polynomial with one extra term. If the initial + // value of `c` consists of the coefficients of c(x) = f(x) mod g(x), we modify it to + // correspond to c'(x) = (f(x) * x + v_i) mod g(x), where v_i is the next input to + // process. Simplifying: + // c'(x) = (f(x) * x + v_i) mod g(x) + // ((f(x) mod g(x)) * x + v_i) mod g(x) + // (c(x) * x + v_i) mod g(x) + // If c(x) = c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5, we want to compute + // c'(x) = (c0*x^5 + c1*x^4 + c2*x^3 + c3*x^2 + c4*x + c5) * x + v_i mod g(x) + // = c0*x^6 + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i mod g(x) + // = c0*(x^6 mod g(x)) + c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i + // If we call (x^6 mod g(x)) = k(x), this can be written as + // c'(x) = (c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i) + c0*k(x) + + // First, determine the value of c0: + uint8_t c0 = c >> 25; + + // Then compute c1*x^5 + c2*x^4 + c3*x^3 + c4*x^2 + c5*x + v_i: + c = ((c & 0x1ffffff) << 5) ^ v_i; + + // Finally, for each set bit n in c0, conditionally add {2^n}k(x): + if (c0 & 1) c ^= 0x3b6a57b2; // k(x) = {29}x^5 + {22}x^4 + {20}x^3 + {21}x^2 + {29}x + {18} + if (c0 & 2) c ^= 0x26508e6d; // {2}k(x) = {19}x^5 + {5}x^4 + x^3 + {3}x^2 + {19}x + {13} + if (c0 & 4) c ^= 0x1ea119fa; // {4}k(x) = {15}x^5 + {10}x^4 + {2}x^3 + {6}x^2 + {15}x + {26} + if (c0 & 8) c ^= 0x3d4233dd; // {8}k(x) = {30}x^5 + {20}x^4 + {4}x^3 + {12}x^2 + {30}x + {29} + if (c0 & 16) c ^= 0x2a1462b3; // {16}k(x) = {21}x^5 + x^4 + {8}x^3 + {24}x^2 + {21}x + {19} + } + return c; +} + +/** Convert to lower case. */ +inline unsigned char LowerCase(unsigned char c) +{ + return (c >= 'A' && c <= 'Z') ? (c - 'A') + 'a' : c; +} + +/** Expand a HRP for use in checksum computation. */ +data ExpandHRP(const std::string& hrp) +{ + data ret; + ret.reserve(hrp.size() + 90); + ret.resize(hrp.size() * 2 + 1); + for (size_t i = 0; i < hrp.size(); ++i) { + unsigned char c = hrp[i]; + ret[i] = c >> 5; + ret[i + hrp.size() + 1] = c & 0x1f; + } + ret[hrp.size()] = 0; + return ret; +} + +/** Verify a checksum. */ +bool VerifyChecksum(const std::string& hrp, const data& values) +{ + // PolyMod computes what value to xor into the final values to make the checksum 0. However, + // if we required that the checksum was 0, it would be the case that appending a 0 to a valid + // list of values would result in a new valid list. For that reason, Bech32 requires the + // resulting checksum to be 1 instead. + return PolyMod(Cat(ExpandHRP(hrp), values)) == 1; +} + +/** Create a checksum. */ +data CreateChecksum(const std::string& hrp, const data& values) +{ + data enc = Cat(ExpandHRP(hrp), values); + enc.resize(enc.size() + 6); // Append 6 zeroes + uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes. + data ret(6); + for (size_t i = 0; i < 6; ++i) { + // Convert the 5-bit groups in mod to checksum values. + ret[i] = (mod >> (5 * (5 - i))) & 31; + } + return ret; +} + +} // namespace + +namespace bech32 +{ + +/** Encode a Bech32 string. */ +std::string Encode(const std::string& hrp, const data& values) { + data checksum = CreateChecksum(hrp, values); + data combined = Cat(values, checksum); + std::string ret = hrp + '1'; + ret.reserve(ret.size() + combined.size()); + for (auto c : combined) { + if (c >= 32) { + return ""; + } + ret += CHARSET[c]; + } + return ret; +} + +/** Decode a Bech32 string. */ +std::pair Decode(const std::string& str) { + bool lower = false, upper = false; + for (size_t i = 0; i < str.size(); ++i) { + unsigned char c = str[i]; + if (c < 33 || c > 126) return {}; + if (c >= 'a' && c <= 'z') lower = true; + if (c >= 'A' && c <= 'Z') upper = true; + } + if (lower && upper) return {}; + size_t pos = str.rfind('1'); + if (str.size() > 1023 || pos == str.npos || pos == 0 || pos + 7 > str.size()) { + return {}; + } + data values(str.size() - 1 - pos); + for (size_t i = 0; i < str.size() - 1 - pos; ++i) { + unsigned char c = str[i + pos + 1]; + int8_t rev = (c < 33 || c > 126) ? -1 : CHARSET_REV[c]; + if (rev == -1) { + return {}; + } + values[i] = rev; + } + std::string hrp; + for (size_t i = 0; i < pos; ++i) { + hrp += LowerCase(str[i]); + } + if (!VerifyChecksum(hrp, values)) { + return {}; + } + return {hrp, data(values.begin(), values.end() - 6)}; +} + +} // namespace bech32 diff --git a/src/bech32.h b/src/bech32.h new file mode 100644 index 000000000..2e2823e97 --- /dev/null +++ b/src/bech32.h @@ -0,0 +1,30 @@ +// Copyright (c) 2017 Pieter Wuille +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Bech32 is a string encoding format used in newer address types. +// The output consists of a human-readable part (alphanumeric), a +// separator character (1), and a base32 data section, the last +// 6 characters of which are a checksum. +// +// For more information, see BIP 173. + +#ifndef BITCOIN_BECH32_H +#define BITCOIN_BECH32_H + +#include +#include +#include + +namespace bech32 +{ + +/** Encode a Bech32 string. Returns the empty string in case of failure. */ +std::string Encode(const std::string& hrp, const std::vector& values); + +/** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */ +std::pair> Decode(const std::string& str); + +} // namespace bech32 + +#endif // BITCOIN_BECH32_H diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index bf189e483..5d818eb5b 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -5,8 +5,8 @@ #include "chainparamsbase.h" #include "clientversion.h" -#include "rpcclient.h" -#include "rpcprotocol.h" +#include "rpc/client.h" +#include "rpc/protocol.h" #include "util.h" #include "utilstrencodings.h" @@ -21,14 +21,12 @@ using namespace std; -int64_t MAX_MONEY = 200000000 * 100000000LL; -uint64_t komodo_maxallowed(int32_t baseid) { return(100000000LL * 1000000); } // stub - static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; +static const int CONTINUE_EXECUTION=-1; std::string HelpMessageCli() { - string strUsage; + std::string strUsage; strUsage += HelpMessageGroup(_("Options:")); strUsage += HelpMessageOpt("-?", _("This help message")); strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), "komodo.conf")); @@ -42,6 +40,7 @@ std::string HelpMessageCli() strUsage += HelpMessageOpt("-rpcuser=", _("Username for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcpassword=", _("Password for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcclienttimeout=", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT)); + strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)")); return strUsage; } @@ -86,8 +85,16 @@ uint32_t komodo_heightstamp(int32_t height) return(0); } -static bool AppInitRPC(int argc, char* argv[]) +// +// This function returns either one of EXIT_ codes when it's expected to stop the process or +// CONTINUE_EXECUTION when it's expected to continue further. +// +static int AppInitRPC(int argc, char* argv[]) { + static_assert(CONTINUE_EXECUTION != EXIT_FAILURE, + "CONTINUE_EXECUTION should be different from EXIT_FAILURE"); + static_assert(CONTINUE_EXECUTION != EXIT_SUCCESS, + "CONTINUE_EXECUTION should be different from EXIT_SUCCESS"); // // Parameters // @@ -107,29 +114,33 @@ static bool AppInitRPC(int argc, char* argv[]) } fprintf(stdout, "%s", strUsage.c_str()); - return false; + if (argc < 2) { + fprintf(stderr, "Error: too few parameters\n"); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; } if (!boost::filesystem::is_directory(GetDataDir(false))) { fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str()); - return false; + return EXIT_FAILURE; } try { ReadConfigFile(mapArgs, mapMultiArgs); } catch (const std::exception& e) { fprintf(stderr,"Error reading configuration file: %s\n", e.what()); - return false; + return EXIT_FAILURE; } // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause) if (!SelectBaseParamsFromCommandLine()) { fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n"); - return false; + return EXIT_FAILURE; } if (GetBoolArg("-rpcssl", false)) { fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n"); - return false; + return EXIT_FAILURE; } - return true; + return CONTINUE_EXECUTION; } @@ -198,7 +209,7 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx) } #endif -UniValue CallRPC(const string& strMethod, const UniValue& params) +UniValue CallRPC(const std::string& strMethod, const UniValue& params) { std::string host = GetArg("-rpcconnect", "127.0.0.1"); int port = GetArg("-rpcport", BaseParams().RPCPort()); @@ -213,7 +224,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) HTTPReply response; raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response); if (req == NULL) - throw runtime_error("create http request failed"); + throw std::runtime_error("create http request failed"); #if LIBEVENT_VERSION_NUMBER >= 0x02010300 evhttp_request_set_error_cb(req.get(), http_error_cb); #endif @@ -223,7 +234,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) if (mapArgs["-rpcpassword"] == "") { // Try fall back to cookie-based authentication if no password is provided if (!GetAuthCookie(&strRPCUserColonPass)) { - throw runtime_error(strprintf( + throw std::runtime_error(strprintf( _("Could not locate RPC credentials. No authentication cookie could be found,\n" "and no rpcpassword is set in the configuration file (%s)."), GetConfigFile().string().c_str())); @@ -256,26 +267,26 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) if (response.status == 0) throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error)); else if (response.status == HTTP_UNAUTHORIZED) - throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); + throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) - throw runtime_error(strprintf("server returned HTTP error %d", response.status)); + throw std::runtime_error(strprintf("server returned HTTP error %d", response.status)); else if (response.body.empty()) - throw runtime_error("no response from server"); + throw std::runtime_error("no response from server"); // Parse reply UniValue valReply(UniValue::VSTR); if (!valReply.read(response.body)) - throw runtime_error("couldn't parse reply from server"); + throw std::runtime_error("couldn't parse reply from server"); const UniValue& reply = valReply.get_obj(); if (reply.empty()) - throw runtime_error("expected reply to have result, error and id properties"); + throw std::runtime_error("expected reply to have result, error and id properties"); return reply; } int CommandLineRPC(int argc, char *argv[]) { - string strPrint; + std::string strPrint; int nRet = 0; try { // Skip switches @@ -283,15 +294,17 @@ int CommandLineRPC(int argc, char *argv[]) argc--; argv++; } - - // Method - if (argc < 2) - throw runtime_error("too few parameters"); - string strMethod = argv[1]; - - // Parameters default to strings - std::vector strParams(&argv[2], &argv[argc]); - UniValue params = RPCConvertValues(strMethod, strParams); + std::vector args = std::vector(&argv[1], &argv[argc]); + if (GetBoolArg("-stdin", false)) { + // Read one arg per line from stdin and append + std::string line; + while (std::getline(std::cin,line)) + args.push_back(line); + } + if (args.size() < 1) + throw std::runtime_error("too few parameters (need at least command)"); + std::string strMethod = args[0]; + UniValue params = RPCConvertValues(strMethod, std::vector(args.begin()+1, args.end())); // Execute and handle connection failures with -rpcwait const bool fWait = GetBoolArg("-rpcwait", false); @@ -343,7 +356,7 @@ int CommandLineRPC(int argc, char *argv[]) throw; } catch (const std::exception& e) { - strPrint = string("error: ") + e.what(); + strPrint = std::string("error: ") + e.what(); nRet = EXIT_FAILURE; } catch (...) { @@ -362,12 +375,13 @@ int main(int argc, char* argv[]) SetupEnvironment(); if (!SetupNetworking()) { fprintf(stderr, "Error: Initializing networking failed\n"); - exit(1); + return EXIT_FAILURE; } try { - if(!AppInitRPC(argc, argv)) - return EXIT_FAILURE; + int ret = AppInitRPC(argc, argv); + if (ret != CONTINUE_EXECUTION) + return ret; } catch (const std::exception& e) { PrintExceptionContinue(&e, "AppInitRPC()"); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 36fea57bf..793697631 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -4,7 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "clientversion.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "init.h" #include "main.h" #include "noui.h" @@ -12,7 +12,6 @@ #include "util.h" #include "httpserver.h" #include "httprpc.h" -#include "rpcserver.h" #include #include @@ -115,7 +114,7 @@ bool AppInit(int argc, char* argv[]) } fprintf(stdout, "%s", strUsage.c_str()); - return false; + return true; } try @@ -179,7 +178,7 @@ bool AppInit(int argc, char* argv[]) if (fCommandLine) { fprintf(stderr, "Error: There is no RPC client functionality in komodod. Use the komodo-cli utility instead.\n"); - exit(1); + exit(EXIT_FAILURE); } #ifndef _WIN32 @@ -236,5 +235,5 @@ int main(int argc, char* argv[]) // Connect bitcoind signal handlers noui_connect(); - return (AppInit(argc, argv) ? 0 : 1); + return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/src/bloom.h b/src/bloom.h index a4dba8cb4..df5c30b1e 100644 --- a/src/bloom.h +++ b/src/bloom.h @@ -73,7 +73,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vData); READWRITE(nHashFuncs); READWRITE(nTweak); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 50bb9616f..fa3c8df01 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -14,6 +14,7 @@ ******************************************************************************/ #include "CCinclude.h" +#include "key_io.h" /* FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and the opreturn. diff --git a/src/cc/betprotocol.h b/src/cc/betprotocol.h index 3724aae96..ac76f87b1 100644 --- a/src/cc/betprotocol.h +++ b/src/cc/betprotocol.h @@ -29,7 +29,7 @@ public: uint256 notarisationHash; ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(branch); READWRITE(notarisationHash); } diff --git a/src/cc/dice.cpp b/src/cc/dice.cpp index 20524a84a..4a3cf4f9b 100644 --- a/src/cc/dice.cpp +++ b/src/cc/dice.cpp @@ -170,10 +170,9 @@ CPubKey DiceFundingPk(CScript scriptPubKey) CPubKey pk; uint8_t *ptr,*dest; int32_t i; if ( scriptPubKey.size() == 35 ) { - ptr = (uint8_t *)scriptPubKey.data(); dest = (uint8_t *)pk.begin(); for (i=0; i<33; i++) - dest[i] = ptr[i+1]; + dest[i] = scriptPubKey[i+1]; } else fprintf(stderr,"DiceFundingPk invalid size.%d\n",(int32_t)scriptPubKey.size()); return(pk); } @@ -514,13 +513,12 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) fprintf(stderr,"bidTx.%s\n",uint256_str(str,txid)); fprintf(stderr,"entropyTx.%s v%d\n",uint256_str(str,tx.vin[0].prevout.hash),(int32_t)tx.vin[0].prevout.n); fprintf(stderr,"entropyTx vin0 %s v%d\n",uint256_str(str,vinTx.vin[0].prevout.hash),(int32_t)vinTx.vin[0].prevout.n); - ptr0 = (uint8_t *)vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey.data(); - ptr1 = (uint8_t *)fundingPubKey.data(); + const CScript &s0 = vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey; for (i=0; iInvalid("vin1 of entropy tx not fundingPubKey for bet"); } @@ -562,7 +560,7 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) return eval->Invalid("vout[0] != inputs-txfee for loss"); else if ( tx.vout[2].scriptPubKey != fundingPubKey ) { - if ( tx.vout[2].scriptPubKey.size() == 0 || ((uint8_t *)tx.vout[2].scriptPubKey.data())[0] != 0x6a ) + if ( tx.vout[2].scriptPubKey.size() == 0 || tx.vout[2].scriptPubKey[0] != 0x6a ) return eval->Invalid("vout[2] not send to fundingPubKey for loss"); } iswin = -1; @@ -586,7 +584,7 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) } else if ( tx.vout[3].scriptPubKey != fundingPubKey ) { - if ( tx.vout[3].scriptPubKey.size() == 0 || ((uint8_t *)tx.vout[3].scriptPubKey.data())[0] != 0x6a ) + if ( tx.vout[3].scriptPubKey.size() == 0 || tx.vout[3].scriptPubKey[0] != 0x6a ) return eval->Invalid("vout[3] not send to fundingPubKey for win/timeout"); } iswin = (funcid == 'W'); @@ -700,13 +698,12 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit if ( vinTx.vout[tx.vin[0].prevout.n].scriptPubKey != fundingPubKey ) { uint8_t *ptr0,*ptr1; int32_t i; char str[65]; - ptr0 = (uint8_t *)vinTx.vout[tx.vin[0].prevout.n].scriptPubKey.data(); - ptr1 = (uint8_t *)fundingPubKey.data(); + const CScript &s0 = vinTx.vout[tx.vin[0].prevout.n].scriptPubKey; for (i=0; i scriptVec = std::vector(spk.begin(),spk.end()); + const unsigned char *pk = scriptVec.data(); if (pk++[0] != 33) return false; if (pk[33] != OP_CHECKSIG) return false; diff --git a/src/cc/eval.h b/src/cc/eval.h index 9ff0ca623..ee83df979 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -174,7 +174,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { bool IsBack = IsBackNotarisation; if (2 == IsBackNotarisation) IsBack = DetectBackNotarisation(s, ser_action); @@ -270,7 +270,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(VARINT(nIndex)); READWRITE(branch); } diff --git a/src/chain.cpp b/src/chain.cpp index d79a66f9a..8a5a42777 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -94,6 +94,7 @@ CBlockIndex* CBlockIndex::GetAncestor(int height) pindexWalk = pindexWalk->pskip; heightWalk = heightSkip; } else { + assert(pindexWalk->pprev); pindexWalk = pindexWalk->pprev; heightWalk--; } diff --git a/src/chain.h b/src/chain.h index e12fa0dd3..45e478aef 100644 --- a/src/chain.h +++ b/src/chain.h @@ -17,6 +17,7 @@ #include static const int SPROUT_VALUE_VERSION = 1001400; +static const int SAPLING_VALUE_VERSION = 1010100; struct CDiskBlockPos { @@ -26,7 +27,7 @@ struct CDiskBlockPos ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(VARINT(nFile)); READWRITE(VARINT(nPos)); } @@ -152,10 +153,10 @@ public: boost::optional nCachedBranchId; //! The anchor for the tree state up to the start of this block - uint256 hashAnchor; + uint256 hashSproutAnchor; //! (memory only) The anchor for the tree state up to the end of this block - uint256 hashAnchorEnd; + uint256 hashFinalSproutRoot; //! Change in value held by the Sprout circuit over this block. //! Will be boost::none for older blocks on old nodes until a reindex has taken place. @@ -166,10 +167,19 @@ public: //! Will be boost::none if nChainTx is zero. boost::optional nChainSproutValue; + //! Change in value held by the Sapling circuit over this block. + //! Not a boost::optional because this was added before Sapling activated, so we can + //! rely on the invariant that every block before this was added had nSaplingValue = 0. + CAmount nSaplingValue; + + //! (memory only) Total value held by the Sapling circuit up to and including this block. + //! Will be boost::none if nChainTx is zero. + boost::optional nChainSaplingValue; + //! block header int nVersion; uint256 hashMerkleRoot; - uint256 hashReserved; + uint256 hashFinalSaplingRoot; unsigned int nTime; unsigned int nBits; uint256 nNonce; @@ -194,15 +204,17 @@ public: nChainTx = 0; nStatus = 0; nCachedBranchId = boost::none; - hashAnchor = uint256(); - hashAnchorEnd = uint256(); + hashSproutAnchor = uint256(); + hashFinalSproutRoot = uint256(); nSequenceId = 0; nSproutValue = boost::none; nChainSproutValue = boost::none; + nSaplingValue = 0; + nChainSaplingValue = boost::none; nVersion = 0; hashMerkleRoot = uint256(); - hashReserved = uint256(); + hashFinalSaplingRoot = uint256(); nTime = 0; nBits = 0; nNonce = uint256(); @@ -220,7 +232,7 @@ public: nVersion = block.nVersion; hashMerkleRoot = block.hashMerkleRoot; - hashReserved = block.hashReserved; + hashFinalSaplingRoot = block.hashFinalSaplingRoot; nTime = block.nTime; nBits = block.nBits; nNonce = block.nNonce; @@ -252,7 +264,7 @@ public: if (pprev) block.hashPrevBlock = pprev->GetBlockHash(); block.hashMerkleRoot = hashMerkleRoot; - block.hashReserved = hashReserved; + block.hashFinalSaplingRoot = hashFinalSaplingRoot; block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; @@ -352,8 +364,9 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(VARINT(nVersion)); READWRITE(VARINT(nHeight)); @@ -377,13 +390,13 @@ public: READWRITE(branchId); } } - READWRITE(hashAnchor); + READWRITE(hashSproutAnchor); // block header READWRITE(this->nVersion); READWRITE(hashPrev); READWRITE(hashMerkleRoot); - READWRITE(hashReserved); + READWRITE(hashFinalSaplingRoot); READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); @@ -391,9 +404,15 @@ public: // Only read/write nSproutValue if the client version used to create // this index was storing them. - if ((nType & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) { + if ((s.GetType() & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) { READWRITE(nSproutValue); } + + // Only read/write nSaplingValue if the client version used to create + // this index was storing them. + if ((s.GetType() & SER_DISK) && (nVersion >= SAPLING_VALUE_VERSION)) { + READWRITE(nSaplingValue); + } } uint256 GetBlockHash() const @@ -402,7 +421,7 @@ public: block.nVersion = nVersion; block.hashPrevBlock = hashPrev; block.hashMerkleRoot = hashMerkleRoot; - block.hashReserved = hashReserved; + block.hashFinalSaplingRoot = hashFinalSaplingRoot; block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index a500d2f2b..03ee98ceb 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "key_io.h" #include "main.h" #include "crypto/equihash.h" @@ -13,14 +14,12 @@ #include -#include "base58.h" - #include "chainparamsseeds.h" static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, const uint256& nNonce, const std::vector& nSolution, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) { // To create a genesis block for a new chain which is Overwintered: - // txNew.nVersion = 3 + // txNew.nVersion = OVERWINTER_TX_VERSION // txNew.fOverwintered = true // txNew.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID // txNew.nExpiryHeight = @@ -92,6 +91,7 @@ public: { strNetworkID = "main"; strCurrencyUnits = "KMD"; + bip44CoinType = 133; // As registered in https://github.com/satoshilabs/slips/blob/master/slip-0044.md (ZCASH, should be VRSC) consensus.fCoinbaseMustBeProtected = false; // true this is only true wuth Verus and enforced after block 12800 consensus.nSubsidySlowStartInterval = 20000; consensus.nSubsidyHalvingInterval = 840000; @@ -114,9 +114,13 @@ public: consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nProtocolVersion = 170002; consensus.vUpgrades[Consensus::UPGRADE_TESTDUMMY].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; - consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170004; - consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = - Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170005; + consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 227520; + consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007; + consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 227520; + + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000281b32ff3198a1"); /** * The message start string is designed to be unlikely to occur in normal data. @@ -128,6 +132,7 @@ public: pchMessageStart[2] = 0xe4; pchMessageStart[3] = 0x8d; vAlertPubKey = ParseHex("020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9"); + // (Zcash) vAlertPubKey = ParseHex("04b7ecf0baa90495ceb4e4090f6b2fd37eec1e9c85fac68a487f3ce11589692e4a317479316ee814e066638e1db54e37a10689b70286e6315b1087b6615d179264"); nDefaultPort = 7770; nMinerThreads = 0; nMaxTipAge = 24 * 60 * 60; @@ -182,6 +187,11 @@ public: // guarantees the first two characters, when base58 encoded, are "SK" base58Prefixes[ZCSPENDING_KEY] = {171,54}; + bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zs"; + bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviews"; + bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivks"; + bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-main"; + vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); fMiningRequiresPeers = true; @@ -455,6 +465,7 @@ public: CTestNetParams() { strNetworkID = "test"; strCurrencyUnits = "TAZ"; + bip44CoinType = 1; consensus.fCoinbaseMustBeProtected = true; consensus.nSubsidySlowStartInterval = 20000; consensus.nSubsidyHalvingInterval = 840000; @@ -481,6 +492,11 @@ public: Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170003; consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 207500; + consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007; + consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 280000; + + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000001d0c4d9cd"); consensus.fPowAllowMinDifficultyBlocks = true; pchMessageStart[0] = 0x5A; @@ -518,6 +534,11 @@ public: base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; base58Prefixes[ZCSPENDING_KEY] = {177,235}; + bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "ztestsapling"; + bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewtestsapling"; + bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivktestsapling"; + bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-test"; + vFixedSeeds = std::vector(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); //fRequireRPCPassword = true; @@ -527,6 +548,7 @@ public: fMineBlocksOnDemand = false; fTestnetToBeDeprecatedFieldRPC = true; + checkpointData = (CCheckpointData) { boost::assign::map_list_of (0, consensus.hashGenesisBlock) @@ -548,6 +570,7 @@ public: CRegTestParams() { strNetworkID = "regtest"; strCurrencyUnits = "REG"; + bip44CoinType = 1; consensus.fCoinbaseMustBeProtected = false; consensus.nSubsidySlowStartInterval = 0; consensus.nSubsidyHalvingInterval = 150; @@ -571,6 +594,12 @@ public: consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nProtocolVersion = 170003; consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170006; + consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = + Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x00"); pchMessageStart[0] = 0xaa; pchMessageStart[1] = 0x8e; @@ -628,6 +657,11 @@ public: base58Prefixes[ZCVIEWING_KEY] = {0xA8,0xAC,0x0C}; base58Prefixes[ZCSPENDING_KEY] = {0xAC,0x08}; + bech32HRPs[SAPLING_PAYMENT_ADDRESS] = "zregtestsapling"; + bech32HRPs[SAPLING_FULL_VIEWING_KEY] = "zviewregtestsapling"; + bech32HRPs[SAPLING_INCOMING_VIEWING_KEY] = "zivkregtestsapling"; + bech32HRPs[SAPLING_EXTENDED_SPEND_KEY] = "secret-extended-key-regtest"; + // Founders reward script expects a vector of 2-of-3 multisig addresses vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" }; assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight()); @@ -699,10 +733,10 @@ std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const { CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const { assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight()); - CBitcoinAddress address(GetFoundersRewardAddressAtHeight(nHeight).c_str()); - assert(address.IsValid()); - assert(address.IsScript()); - CScriptID scriptID = boost::get(address.Get()); // Get() returns a boost variant + CTxDestination address = DecodeDestination(GetFoundersRewardAddressAtHeight(nHeight).c_str()); + assert(IsValidDestination(address)); + assert(boost::get(&address) != nullptr); + CScriptID scriptID = boost::get(address); // address is a boost variant CScript script = CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL; return script; } diff --git a/src/chainparams.h b/src/chainparams.h index 2041b2209..566f07f36 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -58,6 +58,15 @@ public: double fTransactionsPerDay; }; + enum Bech32Type { + SAPLING_PAYMENT_ADDRESS, + SAPLING_FULL_VIEWING_KEY, + SAPLING_INCOMING_VIEWING_KEY, + SAPLING_EXTENDED_SPEND_KEY, + + MAX_BECH32_TYPES + }; + const Consensus::Params& GetConsensus() const { return consensus; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } const std::vector& AlertKey() const { return vAlertPubKey; } @@ -70,11 +79,11 @@ public: bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } - int64_t MaxTipAge() const { return nMaxTipAge; } int64_t PruneAfterHeight() const { return nPruneAfterHeight; } unsigned int EquihashN() const { return nEquihashN; } unsigned int EquihashK() const { return nEquihashK; } std::string CurrencyUnits() const { return strCurrencyUnits; } + uint32_t BIP44CoinType() const { return bip44CoinType; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } /** In the future use NetworkIDString() for RPC fields */ @@ -83,6 +92,7 @@ public: std::string NetworkIDString() const { return strNetworkID; } const std::vector& DNSSeeds() const { return vSeeds; } const std::vector& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } + const std::string& Bech32HRP(Bech32Type type) const { return bech32HRPs[type]; } const std::vector& FixedSeeds() const { return vFixedSeeds; } const CCheckpointData& Checkpoints() const { return checkpointData; } /** Return the founder's reward address and script for a given block height */ @@ -99,7 +109,6 @@ public: //void settimestamp(uint32_t timestamp) { genesis.nTime = timestamp; } //void setgenesis(CBlock &block) { genesis = block; } //void recalc_genesis(uint32_t nonce) { genesis = CreateGenesisBlock(ASSETCHAINS_TIMESTAMP, nonce, GENESIS_NBITS, 1, COIN); }; - int nDefaultPort = 0; CMessageHeader::MessageStartChars pchMessageStart; // jl777 moved Consensus::Params consensus; @@ -110,13 +119,16 @@ protected: std::vector vAlertPubKey; int nMinerThreads = 0; long nMaxTipAge = 0; + int nDefaultPort = 0; uint64_t nPruneAfterHeight = 0; unsigned int nEquihashN = 0; unsigned int nEquihashK = 0; std::vector vSeeds; std::vector base58Prefixes[MAX_BASE58_TYPES]; + std::string bech32HRPs[MAX_BECH32_TYPES]; std::string strNetworkID; std::string strCurrencyUnits; + uint32_t bip44CoinType; CBlock genesis; std::vector vFixedSeeds; bool fMiningRequiresPeers = false; diff --git a/src/clientversion.h b/src/clientversion.h index 1203760bb..fe4fd0618 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -15,7 +15,7 @@ */ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it -#define CLIENT_VERSION_MAJOR 1 +#define CLIENT_VERSION_MAJOR 2 #define CLIENT_VERSION_MINOR 0 #define CLIENT_VERSION_REVISION 15 #define CLIENT_VERSION_BUILD 52 diff --git a/src/coins.cpp b/src/coins.cpp index cb33d5ce2..d8e08b923 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -44,34 +44,42 @@ bool CCoins::Spend(uint32_t nPos) Cleanup(); return true; } -bool CCoinsView::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return false; } -bool CCoinsView::GetNullifier(const uint256 &nullifier) const { return false; } +bool CCoinsView::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return false; } +bool CCoinsView::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return false; } +bool CCoinsView::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return false; } bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; } bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; } uint256 CCoinsView::GetBestBlock() const { return uint256(); } -uint256 CCoinsView::GetBestAnchor() const { return uint256(); }; +uint256 CCoinsView::GetBestAnchor(ShieldedType type) const { return uint256(); }; bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, - const uint256 &hashAnchor, - CAnchorsMap &mapAnchors, - CNullifiersMap &mapNullifiers) { return false; } + const uint256 &hashSproutAnchor, + const uint256 &hashSaplingAnchor, + CAnchorsSproutMap &mapSproutAnchors, + CAnchorsSaplingMap &mapSaplingAnchors, + CNullifiersMap &mapSproutNullifiers, + CNullifiersMap &mapSaplingNullifiers) { return false; } bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; } CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { } -bool CCoinsViewBacked::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return base->GetAnchorAt(rt, tree); } -bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); } +bool CCoinsViewBacked::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return base->GetSproutAnchorAt(rt, tree); } +bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); } +bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return base->GetNullifier(nullifier, type); } bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); } bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); } uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } -uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); } +uint256 CCoinsViewBacked::GetBestAnchor(ShieldedType type) const { return base->GetBestAnchor(type); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, - const uint256 &hashAnchor, - CAnchorsMap &mapAnchors, - CNullifiersMap &mapNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashAnchor, mapAnchors, mapNullifiers); } + const uint256 &hashSproutAnchor, + const uint256 &hashSaplingAnchor, + CAnchorsSproutMap &mapSproutAnchors, + CAnchorsSaplingMap &mapSaplingAnchors, + CNullifiersMap &mapSproutNullifiers, + CNullifiersMap &mapSaplingNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, mapSproutAnchors, mapSaplingAnchors, mapSproutNullifiers, mapSaplingNullifiers); } bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); } CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {} @@ -85,8 +93,10 @@ CCoinsViewCache::~CCoinsViewCache() size_t CCoinsViewCache::DynamicMemoryUsage() const { return memusage::DynamicUsage(cacheCoins) + - memusage::DynamicUsage(cacheAnchors) + - memusage::DynamicUsage(cacheNullifiers) + + memusage::DynamicUsage(cacheSproutAnchors) + + memusage::DynamicUsage(cacheSaplingAnchors) + + memusage::DynamicUsage(cacheSproutNullifiers) + + memusage::DynamicUsage(cacheSaplingNullifiers) + cachedCoinsUsage; } @@ -109,9 +119,9 @@ CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const } -bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { - CAnchorsMap::const_iterator it = cacheAnchors.find(rt); - if (it != cacheAnchors.end()) { +bool CCoinsViewCache::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { + CAnchorsSproutMap::const_iterator it = cacheSproutAnchors.find(rt); + if (it != cacheSproutAnchors.end()) { if (it->second.entered) { tree = it->second.tree; return true; @@ -120,11 +130,11 @@ bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tr } } - if (!base->GetAnchorAt(rt, tree)) { + if (!base->GetSproutAnchorAt(rt, tree)) { return false; } - CAnchorsMap::iterator ret = cacheAnchors.insert(std::make_pair(rt, CAnchorsCacheEntry())).first; + CAnchorsSproutMap::iterator ret = cacheSproutAnchors.insert(std::make_pair(rt, CAnchorsSproutCacheEntry())).first; ret->second.entered = true; ret->second.tree = tree; cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage(); @@ -132,24 +142,65 @@ bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tr return true; } -bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const { - CNullifiersMap::iterator it = cacheNullifiers.find(nullifier); - if (it != cacheNullifiers.end()) +bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { + CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt); + if (it != cacheSaplingAnchors.end()) { + if (it->second.entered) { + tree = it->second.tree; + return true; + } else { + return false; + } + } + + if (!base->GetSaplingAnchorAt(rt, tree)) { + return false; + } + + CAnchorsSaplingMap::iterator ret = cacheSaplingAnchors.insert(std::make_pair(rt, CAnchorsSaplingCacheEntry())).first; + ret->second.entered = true; + ret->second.tree = tree; + cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage(); + + return true; +} + +bool CCoinsViewCache::GetNullifier(const uint256 &nullifier, ShieldedType type) const { + CNullifiersMap* cacheToUse; + switch (type) { + case SPROUT: + cacheToUse = &cacheSproutNullifiers; + break; + case SAPLING: + cacheToUse = &cacheSaplingNullifiers; + break; + default: + throw std::runtime_error("Unknown shielded type"); + } + CNullifiersMap::iterator it = cacheToUse->find(nullifier); + if (it != cacheToUse->end()) return it->second.entered; CNullifiersCacheEntry entry; - bool tmp = base->GetNullifier(nullifier); + bool tmp = base->GetNullifier(nullifier, type); entry.entered = tmp; - cacheNullifiers.insert(std::make_pair(nullifier, entry)); + cacheToUse->insert(std::make_pair(nullifier, entry)); return tmp; } -void CCoinsViewCache::PushAnchor(const ZCIncrementalMerkleTree &tree) { +template +void CCoinsViewCache::AbstractPushAnchor( + const Tree &tree, + ShieldedType type, + Cache &cacheAnchors, + uint256 &hash +) +{ uint256 newrt = tree.root(); - auto currentRoot = GetBestAnchor(); + auto currentRoot = GetBestAnchor(type); // We don't want to overwrite an anchor we already have. // This occurs when a block doesn't modify mapAnchors at all, @@ -157,24 +208,69 @@ void CCoinsViewCache::PushAnchor(const ZCIncrementalMerkleTree &tree) { // different way (make all blocks modify mapAnchors somehow) // but this is simpler to reason about. if (currentRoot != newrt) { - auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CAnchorsCacheEntry())); - CAnchorsMap::iterator ret = insertRet.first; + auto insertRet = cacheAnchors.insert(std::make_pair(newrt, CacheEntry())); + CacheIterator ret = insertRet.first; ret->second.entered = true; ret->second.tree = tree; - ret->second.flags = CAnchorsCacheEntry::DIRTY; + ret->second.flags = CacheEntry::DIRTY; if (insertRet.second) { // An insert took place cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage(); } - hashAnchor = newrt; + hash = newrt; } } -void CCoinsViewCache::PopAnchor(const uint256 &newrt) { - auto currentRoot = GetBestAnchor(); +template<> void CCoinsViewCache::PushAnchor(const SproutMerkleTree &tree) +{ + AbstractPushAnchor( + tree, + SPROUT, + cacheSproutAnchors, + hashSproutAnchor + ); +} + +template<> void CCoinsViewCache::PushAnchor(const SaplingMerkleTree &tree) +{ + AbstractPushAnchor( + tree, + SAPLING, + cacheSaplingAnchors, + hashSaplingAnchor + ); +} + +template<> +void CCoinsViewCache::BringBestAnchorIntoCache( + const uint256 ¤tRoot, + SproutMerkleTree &tree +) +{ + assert(GetSproutAnchorAt(currentRoot, tree)); +} + +template<> +void CCoinsViewCache::BringBestAnchorIntoCache( + const uint256 ¤tRoot, + SaplingMerkleTree &tree +) +{ + assert(GetSaplingAnchorAt(currentRoot, tree)); +} + +template +void CCoinsViewCache::AbstractPopAnchor( + const uint256 &newrt, + ShieldedType type, + Cache &cacheAnchors, + uint256 &hash +) +{ + auto currentRoot = GetBestAnchor(type); // Blocks might not change the commitment tree, in which // case restoring the "old" anchor during a reorg must @@ -183,25 +279,57 @@ void CCoinsViewCache::PopAnchor(const uint256 &newrt) { // Bring the current best anchor into our local cache // so that its tree exists in memory. { - ZCIncrementalMerkleTree tree; - assert(GetAnchorAt(currentRoot, tree)); + Tree tree; + BringBestAnchorIntoCache(currentRoot, tree); } // Mark the anchor as unentered, removing it from view cacheAnchors[currentRoot].entered = false; // Mark the cache entry as dirty so it's propagated - cacheAnchors[currentRoot].flags = CAnchorsCacheEntry::DIRTY; + cacheAnchors[currentRoot].flags = CacheEntry::DIRTY; // Mark the new root as the best anchor - hashAnchor = newrt; + hash = newrt; } } -void CCoinsViewCache::SetNullifier(const uint256 &nullifier, bool spent) { - std::pair ret = cacheNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry())); - ret.first->second.entered = spent; - ret.first->second.flags |= CNullifiersCacheEntry::DIRTY; +void CCoinsViewCache::PopAnchor(const uint256 &newrt, ShieldedType type) { + switch (type) { + case SPROUT: + AbstractPopAnchor( + newrt, + SPROUT, + cacheSproutAnchors, + hashSproutAnchor + ); + break; + case SAPLING: + AbstractPopAnchor( + newrt, + SAPLING, + cacheSaplingAnchors, + hashSaplingAnchor + ); + break; + default: + throw std::runtime_error("Unknown shielded type"); + } +} + +void CCoinsViewCache::SetNullifiers(const CTransaction& tx, bool spent) { + for (const JSDescription &joinsplit : tx.vjoinsplit) { + for (const uint256 &nullifier : joinsplit.nullifiers) { + std::pair ret = cacheSproutNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry())); + ret.first->second.entered = spent; + ret.first->second.flags |= CNullifiersCacheEntry::DIRTY; + } + } + for (const SpendDescription &spendDescription : tx.vShieldedSpend) { + std::pair ret = cacheSaplingNullifiers.insert(std::make_pair(spendDescription.nullifier, CNullifiersCacheEntry())); + ret.first->second.entered = spent; + ret.first->second.flags |= CNullifiersCacheEntry::DIRTY; + } } bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const { @@ -268,21 +396,90 @@ uint256 CCoinsViewCache::GetBestBlock() const { } -uint256 CCoinsViewCache::GetBestAnchor() const { - if (hashAnchor.IsNull()) - hashAnchor = base->GetBestAnchor(); - return hashAnchor; +uint256 CCoinsViewCache::GetBestAnchor(ShieldedType type) const { + switch (type) { + case SPROUT: + if (hashSproutAnchor.IsNull()) + hashSproutAnchor = base->GetBestAnchor(type); + return hashSproutAnchor; + break; + case SAPLING: + if (hashSaplingAnchor.IsNull()) + hashSaplingAnchor = base->GetBestAnchor(type); + return hashSaplingAnchor; + break; + default: + throw std::runtime_error("Unknown shielded type"); + } } void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { hashBlock = hashBlockIn; } +void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers) +{ + for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) { + if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization). + CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first); + + if (parent_it == cacheNullifiers.end()) { + CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first]; + entry.entered = child_it->second.entered; + entry.flags = CNullifiersCacheEntry::DIRTY; + } else { + if (parent_it->second.entered != child_it->second.entered) { + parent_it->second.entered = child_it->second.entered; + parent_it->second.flags |= CNullifiersCacheEntry::DIRTY; + } + } + } + CNullifiersMap::iterator itOld = child_it++; + mapNullifiers.erase(itOld); + } +} + +template +void BatchWriteAnchors( + Map &mapAnchors, + Map &cacheAnchors, + size_t &cachedCoinsUsage +) +{ + for (MapIterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();) + { + if (child_it->second.flags & MapEntry::DIRTY) { + MapIterator parent_it = cacheAnchors.find(child_it->first); + + if (parent_it == cacheAnchors.end()) { + MapEntry& entry = cacheAnchors[child_it->first]; + entry.entered = child_it->second.entered; + entry.tree = child_it->second.tree; + entry.flags = MapEntry::DIRTY; + + cachedCoinsUsage += entry.tree.DynamicMemoryUsage(); + } else { + if (parent_it->second.entered != child_it->second.entered) { + // The parent may have removed the entry. + parent_it->second.entered = child_it->second.entered; + parent_it->second.flags |= MapEntry::DIRTY; + } + } + } + + MapIterator itOld = child_it++; + mapAnchors.erase(itOld); + } +} + bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn, - const uint256 &hashAnchorIn, - CAnchorsMap &mapAnchors, - CNullifiersMap &mapNullifiers) { + const uint256 &hashSproutAnchorIn, + const uint256 &hashSaplingAnchorIn, + CAnchorsSproutMap &mapSproutAnchors, + CAnchorsSaplingMap &mapSaplingAnchors, + CNullifiersMap &mapSproutNullifiers, + CNullifiersMap &mapSaplingNullifiers) { assert(!hasModifier); for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization). @@ -319,61 +516,25 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, mapCoins.erase(itOld); } - for (CAnchorsMap::iterator child_it = mapAnchors.begin(); child_it != mapAnchors.end();) - { - if (child_it->second.flags & CAnchorsCacheEntry::DIRTY) { - CAnchorsMap::iterator parent_it = cacheAnchors.find(child_it->first); + ::BatchWriteAnchors(mapSproutAnchors, cacheSproutAnchors, cachedCoinsUsage); + ::BatchWriteAnchors(mapSaplingAnchors, cacheSaplingAnchors, cachedCoinsUsage); - if (parent_it == cacheAnchors.end()) { - CAnchorsCacheEntry& entry = cacheAnchors[child_it->first]; - entry.entered = child_it->second.entered; - entry.tree = child_it->second.tree; - entry.flags = CAnchorsCacheEntry::DIRTY; + ::BatchWriteNullifiers(mapSproutNullifiers, cacheSproutNullifiers); + ::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers); - cachedCoinsUsage += entry.tree.DynamicMemoryUsage(); - } else { - if (parent_it->second.entered != child_it->second.entered) { - // The parent may have removed the entry. - parent_it->second.entered = child_it->second.entered; - parent_it->second.flags |= CAnchorsCacheEntry::DIRTY; - } - } - } - - CAnchorsMap::iterator itOld = child_it++; - mapAnchors.erase(itOld); - } - - for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) - { - if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization). - CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first); - - if (parent_it == cacheNullifiers.end()) { - CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first]; - entry.entered = child_it->second.entered; - entry.flags = CNullifiersCacheEntry::DIRTY; - } else { - if (parent_it->second.entered != child_it->second.entered) { - parent_it->second.entered = child_it->second.entered; - parent_it->second.flags |= CNullifiersCacheEntry::DIRTY; - } - } - } - CNullifiersMap::iterator itOld = child_it++; - mapNullifiers.erase(itOld); - } - - hashAnchor = hashAnchorIn; + hashSproutAnchor = hashSproutAnchorIn; + hashSaplingAnchor = hashSaplingAnchorIn; hashBlock = hashBlockIn; return true; } bool CCoinsViewCache::Flush() { - bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheNullifiers); + bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, cacheSproutAnchors, cacheSaplingAnchors, cacheSproutNullifiers, cacheSaplingNullifiers); cacheCoins.clear(); - cacheAnchors.clear(); - cacheNullifiers.clear(); + cacheSproutAnchors.clear(); + cacheSaplingAnchors.clear(); + cacheSproutNullifiers.clear(); + cacheSaplingNullifiers.clear(); cachedCoinsUsage = 0; return fOk; } @@ -445,7 +606,7 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr } #endif } - nResult += tx.GetJoinSplitValueIn(); + nResult += tx.GetShieldedValueIn(); return nResult; } @@ -453,24 +614,24 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const { - boost::unordered_map intermediates; + boost::unordered_map intermediates; BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { BOOST_FOREACH(const uint256& nullifier, joinsplit.nullifiers) { - if (GetNullifier(nullifier)) { + if (GetNullifier(nullifier, SPROUT)) { // If the nullifier is set, this transaction // double-spends! return false; } } - ZCIncrementalMerkleTree tree; + SproutMerkleTree tree; auto it = intermediates.find(joinsplit.anchor); if (it != intermediates.end()) { tree = it->second; - } else if (!GetAnchorAt(joinsplit.anchor, tree)) { + } else if (!GetSproutAnchorAt(joinsplit.anchor, tree)) { return false; } @@ -482,6 +643,16 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const intermediates.insert(std::make_pair(tree.root(), tree)); } + for (const SpendDescription &spendDescription : tx.vShieldedSpend) { + if (GetNullifier(spendDescription.nullifier, SAPLING)) // Prevent double spends + return false; + + SaplingMerkleTree tree; + if (!GetSaplingAnchorAt(spendDescription.anchor, tree)) { + return false; + } + } + return true; } diff --git a/src/coins.h b/src/coins.h index c0e06f64a..f35af02f0 100644 --- a/src/coins.h +++ b/src/coins.h @@ -162,31 +162,8 @@ public: return fCoinBase; } - unsigned int GetSerializeSize(int nType, int nVersion) const { - unsigned int nSize = 0; - unsigned int nMaskSize = 0, nMaskCode = 0; - CalcMaskSize(nMaskSize, nMaskCode); - bool fFirst = vout.size() > 0 && !vout[0].IsNull(); - bool fSecond = vout.size() > 1 && !vout[1].IsNull(); - assert(fFirst || fSecond || nMaskCode); - unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0); - // version - nSize += ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion); - // size of header code - nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion); - // spentness bitmask - nSize += nMaskSize; - // txouts - for (unsigned int i = 0; i < vout.size(); i++) - if (!vout[i].IsNull()) - nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion); - // height - nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion); - return nSize; - } - template - void Serialize(Stream &s, int nType, int nVersion) const { + void Serialize(Stream &s) const { unsigned int nMaskSize = 0, nMaskCode = 0; CalcMaskSize(nMaskSize, nMaskCode); bool fFirst = vout.size() > 0 && !vout[0].IsNull(); @@ -194,33 +171,33 @@ public: assert(fFirst || fSecond || nMaskCode); unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0); // version - ::Serialize(s, VARINT(this->nVersion), nType, nVersion); + ::Serialize(s, VARINT(this->nVersion)); // header code - ::Serialize(s, VARINT(nCode), nType, nVersion); + ::Serialize(s, VARINT(nCode)); // spentness bitmask for (unsigned int b = 0; b - void Unserialize(Stream &s, int nType, int nVersion) { + void Unserialize(Stream &s) { unsigned int nCode = 0; // version - ::Unserialize(s, VARINT(this->nVersion), nType, nVersion); + ::Unserialize(s, VARINT(this->nVersion)); // header code - ::Unserialize(s, VARINT(nCode), nType, nVersion); + ::Unserialize(s, VARINT(nCode)); fCoinBase = nCode & 1; std::vector vAvail(2, false); vAvail[0] = (nCode & 2) != 0; @@ -229,7 +206,7 @@ public: // spentness bitmask while (nMaskCode > 0) { unsigned char chAvail = 0; - ::Unserialize(s, chAvail, nType, nVersion); + ::Unserialize(s, chAvail); for (unsigned int p = 0; p < 8; p++) { bool f = (chAvail & (1 << p)) != 0; vAvail.push_back(f); @@ -241,10 +218,10 @@ public: vout.assign(vAvail.size(), CTxOut()); for (unsigned int i = 0; i < vAvail.size(); i++) { if (vAvail[i]) - ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion); + ::Unserialize(s, REF(CTxOutCompressor(vout[i]))); } // coinbase height - ::Unserialize(s, VARINT(nHeight), nType, nVersion); + ::Unserialize(s, VARINT(nHeight)); Cleanup(); } @@ -313,17 +290,30 @@ struct CCoinsCacheEntry CCoinsCacheEntry() : coins(), flags(0) {} }; -struct CAnchorsCacheEntry +struct CAnchorsSproutCacheEntry { bool entered; // This will be false if the anchor is removed from the cache - ZCIncrementalMerkleTree tree; // The tree itself + SproutMerkleTree tree; // The tree itself unsigned char flags; enum Flags { DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view. }; - CAnchorsCacheEntry() : entered(false), flags(0) {} + CAnchorsSproutCacheEntry() : entered(false), flags(0) {} +}; + +struct CAnchorsSaplingCacheEntry +{ + bool entered; // This will be false if the anchor is removed from the cache + SaplingMerkleTree tree; // The tree itself + unsigned char flags; + + enum Flags { + DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view. + }; + + CAnchorsSaplingCacheEntry() : entered(false), flags(0) {} }; struct CNullifiersCacheEntry @@ -338,8 +328,15 @@ struct CNullifiersCacheEntry CNullifiersCacheEntry() : entered(false), flags(0) {} }; +enum ShieldedType +{ + SPROUT, + SAPLING, +}; + typedef boost::unordered_map CCoinsMap; -typedef boost::unordered_map CAnchorsMap; +typedef boost::unordered_map CAnchorsSproutMap; +typedef boost::unordered_map CAnchorsSaplingMap; typedef boost::unordered_map CNullifiersMap; struct CCoinsStats @@ -360,11 +357,14 @@ struct CCoinsStats class CCoinsView { public: - //! Retrieve the tree at a particular anchored root in the chain - virtual bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const; + //! Retrieve the tree (Sprout) at a particular anchored root in the chain + virtual bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const; + + //! Retrieve the tree (Sapling) at a particular anchored root in the chain + virtual bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const; //! Determine whether a nullifier is spent or not - virtual bool GetNullifier(const uint256 &nullifier) const; + virtual bool GetNullifier(const uint256 &nullifier, ShieldedType type) const; //! Retrieve the CCoins (unspent transaction outputs) for a given txid virtual bool GetCoins(const uint256 &txid, CCoins &coins) const; @@ -377,15 +377,18 @@ public: virtual uint256 GetBestBlock() const; //! Get the current "tip" or the latest anchored tree root in the chain - virtual uint256 GetBestAnchor() const; + virtual uint256 GetBestAnchor(ShieldedType type) const; //! Do a bulk modification (multiple CCoins changes + BestBlock change). //! The passed mapCoins can be modified. virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, - const uint256 &hashAnchor, - CAnchorsMap &mapAnchors, - CNullifiersMap &mapNullifiers); + const uint256 &hashSproutAnchor, + const uint256 &hashSaplingAnchor, + CAnchorsSproutMap &mapSproutAnchors, + CAnchorsSaplingMap &mapSaplingAnchors, + CNullifiersMap &mapSproutNullifiers, + CNullifiersMap &mapSaplingNullifiers); //! Calculate statistics about the unspent transaction output set virtual bool GetStats(CCoinsStats &stats) const; @@ -403,18 +406,22 @@ protected: public: CCoinsViewBacked(CCoinsView *viewIn); - bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const; - bool GetNullifier(const uint256 &nullifier) const; + bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const; + bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const; + bool GetNullifier(const uint256 &nullifier, ShieldedType type) const; bool GetCoins(const uint256 &txid, CCoins &coins) const; bool HaveCoins(const uint256 &txid) const; uint256 GetBestBlock() const; - uint256 GetBestAnchor() const; + uint256 GetBestAnchor(ShieldedType type) const; void SetBackend(CCoinsView &viewIn); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, - const uint256 &hashAnchor, - CAnchorsMap &mapAnchors, - CNullifiersMap &mapNullifiers); + const uint256 &hashSproutAnchor, + const uint256 &hashSaplingAnchor, + CAnchorsSproutMap &mapSproutAnchors, + CAnchorsSaplingMap &mapSaplingAnchors, + CNullifiersMap &mapSproutNullifiers, + CNullifiersMap &mapSaplingNullifiers); bool GetStats(CCoinsStats &stats) const; }; @@ -485,9 +492,12 @@ protected: */ mutable uint256 hashBlock; mutable CCoinsMap cacheCoins; - mutable uint256 hashAnchor; - mutable CAnchorsMap cacheAnchors; - mutable CNullifiersMap cacheNullifiers; + mutable uint256 hashSproutAnchor; + mutable uint256 hashSaplingAnchor; + mutable CAnchorsSproutMap cacheSproutAnchors; + mutable CAnchorsSaplingMap cacheSaplingAnchors; + mutable CNullifiersMap cacheSproutNullifiers; + mutable CNullifiersMap cacheSaplingNullifiers; /* Cached dynamic memory usage for the inner CCoins objects. */ mutable size_t cachedCoinsUsage; @@ -498,30 +508,34 @@ public: // Standard CCoinsView methods static CLaunchMap &LaunchMap() { return launchMap; } - bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const; - bool GetNullifier(const uint256 &nullifier) const; + bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const; + bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const; + bool GetNullifier(const uint256 &nullifier, ShieldedType type) const; bool GetCoins(const uint256 &txid, CCoins &coins) const; bool HaveCoins(const uint256 &txid) const; uint256 GetBestBlock() const; - uint256 GetBestAnchor() const; + uint256 GetBestAnchor(ShieldedType type) const; void SetBestBlock(const uint256 &hashBlock); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, - const uint256 &hashAnchor, - CAnchorsMap &mapAnchors, - CNullifiersMap &mapNullifiers); + const uint256 &hashSproutAnchor, + const uint256 &hashSaplingAnchor, + CAnchorsSproutMap &mapSproutAnchors, + CAnchorsSaplingMap &mapSaplingAnchors, + CNullifiersMap &mapSproutNullifiers, + CNullifiersMap &mapSaplingNullifiers); - // Adds the tree to mapAnchors and sets the current commitment - // root to this root. - void PushAnchor(const ZCIncrementalMerkleTree &tree); + // Adds the tree to mapSproutAnchors (or mapSaplingAnchors based on the type of tree) + // and sets the current commitment root to this root. + template void PushAnchor(const Tree &tree); // Removes the current commitment root from mapAnchors and sets // the new current root. - void PopAnchor(const uint256 &rt); + void PopAnchor(const uint256 &rt, ShieldedType type); - // Marks a nullifier as spent or not. - void SetNullifier(const uint256 &nullifier, bool spent); + // Marks nullifiers for a given transaction as spent or not. + void SetNullifiers(const CTransaction& tx, bool spent); /** * Return a pointer to CCoins in the cache, or NULL if not found. This is @@ -556,7 +570,7 @@ public: * so may not be able to calculate this. * * @param[in] tx transaction for which we are checking input total - * @return Sum of value of all inputs (scriptSigs) + * @return Sum of value of all inputs (scriptSigs), (positive valueBalance or zero) and JoinSplit vpub_new */ CAmount GetValueIn(int32_t nHeight,int64_t *interestp,const CTransaction& tx,uint32_t prevblocktime) const; @@ -583,6 +597,31 @@ private: * By making the copy constructor private, we prevent accidentally using it when one intends to create a cache on top of a base cache. */ CCoinsViewCache(const CCoinsViewCache &); + + //! Generalized interface for popping anchors + template + void AbstractPopAnchor( + const uint256 &newrt, + ShieldedType type, + Cache &cacheAnchors, + uint256 &hash + ); + + //! Generalized interface for pushing anchors + template + void AbstractPushAnchor( + const Tree &tree, + ShieldedType type, + Cache &cacheAnchors, + uint256 &hash + ); + + //! Interface for bringing an anchor into the cache. + template + void BringBestAnchorIntoCache( + const uint256 ¤tRoot, + Tree &tree + ); }; #endif // BITCOIN_COINS_H diff --git a/src/compressor.h b/src/compressor.h index fa702f0df..961365d26 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -55,16 +55,8 @@ protected: public: CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } - unsigned int GetSerializeSize(int nType, int nVersion) const { - std::vector compr; - if (Compress(compr)) - return compr.size(); - unsigned int nSize = script.size() + nSpecialScripts; - return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); - } - template - void Serialize(Stream &s, int nType, int nVersion) const { + void Serialize(Stream &s) const { std::vector compr; if (Compress(compr)) { s << CFlatData(compr); @@ -76,7 +68,7 @@ public: } template - void Unserialize(Stream &s, int nType, int nVersion) { + void Unserialize(Stream &s) { unsigned int nSize = 0; s >> VARINT(nSize); if (nSize < nSpecialScripts) { @@ -112,7 +104,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { if (!ser_action.ForRead()) { uint64_t nVal = CompressAmount(txout.nValue); READWRITE(VARINT(nVal)); diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index c2972e598..50cac5531 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -10,16 +10,21 @@ static const int32_t MIN_BLOCK_VERSION = 4; /** The minimum allowed transaction version (network rule) */ static const int32_t SPROUT_MIN_TX_VERSION = 1; -/** The minimum allowed transaction version (network rule) */ +/** The minimum allowed Overwinter transaction version (network rule) */ static const int32_t OVERWINTER_MIN_TX_VERSION = 3; -/** The maximum allowed transaction version (network rule) */ +/** The maximum allowed Overwinter transaction version (network rule) */ static const int32_t OVERWINTER_MAX_TX_VERSION = 3; +/** The minimum allowed Sapling transaction version (network rule) */ +static const int32_t SAPLING_MIN_TX_VERSION = 4; +/** The maximum allowed Sapling transaction version (network rule) */ +static const int32_t SAPLING_MAX_TX_VERSION = 4; /** The maximum allowed size for a serialized block, in bytes (network rule) */ static const unsigned int MAX_BLOCK_SIZE = 2000000; /** The maximum allowed number of signature check operations in a block (network rule) */ extern unsigned int MAX_BLOCK_SIGOPS; /** The maximum size of a transaction (network rule) */ -static const unsigned int MAX_TX_SIZE = 100000; +static const unsigned int MAX_TX_SIZE_BEFORE_SAPLING = 100000; +static const unsigned int MAX_TX_SIZE_AFTER_SAPLING = MAX_BLOCK_SIZE; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ extern int COINBASE_MATURITY; /** The minimum value which is invalid for expiry height, used by CTransaction and CMutableTransaction */ diff --git a/src/consensus/params.h b/src/consensus/params.h index 61c35c837..7f860388c 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -23,6 +23,7 @@ enum UpgradeIndex { BASE_SPROUT, UPGRADE_TESTDUMMY, UPGRADE_OVERWINTER, + UPGRADE_SAPLING, // NOTE: Also add new upgrades to NetworkUpgradeInfo in upgrades.cpp MAX_NETWORK_UPGRADES }; @@ -111,6 +112,7 @@ struct Params { int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; } int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; } int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; } + uint256 nMinimumChainWork; }; } // namespace Consensus diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp index c913c7ea0..95bde7925 100644 --- a/src/consensus/upgrades.cpp +++ b/src/consensus/upgrades.cpp @@ -23,6 +23,11 @@ const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = { /*.nBranchId =*/ 0x5ba81b19, /*.strName =*/ "Overwinter", /*.strInfo =*/ "See https://z.cash/upgrade/overwinter.html for details.", + }, + { + /*.nBranchId =*/ 0x76b809bb, + /*.strName =*/ "Sapling", + /*.strInfo =*/ "See https://z.cash/upgrade/sapling.html for details.", } }; @@ -69,6 +74,8 @@ int CurrentEpoch(int nHeight, const Consensus::Params& params) { return idxInt; } } + // Base case + return Consensus::BASE_SPROUT; } uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params) { diff --git a/src/core_io.h b/src/core_io.h index 115e3199d..ba5b4e648 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -16,6 +16,7 @@ class UniValue; // core_read.cpp extern CScript ParseScript(const std::string& s); +extern std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false); extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); extern bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); extern uint256 ParseHashUV(const UniValue& v, const std::string& strName); @@ -25,8 +26,7 @@ extern std::vector ParseHexUV(const UniValue& v, const std::strin // core_write.cpp extern std::string FormatScript(const CScript& script); extern std::string EncodeHexTx(const CTransaction& tx); -extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, - UniValue& out, bool fIncludeHex); +extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); extern void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry); #endif // BITCOIN_CORE_IO_H diff --git a/src/core_memusage.h b/src/core_memusage.h index 711135bb4..b2f4a28ae 100644 --- a/src/core_memusage.h +++ b/src/core_memusage.h @@ -10,7 +10,7 @@ #include "memusage.h" static inline size_t RecursiveDynamicUsage(const CScript& script) { - return memusage::DynamicUsage(*static_cast*>(&script)); + return memusage::DynamicUsage(*static_cast(&script)); } static inline size_t RecursiveDynamicUsage(const COutPoint& out) { diff --git a/src/core_write.cpp b/src/core_write.cpp index 26eeba655..43344656b 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -4,7 +4,7 @@ #include "core_io.h" -#include "base58.h" +#include "key_io.h" #include "primitives/transaction.h" #include "script/script.h" #include "script/standard.h" @@ -15,6 +15,7 @@ #include "utilmoneystr.h" #include "utilstrencodings.h" +#include #include using namespace std; @@ -54,6 +55,67 @@ string FormatScript(const CScript& script) return ret.substr(0, ret.size() - 1); } +const map mapSigHashTypes = + boost::assign::map_list_of + (static_cast(SIGHASH_ALL), string("ALL")) + (static_cast(SIGHASH_ALL|SIGHASH_ANYONECANPAY), string("ALL|ANYONECANPAY")) + (static_cast(SIGHASH_NONE), string("NONE")) + (static_cast(SIGHASH_NONE|SIGHASH_ANYONECANPAY), string("NONE|ANYONECANPAY")) + (static_cast(SIGHASH_SINGLE), string("SINGLE")) + (static_cast(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), string("SINGLE|ANYONECANPAY")) + ; + +/** + * Create the assembly string representation of a CScript object. + * @param[in] script CScript object to convert into the asm string representation. + * @param[in] fAttemptSighashDecode Whether to attempt to decode sighash types on data within the script that matches the format + * of a signature. Only pass true for scripts you believe could contain signatures. For example, + * pass false, or omit the this argument (defaults to false), for scriptPubKeys. + */ +string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) +{ + string str; + opcodetype opcode; + vector vch; + CScript::const_iterator pc = script.begin(); + while (pc < script.end()) { + if (!str.empty()) { + str += " "; + } + if (!script.GetOp(pc, opcode, vch)) { + str += "[error]"; + return str; + } + if (0 <= opcode && opcode <= OP_PUSHDATA4) { + if (vch.size() <= static_cast::size_type>(4)) { + str += strprintf("%d", CScriptNum(vch, false).getint()); + } else { + // the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature + if (fAttemptSighashDecode && !script.IsUnspendable()) { + string strSigHashDecode; + // goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig. + // this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to + // the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the + // checks in CheckSignatureEncoding. + if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, NULL)) { + const unsigned char chSigHashType = vch.back(); + if (mapSigHashTypes.count(chSigHashType)) { + strSigHashDecode = "[" + mapSigHashTypes.find(chSigHashType)->second + "]"; + vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode. + } + } + str += HexStr(vch) + strSigHashDecode; + } else { + str += HexStr(vch); + } + } + } else { + str += GetOpName(opcode); + } + } + return str; +} + string EncodeHexTx(const CTransaction& tx) { CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); @@ -68,7 +130,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, vector addresses; int nRequired; - out.pushKV("asm", scriptPubKey.ToString()); + out.pushKV("asm", ScriptToAsmStr(scriptPubKey)); if (fIncludeHex) out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())); @@ -81,8 +143,9 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("type", GetTxnOutputType(type)); UniValue a(UniValue::VARR); - BOOST_FOREACH(const CTxDestination& addr, addresses) - a.push_back(CBitcoinAddress(addr).ToString()); + for (const CTxDestination& addr : addresses) { + a.push_back(EncodeDestination(addr)); + } out.pushKV("addresses", a); } @@ -101,7 +164,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) in.pushKV("txid", txin.prevout.hash.GetHex()); in.pushKV("vout", (int64_t)txin.prevout.n); UniValue o(UniValue::VOBJ); - o.pushKV("asm", txin.scriptSig.ToString()); + o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); in.pushKV("scriptSig", o); } diff --git a/src/crypto/common.h b/src/crypto/common.h index ad4c6dd5e..9d2100af9 100644 --- a/src/crypto/common.h +++ b/src/crypto/common.h @@ -11,6 +11,7 @@ #include #include +#include #include "sodium.h" #include "compat/endian.h" @@ -21,52 +22,67 @@ uint16_t static inline ReadLE16(const unsigned char* ptr) { - return le16toh(*((uint16_t*)ptr)); + uint16_t x; + memcpy((char*)&x, ptr, 2); + return le16toh(x); } uint32_t static inline ReadLE32(const unsigned char* ptr) { - return le32toh(*((uint32_t*)ptr)); + uint32_t x; + memcpy((char*)&x, ptr, 4); + return le32toh(x); } uint64_t static inline ReadLE64(const unsigned char* ptr) { - return le64toh(*((uint64_t*)ptr)); + uint64_t x; + memcpy((char*)&x, ptr, 8); + return le64toh(x); } void static inline WriteLE16(unsigned char* ptr, uint16_t x) { - *((uint16_t*)ptr) = htole16(x); + uint16_t v = htole16(x); + memcpy(ptr, (char*)&v, 2); } void static inline WriteLE32(unsigned char* ptr, uint32_t x) { - *((uint32_t*)ptr) = htole32(x); + uint32_t v = htole32(x); + memcpy(ptr, (char*)&v, 4); } void static inline WriteLE64(unsigned char* ptr, uint64_t x) { - *((uint64_t*)ptr) = htole64(x); + uint64_t v = htole64(x); + memcpy(ptr, (char*)&v, 8); } uint32_t static inline ReadBE32(const unsigned char* ptr) { - return be32toh(*((uint32_t*)ptr)); + uint32_t x; + memcpy((char*)&x, ptr, 4); + return be32toh(x); } uint64_t static inline ReadBE64(const unsigned char* ptr) { - return be64toh(*((uint64_t*)ptr)); + uint64_t x; + memcpy((char*)&x, ptr, 8); + return be64toh(x); } void static inline WriteBE32(unsigned char* ptr, uint32_t x) { - *((uint32_t*)ptr) = htobe32(x); + uint32_t v = htobe32(x); + memcpy(ptr, (char*)&v, 4); } void static inline WriteBE64(unsigned char* ptr, uint64_t x) { - *((uint64_t*)ptr) = htobe64(x); + uint64_t v = htobe64(x); + memcpy(ptr, (char*)&v, 8); } int inline init_and_check_sodium() diff --git a/src/crypto/equihash.cpp b/src/crypto/equihash.cpp index 04ee5f3b7..fdb907d35 100644 --- a/src/crypto/equihash.cpp +++ b/src/crypto/equihash.cpp @@ -54,7 +54,7 @@ #define __BYTE_ORDER BYTE_ORDER #endif */ -EhSolverCancelledException solver_cancelled; +static EhSolverCancelledException solver_cancelled; template int Equihash::InitialiseState(eh_HashState& base_state) diff --git a/src/leveldbwrapper.cpp b/src/dbwrapper.cpp similarity index 69% rename from src/leveldbwrapper.cpp rename to src/dbwrapper.cpp index 3f1abbe14..47bbb0f05 100644 --- a/src/leveldbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -2,7 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "leveldbwrapper.h" +#include "dbwrapper.h" #include "util.h" @@ -12,20 +12,7 @@ #include #include #include - -void HandleError(const leveldb::Status& status) -{ - if (status.ok()) - return; - LogPrintf("%s\n", status.ToString()); - if (status.IsCorruption()) - throw leveldb_error("Database corrupted"); - if (status.IsIOError()) - throw leveldb_error("Database I/O error"); - if (status.IsNotFound()) - throw leveldb_error("Database entry missing"); - throw leveldb_error("Unknown database error"); -} +#include static leveldb::Options GetOptions(size_t nCacheSize, bool compression, int maxOpenFiles) { @@ -43,7 +30,7 @@ static leveldb::Options GetOptions(size_t nCacheSize, bool compression, int maxO return options; } -CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool compression, int maxOpenFiles) +CDBWrapper::CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool compression, int maxOpenFiles) { penv = NULL; readoptions.verify_checksums = true; @@ -59,17 +46,17 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa if (fWipe) { LogPrintf("Wiping LevelDB in %s\n", path.string()); leveldb::Status result = leveldb::DestroyDB(path.string(), options); - HandleError(result); + dbwrapper_private::HandleError(result); } TryCreateDirectory(path); LogPrintf("Opening LevelDB in %s\n", path.string()); } leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb); - HandleError(status); + dbwrapper_private::HandleError(status); LogPrintf("Opened LevelDB successfully\n"); } -CLevelDBWrapper::~CLevelDBWrapper() +CDBWrapper::~CDBWrapper() { delete pdb; pdb = NULL; @@ -81,9 +68,41 @@ CLevelDBWrapper::~CLevelDBWrapper() options.env = NULL; } -bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) +bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) { leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); - HandleError(status); + dbwrapper_private::HandleError(status); return true; } + +bool CDBWrapper::IsEmpty() +{ + boost::scoped_ptr it(NewIterator()); + it->SeekToFirst(); + return !(it->Valid()); +} + +CDBIterator::~CDBIterator() { delete piter; } +bool CDBIterator::Valid() { return piter->Valid(); } +void CDBIterator::SeekToFirst() { piter->SeekToFirst(); } +void CDBIterator::SeekToLast() { piter->SeekToLast(); } +void CDBIterator::Next() { piter->Next(); } +void CDBIterator::Prev() { piter->Prev(); } + +namespace dbwrapper_private { + +void HandleError(const leveldb::Status& status) +{ + if (status.ok()) + return; + LogPrintf("%s\n", status.ToString()); + if (status.IsCorruption()) + throw dbwrapper_error("Database corrupted"); + if (status.IsIOError()) + throw dbwrapper_error("Database I/O error"); + if (status.IsNotFound()) + throw dbwrapper_error("Database entry missing"); + throw dbwrapper_error("Unknown database error"); +} + +}; diff --git a/src/dbwrapper.h b/src/dbwrapper.h new file mode 100644 index 000000000..ab0c2c707 --- /dev/null +++ b/src/dbwrapper.h @@ -0,0 +1,267 @@ +// Copyright (c) 2012-2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_DBWRAPPER_H +#define BITCOIN_DBWRAPPER_H + +#include "clientversion.h" +#include "serialize.h" +#include "streams.h" +#include "util.h" +#include "version.h" + +#include + +#include +#include + +static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; +static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; + +class dbwrapper_error : public std::runtime_error +{ +public: + dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {} +}; + +class CDBWrapper; + +/** These should be considered an implementation detail of the specific database. + */ +namespace dbwrapper_private { + +/** Handle database error by throwing dbwrapper_error exception. + */ +void HandleError(const leveldb::Status& status); + +}; + +/** Batch of changes queued to be written to a CDBWrapper */ +class CDBBatch +{ + friend class CDBWrapper; + +private: + const CDBWrapper &parent; + leveldb::WriteBatch batch; + +public: + /** + * @param[in] _parent CDBWrapper that this batch is to be submitted to + */ + CDBBatch(const CDBWrapper &_parent) : parent(_parent) { }; + + template + void Write(const K& key, const V& value) + { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); + ssKey << key; + leveldb::Slice slKey(&ssKey[0], ssKey.size()); + + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE); + ssValue << value; + leveldb::Slice slValue(&ssValue[0], ssValue.size()); + + batch.Put(slKey, slValue); + } + + template + void Erase(const K& key) + { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); + ssKey << key; + leveldb::Slice slKey(&ssKey[0], ssKey.size()); + + batch.Delete(slKey); + } +}; + +class CDBIterator +{ +private: + const CDBWrapper &parent; + leveldb::Iterator *piter; + +public: + + /** + * @param[in] _parent Parent CDBWrapper instance. + * @param[in] _piter The original leveldb iterator. + */ + CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) : + parent(_parent), piter(_piter) { }; + ~CDBIterator(); + + bool Valid(); + + void SeekToFirst(); + void SeekToLast(); + + template void Seek(const K& key) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(GetSerializeSize(ssKey, key)); + ssKey << key; + leveldb::Slice slKey(&ssKey[0], ssKey.size()); + piter->Seek(slKey); + } + + void Next(); + void Prev(); + + template bool GetKey(K& key) { + leveldb::Slice slKey = piter->key(); + try { + CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); + ssKey >> key; + } catch(std::exception &e) { + return false; + } + return true; + } + + unsigned int GetKeySize() { + return piter->key().size(); + } + + template bool GetValue(V& value) { + leveldb::Slice slValue = piter->value(); + try { + CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); + ssValue >> value; + } catch(std::exception &e) { + return false; + } + return true; + } + + unsigned int GetValueSize() { + return piter->value().size(); + } + +}; + +class CDBWrapper +{ +private: + //! custom environment this database is using (may be NULL in case of default environment) + leveldb::Env* penv; + + //! database options used + leveldb::Options options; + + //! options used when reading from the database + leveldb::ReadOptions readoptions; + + //! options used when iterating over values of the database + leveldb::ReadOptions iteroptions; + + //! options used when writing to the database + leveldb::WriteOptions writeoptions; + + //! options used when sync writing to the database + leveldb::WriteOptions syncoptions; + + //! the database itself + leveldb::DB* pdb; + +public: + /** + * @param[in] path Location in the filesystem where leveldb data will be stored. + * @param[in] nCacheSize Configures various leveldb cache settings. + * @param[in] fMemory If true, use leveldb's memory environment. + * @param[in] fWipe If true, remove all existing data. + */ + CDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool compression = false, int maxOpenFiles = 64); + ~CDBWrapper(); + + template + bool Read(const K& key, V& value) const + { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); + ssKey << key; + leveldb::Slice slKey(&ssKey[0], ssKey.size()); + + std::string strValue; + leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); + if (!status.ok()) { + if (status.IsNotFound()) + return false; + LogPrintf("LevelDB read failure: %s\n", status.ToString()); + dbwrapper_private::HandleError(status); + } + try { + CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); + ssValue >> value; + } catch (const std::exception&) { + return false; + } + return true; + } + + template + bool Write(const K& key, const V& value, bool fSync = false) + { + CDBBatch batch(*this); + batch.Write(key, value); + return WriteBatch(batch, fSync); + } + + template + bool Exists(const K& key) const + { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); + ssKey << key; + leveldb::Slice slKey(&ssKey[0], ssKey.size()); + + std::string strValue; + leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); + if (!status.ok()) { + if (status.IsNotFound()) + return false; + LogPrintf("LevelDB read failure: %s\n", status.ToString()); + dbwrapper_private::HandleError(status); + } + return true; + } + + template + bool Erase(const K& key, bool fSync = false) + { + CDBBatch batch(*this); + batch.Erase(key); + return WriteBatch(batch, fSync); + } + + bool WriteBatch(CDBBatch& batch, bool fSync = false); + + // not available for LevelDB; provide for compatibility with BDB + bool Flush() + { + return true; + } + + bool Sync() + { + CDBBatch batch(*this); + return WriteBatch(batch, true); + } + + CDBIterator *NewIterator() + { + return new CDBIterator(*this, pdb->NewIterator(iteroptions)); + } + + /** + * Return true if the database managed by this class contains no entries. + */ + bool IsEmpty(); +}; + +#endif // BITCOIN_DBWRAPPER_H + diff --git a/src/deprecation.cpp b/src/deprecation.cpp index fa8b7c521..bc6f4abbe 100644 --- a/src/deprecation.cpp +++ b/src/deprecation.cpp @@ -4,6 +4,7 @@ #include "deprecation.h" +#include "alert.h" #include "clientversion.h" #include "init.h" #include "ui_interface.h" @@ -13,14 +14,15 @@ static const std::string CLIENT_VERSION_STR = FormatVersion(CLIENT_VERSION); extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; -void EnforceNodeDeprecation(int nHeight, bool forceLogging) { +void EnforceNodeDeprecation(int nHeight, bool forceLogging, bool fThread) { // Do not enforce deprecation in regtest or on testnet std::string networkID = Params().NetworkIDString(); + std::string msg; + if (networkID != "main" || ASSETCHAINS_SYMBOL[0] != 0 ) return; int blocksToDeprecation = DEPRECATION_HEIGHT - nHeight; - bool disableDeprecation = (GetArg("-disabledeprecation", "") == CLIENT_VERSION_STR); if (blocksToDeprecation <= 0) { // In order to ensure we only log once per process when deprecation is // disabled (to avoid log spam), we only need to log in two cases: @@ -29,34 +31,20 @@ void EnforceNodeDeprecation(int nHeight, bool forceLogging) { // occurs, but that's an irregular event that won't cause spam. // - The node is starting if (blocksToDeprecation == 0 || forceLogging) { - auto msg = strprintf(_("This version has been deprecated as of block height %d."), + msg = strprintf(_("This version has been deprecated as of block height %d."), DEPRECATION_HEIGHT) + " " + _("You should upgrade to the latest version of Komodo."); - if (!disableDeprecation) { - msg += " " + strprintf(_("To disable deprecation for this version, set %s%s."), - "-disabledeprecation=", CLIENT_VERSION_STR); - } LogPrintf("*** %s\n", msg); + CAlert::Notify(msg, fThread); uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); } - if (!disableDeprecation) { - StartShutdown(); - } - } else if (blocksToDeprecation == DEPRECATION_WARN_LIMIT || - (blocksToDeprecation < DEPRECATION_WARN_LIMIT && forceLogging)) { - std::string msg; - if (disableDeprecation) { - msg = strprintf(_("This version will be deprecated at block height %d."), + StartShutdown(); + } else if (blocksToDeprecation == DEPRECATION_WARN_LIMIT || (blocksToDeprecation < DEPRECATION_WARN_LIMIT && forceLogging)) { + msg = strprintf(_("This version will be deprecated at block height %d, and will automatically shut down."), DEPRECATION_HEIGHT) + " " + _("You should upgrade to the latest version of Komodo."); - } else { - msg = strprintf(_("This version will be deprecated at block height %d, and will automatically shut down."), - DEPRECATION_HEIGHT) + " " + - _("You should upgrade to the latest version of Komodo.") + " " + - strprintf(_("To disable deprecation for this version, set %s%s."), - "-disabledeprecation=", CLIENT_VERSION_STR); - } - LogPrintf("*** %s\n", msg); - uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_WARNING); } + LogPrintf("*** %s\n", msg); + CAlert::Notify(msg, fThread); + uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_WARNING); } diff --git a/src/deprecation.h b/src/deprecation.h index 11eb69ef4..78d449129 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -18,8 +18,11 @@ static const int DEPRECATION_WARN_LIMIT = 60 * 24 * 60; // 2 months /** * Checks whether the node is deprecated based on the current block height, and * shuts down the node with an error if so (and deprecation is not disabled for - * the current client version). + * the current client version). Warning and error messages are sent to the debug + * log, the metrics UI, and (if configured) -alertnofity. + * + * fThread means run -alertnotify in a free-running thread. */ -void EnforceNodeDeprecation(int nHeight, bool forceLogging=false); +void EnforceNodeDeprecation(int nHeight, bool forceLogging=false, bool fThread=true); #endif // ZCASH_DEPRECATION_H diff --git a/src/gtest/json_test_vectors.h b/src/gtest/json_test_vectors.h index 3639c9121..907d4834a 100644 --- a/src/gtest/json_test_vectors.h +++ b/src/gtest/json_test_vectors.h @@ -26,7 +26,7 @@ void expect_deser_same(const T& expected) CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); ss2 << object; - ASSERT_TRUE(serialized_size == ss2.size()); + ASSERT_EQ(serialized_size, ss2.size()); ASSERT_TRUE(memcmp(&*ss1.begin(), &*ss2.begin(), serialized_size) == 0); } @@ -45,7 +45,7 @@ void expect_test_vector(T& v, const U& expected) std::string raw = v.get_str(); CDataStream ss2(ParseHex(raw), SER_NETWORK, PROTOCOL_VERSION); - ASSERT_TRUE(ss1.size() == ss2.size()); + ASSERT_EQ(ss1.size(), ss2.size()); ASSERT_TRUE(memcmp(&*ss1.begin(), &*ss2.begin(), ss1.size()) == 0); #endif } diff --git a/src/gtest/main.cpp b/src/gtest/main.cpp index d2ae0b23d..00700d05b 100644 --- a/src/gtest/main.cpp +++ b/src/gtest/main.cpp @@ -1,5 +1,6 @@ #include "gmock/gmock.h" #include "crypto/common.h" +#include "key.h" #include "pubkey.h" #include "zcash/JoinSplit.hpp" #include "util.h" @@ -7,6 +8,8 @@ #include #include +#include "librustzcash.h" + struct ECCryptoClosure { ECCVerifyHandle handle; @@ -18,13 +21,36 @@ ZCJoinSplit* params; int main(int argc, char **argv) { assert(init_and_check_sodium() != -1); + ECC_Start(); + libsnark::default_r1cs_ppzksnark_pp::init_public_params(); libsnark::inhibit_profiling_info = true; libsnark::inhibit_profiling_counters = true; boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key"; boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key"; params = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string()); + + boost::filesystem::path sapling_spend = ZC_GetParamsDir() / "sapling-spend.params"; + boost::filesystem::path sapling_output = ZC_GetParamsDir() / "sapling-output.params"; + boost::filesystem::path sprout_groth16 = ZC_GetParamsDir() / "sprout-groth16.params"; + + std::string sapling_spend_str = sapling_spend.string(); + std::string sapling_output_str = sapling_output.string(); + std::string sprout_groth16_str = sprout_groth16.string(); + + librustzcash_init_zksnark_params( + sapling_spend_str.c_str(), + "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c", + sapling_output_str.c_str(), + "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028", + sprout_groth16_str.c_str(), + "e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a" + ); testing::InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); + + auto ret = RUN_ALL_TESTS(); + + ECC_Stop(); + return ret; } diff --git a/src/gtest/test_checkblock.cpp b/src/gtest/test_checkblock.cpp index 284cff134..7c13535c2 100644 --- a/src/gtest/test_checkblock.cpp +++ b/src/gtest/test_checkblock.cpp @@ -68,27 +68,99 @@ TEST(CheckBlock, BlockSproutRejectsBadVersion) { } -TEST(ContextualCheckBlock, BadCoinbaseHeight) { - SelectParams(CBaseChainParams::MAIN); +class ContextualCheckBlockTest : public ::testing::Test { +protected: + virtual void SetUp() { + SelectParams(CBaseChainParams::MAIN); + } - // Create a block with no height in scriptSig - CMutableTransaction mtx; - mtx.vin.resize(1); - mtx.vin[0].prevout.SetNull(); + virtual void TearDown() { + // Revert to test default. No-op on mainnet params. + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + } + + // Returns a valid but empty mutable transaction at block height 1. + CMutableTransaction GetFirstBlockCoinbaseTx() { + CMutableTransaction mtx; + + // No inputs. + mtx.vin.resize(1); + mtx.vin[0].prevout.SetNull(); + + // Set height to 1. + mtx.vin[0].scriptSig = CScript() << 1 << OP_0; + + // Give it a single zero-valued, always-valid output. + mtx.vout.resize(1); + mtx.vout[0].scriptPubKey = CScript() << OP_TRUE; + mtx.vout[0].nValue = 0; + + // Give it a Founder's Reward vout for height 1. + mtx.vout.push_back(CTxOut( + GetBlockSubsidy(1, Params().GetConsensus())/5, + Params().GetFoundersRewardScriptAtHeight(1))); + + return mtx; + } + + // Expects a height-1 block containing a given transaction to pass + // ContextualCheckBlock. This is used in accepting (Sprout-Sprout, + // Overwinter-Overwinter, ...) tests. You should not call it without + // calling a SCOPED_TRACE macro first to usefully label any failures. + void ExpectValidBlockFromTx(const CTransaction& tx) { + // Create a block and add the transaction to it. + CBlock block; + block.vtx.push_back(tx); + + // Set the previous block index to the genesis block. + CBlockIndex indexPrev {Params().GenesisBlock()}; + + // We now expect this to be a valid block. + MockCValidationState state; + EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev)); + } + + // Expects a height-1 block containing a given transaction to fail + // ContextualCheckBlock. This is used in rejecting (Sprout-Overwinter, + // Overwinter-Sprout, ...) tests. You should not call it without + // calling a SCOPED_TRACE macro first to usefully label any failures. + void ExpectInvalidBlockFromTx(const CTransaction& tx, int level, std::string reason) { + // Create a block and add the transaction to it. + CBlock block; + block.vtx.push_back(tx); + + // Set the previous block index to the genesis block. + CBlockIndex indexPrev {Params().GenesisBlock()}; + + // We now expect this to be an invalid block, for the given reason. + MockCValidationState state; + EXPECT_CALL(state, DoS(level, false, REJECT_INVALID, reason, false)).Times(1); + EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev)); + } + +}; + + +TEST_F(ContextualCheckBlockTest, BadCoinbaseHeight) { + // Put a transaction in a block with no height in scriptSig + CMutableTransaction mtx = GetFirstBlockCoinbaseTx(); mtx.vin[0].scriptSig = CScript() << OP_0; - mtx.vout.resize(1); - mtx.vout[0].scriptPubKey = CScript() << OP_TRUE; - mtx.vout[0].nValue = 0; - CTransaction tx {mtx}; + mtx.vout.pop_back(); // remove the FR output + CBlock block; - block.vtx.push_back(tx); + block.vtx.push_back(mtx); // Treating block as genesis should pass MockCValidationState state; EXPECT_TRUE(ContextualCheckBlock(block, state, NULL)); + // Give the transaction a Founder's Reward vout + mtx.vout.push_back(CTxOut( + GetBlockSubsidy(1, Params().GetConsensus())/5, + Params().GetFoundersRewardScriptAtHeight(1))); + // Treating block as non-genesis should fail - mtx.vout.push_back(CTxOut(GetBlockSubsidy(1, Params().GetConsensus())/5, Params().GetFoundersRewardScriptAtHeight(1))); CTransaction tx2 {mtx}; block.vtx[0] = tx2; CBlock prev; @@ -111,124 +183,142 @@ TEST(ContextualCheckBlock, BadCoinbaseHeight) { EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev)); } -// Test that a block evaluated under Sprout rules cannot contain Overwinter transactions. +// TEST PLAN: first, check that each ruleset accepts its own transaction type. +// Currently (May 2018) this means we'll test Sprout-Sprout, +// Overwinter-Overwinter, and Sapling-Sapling. + +// Test block evaluated under Sprout rules will accept Sprout transactions. // This test assumes that mainnet Overwinter activation is at least height 2. -TEST(ContextualCheckBlock, BlockSproutRulesRejectOverwinterTx) { - SelectParams(CBaseChainParams::MAIN); +TEST_F(ContextualCheckBlockTest, BlockSproutRulesAcceptSproutTx) { + CMutableTransaction mtx = GetFirstBlockCoinbaseTx(); - CMutableTransaction mtx; - mtx.vin.resize(1); - mtx.vin[0].prevout.SetNull(); - mtx.vin[0].scriptSig = CScript() << 1 << OP_0; - mtx.vout.resize(1); - mtx.vout[0].scriptPubKey = CScript() << OP_TRUE; - mtx.vout[0].nValue = 0; - - mtx.fOverwintered = true; - mtx.nVersion = 3; - mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; - - CTransaction tx {mtx}; - CBlock block; - block.vtx.push_back(tx); - - MockCValidationState state; - CBlockIndex indexPrev {Params().GenesisBlock()}; - - EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1); - EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev)); -} - - -// Test block evaluated under Sprout rules will accept Sprout transactions -TEST(ContextualCheckBlock, BlockSproutRulesAcceptSproutTx) { - SelectParams(CBaseChainParams::REGTEST); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); - - CMutableTransaction mtx; - mtx.vin.resize(1); - mtx.vin[0].prevout.SetNull(); - mtx.vin[0].scriptSig = CScript() << 1 << OP_0; - mtx.vout.resize(1); - mtx.vout[0].scriptPubKey = CScript() << OP_TRUE; - mtx.vout[0].nValue = 0; - mtx.vout.push_back(CTxOut( - GetBlockSubsidy(1, Params().GetConsensus())/5, - Params().GetFoundersRewardScriptAtHeight(1))); + // Make it a Sprout transaction w/o JoinSplits mtx.fOverwintered = false; mtx.nVersion = 1; - CTransaction tx {mtx}; - CBlock block; - block.vtx.push_back(tx); - MockCValidationState state; - CBlockIndex indexPrev {Params().GenesisBlock()}; - - EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev)); - - // Revert to default - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + SCOPED_TRACE("BlockSproutRulesAcceptSproutTx"); + ExpectValidBlockFromTx(CTransaction(mtx)); } -// Test block evaluated under Overwinter rules will accept Overwinter transactions -TEST(ContextualCheckBlock, BlockOverwinterRulesAcceptOverwinterTx) { +// Test block evaluated under Overwinter rules will accept Overwinter transactions. +TEST_F(ContextualCheckBlockTest, BlockOverwinterRulesAcceptOverwinterTx) { SelectParams(CBaseChainParams::REGTEST); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1); - CMutableTransaction mtx; - mtx.vin.resize(1); - mtx.vin[0].prevout.SetNull(); - mtx.vin[0].scriptSig = CScript() << 1 << OP_0; - mtx.vout.resize(1); - mtx.vout[0].scriptPubKey = CScript() << OP_TRUE; - mtx.vout[0].nValue = 0; - mtx.vout.push_back(CTxOut( - GetBlockSubsidy(1, Params().GetConsensus())/5, - Params().GetFoundersRewardScriptAtHeight(1))); + CMutableTransaction mtx = GetFirstBlockCoinbaseTx(); + + // Make it an Overwinter transaction mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; - CTransaction tx {mtx}; - CBlock block; - block.vtx.push_back(tx); - MockCValidationState state; - CBlockIndex indexPrev {Params().GenesisBlock()}; - - EXPECT_TRUE(ContextualCheckBlock(block, state, &indexPrev)); - - // Revert to default - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + SCOPED_TRACE("BlockOverwinterRulesAcceptOverwinterTx"); + ExpectValidBlockFromTx(CTransaction(mtx)); } +// Test that a block evaluated under Sapling rules can contain Sapling transactions. +TEST_F(ContextualCheckBlockTest, BlockSaplingRulesAcceptSaplingTx) { + SelectParams(CBaseChainParams::REGTEST); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, 1); -// Test block evaluated under Overwinter rules will reject Sprout transactions -TEST(ContextualCheckBlock, BlockOverwinterRulesRejectSproutTx) { + CMutableTransaction mtx = GetFirstBlockCoinbaseTx(); + + // Make it a Sapling transaction + mtx.fOverwintered = true; + mtx.nVersion = SAPLING_TX_VERSION; + mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; + + SCOPED_TRACE("BlockSaplingRulesAcceptSaplingTx"); + ExpectValidBlockFromTx(CTransaction(mtx)); +} + +// TEST PLAN: next, check that each ruleset will not accept other transaction +// types. Currently (May 2018) this means we'll test Sprout-Overwinter, +// Sprout-Sapling, Overwinter-Sprout, Overwinter-Sapling, Sapling-Sprout, and +// Sapling-Overwinter. + +// Test that a block evaluated under Sprout rules cannot contain non-Sprout +// transactions which require Overwinter to be active. This test assumes that +// mainnet Overwinter activation is at least height 2. +TEST_F(ContextualCheckBlockTest, BlockSproutRulesRejectOtherTx) { + CMutableTransaction mtx = GetFirstBlockCoinbaseTx(); + + // Make it an Overwinter transaction + mtx.fOverwintered = true; + mtx.nVersion = OVERWINTER_TX_VERSION; + mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; + + { + SCOPED_TRACE("BlockSproutRulesRejectOverwinterTx"); + ExpectInvalidBlockFromTx(CTransaction(mtx), 0, "tx-overwinter-not-active"); + } + + // Make it a Sapling transaction + mtx.fOverwintered = true; + mtx.nVersion = SAPLING_TX_VERSION; + mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; + + { + SCOPED_TRACE("BlockSproutRulesRejectSaplingTx"); + ExpectInvalidBlockFromTx(CTransaction(mtx), 0, "tx-overwinter-not-active"); + } +}; + + +// Test block evaluated under Overwinter rules cannot contain non-Overwinter +// transactions. +TEST_F(ContextualCheckBlockTest, BlockOverwinterRulesRejectOtherTx) { SelectParams(CBaseChainParams::REGTEST); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1); - CMutableTransaction mtx; - mtx.vin.resize(1); - mtx.vin[0].prevout.SetNull(); - mtx.vin[0].scriptSig = CScript() << 1 << OP_0; - mtx.vout.resize(1); - mtx.vout[0].scriptPubKey = CScript() << OP_TRUE; - mtx.vout[0].nValue = 0; + CMutableTransaction mtx = GetFirstBlockCoinbaseTx(); + // Set the version to Sprout+JoinSplit (but nJoinSplit will be 0). mtx.nVersion = 2; - CTransaction tx {mtx}; - CBlock block; - block.vtx.push_back(tx); + { + SCOPED_TRACE("BlockOverwinterRulesRejectSproutTx"); + ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "tx-overwinter-active"); + } - MockCValidationState state; - CBlockIndex indexPrev {Params().GenesisBlock()}; + // Make it a Sapling transaction + mtx.fOverwintered = true; + mtx.nVersion = SAPLING_TX_VERSION; + mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; - EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-active", false)).Times(1); - EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev)); - - // Revert to default - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + { + SCOPED_TRACE("BlockOverwinterRulesRejectSaplingTx"); + ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "bad-overwinter-tx-version-group-id"); + } +} + + +// Test block evaluated under Sapling rules cannot contain non-Sapling transactions. +TEST_F(ContextualCheckBlockTest, BlockSaplingRulesRejectOtherTx) { + SelectParams(CBaseChainParams::REGTEST); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, 1); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, 1); + + CMutableTransaction mtx = GetFirstBlockCoinbaseTx(); + + // Set the version to Sprout+JoinSplit (but nJoinSplit will be 0). + mtx.nVersion = 2; + + { + SCOPED_TRACE("BlockSaplingRulesRejectSproutTx"); + ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "tx-overwinter-active"); + } + + // Make it an Overwinter transaction + mtx.fOverwintered = true; + mtx.nVersion = OVERWINTER_TX_VERSION; + mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; + + { + SCOPED_TRACE("BlockSaplingRulesRejectOverwinterTx"); + ExpectInvalidBlockFromTx(CTransaction(mtx), 100, "bad-sapling-tx-version-group-id"); + } } diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index bec9cdd6f..8e82f3850 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -6,6 +6,8 @@ #include "primitives/transaction.h" #include "consensus/validation.h" +extern ZCJoinSplit* params; + TEST(checktransaction_tests, check_vpub_not_both_nonzero) { CMutableTransaction tx; tx.nVersion = 2; @@ -43,6 +45,7 @@ public: MOCK_CONST_METHOD0(GetRejectReason, std::string()); }; +void CreateJoinSplitSignature(CMutableTransaction& mtx, uint32_t consensusBranchId); CMutableTransaction GetValidTransaction() { uint32_t consensusBranchId = SPROUT_BRANCH_ID; @@ -63,7 +66,11 @@ CMutableTransaction GetValidTransaction() { mtx.vjoinsplit[1].nullifiers.at(0) = uint256S("0000000000000000000000000000000000000000000000000000000000000002"); mtx.vjoinsplit[1].nullifiers.at(1) = uint256S("0000000000000000000000000000000000000000000000000000000000000003"); + CreateJoinSplitSignature(mtx, consensusBranchId); + return mtx; +} +void CreateJoinSplitSignature(CMutableTransaction& mtx, uint32_t consensusBranchId) { // Generate an ephemeral keypair. uint256 joinSplitPubKey; unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES]; @@ -86,7 +93,6 @@ CMutableTransaction GetValidTransaction() { dataToBeSigned.begin(), 32, joinSplitPrivKey ) == 0); - return mtx; } TEST(checktransaction_tests, valid_transaction) { @@ -129,7 +135,8 @@ TEST(checktransaction_tests, bad_txns_vout_empty) { CheckTransactionWithoutProofVerification(tx, state); } -TEST(checktransaction_tests, bad_txns_oversize) { +TEST(checktransaction_tests, BadTxnsOversize) { + SelectParams(CBaseChainParams::REGTEST); CMutableTransaction mtx = GetValidTransaction(); mtx.vin[0].scriptSig = CScript(); @@ -153,10 +160,100 @@ TEST(checktransaction_tests, bad_txns_oversize) { CTransaction tx(mtx); ASSERT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), 100202); + // Passes non-contextual checks... + MockCValidationState state; + EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state)); + + // ... but fails contextual ones! + EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1); + EXPECT_FALSE(ContextualCheckTransaction(tx, state, 1, 100)); + } + + { + // But should be fine again once Sapling activates! + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + + mtx.fOverwintered = true; + mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; + mtx.nVersion = SAPLING_TX_VERSION; + + // Change the proof types (which requires re-signing the JoinSplit data) + mtx.vjoinsplit[0].proof = libzcash::GrothProof(); + mtx.vjoinsplit[1].proof = libzcash::GrothProof(); + CreateJoinSplitSignature(mtx, NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId); + + CTransaction tx(mtx); + EXPECT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), 103713); + + MockCValidationState state; + EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state)); + EXPECT_TRUE(ContextualCheckTransaction(tx, state, 1, 100)); + + // Revert to default + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + } +} + +TEST(checktransaction_tests, OversizeSaplingTxns) { + SelectParams(CBaseChainParams::REGTEST); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + + CMutableTransaction mtx = GetValidTransaction(); + mtx.fOverwintered = true; + mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; + mtx.nVersion = SAPLING_TX_VERSION; + + // Change the proof types (which requires re-signing the JoinSplit data) + mtx.vjoinsplit[0].proof = libzcash::GrothProof(); + mtx.vjoinsplit[1].proof = libzcash::GrothProof(); + CreateJoinSplitSignature(mtx, NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId); + + // Transaction just under the limit + mtx.vin[0].scriptSig = CScript(); + std::vector vchData(520); + for (unsigned int i = 0; i < 3809; ++i) + mtx.vin[0].scriptSig << vchData << OP_DROP; + std::vector vchDataRemainder(453); + mtx.vin[0].scriptSig << vchDataRemainder << OP_DROP; + mtx.vin[0].scriptSig << OP_1; + + { + CTransaction tx(mtx); + EXPECT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), MAX_TX_SIZE_AFTER_SAPLING - 1); + + CValidationState state; + EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state)); + } + + // Transaction equal to the limit + mtx.vin[1].scriptSig << OP_1; + + { + CTransaction tx(mtx); + EXPECT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), MAX_TX_SIZE_AFTER_SAPLING); + + CValidationState state; + EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state)); + } + + // Transaction just over the limit + mtx.vin[1].scriptSig << OP_1; + + { + CTransaction tx(mtx); + EXPECT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), MAX_TX_SIZE_AFTER_SAPLING + 1); + MockCValidationState state; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1); - CheckTransactionWithoutProofVerification(tx, state); + EXPECT_FALSE(CheckTransactionWithoutProofVerification(tx, state)); } + + // Revert to default + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); } TEST(checktransaction_tests, bad_txns_vout_negative) { @@ -193,6 +290,54 @@ TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_outputs) { CheckTransactionWithoutProofVerification(tx, state); } +TEST(checktransaction_tests, ValueBalanceNonZero) { + CMutableTransaction mtx = GetValidTransaction(); + mtx.valueBalance = 10; + + CTransaction tx(mtx); + + MockCValidationState state; + EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-valuebalance-nonzero", false)).Times(1); + CheckTransactionWithoutProofVerification(tx, state); +} + +TEST(checktransaction_tests, PositiveValueBalanceTooLarge) { + CMutableTransaction mtx = GetValidTransaction(); + mtx.vShieldedSpend.resize(1); + mtx.valueBalance = MAX_MONEY + 1; + + CTransaction tx(mtx); + + MockCValidationState state; + EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-valuebalance-toolarge", false)).Times(1); + CheckTransactionWithoutProofVerification(tx, state); +} + +TEST(checktransaction_tests, NegativeValueBalanceTooLarge) { + CMutableTransaction mtx = GetValidTransaction(); + mtx.vShieldedSpend.resize(1); + mtx.valueBalance = -(MAX_MONEY + 1); + + CTransaction tx(mtx); + + MockCValidationState state; + EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-valuebalance-toolarge", false)).Times(1); + CheckTransactionWithoutProofVerification(tx, state); +} + +TEST(checktransaction_tests, ValueBalanceOverflowsTotal) { + CMutableTransaction mtx = GetValidTransaction(); + mtx.vShieldedSpend.resize(1); + mtx.vout[0].nValue = 1; + mtx.valueBalance = -MAX_MONEY; + + CTransaction tx(mtx); + + MockCValidationState state; + EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge", false)).Times(1); + CheckTransactionWithoutProofVerification(tx, state); +} + TEST(checktransaction_tests, bad_txns_txouttotal_toolarge_joinsplit) { CMutableTransaction mtx = GetValidTransaction(); mtx.vout[0].nValue = 1; @@ -361,7 +506,7 @@ TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) { CTransaction tx(mtx); MockCValidationState state; - EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); + EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); ContextualCheckTransaction(tx, state, 0, 100); } @@ -394,14 +539,14 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) { CTransaction tx(mtx); MockCValidationState state; - EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); + EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); ContextualCheckTransaction(tx, state, 0, 100); } TEST(checktransaction_tests, OverwinterConstructors) { CMutableTransaction mtx; mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 20; @@ -432,7 +577,7 @@ TEST(checktransaction_tests, OverwinterConstructors) { TEST(checktransaction_tests, OverwinterSerialization) { CMutableTransaction mtx; mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 99; @@ -496,7 +641,7 @@ TEST(checktransaction_tests, OverwinterValidTx) { CMutableTransaction mtx = GetValidTransaction(); mtx.vjoinsplit.resize(0); mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 0; CTransaction tx(mtx); @@ -508,7 +653,7 @@ TEST(checktransaction_tests, OverwinterExpiryHeight) { CMutableTransaction mtx = GetValidTransaction(); mtx.vjoinsplit.resize(0); mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 0; @@ -567,6 +712,58 @@ class UNSAFE_CTransaction : public CTransaction { UNSAFE_CTransaction(const CMutableTransaction &tx) : CTransaction(tx, true) {} }; +TEST(checktransaction_tests, SaplingSproutInputSumsTooLarge) { + CMutableTransaction mtx = GetValidTransaction(); + mtx.vjoinsplit.resize(0); + mtx.fOverwintered = true; + mtx.nVersion = SAPLING_TX_VERSION; + mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; + mtx.nExpiryHeight = 0; + + { + // create JSDescription + uint256 rt; + uint256 joinSplitPubKey; + std::array inputs = { + libzcash::JSInput(), + libzcash::JSInput() + }; + std::array outputs = { + libzcash::JSOutput(), + libzcash::JSOutput() + }; + std::array inputMap; + std::array outputMap; + + auto jsdesc = JSDescription::Randomized( + true, + *params, joinSplitPubKey, rt, + inputs, outputs, + inputMap, outputMap, + 0, 0, false); + + mtx.vjoinsplit.push_back(jsdesc); + } + + mtx.vShieldedSpend.push_back(SpendDescription()); + + mtx.vjoinsplit[0].vpub_new = (MAX_MONEY / 2) + 10; + + { + UNSAFE_CTransaction tx(mtx); + CValidationState state; + EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state)); + } + + mtx.valueBalance = (MAX_MONEY / 2) + 10; + + { + UNSAFE_CTransaction tx(mtx); + MockCValidationState state; + EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-txintotal-toolarge", false)).Times(1); + CheckTransactionWithoutProofVerification(tx, state); + } +} // Test bad Overwinter version number in CheckTransactionWithoutProofVerification TEST(checktransaction_tests, OverwinterVersionNumberLow) { @@ -610,7 +807,7 @@ TEST(checktransaction_tests, OverwinterBadVersionGroupId) { CMutableTransaction mtx = GetValidTransaction(); mtx.vjoinsplit.resize(0); mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nExpiryHeight = 0; mtx.nVersionGroupId = 0x12345678; @@ -626,13 +823,13 @@ TEST(checktransaction_tests, OverwinterNotActive) { CMutableTransaction mtx = GetValidTransaction(); mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 0; CTransaction tx(mtx); MockCValidationState state; - EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1); + EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1); ContextualCheckTransaction(tx, state, 1, 100); } @@ -643,7 +840,7 @@ TEST(checktransaction_tests, OverwinterFlagNotSet) { CMutableTransaction mtx = GetValidTransaction(); mtx.fOverwintered = false; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 0; @@ -684,7 +881,9 @@ TEST(checktransaction_tests, OverwinteredContextualCreateTx) { SelectParams(CBaseChainParams::REGTEST); const Consensus::Params& consensusParams = Params().GetConsensus(); int activationHeight = 5; + int saplingActivationHeight = 30; UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, activationHeight); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, saplingActivationHeight); { CMutableTransaction mtx = CreateNewContextualCMutableTransaction( @@ -704,10 +903,64 @@ TEST(checktransaction_tests, OverwinteredContextualCreateTx) { EXPECT_EQ(mtx.nVersion, 3); EXPECT_EQ(mtx.fOverwintered, true); EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); - EXPECT_EQ(mtx.nExpiryHeight, 0); + EXPECT_EQ(mtx.nExpiryHeight, activationHeight + expiryDelta); + } + + // Close to Sapling activation + { + CMutableTransaction mtx = CreateNewContextualCMutableTransaction( + consensusParams, saplingActivationHeight - expiryDelta - 2); + + EXPECT_EQ(mtx.fOverwintered, true); + EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); + EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION); + EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 2); + } + + { + CMutableTransaction mtx = CreateNewContextualCMutableTransaction( + consensusParams, saplingActivationHeight - expiryDelta - 1); + + EXPECT_EQ(mtx.fOverwintered, true); + EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); + EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION); + EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 1); + } + + { + CMutableTransaction mtx = CreateNewContextualCMutableTransaction( + consensusParams, saplingActivationHeight - expiryDelta); + + EXPECT_EQ(mtx.fOverwintered, true); + EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); + EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION); + EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 1); + } + + // Just before Sapling activation + { + CMutableTransaction mtx = CreateNewContextualCMutableTransaction( + consensusParams, saplingActivationHeight - 1); + + EXPECT_EQ(mtx.fOverwintered, true); + EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); + EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION); + EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 1); + } + + // Sapling activates + { + CMutableTransaction mtx = CreateNewContextualCMutableTransaction( + consensusParams, saplingActivationHeight); + + EXPECT_EQ(mtx.fOverwintered, true); + EXPECT_EQ(mtx.nVersionGroupId, SAPLING_VERSION_GROUP_ID); + EXPECT_EQ(mtx.nVersion, SAPLING_TX_VERSION); + EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight + expiryDelta); } // Revert to default + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); } @@ -771,4 +1024,4 @@ TEST(checktransaction_tests, BadTxReceivedOverNetwork) FAIL() << "Expected std::ios_base::failure 'Unknown transaction format', got some other exception"; } } -} \ No newline at end of file +} diff --git a/src/gtest/test_circuit.cpp b/src/gtest/test_circuit.cpp index 2cc9dbcbb..ab2a8ecb6 100644 --- a/src/gtest/test_circuit.cpp +++ b/src/gtest/test_circuit.cpp @@ -106,7 +106,7 @@ bool test_merkle_gadget( mgadget1.generate_r1cs_constraints(); mgadget2.generate_r1cs_constraints(); - ZCIncrementalMerkleTree tree; + SproutMerkleTree tree; uint256 commitment1_data = uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c"); uint256 commitment2_data = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7"); tree.append(commitment1_data); diff --git a/src/gtest/test_deprecation.cpp b/src/gtest/test_deprecation.cpp index eb2d7bfc6..a6ff40f70 100644 --- a/src/gtest/test_deprecation.cpp +++ b/src/gtest/test_deprecation.cpp @@ -1,12 +1,16 @@ #include #include +#include "chainparams.h" #include "clientversion.h" #include "deprecation.h" #include "init.h" #include "ui_interface.h" #include "util.h" -#include "chainparams.h" +#include "utilstrencodings.h" + +#include +#include using ::testing::StrictMock; @@ -43,6 +47,18 @@ protected: } StrictMock mock_; + + static std::vector read_lines(boost::filesystem::path filepath) { + std::vector result; + + std::ifstream f(filepath.string().c_str()); + std::string line; + while (std::getline(f,line)) { + result.push_back(line); + } + + return result; + } }; TEST_F(DeprecationTest, NonDeprecatedNodeKeepsRunning) { @@ -91,22 +107,6 @@ TEST_F(DeprecationTest, DeprecatedNodeErrorIsRepeatedOnStartup) { EXPECT_TRUE(ShutdownRequested()); } -TEST_F(DeprecationTest, DeprecatedNodeShutsDownIfOldVersionDisabled) { - EXPECT_FALSE(ShutdownRequested()); - mapArgs["-disabledeprecation"] = "1.0.0"; - EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_ERROR)); - EnforceNodeDeprecation(DEPRECATION_HEIGHT); - EXPECT_TRUE(ShutdownRequested()); -} - -TEST_F(DeprecationTest, DeprecatedNodeKeepsRunningIfCurrentVersionDisabled) { - EXPECT_FALSE(ShutdownRequested()); - mapArgs["-disabledeprecation"] = CLIENT_VERSION_STR; - EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_ERROR)); - EnforceNodeDeprecation(DEPRECATION_HEIGHT); - EXPECT_FALSE(ShutdownRequested()); -} - TEST_F(DeprecationTest, DeprecatedNodeIgnoredOnRegtest) { SelectParams(CBaseChainParams::REGTEST); EXPECT_FALSE(ShutdownRequested()); @@ -119,4 +119,31 @@ TEST_F(DeprecationTest, DeprecatedNodeIgnoredOnTestnet) { EXPECT_FALSE(ShutdownRequested()); EnforceNodeDeprecation(DEPRECATION_HEIGHT+1); EXPECT_FALSE(ShutdownRequested()); -} \ No newline at end of file +} + +TEST_F(DeprecationTest, AlertNotify) { + boost::filesystem::path temp = GetTempPath() / + boost::filesystem::unique_path("alertnotify-%%%%.txt"); + + mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string(); + + EXPECT_CALL(mock_, ThreadSafeMessageBox(::testing::_, "", CClientUIInterface::MSG_WARNING)); + EnforceNodeDeprecation(DEPRECATION_HEIGHT - DEPRECATION_WARN_LIMIT, false, false); + + std::vector r = read_lines(temp); + EXPECT_EQ(r.size(), 1u); + + // -alertnotify restricts the message to safe characters. + auto expectedMsg = strprintf( + "This version will be deprecated at block height %d, and will automatically shut down. You should upgrade to the latest version of Zcash.", + DEPRECATION_HEIGHT); + + // Windows built-in echo semantics are different than posixy shells. Quotes and + // whitespace are printed literally. +#ifndef WIN32 + EXPECT_EQ(r[0], expectedMsg); +#else + EXPECT_EQ(r[0], strprintf("'%s' ", expectedMsg)); +#endif + boost::filesystem::remove(temp); +} diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index 63649cee1..7e5a3cf05 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -25,7 +25,6 @@ // #if 0 TEST(founders_reward_test, create_testnet_2of3multisig) { - ECC_Start(); SelectParams(CBaseChainParams::TESTNET); boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); boost::filesystem::create_directories(pathTemp); @@ -60,7 +59,7 @@ TEST(founders_reward_test, create_testnet_2of3multisig) { pWallet->AddCScript(result); pWallet->SetAddressBook(innerID, "", "receive"); - std::string address = CBitcoinAddress(innerID).ToString(); + std::string address = EncodeDestination(innerID); addresses.push_back(address); } @@ -81,8 +80,6 @@ TEST(founders_reward_test, create_testnet_2of3multisig) { std::cout << s << std::endl; pWallet->Flush(true); - - ECC_Stop(); } #endif @@ -107,11 +104,11 @@ TEST(founders_reward_test, general) { // address = t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy // script.ToString() = OP_HASH160 55d64928e69829d9376c776550b6cc710d427153 OP_EQUAL // HexStr(script) = a91455d64928e69829d9376c776550b6cc710d42715387 - EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(1), ParseHex("a914ef775f1f997f122a062fff1a2d7443abd1f9c64287")); + EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(1)), "a914ef775f1f997f122a062fff1a2d7443abd1f9c64287"); EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(1), "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi"); - EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(53126), ParseHex("a914ac67f4c072668138d88a86ff21b27207b283212f87")); + EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(53126)), "a914ac67f4c072668138d88a86ff21b27207b283212f87"); EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53126), "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2"); - EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(53127), ParseHex("a91455d64928e69829d9376c776550b6cc710d42715387")); + EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(53127)), "a91455d64928e69829d9376c776550b6cc710d42715387"); EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53127), "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy"); int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(); diff --git a/src/gtest/test_joinsplit.cpp b/src/gtest/test_joinsplit.cpp index 979d0d518..4de2fc471 100644 --- a/src/gtest/test_joinsplit.cpp +++ b/src/gtest/test_joinsplit.cpp @@ -3,192 +3,222 @@ #include "utilstrencodings.h" #include +#include #include "zcash/prf.h" #include "util.h" - +#include "streams.h" +#include "version.h" +#include "serialize.h" +#include "primitives/transaction.h" #include "zcash/JoinSplit.hpp" #include "zcash/Note.hpp" #include "zcash/NoteEncryption.hpp" #include "zcash/IncrementalMerkleTree.hpp" +#include + using namespace libzcash; extern ZCJoinSplit* params; +typedef std::array SproutProofs; +// Make both the PHGR and Groth proof for a Sprout statement, +// and store the results in JSDescription objects. +SproutProofs makeSproutProofs( + ZCJoinSplit& js, + const std::array& inputs, + const std::array& outputs, + const uint256& joinSplitPubKey, + uint64_t vpub_old, + uint64_t vpub_new, + const uint256& rt +){ + //Making the PHGR proof + JSDescription phgr(false, js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new); + //Making the Groth proof + JSDescription groth(true, js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new); + + return {phgr, groth}; + +} + +bool verifySproutProofs( + ZCJoinSplit& js, + const SproutProofs& jsdescs, + const uint256& joinSplitPubKey +) +{ + auto verifier = libzcash::ProofVerifier::Strict(); + bool phgrPassed = jsdescs[0].Verify(js, verifier, joinSplitPubKey); + bool grothPassed = jsdescs[1].Verify(js, verifier, joinSplitPubKey); + return phgrPassed && grothPassed; +} + + void test_full_api(ZCJoinSplit* js) { // Create verification context. auto verifier = libzcash::ProofVerifier::Strict(); // The recipient's information. - SpendingKey recipient_key = SpendingKey::random(); - PaymentAddress recipient_addr = recipient_key.address(); + SproutSpendingKey recipient_key = SproutSpendingKey::random(); + SproutPaymentAddress recipient_addr = recipient_key.address(); // Create the commitment tree - ZCIncrementalMerkleTree tree; + SproutMerkleTree tree; // Set up a JoinSplit description - uint256 ephemeralKey; - uint256 randomSeed; uint64_t vpub_old = 10; uint64_t vpub_new = 0; - uint256 pubKeyHash = random_uint256(); - boost::array macs; - boost::array nullifiers; - boost::array commitments; + uint256 joinSplitPubKey = random_uint256(); uint256 rt = tree.root(); - boost::array ciphertexts; - ZCProof proof; + SproutProofs jsdescs; { - boost::array inputs = { + std::array inputs = { JSInput(), // dummy input JSInput() // dummy input }; - boost::array outputs = { + std::array outputs = { JSOutput(recipient_addr, 10), JSOutput() // dummy output }; - boost::array output_notes; + std::array output_notes; - // Perform the proof - proof = js->prove( + // Perform the proofs + jsdescs = makeSproutProofs( + *js, inputs, outputs, - output_notes, - ciphertexts, - ephemeralKey, - pubKeyHash, - randomSeed, - macs, - nullifiers, - commitments, + joinSplitPubKey, vpub_old, vpub_new, rt ); } - // Verify the transaction: - ASSERT_TRUE(js->verify( - proof, - verifier, - pubKeyHash, - randomSeed, - macs, - nullifiers, - commitments, - vpub_old, - vpub_new, - rt - )); - - // Recipient should decrypt - // Now the recipient should spend the money again - auto h_sig = js->h_sig(randomSeed, nullifiers, pubKeyHash); - ZCNoteDecryption decryptor(recipient_key.receiving_key()); - - auto note_pt = NotePlaintext::decrypt( - decryptor, - ciphertexts[0], - ephemeralKey, - h_sig, - 0 - ); - - auto decrypted_note = note_pt.note(recipient_addr); - - ASSERT_TRUE(decrypted_note.value == 10); - - // Insert the commitments from the last tx into the tree - tree.append(commitments[0]); - auto witness_recipient = tree.witness(); - tree.append(commitments[1]); - witness_recipient.append(commitments[1]); - vpub_old = 0; - vpub_new = 1; - rt = tree.root(); - pubKeyHash = random_uint256(); + // Verify both PHGR and Groth Proof: + ASSERT_TRUE(verifySproutProofs(*js, jsdescs, joinSplitPubKey)); + // Run tests using both phgr and groth as basis for field values + for (auto jsdesc : jsdescs) { - boost::array inputs = { - JSInput(), // dummy input - JSInput(witness_recipient, decrypted_note, recipient_key) - }; + SproutMerkleTree tree; + SproutProofs jsdescs2; + // Recipient should decrypt + // Now the recipient should spend the money again + auto h_sig = js->h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey); + ZCNoteDecryption decryptor(recipient_key.receiving_key()); - SpendingKey second_recipient = SpendingKey::random(); - PaymentAddress second_addr = second_recipient.address(); - - boost::array outputs = { - JSOutput(second_addr, 9), - JSOutput() // dummy output - }; - - boost::array output_notes; - - // Perform the proof - proof = js->prove( - inputs, - outputs, - output_notes, - ciphertexts, - ephemeralKey, - pubKeyHash, - randomSeed, - macs, - nullifiers, - commitments, - vpub_old, - vpub_new, - rt + auto note_pt = SproutNotePlaintext::decrypt( + decryptor, + jsdesc.ciphertexts[0], + jsdesc.ephemeralKey, + h_sig, + 0 ); - } - // Verify the transaction: - ASSERT_TRUE(js->verify( - proof, - verifier, - pubKeyHash, - randomSeed, - macs, - nullifiers, - commitments, - vpub_old, - vpub_new, - rt - )); + auto decrypted_note = note_pt.note(recipient_addr); + + ASSERT_TRUE(decrypted_note.value() == 10); + + // Insert the commitments from the last tx into the tree + tree.append(jsdesc.commitments[0]); + auto witness_recipient = tree.witness(); + tree.append(jsdesc.commitments[1]); + witness_recipient.append(jsdesc.commitments[1]); + vpub_old = 0; + vpub_new = 1; + rt = tree.root(); + auto joinSplitPubKey2 = random_uint256(); + + { + std::array inputs = { + JSInput(), // dummy input + JSInput(witness_recipient, decrypted_note, recipient_key) + }; + + SproutSpendingKey second_recipient = SproutSpendingKey::random(); + SproutPaymentAddress second_addr = second_recipient.address(); + + std::array outputs = { + JSOutput(second_addr, 9), + JSOutput() // dummy output + }; + + std::array output_notes; + + + // Perform the proofs + jsdescs2 = makeSproutProofs( + *js, + inputs, + outputs, + joinSplitPubKey2, + vpub_old, + vpub_new, + rt + ); + + } + + + // Verify both PHGR and Groth Proof: + ASSERT_TRUE(verifySproutProofs(*js, jsdescs2, joinSplitPubKey2)); + } } // Invokes the API (but does not compute a proof) // to test exceptions void invokeAPI( ZCJoinSplit* js, - const boost::array& inputs, - const boost::array& outputs, + const std::array& inputs, + const std::array& outputs, uint64_t vpub_old, uint64_t vpub_new, const uint256& rt ) { uint256 ephemeralKey; uint256 randomSeed; - uint256 pubKeyHash = random_uint256(); - boost::array macs; - boost::array nullifiers; - boost::array commitments; - boost::array ciphertexts; + uint256 joinSplitPubKey = random_uint256(); + std::array macs; + std::array nullifiers; + std::array commitments; + std::array ciphertexts; - boost::array output_notes; + std::array output_notes; - ZCProof proof = js->prove( + // PHGR + SproutProof proof = js->prove( + false, inputs, outputs, output_notes, ciphertexts, ephemeralKey, - pubKeyHash, + joinSplitPubKey, + randomSeed, + macs, + nullifiers, + commitments, + vpub_old, + vpub_new, + rt, + false + ); + + // Groth + proof = js->prove( + true, + inputs, + outputs, + output_notes, + ciphertexts, + ephemeralKey, + joinSplitPubKey, randomSeed, macs, nullifiers, @@ -202,8 +232,8 @@ void invokeAPI( void invokeAPIFailure( ZCJoinSplit* js, - const boost::array& inputs, - const boost::array& outputs, + const std::array& inputs, + const std::array& outputs, uint64_t vpub_old, uint64_t vpub_new, const uint256& rt, @@ -228,9 +258,9 @@ TEST(joinsplit, h_sig) import pyblake2 import binascii -def hSig(randomSeed, nf1, nf2, pubKeyHash): +def hSig(randomSeed, nf1, nf2, joinSplitPubKey): return pyblake2.blake2b( - data=(randomSeed + nf1 + nf2 + pubKeyHash), + data=(randomSeed + nf1 + nf2 + joinSplitPubKey), digest_size=32, person=b"ZcashComputehSig" ).digest() @@ -297,12 +327,12 @@ for test_input in TEST_VECTORS: void increment_note_witnesses( const uint256& element, - std::vector& witnesses, - ZCIncrementalMerkleTree& tree + std::vector& witnesses, + SproutMerkleTree& tree ) { tree.append(element); - for (ZCIncrementalWitness& w : witnesses) { + for (SproutWitness& w : witnesses) { w.append(element); } witnesses.push_back(tree.witness()); @@ -311,20 +341,20 @@ void increment_note_witnesses( TEST(joinsplit, full_api_test) { { - std::vector witnesses; - ZCIncrementalMerkleTree tree; + std::vector witnesses; + SproutMerkleTree tree; increment_note_witnesses(uint256(), witnesses, tree); - SpendingKey sk = SpendingKey::random(); - PaymentAddress addr = sk.address(); - Note note1(addr.a_pk, 100, random_uint256(), random_uint256()); + SproutSpendingKey sk = SproutSpendingKey::random(); + SproutPaymentAddress addr = sk.address(); + SproutNote note1(addr.a_pk, 100, random_uint256(), random_uint256()); increment_note_witnesses(note1.cm(), witnesses, tree); - Note note2(addr.a_pk, 100, random_uint256(), random_uint256()); + SproutNote note2(addr.a_pk, 100, random_uint256(), random_uint256()); increment_note_witnesses(note2.cm(), witnesses, tree); - Note note3(addr.a_pk, 2100000000000001, random_uint256(), random_uint256()); + SproutNote note3(addr.a_pk, 2100000000000001, random_uint256(), random_uint256()); increment_note_witnesses(note3.cm(), witnesses, tree); - Note note4(addr.a_pk, 1900000000000000, random_uint256(), random_uint256()); + SproutNote note4(addr.a_pk, 1900000000000000, random_uint256(), random_uint256()); increment_note_witnesses(note4.cm(), witnesses, tree); - Note note5(addr.a_pk, 1900000000000000, random_uint256(), random_uint256()); + SproutNote note5(addr.a_pk, 1900000000000000, random_uint256(), random_uint256()); increment_note_witnesses(note5.cm(), witnesses, tree); // Should work @@ -419,7 +449,7 @@ TEST(joinsplit, full_api_test) // Wrong secret key invokeAPIFailure(params, { - JSInput(witnesses[1], note1, SpendingKey::random()), + JSInput(witnesses[1], note1, SproutSpendingKey::random()), JSInput() }, { @@ -516,34 +546,71 @@ TEST(joinsplit, note_plaintexts) uint256 a_pk = PRF_addr_a_pk(a_sk); uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk); uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc); - PaymentAddress addr_pk(a_pk, pk_enc); + SproutPaymentAddress addr_pk(a_pk, pk_enc); uint256 h_sig; ZCNoteEncryption encryptor(h_sig); uint256 epk = encryptor.get_epk(); - Note note(a_pk, + SproutNote note(a_pk, 1945813, random_uint256(), random_uint256() ); - boost::array memo; + std::array memo; - NotePlaintext note_pt(note, memo); + SproutNotePlaintext note_pt(note, memo); ZCNoteEncryption::Ciphertext ct = note_pt.encrypt(encryptor, pk_enc); ZCNoteDecryption decryptor(sk_enc); - auto decrypted = NotePlaintext::decrypt(decryptor, ct, epk, h_sig, 0); + auto decrypted = SproutNotePlaintext::decrypt(decryptor, ct, epk, h_sig, 0); auto decrypted_note = decrypted.note(addr_pk); ASSERT_TRUE(decrypted_note.a_pk == note.a_pk); ASSERT_TRUE(decrypted_note.rho == note.rho); ASSERT_TRUE(decrypted_note.r == note.r); - ASSERT_TRUE(decrypted_note.value == note.value); + ASSERT_TRUE(decrypted_note.value() == note.value()); - ASSERT_TRUE(decrypted.memo == note_pt.memo); + ASSERT_TRUE(decrypted.memo() == note_pt.memo()); + + // Check memo() returns by reference, not return by value, for use cases such as: + // std::string data(plaintext.memo().begin(), plaintext.memo().end()); + ASSERT_TRUE(decrypted.memo().data() == decrypted.memo().data()); + + // Check serialization of note plaintext + CDataStream ss(SER_DISK, PROTOCOL_VERSION); + ss << note_pt; + SproutNotePlaintext note_pt2; + ss >> note_pt2; + ASSERT_EQ(note_pt.value(), note.value()); + ASSERT_EQ(note_pt.value(), note_pt2.value()); + ASSERT_EQ(note_pt.memo(), note_pt2.memo()); + ASSERT_EQ(note_pt.rho, note_pt2.rho); + ASSERT_EQ(note_pt.r, note_pt2.r); +} + +TEST(joinsplit, note_class) +{ + uint252 a_sk = uint252(uint256S("f6da8716682d600f74fc16bd0187faad6a26b4aa4c24d5c055b216d94516840e")); + uint256 a_pk = PRF_addr_a_pk(a_sk); + uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk); + uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc); + SproutPaymentAddress addr_pk(a_pk, pk_enc); + + SproutNote note(a_pk, + 1945813, + random_uint256(), + random_uint256()); + + SproutNote clone = note; + ASSERT_NE(¬e, &clone); + ASSERT_EQ(note.value(), clone.value()); + ASSERT_EQ(note.cm(), clone.cm()); + ASSERT_EQ(note.rho, clone.rho); + ASSERT_EQ(note.r, clone.r); + ASSERT_EQ(note.a_pk, clone.a_pk); } diff --git a/src/gtest/test_keys.cpp b/src/gtest/test_keys.cpp new file mode 100644 index 000000000..450bc5708 --- /dev/null +++ b/src/gtest/test_keys.cpp @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +#include + +TEST(Keys, DISABLED_EncodeAndDecodeSapling) +{ + SelectParams(CBaseChainParams::MAIN); + + std::vector> rawSeed(32); + HDSeed seed(rawSeed); + auto m = libzcash::SaplingExtendedSpendingKey::Master(seed); + + for (uint32_t i = 0; i < 1000; i++) { + auto sk = m.Derive(i); + { + std::string sk_string = EncodeSpendingKey(sk); + EXPECT_EQ( + sk_string.substr(0, 24), + Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY)); + + auto spendingkey2 = DecodeSpendingKey(sk_string); + EXPECT_TRUE(IsValidSpendingKey(spendingkey2)); + + ASSERT_TRUE(boost::get(&spendingkey2) != nullptr); + auto sk2 = boost::get(spendingkey2); + EXPECT_EQ(sk, sk2); + } + { + auto addr = sk.DefaultAddress(); + + std::string addr_string = EncodePaymentAddress(addr); + EXPECT_EQ( + addr_string.substr(0, 2), + Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS)); + + auto paymentaddr2 = DecodePaymentAddress(addr_string); + EXPECT_TRUE(IsValidPaymentAddress(paymentaddr2)); + + ASSERT_TRUE(boost::get(&paymentaddr2) != nullptr); + auto addr2 = boost::get(paymentaddr2); + EXPECT_EQ(addr, addr2); + } + } +} diff --git a/src/gtest/test_keystore.cpp b/src/gtest/test_keystore.cpp index 76b57cd9f..6b4d08a59 100644 --- a/src/gtest/test_keystore.cpp +++ b/src/gtest/test_keystore.cpp @@ -1,33 +1,121 @@ #include +#include "test/data/sapling_key_components.json.h" + #include "keystore.h" #include "random.h" #ifdef ENABLE_WALLET #include "wallet/crypter.h" #endif #include "zcash/Address.hpp" +#include "zcash/zip32.h" + +#include "json_test_vectors.h" + +#define MAKE_STRING(x) std::string((x), (x)+sizeof(x)) + +TEST(keystore_tests, StoreAndRetrieveHDSeed) { + CBasicKeyStore keyStore; + HDSeed seedOut; + + // When we haven't set a seed, we shouldn't get one + EXPECT_FALSE(keyStore.HaveHDSeed()); + EXPECT_FALSE(keyStore.GetHDSeed(seedOut)); + + // Generate a random seed + auto seed = HDSeed::Random(); + + // We should be able to set and retrieve the seed + ASSERT_TRUE(keyStore.SetHDSeed(seed)); + EXPECT_TRUE(keyStore.HaveHDSeed()); + ASSERT_TRUE(keyStore.GetHDSeed(seedOut)); + EXPECT_EQ(seed, seedOut); + + // Generate another random seed + auto seed2 = HDSeed::Random(); + EXPECT_NE(seed, seed2); + + // We should not be able to set and retrieve a different seed + EXPECT_FALSE(keyStore.SetHDSeed(seed2)); + ASSERT_TRUE(keyStore.GetHDSeed(seedOut)); + EXPECT_EQ(seed, seedOut); +} + +TEST(keystore_tests, sapling_keys) { + // ["sk, ask, nsk, ovk, ak, nk, ivk, default_d, default_pk_d, note_v, note_r, note_cm, note_pos, note_nf"], + UniValue sapling_keys = read_json(MAKE_STRING(json_tests::sapling_key_components)); + + // Skipping over comments in sapling_key_components.json file + for (size_t i = 2; i < 12; i++) { + uint256 skSeed, ask, nsk, ovk, ak, nk, ivk; + skSeed.SetHex(sapling_keys[i][0].getValStr()); + ask.SetHex(sapling_keys[i][1].getValStr()); + nsk.SetHex(sapling_keys[i][2].getValStr()); + ovk.SetHex(sapling_keys[i][3].getValStr()); + ak.SetHex(sapling_keys[i][4].getValStr()); + nk.SetHex(sapling_keys[i][5].getValStr()); + ivk.SetHex(sapling_keys[i][6].getValStr()); + + libzcash::diversifier_t default_d; + std::copy_n(ParseHex(sapling_keys[i][7].getValStr()).begin(), 11, default_d.begin()); + + uint256 default_pk_d; + default_pk_d.SetHex(sapling_keys[i][8].getValStr()); + + auto sk = libzcash::SaplingSpendingKey(skSeed); + + // Check that expanded spending key from primitives and from sk are the same + auto exp_sk_2 = libzcash::SaplingExpandedSpendingKey(ask, nsk, ovk); + auto exp_sk = sk.expanded_spending_key(); + EXPECT_EQ(exp_sk, exp_sk_2); + + // Check that full viewing key derived from sk and expanded sk are the same + auto full_viewing_key = sk.full_viewing_key(); + EXPECT_EQ(full_viewing_key, exp_sk.full_viewing_key()); + + // Check that full viewing key from primitives and from sk are the same + auto full_viewing_key_2 = libzcash::SaplingFullViewingKey(ak, nk, ovk); + EXPECT_EQ(full_viewing_key, full_viewing_key_2); + + // Check that incoming viewing key from primitives and from sk are the same + auto in_viewing_key = full_viewing_key.in_viewing_key(); + auto in_viewing_key_2 = libzcash::SaplingIncomingViewingKey(ivk); + EXPECT_EQ(in_viewing_key, in_viewing_key_2); + + // Check that the default address from primitives and from sk method are the same + auto default_addr = sk.default_address(); + auto addrOpt2 = in_viewing_key.address(default_d); + EXPECT_TRUE(addrOpt2); + auto default_addr_2 = addrOpt2.value(); + EXPECT_EQ(default_addr, default_addr_2); + + auto default_addr_3 = libzcash::SaplingPaymentAddress(default_d, default_pk_d); + EXPECT_EQ(default_addr_2, default_addr_3); + EXPECT_EQ(default_addr, default_addr_3); + } +} TEST(keystore_tests, store_and_retrieve_spending_key) { CBasicKeyStore keyStore; - libzcash::SpendingKey skOut; + libzcash::SproutSpendingKey skOut; - std::set addrs; - keyStore.GetPaymentAddresses(addrs); + std::set addrs; + keyStore.GetSproutPaymentAddresses(addrs); EXPECT_EQ(0, addrs.size()); - auto sk = libzcash::SpendingKey::random(); + auto sk = libzcash::SproutSpendingKey::random(); auto addr = sk.address(); // Sanity-check: we can't get a key we haven't added - EXPECT_FALSE(keyStore.HaveSpendingKey(addr)); - EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut)); + EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr)); + EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut)); - keyStore.AddSpendingKey(sk); - EXPECT_TRUE(keyStore.HaveSpendingKey(addr)); - EXPECT_TRUE(keyStore.GetSpendingKey(addr, skOut)); + keyStore.AddSproutSpendingKey(sk); + EXPECT_TRUE(keyStore.HaveSproutSpendingKey(addr)); + EXPECT_TRUE(keyStore.GetSproutSpendingKey(addr, skOut)); EXPECT_EQ(sk, skOut); - keyStore.GetPaymentAddresses(addrs); + keyStore.GetSproutPaymentAddresses(addrs); EXPECT_EQ(1, addrs.size()); EXPECT_EQ(1, addrs.count(addr)); } @@ -36,48 +124,48 @@ TEST(keystore_tests, store_and_retrieve_note_decryptor) { CBasicKeyStore keyStore; ZCNoteDecryption decOut; - auto sk = libzcash::SpendingKey::random(); + auto sk = libzcash::SproutSpendingKey::random(); auto addr = sk.address(); EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut)); - keyStore.AddSpendingKey(sk); + keyStore.AddSproutSpendingKey(sk); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); } TEST(keystore_tests, StoreAndRetrieveViewingKey) { CBasicKeyStore keyStore; - libzcash::ViewingKey vkOut; - libzcash::SpendingKey skOut; + libzcash::SproutViewingKey vkOut; + libzcash::SproutSpendingKey skOut; ZCNoteDecryption decOut; - auto sk = libzcash::SpendingKey::random(); + auto sk = libzcash::SproutSpendingKey::random(); auto vk = sk.viewing_key(); auto addr = sk.address(); // Sanity-check: we can't get a viewing key we haven't added - EXPECT_FALSE(keyStore.HaveViewingKey(addr)); - EXPECT_FALSE(keyStore.GetViewingKey(addr, vkOut)); + EXPECT_FALSE(keyStore.HaveSproutViewingKey(addr)); + EXPECT_FALSE(keyStore.GetSproutViewingKey(addr, vkOut)); // and we shouldn't have a spending key or decryptor either - EXPECT_FALSE(keyStore.HaveSpendingKey(addr)); - EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut)); + EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr)); + EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut)); EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut)); // and we can't find it in our list of addresses - std::set addresses; - keyStore.GetPaymentAddresses(addresses); + std::set addresses; + keyStore.GetSproutPaymentAddresses(addresses); EXPECT_FALSE(addresses.count(addr)); - keyStore.AddViewingKey(vk); - EXPECT_TRUE(keyStore.HaveViewingKey(addr)); - EXPECT_TRUE(keyStore.GetViewingKey(addr, vkOut)); + keyStore.AddSproutViewingKey(vk); + EXPECT_TRUE(keyStore.HaveSproutViewingKey(addr)); + EXPECT_TRUE(keyStore.GetSproutViewingKey(addr, vkOut)); EXPECT_EQ(vk, vkOut); // We should still not have the spending key... - EXPECT_FALSE(keyStore.HaveSpendingKey(addr)); - EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut)); + EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr)); + EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut)); // ... but we should have a decryptor EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); @@ -85,16 +173,16 @@ TEST(keystore_tests, StoreAndRetrieveViewingKey) { // ... and we should find it in our list of addresses addresses.clear(); - keyStore.GetPaymentAddresses(addresses); + keyStore.GetSproutPaymentAddresses(addresses); EXPECT_TRUE(addresses.count(addr)); - keyStore.RemoveViewingKey(vk); - EXPECT_FALSE(keyStore.HaveViewingKey(addr)); - EXPECT_FALSE(keyStore.GetViewingKey(addr, vkOut)); - EXPECT_FALSE(keyStore.HaveSpendingKey(addr)); - EXPECT_FALSE(keyStore.GetSpendingKey(addr, skOut)); + keyStore.RemoveSproutViewingKey(vk); + EXPECT_FALSE(keyStore.HaveSproutViewingKey(addr)); + EXPECT_FALSE(keyStore.GetSproutViewingKey(addr, vkOut)); + EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr)); + EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut)); addresses.clear(); - keyStore.GetPaymentAddresses(addresses); + keyStore.GetSproutPaymentAddresses(addresses); EXPECT_FALSE(addresses.count(addr)); // We still have a decryptor because those are cached in memory @@ -103,6 +191,49 @@ TEST(keystore_tests, StoreAndRetrieveViewingKey) { EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); } +// Sapling +TEST(keystore_tests, StoreAndRetrieveSaplingSpendingKey) { + CBasicKeyStore keyStore; + libzcash::SaplingExtendedSpendingKey skOut; + libzcash::SaplingFullViewingKey fvkOut; + libzcash::SaplingIncomingViewingKey ivkOut; + + std::vector> rawSeed(32); + HDSeed seed(rawSeed); + auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed); + auto fvk = sk.expsk.full_viewing_key(); + auto ivk = fvk.in_viewing_key(); + auto addr = sk.DefaultAddress(); + + // Sanity-check: we can't get a key we haven't added + EXPECT_FALSE(keyStore.HaveSaplingSpendingKey(fvk)); + EXPECT_FALSE(keyStore.GetSaplingSpendingKey(fvk, skOut)); + // Sanity-check: we can't get a full viewing key we haven't added + EXPECT_FALSE(keyStore.HaveSaplingFullViewingKey(ivk)); + EXPECT_FALSE(keyStore.GetSaplingFullViewingKey(ivk, fvkOut)); + // Sanity-check: we can't get an incoming viewing key we haven't added + EXPECT_FALSE(keyStore.HaveSaplingIncomingViewingKey(addr)); + EXPECT_FALSE(keyStore.GetSaplingIncomingViewingKey(addr, ivkOut)); + + // If we don't specify the default address, that mapping isn't created + keyStore.AddSaplingSpendingKey(sk); + EXPECT_TRUE(keyStore.HaveSaplingSpendingKey(fvk)); + EXPECT_TRUE(keyStore.HaveSaplingFullViewingKey(ivk)); + EXPECT_FALSE(keyStore.HaveSaplingIncomingViewingKey(addr)); + + // When we specify the default address, we get the full mapping + keyStore.AddSaplingSpendingKey(sk, addr); + EXPECT_TRUE(keyStore.HaveSaplingSpendingKey(fvk)); + EXPECT_TRUE(keyStore.GetSaplingSpendingKey(fvk, skOut)); + EXPECT_TRUE(keyStore.HaveSaplingFullViewingKey(ivk)); + EXPECT_TRUE(keyStore.GetSaplingFullViewingKey(ivk, fvkOut)); + EXPECT_TRUE(keyStore.HaveSaplingIncomingViewingKey(addr)); + EXPECT_TRUE(keyStore.GetSaplingIncomingViewingKey(addr, ivkOut)); + EXPECT_EQ(sk, skOut); + EXPECT_EQ(fvk, fvkOut); + EXPECT_EQ(ivk, ivkOut); +} + #ifdef ENABLE_WALLET class TestCCryptoKeyStore : public CCryptoKeyStore { @@ -111,29 +242,89 @@ public: bool Unlock(const CKeyingMaterial& vMasterKeyIn) { return CCryptoKeyStore::Unlock(vMasterKeyIn); } }; +TEST(keystore_tests, StoreAndRetrieveHDSeedInEncryptedStore) { + TestCCryptoKeyStore keyStore; + CKeyingMaterial vMasterKey(32, 0); + GetRandBytes(vMasterKey.data(), 32); + HDSeed seedOut; + + // 1) Test adding a seed to an unencrypted key store, then encrypting it + auto seed = HDSeed::Random(); + EXPECT_FALSE(keyStore.HaveHDSeed()); + EXPECT_FALSE(keyStore.GetHDSeed(seedOut)); + + ASSERT_TRUE(keyStore.SetHDSeed(seed)); + EXPECT_TRUE(keyStore.HaveHDSeed()); + ASSERT_TRUE(keyStore.GetHDSeed(seedOut)); + EXPECT_EQ(seed, seedOut); + + ASSERT_TRUE(keyStore.EncryptKeys(vMasterKey)); + EXPECT_FALSE(keyStore.GetHDSeed(seedOut)); + + // Unlocking with a random key should fail + CKeyingMaterial vRandomKey(32, 0); + GetRandBytes(vRandomKey.data(), 32); + EXPECT_FALSE(keyStore.Unlock(vRandomKey)); + + // Unlocking with a slightly-modified vMasterKey should fail + CKeyingMaterial vModifiedKey(vMasterKey); + vModifiedKey[0] += 1; + EXPECT_FALSE(keyStore.Unlock(vModifiedKey)); + + // Unlocking with vMasterKey should succeed + ASSERT_TRUE(keyStore.Unlock(vMasterKey)); + ASSERT_TRUE(keyStore.GetHDSeed(seedOut)); + EXPECT_EQ(seed, seedOut); + + // 2) Test replacing the seed in an already-encrypted key store fails + auto seed2 = HDSeed::Random(); + EXPECT_FALSE(keyStore.SetHDSeed(seed2)); + EXPECT_TRUE(keyStore.HaveHDSeed()); + ASSERT_TRUE(keyStore.GetHDSeed(seedOut)); + EXPECT_EQ(seed, seedOut); + + // 3) Test adding a new seed to an already-encrypted key store + TestCCryptoKeyStore keyStore2; + + // Add a Sprout address so the wallet has something to test when decrypting + ASSERT_TRUE(keyStore2.AddSproutSpendingKey(libzcash::SproutSpendingKey::random())); + + ASSERT_TRUE(keyStore2.EncryptKeys(vMasterKey)); + ASSERT_TRUE(keyStore2.Unlock(vMasterKey)); + + EXPECT_FALSE(keyStore2.HaveHDSeed()); + EXPECT_FALSE(keyStore2.GetHDSeed(seedOut)); + + auto seed3 = HDSeed::Random(); + ASSERT_TRUE(keyStore2.SetHDSeed(seed3)); + EXPECT_TRUE(keyStore2.HaveHDSeed()); + ASSERT_TRUE(keyStore2.GetHDSeed(seedOut)); + EXPECT_EQ(seed3, seedOut); +} + TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) { TestCCryptoKeyStore keyStore; uint256 r {GetRandHash()}; CKeyingMaterial vMasterKey (r.begin(), r.end()); - libzcash::SpendingKey keyOut; + libzcash::SproutSpendingKey keyOut; ZCNoteDecryption decOut; - std::set addrs; + std::set addrs; // 1) Test adding a key to an unencrypted key store, then encrypting it - auto sk = libzcash::SpendingKey::random(); + auto sk = libzcash::SproutSpendingKey::random(); auto addr = sk.address(); EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut)); - keyStore.AddSpendingKey(sk); - ASSERT_TRUE(keyStore.HaveSpendingKey(addr)); - ASSERT_TRUE(keyStore.GetSpendingKey(addr, keyOut)); + keyStore.AddSproutSpendingKey(sk); + ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr)); + ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr, keyOut)); ASSERT_EQ(sk, keyOut); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); ASSERT_TRUE(keyStore.EncryptKeys(vMasterKey)); - ASSERT_TRUE(keyStore.HaveSpendingKey(addr)); - ASSERT_FALSE(keyStore.GetSpendingKey(addr, keyOut)); + ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr)); + ASSERT_FALSE(keyStore.GetSproutSpendingKey(addr, keyOut)); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); @@ -149,38 +340,38 @@ TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) { // Unlocking with vMasterKey should succeed ASSERT_TRUE(keyStore.Unlock(vMasterKey)); - ASSERT_TRUE(keyStore.GetSpendingKey(addr, keyOut)); + ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr, keyOut)); ASSERT_EQ(sk, keyOut); - keyStore.GetPaymentAddresses(addrs); + keyStore.GetSproutPaymentAddresses(addrs); ASSERT_EQ(1, addrs.size()); ASSERT_EQ(1, addrs.count(addr)); // 2) Test adding a spending key to an already-encrypted key store - auto sk2 = libzcash::SpendingKey::random(); + auto sk2 = libzcash::SproutSpendingKey::random(); auto addr2 = sk2.address(); EXPECT_FALSE(keyStore.GetNoteDecryptor(addr2, decOut)); - keyStore.AddSpendingKey(sk2); - ASSERT_TRUE(keyStore.HaveSpendingKey(addr2)); - ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut)); + keyStore.AddSproutSpendingKey(sk2); + ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr2)); + ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr2, keyOut)); ASSERT_EQ(sk2, keyOut); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut)); EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut); ASSERT_TRUE(keyStore.Lock()); - ASSERT_TRUE(keyStore.HaveSpendingKey(addr2)); - ASSERT_FALSE(keyStore.GetSpendingKey(addr2, keyOut)); + ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr2)); + ASSERT_FALSE(keyStore.GetSproutSpendingKey(addr2, keyOut)); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut)); EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut); ASSERT_TRUE(keyStore.Unlock(vMasterKey)); - ASSERT_TRUE(keyStore.GetSpendingKey(addr2, keyOut)); + ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr2, keyOut)); ASSERT_EQ(sk2, keyOut); EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut)); EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut); - keyStore.GetPaymentAddresses(addrs); + keyStore.GetSproutPaymentAddresses(addrs); ASSERT_EQ(2, addrs.size()); ASSERT_EQ(1, addrs.count(addr)); ASSERT_EQ(1, addrs.count(addr2)); diff --git a/src/gtest/test_mempool.cpp b/src/gtest/test_mempool.cpp index 9256f196a..6ef626e5f 100644 --- a/src/gtest/test_mempool.cpp +++ b/src/gtest/test_mempool.cpp @@ -19,11 +19,15 @@ class FakeCoinsViewDB : public CCoinsView { public: FakeCoinsViewDB() {} - bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { + bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return false; } - bool GetNullifier(const uint256 &nf) const { + bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { + return false; + } + + bool GetNullifier(const uint256 &nf, ShieldedType type) const { return false; } @@ -47,16 +51,19 @@ public: return a; } - uint256 GetBestAnchor() const { + uint256 GetBestAnchor(ShieldedType type) const { uint256 a; return a; } bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, - const uint256 &hashAnchor, - CAnchorsMap &mapAnchors, - CNullifiersMap &mapNullifiers) { + const uint256 &hashSproutAnchor, + const uint256 &hashSaplingAnchor, + CAnchorsSproutMap &mapSproutAnchors, + CAnchorsSaplingMap &mapSaplingAnchors, + CNullifiersMap &mapSproutNullifiers, + CNullifiersMap &mapSaplingNullifiers) { return false; } @@ -96,7 +103,7 @@ TEST(Mempool, PriorityStatsDoNotCrash) { } TEST(Mempool, TxInputLimit) { - SelectParams(CBaseChainParams::TESTNET); + SelectParams(CBaseChainParams::REGTEST); CTxMemPool pool(::minRelayTxFee); bool missingInputs; @@ -133,13 +140,30 @@ TEST(Mempool, TxInputLimit) { // The -mempooltxinputlimit check doesn't set a reason EXPECT_EQ(state3.GetRejectReason(), ""); - // Clear the limit - mapArgs.erase("-mempooltxinputlimit"); + // Activate Overwinter + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); // Check it no longer fails due to exceeding the limit CValidationState state4; EXPECT_FALSE(AcceptToMemoryPool(pool, state4, tx3, false, &missingInputs)); EXPECT_EQ(state4.GetRejectReason(), "bad-txns-version-too-low"); + + // Deactivate Overwinter + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + + // Check it now fails due to exceeding the limit + CValidationState state5; + EXPECT_FALSE(AcceptToMemoryPool(pool, state5, tx3, false, &missingInputs)); + // The -mempooltxinputlimit check doesn't set a reason + EXPECT_EQ(state5.GetRejectReason(), ""); + + // Clear the limit + mapArgs.erase("-mempooltxinputlimit"); + + // Check it no longer fails due to exceeding the limit + CValidationState state6; + EXPECT_FALSE(AcceptToMemoryPool(pool, state6, tx3, false, &missingInputs)); + EXPECT_EQ(state6.GetRejectReason(), "bad-txns-version-too-low"); } // Valid overwinter v3 format tx gets rejected because overwinter hasn't activated yet. @@ -152,7 +176,7 @@ TEST(Mempool, OverwinterNotActiveYet) { CMutableTransaction mtx = GetValidTransaction(); mtx.vjoinsplit.resize(0); // no joinsplits mtx.fOverwintered = true; - mtx.nVersion = 3; + mtx.nVersion = OVERWINTER_TX_VERSION; mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nExpiryHeight = 0; CValidationState state1; @@ -224,7 +248,7 @@ TEST(Mempool, SproutNegativeVersionTxWhenOverwinterActive) { mtx.vjoinsplit.resize(0); // no joinsplits mtx.fOverwintered = false; - // A Sprout transaction with version -3 is created using Sprout code (as found in Zcashd <= 1.0.14). + // A Sprout transaction with version -3 is created using Sprout code (as found in zcashd <= 1.0.14). // First four bytes of transaction, parsed as an uint32_t, has the value: 0xfffffffd // This test simulates an Overwinter node receiving this transaction, but incorrectly deserializing the // transaction due to a (pretend) bug of not detecting the most significant bit, which leads @@ -242,7 +266,7 @@ TEST(Mempool, SproutNegativeVersionTxWhenOverwinterActive) { EXPECT_EQ(state1.GetRejectReason(), "bad-txns-version-too-low"); } - // A Sprout transaction with version -3 created using Overwinter code (as found in Zcashd >= 1.0.15). + // A Sprout transaction with version -3 created using Overwinter code (as found in zcashd >= 1.0.15). // First four bytes of transaction, parsed as an uint32_t, has the value: 0x80000003 // This test simulates the same pretend bug described above. // The resulting Sprout tx with nVersion -2147483645 should be rejected by the Overwinter node's mempool. diff --git a/src/gtest/test_merkletree.cpp b/src/gtest/test_merkletree.cpp index d603b0aa6..23c39c044 100644 --- a/src/gtest/test_merkletree.cpp +++ b/src/gtest/test_merkletree.cpp @@ -7,6 +7,13 @@ #include "test/data/merkle_path.json.h" #include "test/data/merkle_commitments.json.h" +#include "test/data/merkle_roots_sapling.json.h" +#include "test/data/merkle_roots_empty_sapling.json.h" +#include "test/data/merkle_serialization_sapling.json.h" +#include "test/data/merkle_witness_serialization_sapling.json.h" +#include "test/data/merkle_path_sapling.json.h" +#include "test/data/merkle_commitments_sapling.json.h" + #include #include @@ -32,7 +39,7 @@ using namespace std; using namespace libsnark; template<> -void expect_deser_same(const ZCTestingIncrementalWitness& expected) +void expect_deser_same(const SproutTestingWitness& expected) { // Cannot check this; IncrementalWitness cannot be // deserialized because it can only be constructed by @@ -40,16 +47,6 @@ void expect_deser_same(const ZCTestingIncrementalWitness& expected) // canonical serialized representation. } -template<> -void expect_deser_same(const libzcash::MerklePath& expected) -{ - // This deserialization check is pointless for MerklePath, - // since we only serialize it to check it against test - // vectors. See `expect_test_vector` for that. Also, - // it doesn't seem that vector can be properly - // deserialized by Bitcoin's serialization code. -} - template void expect_ser_test_vector(B& b, const C& c, const A& tree) { expect_test_vector(b, c); @@ -61,7 +58,8 @@ void test_tree( UniValue root_tests, UniValue ser_tests, UniValue witness_ser_tests, - UniValue path_tests + UniValue path_tests, + bool libsnark_test ) { size_t witness_ser_i = 0; @@ -116,10 +114,9 @@ void test_tree( ASSERT_THROW(wit.element(), std::runtime_error); } else { auto path = wit.path(); + expect_test_vector(path_tests[path_i++], path); - { - expect_test_vector(path_tests[path_i++], path); - + if (libsnark_test) { typedef Fr FieldT; protoboard pb; @@ -146,7 +143,7 @@ void test_tree( size_t path_index = convertVectorToInt(path.index); commitment.bits.fill_with_bits(pb, bit_vector(commitment_bv)); - positions.fill_with_bits_of_ulong(pb, path_index); + positions.fill_with_bits_of_uint64(pb, path_index); authvars.generate_r1cs_witness(path_index, path.authentication_path); auth.generate_r1cs_witness(); @@ -198,7 +195,31 @@ TEST(merkletree, vectors) { UniValue path_tests = read_json(MAKE_STRING(json_tests::merkle_path)); UniValue commitment_tests = read_json(MAKE_STRING(json_tests::merkle_commitments)); - test_tree(commitment_tests, root_tests, ser_tests, witness_ser_tests, path_tests); + test_tree( + commitment_tests, + root_tests, + ser_tests, + witness_ser_tests, + path_tests, + true + ); +} + +TEST(merkletree, SaplingVectors) { + UniValue root_tests = read_json(MAKE_STRING(json_tests::merkle_roots_sapling)); + UniValue ser_tests = read_json(MAKE_STRING(json_tests::merkle_serialization_sapling)); + UniValue witness_ser_tests = read_json(MAKE_STRING(json_tests::merkle_witness_serialization_sapling)); + UniValue path_tests = read_json(MAKE_STRING(json_tests::merkle_path_sapling)); + UniValue commitment_tests = read_json(MAKE_STRING(json_tests::merkle_commitments_sapling)); + + test_tree( + commitment_tests, + root_tests, + ser_tests, + witness_ser_tests, + path_tests, + false + ); } TEST(merkletree, emptyroots) { @@ -214,19 +235,41 @@ TEST(merkletree, emptyroots) { ASSERT_TRUE(INCREMENTAL_MERKLE_TREE_DEPTH <= 64); } +TEST(merkletree, EmptyrootsSapling) { + UniValue empty_roots = read_json(MAKE_STRING(json_tests::merkle_roots_empty_sapling)); + + libzcash::EmptyMerkleRoots<62, libzcash::PedersenHash> emptyroots; + + for (size_t depth = 0; depth <= 62; depth++) { + expect_test_vector(empty_roots[depth], emptyroots.empty_root(depth)); + } + + // Double check that we're testing (at least) all the empty roots we'll use. + ASSERT_TRUE(INCREMENTAL_MERKLE_TREE_DEPTH <= 62); +} + TEST(merkletree, emptyroot) { // This literal is the depth-20 empty tree root with the bytes reversed to // account for the fact that uint256S() loads a big-endian representation of // an integer which converted to little-endian internally. uint256 expected = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7"); - ASSERT_TRUE(ZCIncrementalMerkleTree::empty_root() == expected); + ASSERT_TRUE(SproutMerkleTree::empty_root() == expected); +} + +TEST(merkletree, EmptyrootSapling) { + // This literal is the depth-20 empty tree root with the bytes reversed to + // account for the fact that uint256S() loads a big-endian representation of + // an integer which converted to little-endian internally. + uint256 expected = uint256S("3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb"); + + ASSERT_TRUE(SaplingMerkleTree::empty_root() == expected); } TEST(merkletree, deserializeInvalid) { // attempt to deserialize a small tree from a serialized large tree // (exceeds depth well-formedness check) - ZCIncrementalMerkleTree newTree; + SproutMerkleTree newTree; for (size_t i = 0; i < 16; i++) { newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c")); @@ -237,7 +280,7 @@ TEST(merkletree, deserializeInvalid) { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << newTree; - ZCTestingIncrementalMerkleTree newTreeSmall; + SproutTestingMerkleTree newTreeSmall; ASSERT_THROW({ss >> newTreeSmall;}, std::ios_base::failure); } @@ -249,7 +292,7 @@ TEST(merkletree, deserializeInvalid2) { PROTOCOL_VERSION ); - ZCIncrementalMerkleTree tree; + SproutMerkleTree tree; ASSERT_THROW(ss >> tree, std::ios_base::failure); } @@ -261,7 +304,7 @@ TEST(merkletree, deserializeInvalid3) { PROTOCOL_VERSION ); - ZCIncrementalMerkleTree tree; + SproutMerkleTree tree; ASSERT_THROW(ss >> tree, std::ios_base::failure); } @@ -273,15 +316,15 @@ TEST(merkletree, deserializeInvalid4) { PROTOCOL_VERSION ); - ZCIncrementalMerkleTree tree; + SproutMerkleTree tree; ASSERT_THROW(ss >> tree, std::ios_base::failure); } TEST(merkletree, testZeroElements) { for (int start = 0; start < 20; start++) { - ZCIncrementalMerkleTree newTree; + SproutMerkleTree newTree; - ASSERT_TRUE(newTree.root() == ZCIncrementalMerkleTree::empty_root()); + ASSERT_TRUE(newTree.root() == SproutMerkleTree::empty_root()); for (int i = start; i > 0; i--) { newTree.append(uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c")); diff --git a/src/gtest/test_noteencryption.cpp b/src/gtest/test_noteencryption.cpp index f521cdb01..0ed6999f8 100644 --- a/src/gtest/test_noteencryption.cpp +++ b/src/gtest/test_noteencryption.cpp @@ -1,11 +1,15 @@ #include #include "sodium.h" +#include #include +#include "zcash/Note.hpp" #include "zcash/NoteEncryption.hpp" #include "zcash/prf.h" +#include "zcash/Address.hpp" #include "crypto/sha256.h" +#include "librustzcash.h" class TestNoteDecryption : public ZCNoteDecryption { public: @@ -16,6 +20,327 @@ public: } }; +TEST(noteencryption, NotePlaintext) +{ + using namespace libzcash; + auto xsk = SaplingSpendingKey(uint256()).expanded_spending_key(); + auto fvk = xsk.full_viewing_key(); + auto ivk = fvk.in_viewing_key(); + SaplingPaymentAddress addr = *ivk.address({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + + std::array memo; + for (size_t i = 0; i < ZC_MEMO_SIZE; i++) { + // Fill the message with dummy data + memo[i] = (unsigned char) i; + } + + SaplingNote note(addr, 39393); + auto cmu_opt = note.cm(); + if (!cmu_opt) { + FAIL(); + } + uint256 cmu = cmu_opt.get(); + SaplingNotePlaintext pt(note, memo); + + auto res = pt.encrypt(addr.pk_d); + if (!res) { + FAIL(); + } + + auto enc = res.get(); + + auto ct = enc.first; + auto encryptor = enc.second; + auto epk = encryptor.get_epk(); + + // Try to decrypt with incorrect commitment + ASSERT_FALSE(SaplingNotePlaintext::decrypt( + ct, + ivk, + epk, + uint256() + )); + + // Try to decrypt with correct commitment + auto foo = SaplingNotePlaintext::decrypt( + ct, + ivk, + epk, + cmu + ); + + if (!foo) { + FAIL(); + } + + auto bar = foo.get(); + + ASSERT_TRUE(bar.value() == pt.value()); + ASSERT_TRUE(bar.memo() == pt.memo()); + ASSERT_TRUE(bar.d == pt.d); + ASSERT_TRUE(bar.rcm == pt.rcm); + + auto foobar = bar.note(ivk); + + if (!foobar) { + FAIL(); + } + + auto new_note = foobar.get(); + + ASSERT_TRUE(note.value() == new_note.value()); + ASSERT_TRUE(note.d == new_note.d); + ASSERT_TRUE(note.pk_d == new_note.pk_d); + ASSERT_TRUE(note.r == new_note.r); + ASSERT_TRUE(note.cm() == new_note.cm()); + + SaplingOutgoingPlaintext out_pt; + out_pt.pk_d = note.pk_d; + out_pt.esk = encryptor.get_esk(); + + auto ovk = random_uint256(); + auto cv = random_uint256(); + auto cm = random_uint256(); + + auto out_ct = out_pt.encrypt( + ovk, + cv, + cm, + encryptor + ); + + auto decrypted_out_ct = out_pt.decrypt( + out_ct, + ovk, + cv, + cm, + encryptor.get_epk() + ); + + if (!decrypted_out_ct) { + FAIL(); + } + + auto decrypted_out_ct_unwrapped = decrypted_out_ct.get(); + + ASSERT_TRUE(decrypted_out_ct_unwrapped.pk_d == out_pt.pk_d); + ASSERT_TRUE(decrypted_out_ct_unwrapped.esk == out_pt.esk); + + // Test sender won't accept invalid commitments + ASSERT_FALSE( + SaplingNotePlaintext::decrypt( + ct, + epk, + decrypted_out_ct_unwrapped.esk, + decrypted_out_ct_unwrapped.pk_d, + uint256() + ) + ); + + // Test sender can decrypt the note ciphertext. + foo = SaplingNotePlaintext::decrypt( + ct, + epk, + decrypted_out_ct_unwrapped.esk, + decrypted_out_ct_unwrapped.pk_d, + cmu + ); + + if (!foo) { + FAIL(); + } + + bar = foo.get(); + + ASSERT_TRUE(bar.value() == pt.value()); + ASSERT_TRUE(bar.memo() == pt.memo()); + ASSERT_TRUE(bar.d == pt.d); + ASSERT_TRUE(bar.rcm == pt.rcm); +} + +TEST(noteencryption, SaplingApi) +{ + using namespace libzcash; + + // Create recipient addresses + auto sk = SaplingSpendingKey(uint256()).expanded_spending_key(); + auto vk = sk.full_viewing_key(); + auto ivk = vk.in_viewing_key(); + SaplingPaymentAddress pk_1 = *ivk.address({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + SaplingPaymentAddress pk_2 = *ivk.address({4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + + // Blob of stuff we're encrypting + std::array message; + for (size_t i = 0; i < ZC_SAPLING_ENCPLAINTEXT_SIZE; i++) { + // Fill the message with dummy data + message[i] = (unsigned char) i; + } + + std::array small_message; + for (size_t i = 0; i < ZC_SAPLING_OUTPLAINTEXT_SIZE; i++) { + // Fill the message with dummy data + small_message[i] = (unsigned char) i; + } + + // Invalid diversifier + ASSERT_EQ(boost::none, SaplingNoteEncryption::FromDiversifier({1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); + + // Encrypt to pk_1 + auto enc = *SaplingNoteEncryption::FromDiversifier(pk_1.d); + auto ciphertext_1 = *enc.encrypt_to_recipient( + pk_1.pk_d, + message + ); + auto epk_1 = enc.get_epk(); + { + uint256 test_epk; + uint256 test_esk = enc.get_esk(); + ASSERT_TRUE(librustzcash_sapling_ka_derivepublic(pk_1.d.begin(), test_esk.begin(), test_epk.begin())); + ASSERT_TRUE(test_epk == epk_1); + } + auto cv_1 = random_uint256(); + auto cm_1 = random_uint256(); + auto out_ciphertext_1 = enc.encrypt_to_ourselves( + sk.ovk, + cv_1, + cm_1, + small_message + ); + + // Encrypt to pk_2 + enc = *SaplingNoteEncryption::FromDiversifier(pk_2.d); + auto ciphertext_2 = *enc.encrypt_to_recipient( + pk_2.pk_d, + message + ); + auto epk_2 = enc.get_epk(); + + auto cv_2 = random_uint256(); + auto cm_2 = random_uint256(); + auto out_ciphertext_2 = enc.encrypt_to_ourselves( + sk.ovk, + cv_2, + cm_2, + small_message + ); + + // Test nonce-reuse resistance of API + { + auto tmp_enc = *SaplingNoteEncryption::FromDiversifier(pk_1.d); + + tmp_enc.encrypt_to_recipient( + pk_1.pk_d, + message + ); + + ASSERT_THROW(tmp_enc.encrypt_to_recipient( + pk_1.pk_d, + message + ), std::logic_error); + + tmp_enc.encrypt_to_ourselves( + sk.ovk, + cv_2, + cm_2, + small_message + ); + + ASSERT_THROW(tmp_enc.encrypt_to_ourselves( + sk.ovk, + cv_2, + cm_2, + small_message + ), std::logic_error); + } + + // Try to decrypt + auto plaintext_1 = *AttemptSaplingEncDecryption( + ciphertext_1, + ivk, + epk_1 + ); + ASSERT_TRUE(message == plaintext_1); + + auto small_plaintext_1 = *AttemptSaplingOutDecryption( + out_ciphertext_1, + sk.ovk, + cv_1, + cm_1, + epk_1 + ); + ASSERT_TRUE(small_message == small_plaintext_1); + + auto plaintext_2 = *AttemptSaplingEncDecryption( + ciphertext_2, + ivk, + epk_2 + ); + ASSERT_TRUE(message == plaintext_2); + + auto small_plaintext_2 = *AttemptSaplingOutDecryption( + out_ciphertext_2, + sk.ovk, + cv_2, + cm_2, + epk_2 + ); + ASSERT_TRUE(small_message == small_plaintext_2); + + // Try to decrypt out ciphertext with wrong key material + ASSERT_FALSE(AttemptSaplingOutDecryption( + out_ciphertext_1, + random_uint256(), + cv_1, + cm_1, + epk_1 + )); + ASSERT_FALSE(AttemptSaplingOutDecryption( + out_ciphertext_1, + sk.ovk, + random_uint256(), + cm_1, + epk_1 + )); + ASSERT_FALSE(AttemptSaplingOutDecryption( + out_ciphertext_1, + sk.ovk, + cv_1, + random_uint256(), + epk_1 + )); + ASSERT_FALSE(AttemptSaplingOutDecryption( + out_ciphertext_1, + sk.ovk, + cv_1, + cm_1, + random_uint256() + )); + + // Try to decrypt with wrong ephemeral key + ASSERT_FALSE(AttemptSaplingEncDecryption( + ciphertext_1, + ivk, + epk_2 + )); + ASSERT_FALSE(AttemptSaplingEncDecryption( + ciphertext_2, + ivk, + epk_1 + )); + + // Try to decrypt with wrong ivk + ASSERT_FALSE(AttemptSaplingEncDecryption( + ciphertext_1, + uint256(), + epk_1 + )); + ASSERT_FALSE(AttemptSaplingEncDecryption( + ciphertext_2, + uint256(), + epk_2 + )); +} + TEST(noteencryption, api) { uint256 sk_enc = ZCNoteEncryption::generate_privkey(uint252(uint256S("21035d60bc1983e37950ce4803418a8fb33ea68d5b937ca382ecbae7564d6a07"))); @@ -29,7 +354,7 @@ TEST(noteencryption, api) ASSERT_TRUE(b.get_epk() != c.get_epk()); } - boost::array message; + std::array message; for (size_t i = 0; i < ZC_NOTEPLAINTEXT_SIZE; i++) { // Fill the message with dummy data message[i] = (unsigned char) i; diff --git a/src/gtest/test_paymentdisclosure.cpp b/src/gtest/test_paymentdisclosure.cpp index ddab3c7e6..c166cdbe1 100644 --- a/src/gtest/test_paymentdisclosure.cpp +++ b/src/gtest/test_paymentdisclosure.cpp @@ -7,6 +7,8 @@ #include "zcash/Address.hpp" #include "wallet/wallet.h" #include "amount.h" + +#include #include #include #include @@ -91,14 +93,13 @@ public: // Note that the zpd: prefix is not part of the payment disclosure blob itself. It is only // used as convention to improve the user experience when sharing payment disclosure blobs. TEST(paymentdisclosure, mainnet) { - ECC_Start(); SelectParams(CBaseChainParams::MAIN); boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); boost::filesystem::create_directories(pathTemp); mapArgs["-datadir"] = pathTemp.string(); - std::cout << "Test payment disclosure database created in folder: " << pathTemp.native() << std::endl; + std::cout << "Test payment disclosure database created in folder: " << pathTemp.string() << std::endl; PaymentDisclosureDBTest mydb(pathTemp); @@ -120,7 +121,7 @@ TEST(paymentdisclosure, mainnet) { PaymentDisclosureInfo info; info.esk = random_uint256(); info.joinSplitPrivKey = joinSplitPrivKey; - info.zaddr = libzcash::SpendingKey::random().address(); + info.zaddr = libzcash::SproutSpendingKey::random().address(); ASSERT_TRUE(mydb.Put(key, info)); // Retrieve info from test database into new local variable and test it matches @@ -131,7 +132,7 @@ TEST(paymentdisclosure, mainnet) { // Modify this local variable and confirm it no longer matches info2.esk = random_uint256(); info2.joinSplitPrivKey = random_uint256(); - info2.zaddr = libzcash::SpendingKey::random().address(); + info2.zaddr = libzcash::SproutSpendingKey::random().address(); ASSERT_NE(info, info2); // Using the payment info object, let's create a dummy payload @@ -167,7 +168,7 @@ TEST(paymentdisclosure, mainnet) { } // Convert signature buffer to boost array - boost::array arrayPayloadSig; + std::array arrayPayloadSig; memcpy(arrayPayloadSig.data(), &payloadSig[0], 64); // Payment disclosure blob to pass around @@ -207,6 +208,4 @@ TEST(paymentdisclosure, mainnet) { #if DUMP_DATABASE_TO_STDOUT == true mydb.DebugDumpAllStdout(); #endif - - ECC_Stop(); } diff --git a/src/gtest/test_pedersen_hash.cpp b/src/gtest/test_pedersen_hash.cpp new file mode 100644 index 000000000..e52b346a8 --- /dev/null +++ b/src/gtest/test_pedersen_hash.cpp @@ -0,0 +1,15 @@ +#include +#include "librustzcash.h" +#include "uint256.h" + +TEST(PedersenHash, TestAPI) { + const uint256 a = uint256S("87a086ae7d2252d58729b30263fb7b66308bf94ef59a76c9c86e7ea016536505"); + const uint256 b = uint256S("a75b84a125b2353da7e8d96ee2a15efe4de23df9601b9d9564ba59de57130406"); + uint256 result; + + librustzcash_merkle_hash(25, a.begin(), b.begin(), result.begin()); + + uint256 expected_result = uint256S("5bf43b5736c19b714d1f462c9d22ba3492c36e3d9bbd7ca24d94b440550aa561"); + + ASSERT_TRUE(result == expected_result); +} diff --git a/src/gtest/test_proofs.cpp b/src/gtest/test_proofs.cpp index e33b1cc0c..5b5c19395 100644 --- a/src/gtest/test_proofs.cpp +++ b/src/gtest/test_proofs.cpp @@ -241,7 +241,7 @@ TEST(proofs, sqrt_fq2) TEST(proofs, size_is_expected) { - ZCProof p; + PHGRProof p; CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << p; @@ -444,7 +444,7 @@ TEST(proofs, zksnark_serializes_properly) auto vkprecomp = libsnark::r1cs_ppzksnark_verifier_process_vk(kp.vk); for (size_t i = 0; i < 20; i++) { - auto badproof = ZCProof::random_invalid(); + auto badproof = PHGRProof::random_invalid(); auto proof = badproof.to_libsnark_proof>(); auto verifierEnabled = ProofVerifier::Strict(); @@ -496,12 +496,12 @@ TEST(proofs, zksnark_serializes_properly) proof )); - ZCProof compressed_proof_0(proof); + PHGRProof compressed_proof_0(proof); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << compressed_proof_0; - ZCProof compressed_proof_1; + PHGRProof compressed_proof_1; ss >> compressed_proof_1; ASSERT_TRUE(compressed_proof_0 == compressed_proof_1); diff --git a/src/gtest/test_rpc.cpp b/src/gtest/test_rpc.cpp index a3fc201cd..3733379a8 100644 --- a/src/gtest/test_rpc.cpp +++ b/src/gtest/test_rpc.cpp @@ -5,7 +5,7 @@ #include "chainparams.h" #include "clientversion.h" #include "primitives/block.h" -#include "rpcserver.h" +#include "rpc/server.h" #include "streams.h" #include "utilstrencodings.h" diff --git a/src/gtest/test_sapling_note.cpp b/src/gtest/test_sapling_note.cpp new file mode 100644 index 000000000..3e336ec7e --- /dev/null +++ b/src/gtest/test_sapling_note.cpp @@ -0,0 +1,72 @@ +#include + +#include "zcash/Address.hpp" +#include "zcash/Note.hpp" + +#include "amount.h" +#include "random.h" +#include "librustzcash.h" + +#include + +using namespace libzcash; + +// Test data from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py +TEST(SaplingNote, TestVectors) +{ + uint64_t v = 0; + uint64_t note_pos = 0; + std::array diversifier{0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39}; + std::vector v_sk{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + std::vector v_pk_d{ + 0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67, + 0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8, + 0x41, 0xae, 0x74, 0x15}; + std::vector v_r{ + 0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89, + 0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + std::vector v_cm{ + 0xcb, 0x3c, 0xf9, 0x15, 0x32, 0x70, 0xd5, 0x7e, 0xb9, 0x14, 0xc6, 0xc2, 0xbc, 0xc0, + 0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2, + 0xdd, 0x07, 0x64, 0x39}; + std::vector v_nf{ + 0x44, 0xfa, 0xd6, 0x56, 0x4f, 0xfd, 0xec, 0x9f, 0xa1, 0x9c, 0x43, 0xa2, 0x8f, 0x86, + 0x1d, 0x5e, 0xbf, 0x60, 0x23, 0x46, 0x00, 0x7d, 0xe7, 0x62, 0x67, 0xd9, 0x75, 0x27, + 0x47, 0xab, 0x40, 0x63}; + uint256 sk(v_sk); + uint256 pk_d(v_pk_d); + uint256 r(v_r); + uint256 cm(v_cm); + uint256 nf(v_nf); + + // Test commitment + SaplingNote note = SaplingNote(diversifier, pk_d, v, r); + ASSERT_EQ(note.cm().get(), cm); + + // Test nullifier + SaplingSpendingKey spendingKey(sk); + ASSERT_EQ(note.nullifier(spendingKey.full_viewing_key(), note_pos), nf); +} + + +TEST(SaplingNote, Random) +{ + // Test creating random notes using the same spending key + auto address = SaplingSpendingKey::random().default_address(); + SaplingNote note1(address, GetRand(MAX_MONEY)); + SaplingNote note2(address, GetRand(MAX_MONEY)); + + ASSERT_EQ(note1.d, note2.d); + ASSERT_EQ(note1.pk_d, note2.pk_d); + ASSERT_NE(note1.value(), note2.value()); + ASSERT_NE(note1.r, note2.r); + + // Test diversifier and pk_d are not the same for different spending keys + SaplingNote note3(SaplingSpendingKey::random().default_address(), GetRand(MAX_MONEY)); + ASSERT_NE(note1.d, note3.d); + ASSERT_NE(note1.pk_d, note3.pk_d); +} diff --git a/src/gtest/test_transaction.cpp b/src/gtest/test_transaction.cpp index cf2394438..1350768ff 100644 --- a/src/gtest/test_transaction.cpp +++ b/src/gtest/test_transaction.cpp @@ -4,18 +4,20 @@ #include "zcash/Note.hpp" #include "zcash/Address.hpp" +#include + extern ZCJoinSplit* params; extern int GenZero(int n); extern int GenMax(int n); TEST(Transaction, JSDescriptionRandomized) { // construct a merkle tree - ZCIncrementalMerkleTree merkleTree; + SproutMerkleTree merkleTree; - libzcash::SpendingKey k = libzcash::SpendingKey::random(); - libzcash::PaymentAddress addr = k.address(); + libzcash::SproutSpendingKey k = libzcash::SproutSpendingKey::random(); + libzcash::SproutPaymentAddress addr = k.address(); - libzcash::Note note(addr.a_pk, 100, uint256(), uint256()); + libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256()); // commitment from coin uint256 commitment = note.cm(); @@ -29,81 +31,59 @@ TEST(Transaction, JSDescriptionRandomized) { auto witness = merkleTree.witness(); // create JSDescription - uint256 pubKeyHash; - boost::array inputs = { + uint256 joinSplitPubKey; + std::array inputs = { libzcash::JSInput(witness, note, k), libzcash::JSInput() // dummy input of zero value }; - boost::array outputs = { + std::array outputs = { libzcash::JSOutput(addr, 50), libzcash::JSOutput(addr, 50) }; - #ifdef __LP64__ // required for building on MacOS - boost::array inputMap; - boost::array outputMap; - #else - boost::array inputMap; - boost::array outputMap; - #endif + std::array inputMap; + std::array outputMap; { auto jsdesc = JSDescription::Randomized( - *params, pubKeyHash, rt, + false, + *params, joinSplitPubKey, rt, inputs, outputs, inputMap, outputMap, 0, 0, false); - #ifdef __LP64__ // required for building on MacOS - std::set inputSet(inputMap.begin(), inputMap.end()); - std::set expectedInputSet {0, 1}; - #else std::set inputSet(inputMap.begin(), inputMap.end()); std::set expectedInputSet {0, 1}; - #endif EXPECT_EQ(expectedInputSet, inputSet); - #ifdef __LP64__ // required for building on MacOS - std::set outputSet(outputMap.begin(), outputMap.end()); - std::set expectedOutputSet {0, 1}; - #else std::set outputSet(outputMap.begin(), outputMap.end()); std::set expectedOutputSet {0, 1}; - #endif EXPECT_EQ(expectedOutputSet, outputSet); } { auto jsdesc = JSDescription::Randomized( - *params, pubKeyHash, rt, + false, + *params, joinSplitPubKey, rt, inputs, outputs, inputMap, outputMap, 0, 0, false, nullptr, GenZero); - #ifdef __LP64__ // required for building on MacOS - boost::array expectedInputMap {1, 0}; - boost::array expectedOutputMap {1, 0}; - #else - boost::array expectedInputMap {1, 0}; - boost::array expectedOutputMap {1, 0}; - #endif + std::array expectedInputMap {1, 0}; + std::array expectedOutputMap {1, 0}; EXPECT_EQ(expectedInputMap, inputMap); EXPECT_EQ(expectedOutputMap, outputMap); } { auto jsdesc = JSDescription::Randomized( - *params, pubKeyHash, rt, + false, + *params, joinSplitPubKey, rt, inputs, outputs, inputMap, outputMap, 0, 0, false, nullptr, GenMax); - #ifdef __LP64__ // required for building on MacOS - boost::array expectedInputMap {0, 1}; - boost::array expectedOutputMap {0, 1}; - #else - boost::array expectedInputMap {0, 1}; - boost::array expectedOutputMap {0, 1}; - #endif + std::array expectedInputMap {0, 1}; + std::array expectedOutputMap {0, 1}; EXPECT_EQ(expectedInputMap, inputMap); EXPECT_EQ(expectedOutputMap, outputMap); } diff --git a/src/gtest/test_transaction_builder.cpp b/src/gtest/test_transaction_builder.cpp new file mode 100644 index 000000000..b8fe54466 --- /dev/null +++ b/src/gtest/test_transaction_builder.cpp @@ -0,0 +1,335 @@ +#include "chainparams.h" +#include "consensus/params.h" +#include "consensus/validation.h" +#include "key_io.h" +#include "main.h" +#include "pubkey.h" +#include "transaction_builder.h" +#include "zcash/Address.hpp" + +#include +#include + +static const std::string tSecretRegtest = "cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN"; + +TEST(TransactionBuilder, Invoke) +{ + SelectParams(CBaseChainParams::REGTEST); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + auto consensusParams = Params().GetConsensus(); + + CBasicKeyStore keystore; + CKey tsk = DecodeSecret(tSecretRegtest); + keystore.AddKey(tsk); + auto scriptPubKey = GetScriptForDestination(tsk.GetPubKey().GetID()); + + auto sk_from = libzcash::SaplingSpendingKey::random(); + auto fvk_from = sk_from.full_viewing_key(); + + auto sk = libzcash::SaplingSpendingKey::random(); + auto expsk = sk.expanded_spending_key(); + auto fvk = sk.full_viewing_key(); + auto ivk = fvk.in_viewing_key(); + libzcash::diversifier_t d = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + auto pk = *ivk.address(d); + + // Create a shielding transaction from transparent to Sapling + // 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee + auto builder1 = TransactionBuilder(consensusParams, 1, &keystore); + builder1.AddTransparentInput(COutPoint(), scriptPubKey, 50000); + builder1.AddSaplingOutput(fvk_from, pk, 40000, {}); + auto maybe_tx1 = builder1.Build(); + ASSERT_EQ(static_cast(maybe_tx1), true); + auto tx1 = maybe_tx1.get(); + + EXPECT_EQ(tx1.vin.size(), 1); + EXPECT_EQ(tx1.vout.size(), 0); + EXPECT_EQ(tx1.vjoinsplit.size(), 0); + EXPECT_EQ(tx1.vShieldedSpend.size(), 0); + EXPECT_EQ(tx1.vShieldedOutput.size(), 1); + EXPECT_EQ(tx1.valueBalance, -40000); + + CValidationState state; + EXPECT_TRUE(ContextualCheckTransaction(tx1, state, 2, 0)); + EXPECT_EQ(state.GetRejectReason(), ""); + + // Prepare to spend the note that was just created + auto maybe_pt = libzcash::SaplingNotePlaintext::decrypt( + tx1.vShieldedOutput[0].encCiphertext, ivk, tx1.vShieldedOutput[0].ephemeralKey, tx1.vShieldedOutput[0].cm); + ASSERT_EQ(static_cast(maybe_pt), true); + auto maybe_note = maybe_pt.get().note(ivk); + ASSERT_EQ(static_cast(maybe_note), true); + auto note = maybe_note.get(); + SaplingMerkleTree tree; + tree.append(tx1.vShieldedOutput[0].cm); + auto anchor = tree.root(); + auto witness = tree.witness(); + + // Create a Sapling-only transaction + // 0.0004 z-ZEC in, 0.00025 z-ZEC out, 0.0001 t-ZEC fee, 0.00005 z-ZEC change + auto builder2 = TransactionBuilder(consensusParams, 2); + ASSERT_TRUE(builder2.AddSaplingSpend(expsk, note, anchor, witness)); + // Check that trying to add a different anchor fails + ASSERT_FALSE(builder2.AddSaplingSpend(expsk, note, uint256(), witness)); + + builder2.AddSaplingOutput(fvk, pk, 25000, {}); + auto maybe_tx2 = builder2.Build(); + ASSERT_EQ(static_cast(maybe_tx2), true); + auto tx2 = maybe_tx2.get(); + + EXPECT_EQ(tx2.vin.size(), 0); + EXPECT_EQ(tx2.vout.size(), 0); + EXPECT_EQ(tx2.vjoinsplit.size(), 0); + EXPECT_EQ(tx2.vShieldedSpend.size(), 1); + EXPECT_EQ(tx2.vShieldedOutput.size(), 2); + EXPECT_EQ(tx2.valueBalance, 10000); + + EXPECT_TRUE(ContextualCheckTransaction(tx2, state, 3, 0)); + EXPECT_EQ(state.GetRejectReason(), ""); + + // Revert to default + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); +} + +TEST(TransactionBuilder, ThrowsOnTransparentInputWithoutKeyStore) +{ + auto consensusParams = Params().GetConsensus(); + + auto builder = TransactionBuilder(consensusParams, 1); + ASSERT_THROW(builder.AddTransparentInput(COutPoint(), CScript(), 1), std::runtime_error); +} + +TEST(TransactionBuilder, RejectsInvalidTransparentOutput) +{ + auto consensusParams = Params().GetConsensus(); + + // Default CTxDestination type is an invalid address + CTxDestination taddr; + auto builder = TransactionBuilder(consensusParams, 1); + EXPECT_FALSE(builder.AddTransparentOutput(taddr, 50)); +} + +TEST(TransactionBuilder, RejectsInvalidTransparentChangeAddress) +{ + auto consensusParams = Params().GetConsensus(); + + // Default CTxDestination type is an invalid address + CTxDestination taddr; + auto builder = TransactionBuilder(consensusParams, 1); + EXPECT_FALSE(builder.SendChangeTo(taddr)); +} + +TEST(TransactionBuilder, FailsWithNegativeChange) +{ + SelectParams(CBaseChainParams::REGTEST); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + auto consensusParams = Params().GetConsensus(); + + // Generate dummy Sapling address + auto sk = libzcash::SaplingSpendingKey::random(); + auto expsk = sk.expanded_spending_key(); + auto fvk = sk.full_viewing_key(); + auto pk = sk.default_address(); + + // Set up dummy transparent address + CBasicKeyStore keystore; + CKey tsk = DecodeSecret(tSecretRegtest); + keystore.AddKey(tsk); + auto tkeyid = tsk.GetPubKey().GetID(); + auto scriptPubKey = GetScriptForDestination(tkeyid); + CTxDestination taddr = tkeyid; + + // Generate dummy Sapling note + libzcash::SaplingNote note(pk, 59999); + auto cm = note.cm().value(); + SaplingMerkleTree tree; + tree.append(cm); + auto anchor = tree.root(); + auto witness = tree.witness(); + + // Fail if there is only a Sapling output + // 0.0005 z-ZEC out, 0.0001 t-ZEC fee + auto builder = TransactionBuilder(consensusParams, 1); + builder.AddSaplingOutput(fvk, pk, 50000, {}); + EXPECT_FALSE(static_cast(builder.Build())); + + // Fail if there is only a transparent output + // 0.0005 t-ZEC out, 0.0001 t-ZEC fee + builder = TransactionBuilder(consensusParams, 1, &keystore); + EXPECT_TRUE(builder.AddTransparentOutput(taddr, 50000)); + EXPECT_FALSE(static_cast(builder.Build())); + + // Fails if there is insufficient input + // 0.0005 t-ZEC out, 0.0001 t-ZEC fee, 0.00059999 z-ZEC in + EXPECT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness)); + EXPECT_FALSE(static_cast(builder.Build())); + + // Succeeds if there is sufficient input + builder.AddTransparentInput(COutPoint(), scriptPubKey, 1); + EXPECT_TRUE(static_cast(builder.Build())); + + // Revert to default + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); +} + +TEST(TransactionBuilder, ChangeOutput) +{ + SelectParams(CBaseChainParams::REGTEST); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + auto consensusParams = Params().GetConsensus(); + + // Generate dummy Sapling address + auto sk = libzcash::SaplingSpendingKey::random(); + auto expsk = sk.expanded_spending_key(); + auto pk = sk.default_address(); + + // Generate dummy Sapling note + libzcash::SaplingNote note(pk, 25000); + auto cm = note.cm().value(); + SaplingMerkleTree tree; + tree.append(cm); + auto anchor = tree.root(); + auto witness = tree.witness(); + + // Generate change Sapling address + auto sk2 = libzcash::SaplingSpendingKey::random(); + auto fvkOut = sk2.full_viewing_key(); + auto zChangeAddr = sk2.default_address(); + + // Set up dummy transparent address + CBasicKeyStore keystore; + CKey tsk = DecodeSecret(tSecretRegtest); + keystore.AddKey(tsk); + auto tkeyid = tsk.GetPubKey().GetID(); + auto scriptPubKey = GetScriptForDestination(tkeyid); + CTxDestination taddr = tkeyid; + + // No change address and no Sapling spends + { + auto builder = TransactionBuilder(consensusParams, 1, &keystore); + builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); + EXPECT_FALSE(static_cast(builder.Build())); + } + + // Change to the same address as the first Sapling spend + { + auto builder = TransactionBuilder(consensusParams, 1, &keystore); + builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); + ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness)); + auto maybe_tx = builder.Build(); + ASSERT_EQ(static_cast(maybe_tx), true); + auto tx = maybe_tx.get(); + + EXPECT_EQ(tx.vin.size(), 1); + EXPECT_EQ(tx.vout.size(), 0); + EXPECT_EQ(tx.vjoinsplit.size(), 0); + EXPECT_EQ(tx.vShieldedSpend.size(), 1); + EXPECT_EQ(tx.vShieldedOutput.size(), 1); + EXPECT_EQ(tx.valueBalance, -15000); + } + + // Change to a Sapling address + { + auto builder = TransactionBuilder(consensusParams, 1, &keystore); + builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); + builder.SendChangeTo(zChangeAddr, fvkOut); + auto maybe_tx = builder.Build(); + ASSERT_EQ(static_cast(maybe_tx), true); + auto tx = maybe_tx.get(); + + EXPECT_EQ(tx.vin.size(), 1); + EXPECT_EQ(tx.vout.size(), 0); + EXPECT_EQ(tx.vjoinsplit.size(), 0); + EXPECT_EQ(tx.vShieldedSpend.size(), 0); + EXPECT_EQ(tx.vShieldedOutput.size(), 1); + EXPECT_EQ(tx.valueBalance, -15000); + } + + // Change to a transparent address + { + auto builder = TransactionBuilder(consensusParams, 1, &keystore); + builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); + ASSERT_TRUE(builder.SendChangeTo(taddr)); + auto maybe_tx = builder.Build(); + ASSERT_EQ(static_cast(maybe_tx), true); + auto tx = maybe_tx.get(); + + EXPECT_EQ(tx.vin.size(), 1); + EXPECT_EQ(tx.vout.size(), 1); + EXPECT_EQ(tx.vjoinsplit.size(), 0); + EXPECT_EQ(tx.vShieldedSpend.size(), 0); + EXPECT_EQ(tx.vShieldedOutput.size(), 0); + EXPECT_EQ(tx.valueBalance, 0); + EXPECT_EQ(tx.vout[0].nValue, 15000); + } + + // Revert to default + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); +} + +TEST(TransactionBuilder, SetFee) +{ + SelectParams(CBaseChainParams::REGTEST); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + auto consensusParams = Params().GetConsensus(); + + // Generate dummy Sapling address + auto sk = libzcash::SaplingSpendingKey::random(); + auto expsk = sk.expanded_spending_key(); + auto fvk = sk.full_viewing_key(); + auto pk = sk.default_address(); + + // Generate dummy Sapling note + libzcash::SaplingNote note(pk, 50000); + auto cm = note.cm().value(); + SaplingMerkleTree tree; + tree.append(cm); + auto anchor = tree.root(); + auto witness = tree.witness(); + + // Default fee + { + auto builder = TransactionBuilder(consensusParams, 1); + ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness)); + builder.AddSaplingOutput(fvk, pk, 25000, {}); + auto maybe_tx = builder.Build(); + ASSERT_EQ(static_cast(maybe_tx), true); + auto tx = maybe_tx.get(); + + EXPECT_EQ(tx.vin.size(), 0); + EXPECT_EQ(tx.vout.size(), 0); + EXPECT_EQ(tx.vjoinsplit.size(), 0); + EXPECT_EQ(tx.vShieldedSpend.size(), 1); + EXPECT_EQ(tx.vShieldedOutput.size(), 2); + EXPECT_EQ(tx.valueBalance, 10000); + } + + // Configured fee + { + auto builder = TransactionBuilder(consensusParams, 1); + ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness)); + builder.AddSaplingOutput(fvk, pk, 25000, {}); + builder.SetFee(20000); + auto maybe_tx = builder.Build(); + ASSERT_EQ(static_cast(maybe_tx), true); + auto tx = maybe_tx.get(); + + EXPECT_EQ(tx.vin.size(), 0); + EXPECT_EQ(tx.vout.size(), 0); + EXPECT_EQ(tx.vjoinsplit.size(), 0); + EXPECT_EQ(tx.vShieldedSpend.size(), 1); + EXPECT_EQ(tx.vShieldedOutput.size(), 2); + EXPECT_EQ(tx.valueBalance, 20000); + } + + // Revert to default + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); +} diff --git a/src/gtest/test_validation.cpp b/src/gtest/test_validation.cpp index db382e96b..fb6b296ec 100644 --- a/src/gtest/test_validation.cpp +++ b/src/gtest/test_validation.cpp @@ -21,11 +21,15 @@ class FakeCoinsViewDB : public CCoinsView { public: FakeCoinsViewDB() {} - bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { + bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return false; } - bool GetNullifier(const uint256 &nf) const { + bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { + return false; + } + + bool GetNullifier(const uint256 &nf, ShieldedType type) const { return false; } @@ -42,16 +46,19 @@ public: return a; } - uint256 GetBestAnchor() const { + uint256 GetBestAnchor(ShieldedType type) const { uint256 a; return a; } bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, - const uint256 &hashAnchor, - CAnchorsMap &mapAnchors, - CNullifiersMap &mapNullifiers) { + const uint256 &hashSproutAnchor, + const uint256 &hashSaplingAnchor, + CAnchorsSproutMap &mapSproutAnchors, + CAnchorsSaplingMap &mapSaplingAnchors, + CNullifiersMap &mapSproutNullifiers, + CNullifiersMap saplingNullifiersMap) { return false; } @@ -71,14 +78,16 @@ TEST(Validation, ContextualCheckInputsPassesWithCoinbase) { FakeCoinsViewDB fakeDB; CCoinsViewCache view(&fakeDB); - auto consensusBranchId = SPROUT_BRANCH_ID; - CValidationState state; - PrecomputedTransactionData txdata(tx); - EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, txdata, Params(CBaseChainParams::MAIN).GetConsensus(), consensusBranchId)); + for (int idx = Consensus::BASE_SPROUT; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) { + auto consensusBranchId = NetworkUpgradeInfo[idx].nBranchId; + CValidationState state; + PrecomputedTransactionData txdata(tx); + EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, txdata, Params(CBaseChainParams::MAIN).GetConsensus(), consensusBranchId)); + } } TEST(Validation, ReceivedBlockTransactions) { - auto sk = libzcash::SpendingKey::random(); + auto sk = libzcash::SproutSpendingKey::random(); // Create a fake genesis block CBlock block1; diff --git a/src/gtest/test_zip32.cpp b/src/gtest/test_zip32.cpp new file mode 100644 index 000000000..d93ff2492 --- /dev/null +++ b/src/gtest/test_zip32.cpp @@ -0,0 +1,134 @@ +#include +#include + +#include + +// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_zip32.py +// Sapling consistently uses little-endian encoding, but uint256S takes its input in +// big-endian byte order, so the test vectors below are byte-reversed. +TEST(ZIP32, TestVectors) { + std::vector> rawSeed { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + HDSeed seed(rawSeed); + + auto m = libzcash::SaplingExtendedSpendingKey::Master(seed); + EXPECT_EQ(m.depth, 0); + EXPECT_EQ(m.parentFVKTag, 0); + EXPECT_EQ(m.childIndex, 0); + EXPECT_EQ( + m.chaincode, + uint256S("8e661820750d557e8b34733ebf7ecdfdf31c6d27724fb47aa372bf034b7c94d0")); + EXPECT_EQ( + m.expsk.ask, + uint256S("06257454c907f6510ba1c1830ebf60657760a8869ee968a2b93260d3930cc0b6")); + EXPECT_EQ( + m.expsk.nsk, + uint256S("06ea21888a749fd38eb443d20a030abd2e6e997f5db4f984bd1f2f3be8ed0482")); + EXPECT_EQ( + m.expsk.ovk, + uint256S("21fb4adfa42183848306ffb27719f27d76cf9bb81d023c93d4b9230389845839")); + EXPECT_EQ( + m.dk, + uint256S("72a196f93e8abc0935280ea2a96fa57d6024c9913e0f9fb3af96775bb77cc177")); + EXPECT_THAT( + m.ToXFVK().DefaultAddress().d, + testing::ElementsAreArray({ 0xd8, 0x62, 0x1b, 0x98, 0x1c, 0xf3, 0x00, 0xe9, 0xd4, 0xcc, 0x89 })); + + auto m_1 = m.Derive(1); + EXPECT_EQ(m_1.depth, 1); + EXPECT_EQ(m_1.parentFVKTag, 0x3a71c214); + EXPECT_EQ(m_1.childIndex, 1); + EXPECT_EQ( + m_1.chaincode, + uint256S("e6bcda05678a43fad229334ef0b795a590e7c50590baf0d9b9031a690c114701")); + EXPECT_EQ( + m_1.expsk.ask, + uint256S("0c357a2655b4b8d761794095df5cb402d3ba4a428cf6a88e7c2816a597c12b28")); + EXPECT_EQ( + m_1.expsk.nsk, + uint256S("01ba6bff1018fd4eac04da7e3f2c6be9c229e662c5c4d1d6fc1ecafd8829a3e7")); + EXPECT_EQ( + m_1.expsk.ovk, + uint256S("7474a4c518551bd82f14a7f7365a8ffa403c50cfeffedf026ada8688fc81135f")); + EXPECT_EQ( + m_1.dk, + uint256S("dcb4c170d878510e96c4a74192d7eecde9c9912b00b99a12ec91d7a232e84de0")); + EXPECT_THAT( + m_1.ToXFVK().DefaultAddress().d, + testing::ElementsAreArray({ 0x8b, 0x41, 0x38, 0x32, 0x0d, 0xfa, 0xfd, 0x7b, 0x39, 0x97, 0x81 })); + + auto m_1_2h = m_1.Derive(2 | ZIP32_HARDENED_KEY_LIMIT); + EXPECT_EQ(m_1_2h.depth, 2); + EXPECT_EQ(m_1_2h.parentFVKTag, 0x079e99db); + EXPECT_EQ(m_1_2h.childIndex, 2 | ZIP32_HARDENED_KEY_LIMIT); + EXPECT_EQ( + m_1_2h.chaincode, + uint256S("35d4a883737742ca41a4baa92323bdb3c93dcb3b462a26b039971bedf415ce97")); + EXPECT_EQ( + m_1_2h.expsk.ask, + uint256S("0dc6e4fe846bda925c82e632980434e17b51dac81fc4821fa71334ee3c11e88b")); + EXPECT_EQ( + m_1_2h.expsk.nsk, + uint256S("0c99a63a275c1c66734761cfb9c62fe9bd1b953f579123d3d0e769c59d057837")); + EXPECT_EQ( + m_1_2h.expsk.ovk, + uint256S("bc1328fc5eb693e18875c5149d06953b11d39447ebd6e38c023c22962e1881cf")); + EXPECT_EQ( + m_1_2h.dk, + uint256S("377bb062dce7e0dcd8a0054d0ca4b4d1481b3710bfa1df12ca46ff9e9fa1eda3")); + EXPECT_THAT( + m_1_2h.ToXFVK().DefaultAddress().d, + testing::ElementsAreArray({ 0xe8, 0xd0, 0x37, 0x93, 0xcd, 0xd2, 0xba, 0xcc, 0x9c, 0x70, 0x41 })); + + auto m_1_2hv = m_1_2h.ToXFVK(); + EXPECT_EQ(m_1_2hv.depth, 2); + EXPECT_EQ(m_1_2hv.parentFVKTag, 0x079e99db); + EXPECT_EQ(m_1_2hv.childIndex, 2 | ZIP32_HARDENED_KEY_LIMIT); + EXPECT_EQ( + m_1_2hv.chaincode, + uint256S("35d4a883737742ca41a4baa92323bdb3c93dcb3b462a26b039971bedf415ce97")); + EXPECT_EQ( + m_1_2hv.fvk.ak, + uint256S("4138cffdf7200e52d4e9f4384481b4a4c4d070493a5e401e4ffa850f5a92c5a6")); + EXPECT_EQ( + m_1_2hv.fvk.nk, + uint256S("11eee22577304f660cc036bc84b3fc88d1ec50ae8a4d657beb6b211659304e30")); + EXPECT_EQ( + m_1_2hv.fvk.ovk, + uint256S("bc1328fc5eb693e18875c5149d06953b11d39447ebd6e38c023c22962e1881cf")); + EXPECT_EQ( + m_1_2hv.dk, + uint256S("377bb062dce7e0dcd8a0054d0ca4b4d1481b3710bfa1df12ca46ff9e9fa1eda3")); + EXPECT_EQ(m_1_2hv.DefaultAddress(), m_1_2h.ToXFVK().DefaultAddress()); + + // Hardened derivation from an xfvk fails + EXPECT_FALSE(m_1_2hv.Derive(3 | ZIP32_HARDENED_KEY_LIMIT)); + + // Non-hardened derivation succeeds + auto maybe_m_1_2hv_3 = m_1_2hv.Derive(3); + EXPECT_TRUE(maybe_m_1_2hv_3); + + auto m_1_2hv_3 = maybe_m_1_2hv_3.get(); + EXPECT_EQ(m_1_2hv_3.depth, 3); + EXPECT_EQ(m_1_2hv_3.parentFVKTag, 0x7583c148); + EXPECT_EQ(m_1_2hv_3.childIndex, 3); + EXPECT_EQ( + m_1_2hv_3.chaincode, + uint256S("e8e7d6a74a5a1c05be41baec7998d91f7b3603a4c0af495b0d43ba81cf7b938d")); + EXPECT_EQ( + m_1_2hv_3.fvk.ak, + uint256S("a3a697bdda9d648d32a97553de4754b2fac866d726d3f2c436259c507bc585b1")); + EXPECT_EQ( + m_1_2hv_3.fvk.nk, + uint256S("4f66c0814b769963f3bf1bc001270b50edabb27de042fc8a5607d2029e0488db")); + EXPECT_EQ( + m_1_2hv_3.fvk.ovk, + uint256S("f61a699934dc78441324ef628b4b4721611571e8ee3bd591eb3d4b1cfae0b969")); + EXPECT_EQ( + m_1_2hv_3.dk, + uint256S("6ee53b1261f2c9c0f7359ab236f87b52a0f1b0ce43305cdad92ebb63c350cbbe")); + EXPECT_THAT( + m_1_2hv_3.DefaultAddress().d, + testing::ElementsAreArray({ 0x03, 0x0f, 0xfb, 0x26, 0x3a, 0x93, 0x9e, 0x23, 0x0e, 0x96, 0xdd })); +} diff --git a/src/hash.h b/src/hash.h index d288af305..09f71b432 100644 --- a/src/hash.h +++ b/src/hash.h @@ -9,6 +9,7 @@ #include "crypto/ripemd160.h" #include "crypto/sha256.h" #include "crypto/verus_hash.h" +#include "prevector.h" #include "serialize.h" #include "uint256.h" #include "version.h" @@ -121,21 +122,30 @@ inline uint160 Hash160(const std::vector& vch) return Hash160(vch.begin(), vch.end()); } +/** Compute the 160-bit hash of a vector. */ +template +inline uint160 Hash160(const prevector& vch) +{ + return Hash160(vch.begin(), vch.end()); +} + /** A writer stream (for serialization) that computes a 256-bit hash. */ class CHashWriter { private: CHash256 ctx; + const int nType; + const int nVersion; public: - int nType; - int nVersion; CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {} - CHashWriter& write(const char *pch, size_t size) { + int GetType() const { return nType; } + int GetVersion() const { return nVersion; } + + void write(const char *pch, size_t size) { ctx.Write((const unsigned char*)pch, size); - return (*this); } // invalidates the object @@ -148,7 +158,7 @@ public: template CHashWriter& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } }; @@ -173,6 +183,9 @@ public: personal) == 0); } + int GetType() const { return nType; } + int GetVersion() const { return nVersion; } + CBLAKE2bWriter& write(const char *pch, size_t size) { crypto_generichash_blake2b_update(&state, (const unsigned char*)pch, size); return (*this); @@ -188,7 +201,7 @@ public: template CBLAKE2bWriter& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } }; @@ -224,7 +237,7 @@ public: template CVerusHashWriter& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } }; @@ -260,7 +273,7 @@ public: template CVerusHashV2Writer& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } }; diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 519798d34..d60770aba 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -1,10 +1,10 @@ #include "httprpc.h" -#include "base58.h" #include "chainparams.h" #include "httpserver.h" -#include "rpcprotocol.h" -#include "rpcserver.h" +#include "key_io.h" +#include "rpc/protocol.h" +#include "rpc/server.h" #include "random.h" #include "sync.h" #include "util.h" diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 59ba7c3bc..2ee8d178f 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -8,7 +8,7 @@ #include "compat.h" #include "util.h" #include "netbase.h" -#include "rpcprotocol.h" // For HTTP status codes +#include "rpc/protocol.h" // For HTTP status codes #include "sync.h" #include "ui_interface.h" diff --git a/src/init.cpp b/src/init.cpp index ca90eb4c8..120879e88 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -12,9 +12,6 @@ #include "primitives/block.h" #include "addrman.h" #include "amount.h" -#ifdef ENABLE_MINING -#include "base58.h" -#endif #include "checkpoints.h" #include "compat/sanity.h" #include "consensus/upgrades.h" @@ -23,11 +20,15 @@ #include "httprpc.h" #include "key.h" #include "notarisationdb.h" +#ifdef ENABLE_MINING +#include "key_io.h" +#endif #include "main.h" #include "metrics.h" #include "miner.h" #include "net.h" -#include "rpcserver.h" +#include "rpc/server.h" +#include "rpc/register.h" #include "script/standard.h" #include "scheduler.h" #include "txdb.h" @@ -68,6 +69,8 @@ #include "amqp/amqpnotificationinterface.h" #endif +#include "librustzcash.h" + using namespace std; extern void ThreadSendAlert(); @@ -352,13 +355,11 @@ std::string HelpMessage(HelpMessageMode mode) #endif } strUsage += HelpMessageOpt("-datadir=", _("Specify data directory")); - strUsage += HelpMessageOpt("-disabledeprecation=", strprintf(_("Disable block-height node deprecation and automatic shutdown (example: -disabledeprecation=%s)"), - FormatVersion(CLIENT_VERSION))); strUsage += HelpMessageOpt("-exportdir=", _("Specify directory to be used when exporting data")); strUsage += HelpMessageOpt("-dbcache=", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache)); strUsage += HelpMessageOpt("-loadblock=", _("Imports blocks from external blk000??.dat file") + " " + _("on startup")); strUsage += HelpMessageOpt("-maxorphantx=", strprintf(_("Keep at most unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); - strUsage += HelpMessageOpt("-mempooltxinputlimit=", _("Set the maximum number of transparent inputs in a transaction that the mempool will accept (default: 0 = no limit applied)")); + strUsage += HelpMessageOpt("-mempooltxinputlimit=", _("[DEPRECATED FROM OVERWINTER] Set the maximum number of transparent inputs in a transaction that the mempool will accept (default: 0 = no limit applied)")); strUsage += HelpMessageOpt("-par=", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS)); #ifndef _WIN32 @@ -394,6 +395,9 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-onion=", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy")); strUsage += HelpMessageOpt("-onlynet=", _("Only connect to nodes in network (ipv4, ipv6 or onion)")); strUsage += HelpMessageOpt("-permitbaremultisig", strprintf(_("Relay non-P2SH multisig (default: %u)"), 1)); + strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with Bloom filters (default: %u)"), 1)); + if (showDebug) + strUsage += HelpMessageOpt("-enforcenodebloom", strprintf("Enforce minimum protocol version to limit use of Bloom filters (default: %u)", 0)); strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), 7770, 17770)); strUsage += HelpMessageOpt("-proxy=", _("Connect through SOCKS5 proxy")); strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), 1)); @@ -472,6 +476,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitfreerelay=", strprintf("Continuously rate-limit free transactions to *1000 bytes per minute (default: %u)", 15)); strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 0)); strUsage += HelpMessageOpt("-maxsigcachesize=", strprintf("Limit size of signature cache to entries (default: %u)", 50000)); + strUsage += HelpMessageOpt("-maxtipage=", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE)); } strUsage += HelpMessageOpt("-minrelaytxfee=", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)"), CURRENCY_UNIT, FormatMoney(::minRelayTxFee.GetFeePerK()))); @@ -683,15 +688,26 @@ bool InitSanityCheck(void) } -static void ZC_LoadParams() +static void ZC_LoadParams( + const CChainParams& chainparams +) { struct timeval tv_start, tv_end; float elapsed; boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key"; boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key"; + boost::filesystem::path sapling_spend = ZC_GetParamsDir() / "sapling-spend.params"; + boost::filesystem::path sapling_output = ZC_GetParamsDir() / "sapling-output.params"; + boost::filesystem::path sprout_groth16 = ZC_GetParamsDir() / "sprout-groth16.params"; - if (!(boost::filesystem::exists(pk_path) && boost::filesystem::exists(vk_path))) { + if (!( + boost::filesystem::exists(pk_path) && + boost::filesystem::exists(vk_path) && + boost::filesystem::exists(sapling_spend) && + boost::filesystem::exists(sapling_output) && + boost::filesystem::exists(sprout_groth16) + )) { uiInterface.ThreadSafeMessageBox(strprintf( _("Cannot find the Zcash network parameters in the following directory:\n" "%s\n" @@ -710,6 +726,28 @@ static void ZC_LoadParams() gettimeofday(&tv_end, 0); elapsed = float(tv_end.tv_sec-tv_start.tv_sec) + (tv_end.tv_usec-tv_start.tv_usec)/float(1000000); LogPrintf("Loaded verifying key in %fs seconds.\n", elapsed); + + std::string sapling_spend_str = sapling_spend.string(); + std::string sapling_output_str = sapling_output.string(); + std::string sprout_groth16_str = sprout_groth16.string(); + + LogPrintf("Loading Sapling (Spend) parameters from %s\n", sapling_spend_str.c_str()); + LogPrintf("Loading Sapling (Output) parameters from %s\n", sapling_output_str.c_str()); + LogPrintf("Loading Sapling (Sprout Groth16) parameters from %s\n", sprout_groth16_str.c_str()); + gettimeofday(&tv_start, 0); + + librustzcash_init_zksnark_params( + sapling_spend_str.c_str(), + "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c", + sapling_output_str.c_str(), + "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028", + sprout_groth16_str.c_str(), + "e9b238411bd6c0ec4791e9d04245ec350c9c5744f5610dfcce4365d5ca49dfefd5054e371842b3f88fa1b9d7e8e075249b3ebabd167fa8b0f3161292d36c180a" + ); + + gettimeofday(&tv_end, 0); + elapsed = float(tv_end.tv_sec-tv_start.tv_sec) + (tv_end.tv_usec-tv_start.tv_usec)/float(1000000); + LogPrintf("Loaded Sapling parameters in %fs seconds.\n", elapsed); } bool AppInitServers(boost::thread_group& threadGroup) @@ -792,6 +830,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) signal(SIGPIPE, SIG_IGN); #endif + std::set_new_handler(new_handler_terminate); + // ********************************************************* Step 2: parameter interactions const CChainParams& chainparams = Params(); @@ -960,8 +1000,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) fPruneMode = true; } + RegisterAllCoreRPCCommands(tableRPC); #ifdef ENABLE_WALLET bool fDisableWallet = GetBoolArg("-disablewallet", false); + if (!fDisableWallet) + RegisterWalletRPCCommands(tableRPC); #endif nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); @@ -1036,10 +1079,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Option to startup with mocktime set (used for regression testing): SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op + if (GetBoolArg("-peerbloomfilters", true)) + nLocalServices |= NODE_BLOOM; + + nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + #ifdef ENABLE_MINING if (mapArgs.count("-mineraddress")) { - CBitcoinAddress addr; - if (!addr.SetString(mapArgs["-mineraddress"])) { + CTxDestination addr = DecodeDestination(mapArgs["-mineraddress"]); + if (!IsValidDestination(addr)) { return InitError(strprintf( _("Invalid address for -mineraddress=: '%s' (must be a transparent address)"), mapArgs["-mineraddress"])); @@ -1183,7 +1231,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) libsnark::inhibit_profiling_counters = true; // Initialize Zcash circuit parameters - ZC_LoadParams(); + ZC_LoadParams(chainparams); /* Start the RPC server already. It will be started in "warmup" mode * and not really process calls already (but it will signify connections @@ -1222,6 +1270,20 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterNodeSignals(GetNodeSignals()); + // sanitize comments per BIP-0014, format user agent and check total size + std::vector uacomments; + BOOST_FOREACH(string cmt, mapMultiArgs["-uacomment"]) + { + if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) + return InitError(strprintf("User Agent comment (%s) contains unsafe characters.", cmt)); + uacomments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)); + } + strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); + if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { + return InitError(strprintf("Total length of network version string %i exceeds maximum of %i characters. Reduce the number and/or size of uacomments.", + strSubVersion.size(), MAX_SUBVERSION_LENGTH)); + } + if (mapArgs.count("-onlynet")) { std::set nets; BOOST_FOREACH(const std::string& snet, mapMultiArgs["-onlynet"]) { @@ -1432,6 +1494,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } + bool clearWitnessCaches = false; + bool fLoaded = false; while (!fLoaded) { bool fReset = fReindex; @@ -1494,7 +1558,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (!fReindex) { uiInterface.InitMessage(_("Rewinding blocks if needed...")); - if (!RewindBlockIndex(chainparams)) { + if (!RewindBlockIndex(chainparams, clearWitnessCaches)) { strLoadError = _("Unable to rewind the database to a pre-upgrade state. You will need to redownload the blockchain"); break; } @@ -1628,6 +1692,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) pwalletMain->SetMaxVersion(nMaxVersion); } + if (!pwalletMain->HaveHDSeed()) + { + // generate a new HD seed + pwalletMain->GenerateNewSeed(); + } + if (fFirstRun) { // Create new keyUser and set as default key @@ -1647,7 +1717,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterValidationInterface(pwalletMain); CBlockIndex *pindexRescan = chainActive.Tip(); - if (GetBoolArg("-rescan", false)) + if (clearWitnessCaches || GetBoolArg("-rescan", false)) { pwalletMain->ClearNoteWitnessCache(); pindexRescan = chainActive.Genesis(); @@ -1717,9 +1787,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) bool minerAddressInLocalWallet = false; if (pwalletMain) { // Address has alreday been validated - CBitcoinAddress addr(mapArgs["-mineraddress"]); - CKeyID keyID; - addr.GetKeyID(keyID); + CTxDestination addr = DecodeDestination(mapArgs["-mineraddress"]); + CKeyID keyID = boost::get(addr); minerAddressInLocalWallet = pwalletMain->HaveKey(keyID); } if (GetBoolArg("-minetolocalwallet", true) && !minerAddressInLocalWallet) { diff --git a/src/key.cpp b/src/key.cpp index c93f8d15d..5688b1302 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -307,7 +307,7 @@ CExtPubKey CExtKey::Neuter() const { return ret; } -void CExtKey::Encode(unsigned char code[74]) const { +void CExtKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const { code[0] = nDepth; memcpy(code+1, vchFingerprint, 4); code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; @@ -318,12 +318,12 @@ void CExtKey::Encode(unsigned char code[74]) const { memcpy(code+42, key.begin(), 32); } -void CExtKey::Decode(const unsigned char code[74]) { +void CExtKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) { nDepth = code[0]; memcpy(vchFingerprint, code+1, 4); nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8]; memcpy(chaincode.begin(), code+9, 32); - key.Set(code+42, code+74, true); + key.Set(code+42, code+BIP32_EXTKEY_SIZE, true); } bool ECC_InitSanityCheck() { diff --git a/src/key.h b/src/key.h index c2b75935c..8d64151e3 100644 --- a/src/key.h +++ b/src/key.h @@ -170,11 +170,28 @@ struct CExtKey { a.chaincode == b.chaincode && a.key == b.key; } - void Encode(unsigned char code[74]) const; - void Decode(const unsigned char code[74]); + void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; + void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); bool Derive(CExtKey& out, unsigned int nChild) const; CExtPubKey Neuter() const; void SetMaster(const unsigned char* seed, unsigned int nSeedLen); + template + void Serialize(Stream& s) const + { + unsigned int len = BIP32_EXTKEY_SIZE; + ::WriteCompactSize(s, len); + unsigned char code[BIP32_EXTKEY_SIZE]; + Encode(code); + s.write((const char *)&code[0], len); + } + template + void Unserialize(Stream& s) + { + unsigned int len = ::ReadCompactSize(s); + unsigned char code[BIP32_EXTKEY_SIZE]; + s.read((char *)&code[0], len); + Decode(code); + } }; /** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */ diff --git a/src/key_io.cpp b/src/key_io.cpp new file mode 100644 index 000000000..636163638 --- /dev/null +++ b/src/key_io.cpp @@ -0,0 +1,377 @@ +// Copyright (c) 2014-2016 The Bitcoin Core developers +// Copyright (c) 2016-2018 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include