diff --git a/.gitignore b/.gitignore index 3916d4e87..01e45a168 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.tar.gz *.deb -*.exe src/bitcoin src/zcashd src/zcash-cli @@ -8,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 @@ -47,6 +42,7 @@ src/univalue/gen .deps .dirstamp +.idea .libs .*.swp *.*~* @@ -121,3 +117,10 @@ src/komodod src/komodo-tx src/komodo-test src/wallet-utility +src/komodo-cli.exe +src/komodod.exe +src/komodo-tx.exe + +#output during builds, symbol tables? +*.dSYM + diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..b26399a9c --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,333 @@ +stages: +- build +- test +- deploy +######################################################################################################################## +####START#### PROJECT LEVEL VARIABLES ####START#### +######################################################################################################################## +variables: + VERSION: 0.4.0c + VERUS_CLI_LINUX: Verus-CLI-Linux-v${VERSION}.tar.gz + VERUS_CLI_WINDOWS: Verus-CLI-Windows-v${VERSION}.zip + VERUS_CLI_MACOS: Verus-CLI-MacOS-v${VERSION}.tar.gz + DOWNSTREAM_AGAMA_BRANCH: ${CI_COMMIT_REF_NAME} + POST_MESSAGE: "Source: ${CI_PROJECT_NAME}/${CI_COMMIT_REF_NAME}\n + Pipeline Trigger: ${CI_PIPELINE_SOURCE}\n + Commit: ${CI_COMMIT_SHA}$\n + ${CI_COMMIT_MESSAGE}" +######################################################################################################################## +####END#### PROJECT LEVEL VARIABLES ####END#### +######################################################################################################################## +######################################################################################################################## +######################################################################################################################## +####START#### Build Stage: compile and package komodo binaries for Verus CLI ####START##### +######################################################################################################################## +######################################################################################################################## +####START#### LINUX ####START#### +######################################################################################################################## +build:linux: + image: asherd/verus-builders:verus-ubuntu + variables: + DOCKER_DRIVER: overlay2 + stage: build + cache: + key: "${CI_JOB_NAME}${CI_COMMIT_REF_NAME}" + paths: + - depends/built + script: + - zcutil/build.sh -j$(nproc) + - mkdir verus-cli + - cp src/komodod + src/komodo-cli + src/fiat/verus + src/verusd + doc/man/verus-cli/linux/README.txt + zcutil/fetch-params.sh + verus-cli + - mv verus-cli/fetch-params.sh verus-cli/fetch-params + - chmod +x verus-cli/komodod + - chmod +x verus-cli/komodo-cli + - chmod +x verus-cli/verus + - chmod +x verus-cli/verusd + - chmod +x verus-cli/fetch-params + - if [ "${CI_COMMIT_REF_NAME}" = "master" ]; then strip -g verus-cli/komodod && strip -g verus-cli/komodod; fi + - tar -czvf ${VERUS_CLI_LINUX} verus-cli + - md5sum ${VERUS_CLI_LINUX} > ${VERUS_CLI_LINUX}.md5 + - curl -F file=@"${VERUS_CLI_LINUX}" + -F channels="${CLI_POST_CHANNEL}" + -F initial_comment="${POST_MESSAGE}" + -H "${SLACK_BOT_AUTH}" + "https://slack.com/api/files.upload" + artifacts: + paths: + - ${VERUS_CLI_LINUX} + - ${VERUS_CLI_LINUX}.md5 + expire_in: 1 week +######################################################################################################################## +####END#### LINUX ####END#### +######################################################################################################################## +####START#### WINDOWS ####START#### +######################################################################################################################## +build:windows: + image: asherd/verus-builders:verus-windows + variables: + DOCKER_DRIVER: overlay2 + stage: build + cache: + key: "${CI_JOB_NAME}${CI_COMMIT_REF_NAME}" + paths: + - depends/built + script: + - zcutil/build-win.sh -j$(nproc) + - mkdir verus-cli + - cp src/komodod.exe + src/komodo-cli.exe + src/komodo-tx.exe + src/fiat/verus.bat + src/verusd.bat + doc/man/verus-cli/windows/README.txt + zcutil/fetch-params.bat + zcutil/wget64.exe + verus-cli + - zip -r ${VERUS_CLI_WINDOWS} verus-cli + - md5sum ${VERUS_CLI_WINDOWS} > ${VERUS_CLI_WINDOWS}.md5 + - curl -F file=@"${VERUS_CLI_WINDOWS}" + -F channels="${CLI_POST_CHANNEL}" + -F initial_comment="${POST_MESSAGE}" + -H "${SLACK_BOT_AUTH}" + "https://slack.com/api/files.upload" + artifacts: + paths: + - ${VERUS_CLI_WINDOWS} + - ${VERUS_CLI_WINDOWS}.md5 + expire_in: 1 week +######################################################################################################################## +####END#### WINDOWS ####END#### +######################################################################################################################## +####START#### MACOS ####START#### +######################################################################################################################## +build:mac: + stage: build + tags: ["High Sierra"] + cache: + key: "${CI_JOB_NAME}${CI_COMMIT_REF_NAME}" + paths: + - depends/built + script: + - zcutil/build-mac.sh -j$(sysctl -n hw.physicalcpu) + - ./makeReleaseMac.sh + - tar -czvf ${VERUS_CLI_MACOS} verus-cli + - md5sum ${VERUS_CLI_MACOS} > ${VERUS_CLI_MACOS}.md5 + - curl -F file=@"${VERUS_CLI_MACOS}" + -F channels="${CLI_POST_CHANNEL}" + -F initial_comment="${POST_MESSAGE}" + -H "${SLACK_BOT_AUTH}" + "https://slack.com/api/files.upload" + artifacts: + paths: + - ${VERUS_CLI_MACOS} + - ${VERUS_CLI_MACOS}.md5 + expire_in: 1 week +######################################################################################################################## +####END#### MACOS ####END#### +######################################################################################################################## +######################################################################################################################## +####END#### Build Stage ####END#### +######################################################################################################################## +######################################################################################################################## +######################################################################################################################## +######################################################################################################################## +####START#### Test stage: Test functionality of komodo binaries. Produce code quality and SAST reports. ####START#### +######################################################################################################################## +######################################################################################################################## +######################################################################################################################## +####START#### Code Quality ####START#### +######################################################################################################################## +.code_quality: + image: docker:stable + variables: + DOCKER_DRIVER: overlay2 + allow_failure: true + services: + - docker:stable-dind + script: + - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') + - docker run + --env SOURCE_CODE="$PWD" + --volume "$PWD":/code + --volume /var/run/docker.sock:/var/run/docker.sock + "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code + artifacts: + paths: [gl-code-quality-report.json] +######################################################################################################################## +####END#### Code Quality ####END#### +######################################################################################################################## +######################################################################################################################## +####START#### Static Application Security Tests ####START#### +######################################################################################################################## +.sast: + image: docker:stable + variables: + DOCKER_DRIVER: overlay2 + allow_failure: true + services: + - docker:stable-dind + script: + - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') + - docker run + --env SAST_CONFIDENCE_LEVEL="${SAST_CONFIDENCE_LEVEL:-3}" + --volume "$PWD:/code" + --volume /var/run/docker.sock:/var/run/docker.sock + "registry.gitlab.com/gitlab-org/security-products/sast:$SP_VERSION" /app/bin/run /code + artifacts: + paths: [gl-sast-report.json] +######################################################################################################################## +####END#### Static Application Security Tests ####END#### +######################################################################################################################## +######################################################################################################################## +####START#### Run Verus CLI on Ubuntu Xenial (16.04) ####START#### +######################################################################################################################## +.ubuntu:xenial: + image: ubuntu:xenial + variables: + DOCKER_DRIVER: overlay2 + stage: test + before_script: + - apt update && apt install -y wget libgomp1 libcurl4-gnutls-dev python + - rm -rf /root/.komodo || true + - mv .komodo /root/ || true + script: + - tar -xzvf ${VERUS_CLI_LINUX} + - export PATH=$PATH:$CI_PROJECT_DIR/verus-cli + - python qa/verus-cli-tests/verus-cli-tester.py + after_script: + - mv /root/.komodo ./ || true + cache: + key: ${CI_JOB_NAME} + paths: [.komodo] + artifacts: + paths: [log.txt] + expire_in: 1 week + dependencies: + - build:linux +######################################################################################################################## +####END#### Run Verus CLI on Ubuntu Xenial (16.04) ####END#### +######################################################################################################################## +######################################################################################################################## +####START#### Run Verus CLI on Ubuntu Bionic (18.04) ####START#### +######################################################################################################################## +.ubuntu:bionic: + image: ubuntu:bionic + variables: + DOCKER_DRIVER: overlay2 + stage: test + before_script: + - apt update && apt install -y wget libgomp1 libcurl4-gnutls-dev python + - rm -rf /root/.komodo || true + - mv .komodo /root/ || true + script: + - tar -xzvf ${VERUS_CLI_LINUX} + - export PATH=$PATH:$CI_PROJECT_DIR/verus-cli + - python qa/verus-cli-tests/verus-cli-tester.py + after_script: + - mv /root/.komodo ./ || true + cache: + key: ${CI_JOB_NAME} + paths: [.komodo] + artifacts: + paths: [log.txt] + expire_in: 1 week + dependencies: + - build:linux +######################################################################################################################## +####END#### Run Verus CLI on Ubuntu Bionic (18.04) ####END#### +######################################################################################################################## +######################################################################################################################## +####START#### Run Verus CLI on MacOS Sierra (10.12.6) ####START#### +######################################################################################################################## +.macos:sierra: + stage: test + tags: ["Sierra"] + script: + - tar -xzvf $VERUS_CLI_MACOS + - export PATH=$PATH:$CI_PROJECT_DIR/verus-cli + - python qa/verus-cli-tests/verus-cli-tester.py + artifacts: + paths: [log.txt] + expire_in: 1 week + dependencies: + - build:mac +######################################################################################################################## +####END#### Run Verus CLI on MacOS Sierra (10.12.6) ####END#### +######################################################################################################################## +######################################################################################################################## +####START#### Run Verus CLI on MacOS High Sierra (10.12.6) ####START#### +######################################################################################################################## +.macos:high-sierra: + stage: test + tags: ["High Sierra"] + script: + - tar -xzvf ${VERUS_CLI_MACOS} + - export PATH=$PATH:$CI_PROJECT_DIR/verus-cli + - python qa/verus-cli-tests/verus-cli-tester.py + artifacts: + paths: [log.txt] + expire_in: 1 week + dependencies: + - build:mac +######################################################################################################################## +####START#### Run Verus CLI on MacOS High Sierra (10.12.6) ####START#### +######################################################################################################################## +######################################################################################################################## +####START#### Run Verus CLI on Windows 10 ####START#### +######################################################################################################################## +.windows:10: + stage: test + tags: ["Windows 10"] + script: + - PowerShell Expand-Archive -Path %VERUS_CLI_WINDOWS% -DestinationPath %CI_PROJECT_DIR% + - set PATH=%PATH%;%CI_PROJECT_DIR%\verus-cli + - qa\verus-cli-tests\verus-cli-tester.py + artifacts: + paths: [log.txt] + expire_in: 1 week + dependencies: + - build:windows +######################################################################################################################## +####END#### Run Verus CLI on Windows 10 ####END#### +######################################################################################################################## +######################################################################################################################## +####END#### Test Stage ####END#### +######################################################################################################################## +######################################################################################################################## +####START#### Deploy ####START#### +######################################################################################################################## +deploy: + stage: deploy + image: google/cloud-sdk:alpine + variables: + DOCKER_DRIVER: overlay2 + dependencies: + - build:linux + - build:windows + - build:mac + script: + - mkdir Windows && mkdir Linux && mkdir MacOS && + mv ${VERUS_CLI_WINDOWS} Windows && + mv ${VERUS_CLI_LINUX} Linux && + mv ${VERUS_CLI_MACOS} MacOS + - echo "$AUTH_KEY" > AUTH_KEY.json && + gcloud auth activate-service-account + --key-file AUTH_KEY.json + - gsutil cp -r Windows Linux MacOS $STAGING/${CI_PROJECT_NAME}/${CI_COMMIT_REF_NAME}/ + - curl -X POST + -F token="$CI_JOB_TOKEN" + -F ref="$DOWNSTREAM_AGAMA_BRANCH" + -F variables\[UPSTREAM_TRIGGER_INFO\]="${POST_MESSAGE}" + -F variables\[VERUS_CLI_LINUX\]="${VERUS_CLI_LINUX}" + -F variables\[VERUS_CLI_WINDOWS\]="${VERUS_CLI_WINDOWS}" + -F variables\[VERUS_CLI_MACOS\]="${VERUS_CLI_MACOS}" + "https://gitlab.com/api/v4/projects/8018592/trigger/pipeline" +######################################################################################################################## +####END#### Deploy ####END#### +######################################################################################################################## diff --git a/AUTH_KEY.json.enc b/AUTH_KEY.json.enc new file mode 100644 index 000000000..ac619b9cb Binary files /dev/null and b/AUTH_KEY.json.enc differ diff --git a/Brewfile b/Brewfile new file mode 100644 index 000000000..7a048b080 --- /dev/null +++ b/Brewfile @@ -0,0 +1,17 @@ +tap "discoteq/discoteq" +tap "homebrew/bundle" +tap "homebrew/cask" +tap "homebrew/cask-versions" +tap "homebrew/core" +brew "autoconf" +brew "autogen" +brew "automake" +brew "binutils" +brew "cmake" +brew "coreutils" +brew "gcc@6" +brew "leveldb" +brew "nanomsg" +brew "protobuf" +brew "wget" +brew "discoteq/discoteq/flock" diff --git a/COPYING b/COPYING index eecf5ccc8..7c046110d 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,8 @@ -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 of this software and associated documentation files (the "Software"), to deal @@ -32,7 +34,7 @@ OpenSSL Toolkit (https://www.openssl.org/). This product includes cryptographic software written by Eric Young (eay@cryptsoft.com). -Although almost all of the Zcash code is licensed under "permissive" open source +Although almost all of the Zcash/Komodo/VerusCoin code is licensed under "permissive" open source licenses, users and distributors should note that when built using the default build options, Zcash depends on Oracle Berkeley DB 6.2.x, which is licensed under the GNU Affero General Public License. diff --git a/Makefile.am b/Makefile.am index 30be7500c..51d0430ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,14 +13,14 @@ pkgconfig_DATA = libzcashconsensus.pc endif -BITCOIND_BIN=$(top_builddir)/src/zcashd$(EXEEXT) -BITCOIN_CLI_BIN=$(top_builddir)/src/zcash-cli$(EXEEXT) +BITCOIND_BIN=$(top_builddir)/src/komodod$(EXEEXT) +BITCOIN_CLI_BIN=$(top_builddir)/src/komodo-cli$(EXEEXT) #WALLET_UTILITY_BIN=$(top_builddir)/src/wallet-utility$(EXEEXT) BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT) if TARGET_DARWIN -OSX_APP=Bitcoin-Qt.app -OSX_DMG=Bitcoin-Core.dmg +OSX_APP=Agama.app +OSX_DMG=Agama.dmg OSX_BACKGROUND_IMAGE=background.tiff OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist diff --git a/README-mac.md b/README-mac.md index f3dd5e281..5ac074dd9 100644 --- a/README-mac.md +++ b/README-mac.md @@ -1,6 +1,5 @@ -## Install for Mac OS X -First off you need Apple's Xcode (at least version 7, preferably 8.x or later) and the Xcode Command Line Tools: +You will need Apple's Xcode (at least version 7, preferably 8.x) and the Xcode Command Line Tools: https://itunes.apple.com/us/app/xcode/id497799835?mt=12 @@ -8,16 +7,10 @@ And Homebrew: http://brew.sh/ -And this is the list of brew packages you'll need installed: +Use the brewfile to install the necessary packages: ```shell -brew tap discoteq/discoteq; brew install flock -brew install autoconf autogen automake -brew install gcc@6 -brew install binutils -brew install protobuf -brew install coreutils -brew install wget +brew bundle ``` or @@ -29,13 +22,13 @@ brew tap discoteq/discoteq; brew install flock autoconf autogen automake gcc@6 b Get all that installed, then run: ```shell -git clone https://github.com/jl777/komodo.git -cd komodo +git clone https://github.com/VerusCoin/VerusCoin.git +cd VerusCoin ./zcutil/build-mac.sh ./zcutil/fetch-params.sh ``` -To build a distributable version of komodo then run the makeDistrib.sh script after building. +To build a distributable version of VerusCoin then run the makeReleaseMac.sh script after building. This will fix the dependency references and move the komodod and komodo-cli binaries to the kmd/mac/verus-cli directory along with the 6 libraries required for it to work properly. When you are done building, you need to create `Komodo.conf` the Mac way. diff --git a/README.md b/README.md index 92a7014f4..bb60c2e6e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,16 @@ -[![Build Status](https://travis-ci.org/KomodoPlatform/komodo.svg?branch=dev)](https://travis-ci.org/KomodoPlatform/komodo) ---- -![Komodo Logo](https://i.imgur.com/vIwVtqv.png "Komodo Logo") +## VerusCoin version 0.4.0c + +VerusCoin is a new, mineable and stakeable cryptocurrency. It is a live fork of Komodo that retains its Zcash lineage and improves it. VerusCoin will leverage the Komodo platform and dPoW notarization for enhanced security and cross-chain interoperability. We have added a variation of a zawy12, lwma difficulty algorithm, a new CPU-optimized hash algorithm and a new algorithm for fair proof of stake. We describe these changes and vision going forward in a [our Phase I white paper](http://185.25.51.16/papers/VerusPhaseI.pdf) and [our Vision](http://185.25.51.16/papers/VerusVision.pdf). +- [VerusCoin web site https://veruscoin.io/ Wallets and CLI tools](https://veruscoin.io/) +- [VerusCoin Explorer](https://explorer.veruscoin.io/) -## Komodo +## Komodo with Bitcore +This version of Komodo contains Bitcore support for komodo and all its assetchains. -This is the official Komodo sourcecode repository based on https://github.com/jl777/komodo. - -## Development Resources +## Komodod +This software is the VerusCoin enhanced Komodo client. Generally, you will use this if you want to mine VRSC or setup a full node. When you run the wallet it launches komodod automatically. On first launch it downloads Zcash parameters, roughly 1GB, which is mildly slow. +The wallet downloads and stores the block chain or asset chain of the coin you select. It downloads and stores the entire history of the coins transactions; depending on the speed of your computer and network connection, the synchronization process could take a day or more once the blockchain has reached a significant size. - Komodo Website: [https://komodoplatform.com](https://komodoplatform.com/) - Komodo Blockexplorer: [https://kmdexplorer.io](https://kmdexplorer.io/) @@ -51,98 +54,67 @@ Komodo is based on Zcash and has been extended by our innovative consensus algor ```shell #The following packages are needed: -sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev unzip git python python-zmq zlib1g-dev wget libcurl4-openssl-dev bsdmainutils automake curl +sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev unzip git python python-zmq zlib1g-dev wget libcurl4-gnutls-dev bsdmainutils automake curl ``` -### Build Komodo -This software is based on zcash and considered experimental and is continously undergoing heavy development. +Building +-------- -The dev branch is considered the bleeding edge codebase while the master-branch is considered tested (unit tests, runtime tests, functionality). At no point of time do the Komodo Platform developers take any responsbility for any damage out of the usage of this software. -Komodo builds for all operating systems out of the same codebase. Follow the OS specific instructions from below. +First time you'll need to get assorted startup values downloaded. This takes a moderate amount of time once but then does not need to be repeated unless you bring a new system up. The command is: +``` +./zcutil/fetch-params.sh +``` +Building for Ubunutu/Mint: +``` +./zcutil/build.sh +``` +Building for Mac OS/X (see README-MAC.md): +``` +./zcutil/build-mac.sh +``` +Building for Windows: +``` +./zcutil/build-win.sh +``` +VerusCoin +------ +We develop on dev and some other branches and produce releases of of the master branch, using pull requests to manage what goes into master. The dev branch is considered the bleeding edge codebase, and may even be oncompatible from time to time, while the master-branch is considered tested (unit tests, runtime tests, functionality). At no point of time do the Komodo Platform developers or Verus Developers take any responsbility for any damage out of the usage of this software. + +Verus builds for all operating systems out of the same codebase. Follow the OS specific instructions from below. #### Linux ```shell -git clone https://github.com/komodoplatform/komodo --branch master --single-branch -cd komodo +git clone https://github.com/VerusCoin/VerusCoin +cd VerusCoin +#you might want to: git checkout ; git pull ./zcutil/fetch-params.sh # -j8 = using 8 threads for the compilation - replace 8 with number of threads you want to use ./zcutil/build.sh -j8 #This can take some time. ``` -#### OSX -Ensure you have [brew](https://brew.sh) and the command line tools installed (comes automatically with XCode) and run: -```shell -brew update && brew install gcc@6 -git clone https://github.com/komodoplatform/komodo --branch master --single-branch -cd komodo -./zcutil/fetch-params.sh -# -j8 = using 8 threads for the compilation - replace 8 with number of threads you want to use -./zcutil/build-mac.sh -j8 -#This can take some time. -``` +**The VerusCoin enhanced komodo is experimental and a work-in-progress.** Use at your own risk. -#### Windows -Use a debian cross-compilation setup with mingw for windows and run: -```shell -git clone https://github.com/komodoplatform/komodo --branch master --single-branch -cd komodo -./zcutil/fetch-params.sh -# -j8 = using 8 threads for the compilation - replace 8 with number of threads you want to use -./zcutil/build-win.sh -j8 -#This can take some time. -``` -**komodo is experimental and a work-in-progress.** Use at your own risk. -To reset the Komodo blockchain change into the *~/.komodo* data directory and delete the corresponding files by running `rm -rf blocks chainstate debug.log komodostate db.log` +#To view komodod output: +tail -f ~/.komodo/debug.log +#To view VRSC output: +tail -f ~/.komodo/VRSC/debug.log +Note that this directory is correct for Linux, not Mac or Windows +#To view all command +./src/komodo-cli help +**Zcash is unfinished and highly experimental.** Use at your own risk. -#### Create komodo.conf +#### :ledger: Deprecation Policy -Create a komodo.conf file: +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. -``` -mkdir ~/.komodo -cd ~/.komodo -touch komodo.conf - -#Add the following lines to the komodo.conf file: -rpcuser=yourrpcusername -rpcpassword=yoursecurerpcpassword -rpcbind=127.0.0.1 -txindex=1 -addnode=5.9.102.210 -addnode=78.47.196.146 -addnode=178.63.69.164 -addnode=88.198.65.74 -addnode=5.9.122.241 -addnode=144.76.94.38 -addnode=89.248.166.91 -``` -### Create your own Blockchain based on Komodo - -Komodo allows anyone to create a runtime fork which represents an independent Blockchain. Below are the detailed instructions: -Setup two independent servers with at least 1 server having a static IP and build komodod on those servers. - -#### On server 1 (with static IP) run: -```shell -./komodod -ac_name=name_of_your_chain -ac_supply=100000 -bind=ip_of_server_1 & -``` - -#### On server 2 run: -```shell -./komodod -ac_name=name_of_your_chain -ac_supply=100000 -addnode=ip_of_server_1 -gen & -``` - -**Komodo is based on Zcash which is unfinished and highly experimental.** Use at your own risk. - -License -------- -For license information see the file [COPYING](COPYING). - -**NOTE TO EXCHANGES:** -https://bitcointalk.org/index.php?topic=1605144.msg17732151#msg17732151 -There is a small chance that an outbound transaction will give an error due to mismatched values in wallet calculations. There is a -exchange option that you can run komodod with, but make sure to have the entire transaction history under the same -exchange mode. Otherwise you will get wallet conflicts. +#Older Komodo Details +The remaining text is from the komodo source we forked when creating VerusCoin/Veruscoin. **To change modes:** @@ -153,18 +125,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/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 7de40ff26..9a1a75f53 100644 --- a/configure.ac +++ b/configure.ac @@ -1,22 +1,22 @@ 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_BUILD, 50) +define(_CLIENT_VERSION_BUILD, 26) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) define(_CLIENT_VERSION_IS_RELEASE, true) -define(_COPYRIGHT_YEAR, 2017) -AC_INIT([Zcash],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_SUFFIX(_ZC_BUILD_VAL)],[https://github.com/zcash/zcash/issues],[zcash]) +define(_COPYRIGHT_YEAR, 2018) +AC_INIT([Verus-CLI],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_SUFFIX(_ZC_BUILD_VAL)],[https://github.com/VerusCoin/VerusCoin/issues],[verus-cli]) AC_CONFIG_SRCDIR([src/main.cpp]) AC_CONFIG_HEADERS([src/config/bitcoin-config.h]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) -BITCOIN_DAEMON_NAME=zcashd -BITCOIN_CLI_NAME=zcash-cli -BITCOIN_TX_NAME=zcash-tx +BITCOIN_DAEMON_NAME=komodod +BITCOIN_CLI_NAME=komodo-cli +BITCOIN_TX_NAME=komodo-tx dnl Unless the user specified ARFLAGS, force it to be cr AC_ARG_VAR(ARFLAGS, [Flags for the archiver, defaults to if not set]) @@ -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)])], @@ -232,15 +226,15 @@ CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS" AC_ARG_WITH([utils], [AS_HELP_STRING([--with-utils], - [build zcash-cli zcash-tx wallet-utility (default=yes)])], + [build komodo-cli komodo-tx wallet-utility (default=yes)])], [build_bitcoin_utils=$withval], [build_bitcoin_utils=yes]) 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,13 +798,13 @@ 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]) AC_MSG_RESULT($build_bitcoind) -AC_MSG_CHECKING([whether to build utils (zcash-cli zcash-tx wallet-utility)]) +AC_MSG_CHECKING([whether to build utils (komodo-cli komodo-tx wallet-utility)]) AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes]) AC_MSG_RESULT($build_bitcoin_utils) @@ -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..1dbe1cc0d 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,3 +1,69 @@ +zcash (2.0.1) stable; urgency=medium + + * 2.0.1 release. + + -- Zcash Company Sun, 14 Oct 2018 13:40:30 -0700 + +zcash (2.0.1~rc1) stable; urgency=medium + + * 2.0.1-rc1 release. + + -- Zcash Company Mon, 08 Oct 2018 12:40:54 -0700 + +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/control b/contrib/debian/control index b0c220cf0..c2921790c 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -1,21 +1,22 @@ -Source: zcash +Source: VerusCoin Section: utils Priority: optional -Maintainer: Zcash Company -Homepage: https://z.cash +Maintainer: VerusCoin +Homepage: https://veruscoin.io Build-Depends: autoconf, automake, bsdmainutils, build-essential, git, g++-multilib, libc6-dev, libtool, m4, ncurses-dev, pkg-config, python, unzip, wget, zlib1g-dev -Vcs-Git: https://github.com/zcash/zcash.git -Vcs-Browser: https://github.com/zcash/zcash +Vcs-Git: https://github.com/VeruscCoin/VerusCoin.git +Vcs-Browser: https://github.com/VerusCoin/VerusCoin -Package: zcash +Package: Verus-CLI Architecture: amd64 Depends: ${shlibs:Depends} -Description: HTTPS for money. - Based on Bitcoin's code, it intends to offer a far higher standard - of privacy and anonymity through a sophisticiated zero-knowledge - proving scheme which preserves confidentiality of transaction metadata. - This package provides the daemon, zcashd, and the CLI tool, - zcash-cli, to interact with the daemon. +Description: VerusCoin is a new, mineable and stakeable cryptocurrency. +It is a live fork of Komodo that retains its Zcash lineage and improves it. +VerusCoin will leverage the Komodo platform and dPoW notarization for enhanced security and cross-chain interoperability. +We have added a variation of a zawy12, lwma difficulty algorithm, a new CPU-optimized hash algorithm and a new algorithm for fair proof of stake. +We describe these changes and vision going forward in a [our Phase I white paper](http://185.25.51.16/papers/VerusPhaseI.pdf) and +[our Vision](http://185.25.51.16/papers/VerusVision.pdf). + 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/debian/zcash.install b/contrib/debian/zcash.install index b39eaeeb3..917d319b8 100644 --- a/contrib/debian/zcash.install +++ b/contrib/debian/zcash.install @@ -1,3 +1,3 @@ -usr/bin/zcashd -usr/bin/zcash-cli +usr/bin/komodod +usr/bin/komodo-cli usr/bin/zcash-fetch-params diff --git a/contrib/devtools/fix-copyright-headers.py b/contrib/devtools/fix-copyright-headers.py index 5e8495254..fc57ae64e 100755 --- a/contrib/devtools/fix-copyright-headers.py +++ b/contrib/devtools/fix-copyright-headers.py @@ -1,4 +1,6 @@ #!/usr/bin/env python +from __future__ import print_function + ''' Run this script inside of src/ and it will look for all the files that were changed this year that still have the last year in the @@ -46,7 +48,7 @@ for extension in extensions: filePath = os.getcwd() + filePath modifiedTime = getLastGitModifiedDate(filePath) if len(modifiedTime) > 0 and str(year) in modifiedTime: - print n,"Last Git Modified: ", modifiedTime, " - ", filePath + print(n, "Last Git Modified: ", modifiedTime, " - ", filePath) os.popen(command % (last_year,year,filePath)) n = n + 1 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..c619cf270 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.1" 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/contrib/seeds/nodes_main.txt b/contrib/seeds/nodes_main.txt index 17339d514..a6e8be207 100644 --- a/contrib/seeds/nodes_main.txt +++ b/contrib/seeds/nodes_main.txt @@ -1,879 +1,6 @@ -1.34.168.128:8333 -1.202.128.218:8333 -2.30.0.210:8333 -5.9.96.203:8333 -5.45.71.130:8333 -5.45.98.141:8333 -5.102.145.68:8333 -5.135.160.77:8333 -5.189.134.246:8333 -5.199.164.132:8333 -5.249.135.102:8333 -8.19.44.110:8333 -8.22.230.8:8333 -14.200.200.145:8333 -18.228.0.188:8333 -18.228.0.200:8333 -23.24.168.97:8333 -23.28.35.227:8333 -23.92.76.170:8333 -23.99.64.119:8333 -23.228.166.128:8333 -23.229.45.32:8333 -24.8.105.128:8333 -24.16.69.137:8333 -24.94.98.96:8333 -24.102.118.7:8333 -24.118.166.228:8333 -24.122.133.49:8333 -24.166.97.162:8333 -24.213.235.242:8333 -24.226.107.64:8333 -24.228.192.171:8333 -27.140.133.18:8333 -31.41.40.25:8333 -31.43.101.59:8333 -31.184.195.181:8333 -31.193.139.66:8333 -37.200.70.102:8333 -37.205.10.151:8333 -42.3.106.227:8333 -42.60.133.106:8333 -45.56.85.231:8333 -45.56.102.228:8333 -45.79.130.235:8333 -46.28.204.61:11101 -46.38.235.229:8333 -46.59.2.74:8333 -46.101.132.37:8333 -46.101.168.50:8333 -46.163.76.230:8333 -46.166.161.103:8333 -46.182.132.100:8333 -46.223.36.94:8333 -46.227.66.132:8333 -46.227.66.138:8333 -46.239.107.74:8333 -46.249.39.100:8333 -46.250.98.108:8333 -50.7.37.114:8333 -50.81.53.151:8333 -50.115.43.253:8333 -50.116.20.87:8333 -50.116.33.92:8333 -50.125.167.245:8333 -50.143.9.51:8333 -50.188.192.133:8333 -54.77.162.76:8333 -54.153.97.109:8333 -54.165.192.125:8333 -58.96.105.85:8333 -59.167.196.135:8333 -60.29.227.163:8333 -61.35.225.19:8333 -62.43.130.178:8333 -62.109.49.26:8333 -62.202.0.97:8333 -62.210.66.227:8333 -62.210.192.169:8333 -64.74.98.205:8333 -64.156.193.100:8333 -64.203.102.86:8333 -64.229.142.48:8333 -65.96.193.165:8333 -66.30.3.7:8333 -66.114.33.49:8333 -66.118.133.194:8333 -66.135.10.126:8333 -66.172.10.4:8333 -66.194.38.250:8333 -66.194.38.253:8333 -66.215.192.104:8333 -67.60.98.115:8333 -67.164.35.36:8333 -67.191.162.244:8333 -67.207.195.77:8333 -67.219.233.140:8333 -67.221.193.55:8333 -67.228.162.228:8333 -68.50.67.199:8333 -68.62.3.203:8333 -68.65.205.226:9000 -68.106.42.191:8333 -68.150.181.198:8333 -68.196.196.106:8333 -68.224.194.81:8333 -69.46.5.194:8333 -69.50.171.238:8333 -69.64.43.152:8333 -69.65.41.13:8333 -69.90.132.200:8333 -69.143.1.243:8333 -69.146.98.216:8333 -69.165.246.38:8333 -69.207.6.135:8333 -69.251.208.26:8333 -70.38.1.101:8333 -70.38.9.66:8333 -70.90.2.18:8333 -71.58.228.226:8333 -71.199.11.189:8333 -71.199.193.202:8333 -71.205.232.181:8333 -71.236.200.162:8333 -72.24.73.186:8333 -72.52.130.110:8333 -72.53.111.37:8333 -72.235.38.70:8333 -73.31.171.149:8333 -73.32.137.72:8333 -73.137.133.238:8333 -73.181.192.103:8333 -73.190.2.60:8333 -73.195.192.137:8333 -73.222.35.117:8333 -74.57.199.180:8333 -74.82.233.205:8333 -74.85.66.82:8333 -74.101.224.127:8333 -74.113.69.16:8333 -74.122.235.68:8333 -74.193.68.141:8333 -74.208.164.219:8333 -75.100.37.122:8333 -75.145.149.169:8333 -75.168.34.20:8333 -76.20.44.240:8333 -76.100.70.17:8333 -76.168.3.239:8333 -76.186.140.103:8333 -77.92.68.221:8333 -77.109.101.142:8333 -77.110.11.86:8333 -77.242.108.18:8333 -78.46.96.150:9020 -78.84.100.95:8333 -79.132.230.144:8333 -79.133.43.63:8333 -79.160.76.153:8333 -79.169.34.24:8333 -79.188.7.78:8333 -80.217.226.25:8333 -80.223.100.179:8333 -80.240.129.221:8333 -81.1.173.243:8333 -81.7.11.50:8333 -81.7.16.17:8333 -81.66.111.3:8333 -81.80.9.71:8333 -81.140.43.138:8333 -81.171.34.37:8333 -81.174.247.50:8333 -81.181.155.53:8333 -81.184.5.253:8333 -81.187.69.130:8333 -81.230.3.84:8333 -82.42.128.51:8333 -82.74.226.21:8333 -82.142.75.50:8333 -82.199.102.10:8333 -82.200.205.30:8333 -82.221.108.21:8333 -82.221.128.35:8333 -82.238.124.41:8333 -82.242.0.245:8333 -83.76.123.110:8333 -83.150.9.196:8333 -83.162.196.192:8333 -83.162.234.224:8333 -83.170.104.91:8333 -83.255.66.118:8334 -84.2.34.104:8333 -84.45.98.91:8333 -84.47.161.150:8333 -84.212.192.131:8333 -84.215.169.101:8333 -84.238.140.176:8333 -84.245.71.31:8333 -85.17.4.212:8333 -85.114.128.134:8333 -85.159.237.191:8333 -85.166.130.189:8333 -85.199.4.228:8333 -85.214.66.168:8333 -85.214.195.210:8333 -85.229.0.73:8333 -86.21.96.45:8333 -87.48.42.199:8333 -87.81.143.82:8333 -87.81.251.72:8333 -87.104.24.185:8333 -87.104.168.104:8333 -87.117.234.71:8333 -87.118.96.197:8333 -87.145.12.57:8333 -87.159.170.190:8333 -88.150.168.160:8333 -88.208.0.79:8333 -88.208.0.149:8333 -88.214.194.226:8343 -89.1.11.32:8333 -89.36.235.108:8333 -89.67.96.2:15321 -89.98.16.41:8333 -89.108.72.195:8333 -89.156.35.157:8333 -89.163.227.28:8333 -89.212.33.237:8333 -89.212.160.165:8333 -89.231.96.83:8333 -89.248.164.64:8333 -90.149.193.199:8333 -91.77.239.245:8333 -91.106.194.97:8333 -91.126.77.77:8333 -91.134.38.195:8333 -91.156.97.181:8333 -91.207.68.144:8333 -91.209.77.101:8333 -91.214.200.205:8333 -91.220.131.242:8333 -91.220.163.18:8333 -91.233.23.35:8333 -92.13.96.93:8333 -92.14.74.114:8333 -92.27.7.209:8333 -92.221.228.13:8333 -92.255.207.73:8333 -93.72.167.148:8333 -93.74.163.234:8333 -93.123.174.66:8333 -93.152.166.29:8333 -93.181.45.188:8333 -94.19.12.244:8333 -94.190.227.112:8333 -94.198.135.29:8333 -94.224.162.65:8333 -94.226.107.86:8333 -94.242.198.161:8333 -95.31.10.209:8333 -95.65.72.244:8333 -95.84.162.95:8333 -95.90.139.46:8333 -95.183.49.27:8005 -95.215.47.133:8333 -96.23.67.85:8333 -96.44.166.190:8333 -97.93.225.74:8333 -98.26.0.34:8333 -98.27.225.102:8333 -98.229.117.229:8333 -98.249.68.125:8333 -98.255.5.155:8333 -99.101.240.114:8333 -101.100.174.138:8333 -101.251.203.6:8333 -103.3.60.61:8333 -103.30.42.189:8333 -103.224.165.48:8333 -104.36.83.233:8333 -104.37.129.22:8333 -104.54.192.251:8333 -104.128.228.252:8333 -104.128.230.185:8334 -104.130.161.47:8333 -104.131.33.60:8333 -104.143.0.156:8333 -104.156.111.72:8333 -104.167.111.84:8333 -104.193.40.248:8333 -104.197.7.174:8333 -104.197.8.250:8333 -104.223.1.133:8333 -104.236.97.140:8333 -104.238.128.214:8333 -104.238.130.182:8333 -106.38.234.84:8333 -106.185.36.204:8333 -107.6.4.145:8333 -107.150.2.6:8333 -107.150.40.234:8333 -107.155.108.130:8333 -107.161.182.115:8333 -107.170.66.231:8333 -107.190.128.226:8333 -107.191.106.115:8333 -108.16.2.61:8333 -109.70.4.168:8333 -109.162.35.196:8333 -109.163.235.239:8333 -109.190.196.220:8333 -109.191.39.60:8333 -109.234.106.191:8333 -109.238.81.82:8333 -114.76.147.27:8333 -115.28.224.127:8333 -115.68.110.82:18333 -118.97.79.218:8333 -118.189.207.197:8333 -119.228.96.233:8333 -120.147.178.81:8333 -121.41.123.5:8333 -121.67.5.230:8333 -122.107.143.110:8333 -123.2.170.98:8333 -123.110.65.94:8333 -123.193.139.19:8333 -125.239.160.41:8333 -128.101.162.193:8333 -128.111.73.10:8333 -128.140.229.73:8333 -128.175.195.31:8333 -128.199.107.63:8333 -128.199.192.153:8333 -128.253.3.193:20020 -129.123.7.7:8333 -130.89.160.234:8333 -131.72.139.164:8333 -131.191.112.98:8333 -133.1.134.162:8333 -134.19.132.53:8333 -137.226.34.42:8333 -141.41.2.172:8333 -141.255.128.204:8333 -142.217.12.106:8333 -143.215.129.126:8333 -146.0.32.101:8337 -147.229.13.199:8333 -149.210.133.244:8333 -149.210.162.187:8333 -150.101.163.241:8333 -151.236.11.189:8333 -153.121.66.211:8333 -154.20.2.139:8333 -159.253.23.132:8333 -162.209.106.123:8333 -162.210.198.184:8333 -162.218.65.121:8333 -162.222.161.49:8333 -162.243.132.6:8333 -162.243.132.58:8333 -162.248.99.164:53011 -162.248.102.117:8333 -163.158.35.110:8333 -164.15.10.189:8333 -164.40.134.171:8333 -166.230.71.67:8333 -167.160.161.199:8333 -168.103.195.250:8333 -168.144.27.112:8333 -168.158.129.29:8333 -170.75.162.86:8333 -172.90.99.174:8333 -172.245.5.156:8333 -173.23.166.47:8333 -173.32.11.194:8333 -173.34.203.76:8333 -173.171.1.52:8333 -173.175.136.13:8333 -173.230.228.139:8333 -173.247.193.70:8333 -174.49.132.28:8333 -174.52.202.72:8333 -174.53.76.87:8333 -174.109.33.28:8333 -176.28.12.169:8333 -176.35.182.214:8333 -176.36.33.113:8333 -176.36.33.121:8333 -176.58.96.173:8333 -176.121.76.84:8333 -178.62.70.16:8333 -178.62.111.26:8333 -178.76.169.59:8333 -178.79.131.32:8333 -178.162.199.216:8333 -178.175.134.35:8333 -178.248.111.4:8333 -178.254.1.170:8333 -178.254.34.161:8333 -179.43.143.120:8333 -179.208.156.198:8333 -180.200.128.58:8333 -183.78.169.108:8333 -183.96.96.152:8333 -184.68.2.46:8333 -184.73.160.160:8333 -184.94.227.58:8333 -184.152.68.163:8333 -185.7.35.114:8333 -185.28.76.179:8333 -185.31.160.202:8333 -185.45.192.129:8333 -185.66.140.15:8333 -186.2.167.23:8333 -186.220.101.142:8333 -188.26.5.33:8333 -188.75.136.146:8333 -188.120.194.140:8333 -188.121.5.150:8333 -188.138.0.114:8333 -188.138.33.239:8333 -188.166.0.82:8333 -188.182.108.129:8333 -188.191.97.208:8333 -188.226.198.102:8001 -190.10.9.217:8333 -190.75.143.144:8333 -190.139.102.146:8333 -191.237.64.28:8333 -192.3.131.61:8333 -192.99.225.3:8333 -192.110.160.122:8333 -192.146.137.1:8333 -192.183.198.204:8333 -192.203.228.71:8333 -193.0.109.3:8333 -193.12.238.204:8333 -193.91.200.85:8333 -193.234.225.156:8333 -194.6.233.38:8333 -194.63.143.136:8333 -194.126.100.246:8333 -195.134.99.195:8333 -195.159.111.98:8333 -195.159.226.139:8333 -195.197.175.190:8333 -198.48.199.108:8333 -198.57.208.134:8333 -198.57.210.27:8333 -198.62.109.223:8333 -198.167.140.8:8333 -198.167.140.18:8333 -199.91.173.234:8333 -199.127.226.245:8333 -199.180.134.116:8333 -200.7.96.99:8333 -201.160.106.86:8333 -202.55.87.45:8333 -202.60.68.242:8333 -202.60.69.232:8333 -202.124.109.103:8333 -203.30.197.77:8333 -203.88.160.43:8333 -203.151.140.14:8333 -203.219.14.204:8333 -205.147.40.62:8333 -207.235.39.214:8333 -207.244.73.8:8333 -208.12.64.225:8333 -208.76.200.200:8333 -209.40.96.121:8333 -209.126.107.176:8333 -209.141.40.149:8333 -209.190.75.59:8333 -209.208.111.142:8333 -210.54.34.164:8333 -211.72.66.229:8333 -212.51.144.42:8333 -212.112.33.157:8333 -212.116.72.63:8333 -212.126.14.122:8333 -213.66.205.194:8333 -213.111.196.21:8333 -213.122.107.102:8333 -213.136.75.175:8333 -213.155.7.24:8333 -213.163.64.31:8333 -213.163.64.208:8333 -213.165.86.136:8333 -213.184.8.22:8333 -216.15.78.182:8333 -216.55.143.154:8333 -216.115.235.32:8333 -216.126.226.166:8333 -216.145.67.87:8333 -216.169.141.169:8333 -216.249.92.230:8333 -216.250.138.230:8333 -217.20.171.43:8333 -217.23.2.71:8333 -217.23.2.242:8333 -217.25.9.76:8333 -217.40.226.169:8333 -217.123.98.9:8333 -217.155.36.62:8333 -217.172.32.18:20993 -218.61.196.202:8333 -218.231.205.41:8333 -220.233.77.200:8333 -223.18.226.85:8333 -223.197.203.82:8333 -223.255.166.142:8333 -[2001:1291:2bf:1::100]:8333 -[2001:1418:100:5c2::2]:8333 -[2001:16d8:dd24:0:86c9:681e:f931:256]:8333 -[2001:19f0:1624:e6::579d:9428]:8333 -[2001:19f0:300:1340:225:90ff:fec9:2b6d]:8333 -[2001:19f0:4009:1405::64]:8333 -[2001:1b40:5000:2e::3fb0:6571]:8333 -[2001:410:a000:4050:8463:90b0:fffb:4e58]:8333 -[2001:410:a002:cafe:8463:90b0:fffb:4e58]:8333 -[2001:41d0:1:541e::1]:8333 -[2001:41d0:1:6a34::3]:8333 -[2001:41d0:1:6cd3::]:8333 -[2001:41d0:1:8b26::1]:8333 -[2001:41d0:1:a33d::1]:8333 -[2001:41d0:1:b855::1]:8333 -[2001:41d0:1:c139::1]:8333 -[2001:41d0:1:c8d7::1]:8333 -[2001:41d0:1:dd3f::1]:8333 -[2001:41d0:1:e29d::1]:8333 -[2001:41d0:1:f59f::33]:8333 -[2001:41d0:1:f7cc::1]:8333 -[2001:41d0:1:ff87::1]:8333 -[2001:41d0:2:2f05::1]:8333 -[2001:41d0:2:37c3::]:8200 -[2001:41d0:2:3e13::1]:8333 -[2001:41d0:2:8619::]:8333 -[2001:41d0:2:9c94::1]:8333 -[2001:41d0:2:a24f::]:8333 -[2001:41d0:2:adbf::]:8333 -[2001:41d0:2:b721::1]:8333 -[2001:41d0:2:ee52::1]:8333 -[2001:41d0:2:f1a5::]:8333 -[2001:41d0:2:fa54::1]:8333 -[2001:41d0:51:1::2036]:8333 -[2001:41d0:52:a00::1a1]:8333 -[2001:41d0:52:cff::6f5]:8333 -[2001:41d0:52:d00::2c0]:8333 -[2001:41d0:52:d00::cf2]:8333 -[2001:41d0:8:1087::1]:8333 -[2001:41d0:8:4a3c::b7c]:8333 -[2001:41d0:8:6728::]:8333 -[2001:41d0:8:b779::1]:8333 -[2001:41d0:8:c30f::1]:8333 -[2001:41d0:8:d2b2::1]:8333 -[2001:41d0:8:d5c3::1]:8333 -[2001:41d0:8:eb8b::]:8333 -[2001:41d0:a:16d0::1]:8333 -[2001:41d0:a:2b18::1]:8333 -[2001:41d0:a:3a9c::1]:8333 -[2001:41d0:a:4903::]:8333 -[2001:41d0:a:57b::1]:8333 -[2001:41d0:a:5c7a::]:8333 -[2001:41d0:a:6c29::1]:8333 -[2001:41d0:a:f482::1]:8333 -[2001:41d0:b:854:b7c:b7c:b7c:b7c]:8333 -[2001:41d0:d:111c::]:8333 -[2001:44b8:4116:7801:4216:7eff:fe78:3fe4]:8333 -[2001:470:1f08:837::2]:8333 -[2001:470:1f08:c33::2]:8333 -[2001:470:1f09:bca:218:7dff:fe10:be33]:8333 -[2001:470:1f0f:22d::212:26]:8333 -[2001:470:1f11:12d5::ae1:5611]:8333 -[2001:470:1f14:57a::2]:8333 -[2001:470:1f14:7d::2]:8333 -[2001:470:1f15:57c::1]:8333 -[2001:470:1f15:dda:3d9a:3f11:9a56:ed64]:8333 -[2001:470:25:482::2]:8333 -[2001:470:25:e4::2]:8333 -[2001:470:4:26b::2]:8333 -[2001:470:5f:5f::232]:8333 -[2001:470:66:119::2]:8333 -[2001:470:67:39d::71]:8333 -[2001:470:6c4f::cafe]:8333 -[2001:470:8:2e1::43]:8333 -[2001:470:90a7:96::afe:6021]:8333 -[2001:470:95c1::2]:8333 -[2001:470:b1d0:ffff::1000]:8333 -[2001:470:c1f2:3::201]:8333 -[2001:470:d00d:0:3664:a9ff:fe9a:5150]:8333 -[2001:470:e250:0:211:11ff:feb9:924c]:8333 -[2001:4800:7817:101:be76:4eff:fe04:dc52]:8333 -[2001:4800:7819:104:be76:4eff:fe04:7809]:8333 -[2001:4800:7819:104:be76:4eff:fe05:c828]:8333 -[2001:4802:7800:2:30d7:1775:ff20:1858]:8333 -[2001:4802:7802:101:be76:4eff:fe20:256]:8333 -[2001:4802:7802:103:be76:4eff:fe20:2de8]:8333 -[2001:4830:1100:2e8::2]:8333 -[2001:4ba0:fff7:181:dead::1]:8333 -[2001:4ba0:fffa:5d::93]:8333 -[2001:4ba0:ffff:1be:1:1005:0:1]:8335 -[2001:4c48:110:101:216:3eff:fe24:1162]:8333 -[2001:4dd0:f101::32]:8333 -[2001:4dd0:ff00:867f::3]:8333 -[2001:4dd0:ff00:9a67::9]:8333 -[2001:4dd0:ff00:9c55:c23f:d5ff:fe6c:7ee9]:8333 -[2001:5c0:1400:b::3cc7]:8333 -[2001:5c0:1400:b::3d01]:8333 -[2001:5c0:1400:b::8df]:8333 -[2001:5c0:1501:300::3]:8333 -[2001:610:1b19::3]:8333 -[2001:620:500:fff0:f21f:afff:fecf:91cc]:8333 -[2001:67c:1220:80c:ad:8de2:f7e2:c784]:8333 -[2001:67c:21ec:1000::b]:8333 -[2001:6f8:1296:0:76d4:35ff:feba:1d26]:8333 -[2001:840:f000:4250:3e4a:92ff:fe6d:145f]:8333 -[2001:8d8:840:500::39:1ae]:8333 -[2001:980:efd8:0:21:de4a:2709:912]:8333 -[2001:981:46:1::3]:8333 -[2001:981:9319:2:c0:a8:c8:8]:8333 -[2001:9d8:cafe:3::91]:8333 -[2001:ad0:1:1:26be:5ff:fe25:959d]:8333 -[2001:ba8:1f1:f34c::2]:8333 -[2001:bc8:381c:100::1]:8333 -[2002:175c:4caa::175c:4caa]:8333 -[2002:4404:82f1:0:8d55:8fbb:15fa:f4e0]:8333 -[2002:4475:2233:0:21f:5bff:fe33:9f70]:8333 -[2002:596c:48c3::596c:48c3]:8333 -[2002:8c6d:6521:9617:12bf:48ff:fed8:1724]:8333 -[2002:a646:5e6a::1:2]:8333 -[2002:b009:20c5::b009:20c5]:8333 -[2400:8900::f03c:91ff:fe6e:823e]:8333 -[2400:8900::f03c:91ff:fe70:d164]:8333 -[2400:8901::f03c:91ff:fe37:9761]:8333 -[2403:4200:403:2::ff]:8333 -[2403:b800:1000:64:40a:e9ff:fe5f:94c1]:8333 -[2403:b800:1000:64:9879:17ff:fe6a:a59f]:8333 -[2600:3c00::f03c:91ff:fe18:59b2]:8333 -[2600:3c00::f03c:91ff:fe37:a4b1]:8333 -[2600:3c00::f03c:91ff:fe56:2973]:8333 -[2600:3c00::f03c:91ff:fe6e:7297]:8333 -[2600:3c00::f03c:91ff:fe84:8a6e]:8333 -[2600:3c01::f03c:91ff:fe18:6adf]:8333 -[2600:3c01::f03c:91ff:fe18:e217]:8333 -[2600:3c01::f03c:91ff:fe33:1b31]:8333 -[2600:3c01::f03c:91ff:fe33:2fe1]:8333 -[2600:3c01::f03c:91ff:fe33:a03f]:8333 -[2600:3c01::f03c:91ff:fe50:5e06]:8333 -[2600:3c01::f03c:91ff:fe56:d645]:8333 -[2600:3c01::f03c:91ff:fe6e:a3dc]:8333 -[2600:3c01::f03c:91ff:fe89:a659]:8333 -[2600:3c02::f03c:91ff:fe6e:6f0b]:8333 -[2600:3c03::f03c:91ff:fe33:f6fb]:8333 -[2600:3c03::f03c:91ff:fe50:5fa7]:8333 -[2600:3c03::f03c:91ff:fe6e:1803]:8333 -[2600:3c03::f03c:91ff:fe6e:4ac0]:8333 -[2601:6:4800:47f:1e4e:1f4d:332c:3bf6]:8333 -[2601:d:5400:fed:8d54:c1e8:7ed7:d45e]:8333 -[2602:100:4b8f:6d2a:20c:29ff:feaf:c4c2]:8333 -[2602:ffc5:1f::1f:2d61]:8333 -[2602:ffc5:1f::1f:9211]:8333 -[2602:ffc5::ffc5:b844]:8333 -[2602:ffe8:100:2::457:936b]:8333 -[2602:ffea:1001:125::2ad4]:8333 -[2602:ffea:1001:6ff::837d]:8333 -[2602:ffea:1001:72b::578b]:8333 -[2602:ffea:1001:77a::9cae]:8333 -[2602:ffea:1:2fe::6bc8]:8333 -[2602:ffea:1:701::7968]:8333 -[2602:ffea:1:70d::82ec]:8333 -[2602:ffea:1:9ff::e957]:8333 -[2602:ffea:1:a5d::4acb]:8333 -[2602:ffea:a::24c4:d9fd]:8333 -[2602:ffea:a::c06:ae32]:8333 -[2604:0:c1:100:1ec1:deff:fe54:2235]:8333 -[2604:180:1:1af::42a9]:8333 -[2604:180::b208:398]:8333 -[2604:2880::6072:aed]:8333 -[2604:4080:1114:0:3285:a9ff:fe93:850c]:8333 -[2604:7c00:17:3d0::5a4d]:8333 -[2604:9a00:2100:a009:2::]:8333 -[2604:a880:1:20::22a:4001]:8333 -[2604:a880:800:10::752:f001]:8333 -[2604:c00:88:32:216:3eff:fee4:fcca]:8333 -[2604:c00:88:32:216:3eff:fef5:bc21]:8333 -[2605:7980:1:2::1761:3d4e]:8333 -[2605:e000:1417:4068:223:32ff:fe96:e2d]:8333 -[2606:6000:a441:9903:5054:ff:fe78:66ff]:8333 -[2606:df00:2::ae85:8fc6]:8333 -[2607:5300:100:200::e7f]:8333 -[2607:5300:10::a1]:8333 -[2607:5300:60:116e::1]:8333 -[2607:5300:60:1535::]:8333 -[2607:5300:60:1b32::1]:8333 -[2607:5300:60:2337::1]:8333 -[2607:5300:60:2b90::1]:8333 -[2607:5300:60:2d99::1]:8333 -[2607:5300:60:3cb::1]:8333 -[2607:5300:60:4a85::]:8333 -[2607:5300:60:5112:0:2:4af5:63fe]:8333 -[2607:5300:60:6dd5::]:8333 -[2607:5300:60:a91::1]:8333 -[2607:f1c0:820:1500::7f:3f44]:8333 -[2607:f1c0:848:1000::48:943c]:8333 -[2607:f948:0:1::7]:8333 -[2607:fcd0:100:2300::4ad:e594]:8333 -[2607:fcd0:100:2300::659e:9cb3]:8333 -[2607:fcd0:100:2300::c74b:a8ae]:8333 -[2607:fcd0:100:2300::d82:d8c2]:8333 -[2607:fcd0:100:4300::8795:2fa8]:8333 -[2607:fcd0:daaa:901::9561:e043]:8333 -[2a00:1178:2:43:5054:ff:fee7:2eb6]:8333 -[2a00:1328:e100:cc42:230:48ff:fe92:55d]:8333 -[2a00:14f0:e000:80d2:cd1a::1]:8333 -[2a00:16d8:c::5b6a:c261]:8333 -[2a00:61e0:4083:6d01:6852:1376:e972:2091]:8333 -[2a00:c98:2030:a02f:2::2]:8333 -[2a01:1b0:7999:402::131]:8333 -[2a01:1e8:e100:811c:700f:65f0:f72a:1084]:8333 -[2a01:238:42da:c500:6546:1293:5422:ab40]:8333 -[2a01:348:6:473::2]:8333 -[2a01:368:e010:2::2]:8333 -[2a01:430:17:1::ffff:549]:8333 -[2a01:430:17:1::ffff:830]:8333 -[2a01:488:66:1000:53a9:d04:0:1]:8333 -[2a01:488:66:1000:57e6:578c:0:1]:8333 -[2a01:488:66:1000:b01c:178d:0:1]:8333 -[2a01:488:67:1000:523:fdce:0:1]:8333 -[2a01:488:67:1000:b01c:30ab:0:1]:8333 -[2a01:4f8:100:24aa::2]:8333 -[2a01:4f8:100:44e7::2]:8333 -[2a01:4f8:100:5128::2]:8333 -[2a01:4f8:100:84a7::1:1]:8333 -[2a01:4f8:110:516c::2]:8333 -[2a01:4f8:110:536e::2]:8333 -[2a01:4f8:120:62e6::2]:8333 -[2a01:4f8:120:702e::2]:8333 -[2a01:4f8:120:8005::2]:8333 -[2a01:4f8:120:8203::2]:8333 -[2a01:4f8:120:8422::2]:8333 -[2a01:4f8:121:11eb::2]:8333 -[2a01:4f8:121:261::2]:8333 -[2a01:4f8:130:242b::10]:8333 -[2a01:4f8:130:242b::5]:8333 -[2a01:4f8:130:2468::3]:8333 -[2a01:4f8:130:632c::2]:8333 -[2a01:4f8:130:6366::2]:8333 -[2a01:4f8:130:6426::2]:8333 -[2a01:4f8:130:934f::2]:8333 -[2a01:4f8:131:2070::2]:8333 -[2a01:4f8:131:54a2::2]:8333 -[2a01:4f8:140:80ad::2]:8333 -[2a01:4f8:141:186::2]:8333 -[2a01:4f8:150:210b::2]:8333 -[2a01:4f8:150:2263::5]:8333 -[2a01:4f8:150:2349::2]:8333 -[2a01:4f8:150:61ee::2]:8333 -[2a01:4f8:150:7088:5054:ff:fe45:bff2]:8333 -[2a01:4f8:150:8324::2]:9001 -[2a01:4f8:151:1d8::2]:8333 -[2a01:4f8:151:5128::2]:8333 -[2a01:4f8:151:6347::2]:9001 -[2a01:4f8:161:526d::2]:8333 -[2a01:4f8:161:9349::2]:8333 -[2a01:4f8:162:23c6::2]:8333 -[2a01:4f8:162:4348::2]:8333 -[2a01:4f8:162:7345::2]:8333 -[2a01:4f8:162:7383::2]:8333 -[2a01:4f8:162:74e3::2]:8333 -[2a01:4f8:190:6065::2]:8333 -[2a01:4f8:190:6349::2]:8333 -[2a01:4f8:190:64c9::2]:8333 -[2a01:4f8:190:91ce::2]:8333 -[2a01:4f8:191:2194::83]:8333 -[2a01:4f8:191:40a1::2]:8333 -[2a01:4f8:191:4a7::2]:8333 -[2a01:4f8:191:63b4:5000::1]:8333 -[2a01:4f8:191:7121::2]:8333 -[2a01:4f8:191:83a2::2]:8333 -[2a01:4f8:191:93c4::2]:8333 -[2a01:4f8:192:60a9:0:1:5:2]:8333 -[2a01:4f8:192:73b2::2]:8333 -[2a01:4f8:192:8098::2]:8333 -[2a01:4f8:192:db::2]:8333 -[2a01:4f8:200:1012::2]:8333 -[2a01:4f8:200:22e3::2]:8333 -[2a01:4f8:200:414e::2]:8333 -[2a01:4f8:200:63af::222]:8333 -[2a01:4f8:200:71e3:78b4:f3ff:fead:e8cf]:8333 -[2a01:4f8:201:5164::2]:8333 -[2a01:4f8:201:6011::4]:8333 -[2a01:4f8:201:60d5::2]:8333 -[2a01:4f8:202:53c3::2]:8333 -[2a01:4f8:210:24aa::2]:8333 -[2a01:4f8:210:502f::2]:8333 -[2a01:4f8:211:14cf::2]:8333 -[2a01:4f8:211:1a59::2]:8333 -[2a01:4f8:211:2ac1::2]:8333 -[2a01:4f8:211:cca::2]:8333 -[2a01:4f8:a0:22a5::2]:8333 -[2a01:4f8:a0:5023::2]:8333 -[2a01:4f8:a0:5243::2]:8333 -[2a01:4f8:a0:74c8::2]:8333 -[2a01:4f8:a0:8227::2]:8333 -[2a01:4f8:a0:822d::2]:8333 -[2a01:4f8:d13:2183::2]:8333 -[2a01:608:ffff:a009:8bf5:879d:e51a:f837]:8333 -[2a01:79d:469e:ed94:c23f:d5ff:fe65:20c5]:8333 -[2a01:7c8:aab5:3e6:5054:ff:fed7:4e54]:8333 -[2a01:7e00::f03c:91ff:fe18:301e]:8333 -[2a01:7e00::f03c:91ff:fe18:7749]:8333 -[2a01:7e00::f03c:91ff:fe33:2d67]:8333 -[2a01:7e00::f03c:91ff:fe33:347c]:8333 -[2a01:7e00::f03c:91ff:fe33:ae50]:8333 -[2a01:7e00::f03c:91ff:fe56:6b5c]:8333 -[2a01:7e00::f03c:91ff:fe56:bee6]:8333 -[2a01:7e00::f03c:91ff:fe69:4895]:8333 -[2a01:7e00::f03c:91ff:fe69:9912]:8333 -[2a01:7e00::f03c:91ff:fe6e:26ee]:8333 -[2a01:7e00::f03c:91ff:fe73:42f1]:8333 -[2a01:7e00::f03c:91ff:fe84:434f]:8333 -[2a01:7e00::f03c:91ff:fe84:b36b]:8333 -[2a01:7e00::f03c:91ff:fe89:1faa]:8333 -[2a01:7e00::f03c:91ff:fe98:816]:8333 -[2a01:7e00::f03c:91ff:fedb:352e]:8333 -[2a01:7e00::f03c:91ff:fedb:4a1d]:8333 -[2a01:e34:edbb:6750:224:1dff:fe89:3897]:8333 -[2a01:e35:2f1d:3fb0:7187:c7ba:bcfc:80ce]:8333 -[2a01:e35:8787:96f0:9032:9297:39ae:496d]:8333 -[2a01:e35:8a3f:47c0:c617:feff:fe3c:9fbd]:8333 -[2a01:e35:8b66:6a0:4900:9dfd:d841:d025]:8333 -[2a02:168:4a01::39]:8333 -[2a02:168:5404:2:c23f:d5ff:fe6a:512e]:8333 -[2a02:180:1:1::5b8f:538c]:8333 -[2a02:2028:1016::2]:8333 -[2a02:2528:503:2::14]:8333 -[2a02:2528:503:2::15]:8333 -[2a02:2528:ff00:81a6:21e:c5ff:fe8d:f9a5]:8333 -[2a02:2770:5:0:21a:4aff:fee4:c7db]:8333 -[2a02:2770:8:0:21a:4aff:fe7b:3dcd]:8333 -[2a02:348:5e:5a29::1]:8333 -[2a02:7aa0:1619::202f:c06a]:8333 -[2a02:8109:8e40:35fc:ba27:ebff:feae:cf16]:8333 -[2a02:af8:6:1500::1:130]:8333 -[2a02:c200:0:10:1:0:6314:2222]:8333 -[2a02:c200:0:10:2:3:3295:1]:8332 -[2a02:c200:0:10:3:0:5449:1]:8333 -[2a02:c200:1:10:2:3:5899:1]:8333 -[2a02:c200:1:10::2705:1]:8333 -[2a02:ce80:0:20::1]:8333 -[2a02:fe0:c321:27e0:6ef0:49ff:fe11:a61d]:8333 -[2a03:4000:2:496::8]:8333 -[2a03:b0c0:0:1010::62:f001]:8333 -[2a03:f80:ed16:ca7:ea75:b12d:2af:9e2a]:8333 -3ffk7iumtx3cegbi.onion:8333 -3hshaantu6ot4upz.onion:8333 -45c5lc77qgpikafy.onion:8333 -77mx2jsxaoyesz2p.onion:8333 -7g7j54btiaxhtsiy.onion:8333 -b6fr7dlbu2kpiysf.onion:8333 -bitcoincfqcssig5.onion:8333 -bitcoinostk4e4re.onion:8333 -bmutjfrj5btseddb.onion:8333 -drp4pvejybx2ejdr.onion:8333 -gixnv56d63buypan.onion:8333 -h2vlpudzphzqxutd.onion:8333 -hhiv5pnxenvbf4am.onion:8333 -lzxpkn6ptp3ohh63.onion:8333 -msphsgfiqfq5stne.onion:8333 -ncwk3lutemffcpc4.onion:8333 -okdzjarwekbshnof.onion:8333 -sjdomi4yb2dwkjbc.onion:8333 -uvwozwxlihntigbb.onion:8333 -v6ylz45dn5ybpk4d.onion:8333 -vk3qjdehyy4dwcxw.onion:8333 -vqpye2k5rcqvj5mq.onion:8333 -xudkoztdfrsuyyou.onion:8333 -z55v4ostefnwfy32.onion:8333 +185.25.48.236:27485 +185.25.48.236:27487 +185.64.105.111:27485 +185.64.105.111:27487 +185.25.48.72:27485 +185.25.48.72:27487 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..ccd6bb8c9 --- /dev/null +++ b/depends/packages/crate_aesni.mk @@ -0,0 +1,15 @@ +package=crate_aesni +$(package)_crate_name=aesni +$(package)_version=0.4.1 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e +$(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..b0ede4e55 --- /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.1 +$(package)_download_path=https://static.crates.io/crates/$($(package)_crate_name) +$(package)_file_name=$($(package)_crate_name)-$($(package)_version).crate +$(package)_sha256_hash=30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab +$(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..a47c757de 100644 --- a/depends/packages/librustzcash.mk +++ b/depends/packages/librustzcash.mk @@ -1,34 +1,38 @@ package=librustzcash $(package)_version=0.1 -$(package)_download_path=https://github.com/zcash/$(package)/archive +$(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=9909ec59fa7a411c2071d6237b3363a0bc6e5e42358505cf64b7da0f58a7ff5a +$(package)_git_commit=06da3b9ac8f278e5d4ae13088cf0a4c03d2c13f5 +$(package)_dependencies=rust $(rust_crates) +$(package)_patches=cargo.config 0001-Start-using-cargo-clippy-for-CI.patch remove-dev-dependencies.diff ifeq ($(host_os),mingw32) -define $(package)_build_cmds - ~/.cargo/bin/cargo build --release --target=x86_64-pc-windows-gnu --verbose -endef +$(package)_library_file=target/x86_64-pc-windows-gnu/release/rustzcash.lib else -define $(package)_build_cmds - cargo build --release -endef +$(package)_library_file=target/release/librustzcash.a endif -ifeq ($(host_os),mingw32) +define $(package)_set_vars +$(package)_build_opts=--frozen --release +$(package)_build_opts_mingw32=--target=x86_64-pc-windows-gnu +endef + +define $(package)_preprocess_cmds + patch -p1 -d pairing < $($(package)_patch_dir)/0001-Start-using-cargo-clippy-for-CI.patch && \ + patch -p1 < $($(package)_patch_dir)/remove-dev-dependencies.diff && \ + mkdir .cargo && \ + cat $($(package)_patch_dir)/cargo.config | sed 's|CRATE_REGISTRY|$(host_prefix)/$(CRATE_REGISTRY)|' > .cargo/config +endef + +define $(package)_build_cmds + cargo build --package librustzcash $($(package)_build_opts) +endef + define $(package)_stage_cmds mkdir $($(package)_staging_dir)$(host_prefix)/lib/ && \ mkdir $($(package)_staging_dir)$(host_prefix)/include/ && \ - cp target/x86_64-pc-windows-gnu/release/rustzcash.lib $($(package)_staging_dir)$(host_prefix)/lib/ && \ - cp include/librustzcash.h $($(package)_staging_dir)$(host_prefix)/include/ + cp $($(package)_library_file) $($(package)_staging_dir)$(host_prefix)/lib/ && \ + cp librustzcash/include/librustzcash.h $($(package)_staging_dir)$(host_prefix)/include/ endef -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 include/librustzcash.h $($(package)_staging_dir)$(host_prefix)/include/ -endef -endif diff --git a/depends/packages/libsnark.mk b/depends/packages/libsnark.mk index cb4bc04ca..c2a620f26 100644 --- a/depends/packages/libsnark.mk +++ b/depends/packages/libsnark.mk @@ -14,15 +14,15 @@ define $(package)_set_vars $(package)_build_env+=CXXFLAGS="$($(package)_cxxflags) -DBINARY_OUTPUT -DSTATICLIB -DNO_PT_COMPRESSION=1 " endef define $(package)_build_cmds - $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64" + $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64 -g " endef else ifeq ($(host_os),mingw32) define $(package)_build_cmds - CXX="x86_64-w64-mingw32-g++-posix" CXXFLAGS="-DBINARY_OUTPUT -DPTW32_STATIC_LIB -DSTATICLIB -DNO_PT_COMPRESSION=1 -fopenmp" $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64" + CXX="x86_64-w64-mingw32-g++-posix" CXXFLAGS="-DBINARY_OUTPUT -DPTW32_STATIC_LIB -DSTATICLIB -DNO_PT_COMPRESSION=1 -fopenmp" $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64 -g " endef else define $(package)_build_cmds - CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64" + CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64 -g " 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..5bc8fcda6 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -7,12 +7,48 @@ else zcash_packages := libgmp libsodium endif +rust_crates := \ + crate_aes \ + crate_aesni \ + crate_aes_soft \ + crate_arrayvec \ + 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_rand \ + crate_stream_cipher \ + crate_typenum \ + crate_winapi_i686_pc_windows_gnu \ + crate_winapi \ + crate_winapi_x86_64_pc_windows_gnu +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/packages/zeromq.mk b/depends/packages/zeromq.mk index 66e491ffb..b9a57cba7 100644 --- a/depends/packages/zeromq.mk +++ b/depends/packages/zeromq.mk @@ -15,7 +15,7 @@ endef else package=zeromq $(package)_version=4.2.1 -$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/ +$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version) $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=27d1e82a099228ee85a7ddb2260f40830212402c605a4a10b5e5498a7e0e9d03 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/0001-Start-using-cargo-clippy-for-CI.patch b/depends/patches/librustzcash/0001-Start-using-cargo-clippy-for-CI.patch new file mode 100644 index 000000000..6bfeee574 --- /dev/null +++ b/depends/patches/librustzcash/0001-Start-using-cargo-clippy-for-CI.patch @@ -0,0 +1,42 @@ +From cc5b83510277632852af67d896a27e0cb40f342b Mon Sep 17 00:00:00 2001 +From: Sean Bowe +Date: Wed, 4 Jul 2018 12:45:08 -0600 +Subject: [PATCH 1/2] Start using cargo-clippy for CI. + +--- + src/lib.rs | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/src/lib.rs b/src/lib.rs +index fefdae3..c3640c4 100644 +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -1,15 +1,14 @@ + // `clippy` is a code linting tool for improving code quality by catching +-// common mistakes or strange code patterns. If the `clippy` feature is +-// provided, it is enabled and all compiler warnings are prohibited. +-#![cfg_attr(feature = "clippy", deny(warnings))] +-#![cfg_attr(feature = "clippy", feature(plugin))] +-#![cfg_attr(feature = "clippy", plugin(clippy))] +-#![cfg_attr(feature = "clippy", allow(inline_always))] +-#![cfg_attr(feature = "clippy", allow(too_many_arguments))] +-#![cfg_attr(feature = "clippy", allow(unreadable_literal))] +-#![cfg_attr(feature = "clippy", allow(many_single_char_names))] +-#![cfg_attr(feature = "clippy", allow(new_without_default_derive))] +-#![cfg_attr(feature = "clippy", allow(write_literal))] ++// common mistakes or strange code patterns. If the `cargo-clippy` feature ++// is provided, all compiler warnings are prohibited. ++#![cfg_attr(feature = "cargo-clippy", deny(warnings))] ++#![cfg_attr(feature = "cargo-clippy", allow(inline_always))] ++#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] ++#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] ++#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))] ++#![cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))] ++#![cfg_attr(feature = "cargo-clippy", allow(write_literal))] ++ + // Force public structures to implement Debug + #![deny(missing_debug_implementations)] + +-- +2.17.1 + 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/depends/patches/librustzcash/remove-dev-dependencies.diff b/depends/patches/librustzcash/remove-dev-dependencies.diff new file mode 100644 index 000000000..d013de8da --- /dev/null +++ b/depends/patches/librustzcash/remove-dev-dependencies.diff @@ -0,0 +1,630 @@ +diff --git a/Cargo.lock b/Cargo.lock +index bc740bb..3c6c94b 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -28,22 +28,6 @@ dependencies = [ + "stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + ] + +-[[package]] +-name = "aho-corasick" +-version = "0.6.8" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "ansi_term" +-version = "0.11.0" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- + [[package]] + name = "arrayvec" + version = "0.4.7" +@@ -52,27 +36,6 @@ dependencies = [ + "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + ] + +-[[package]] +-name = "backtrace" +-version = "0.3.9" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", +- "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", +- "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "backtrace-sys" +-version = "0.1.24" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- + [[package]] + name = "bellman" + version = "0.1.0" +@@ -92,11 +55,6 @@ name = "bit-vec" + version = "0.4.4" + source = "registry+https://github.com/rust-lang/crates.io-index" + +-[[package]] +-name = "bitflags" +-version = "0.9.1" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- + [[package]] + name = "bitflags" + version = "1.0.1" +@@ -130,61 +88,6 @@ name = "byteorder" + version = "1.2.2" + source = "registry+https://github.com/rust-lang/crates.io-index" + +-[[package]] +-name = "cargo_metadata" +-version = "0.5.8" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "cc" +-version = "1.0.22" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "cfg-if" +-version = "0.1.5" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "clippy" +-version = "0.0.200" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "clippy_lints 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)", +- "regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "clippy_lints" +-version = "0.0.200" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +- "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", +- "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +- "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +- "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- + [[package]] + name = "constant_time_eq" + version = "0.1.3" +@@ -203,19 +106,6 @@ dependencies = [ + "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + ] + +-[[package]] +-name = "either" +-version = "1.5.0" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "error-chain" +-version = "0.11.0" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- + [[package]] + name = "fpe" + version = "0.1.0" +@@ -256,11 +146,6 @@ dependencies = [ + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + ] + +-[[package]] +-name = "gcc" +-version = "0.3.54" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- + [[package]] + name = "generic-array" + version = "0.9.0" +@@ -269,59 +154,6 @@ dependencies = [ + "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + ] + +-[[package]] +-name = "getopts" +-version = "0.2.18" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "hex-literal" +-version = "0.1.1" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +- "proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "hex-literal-impl" +-version = "0.1.1" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "idna" +-version = "0.1.5" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +- "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "if_chain" +-version = "0.1.3" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "itertools" +-version = "0.7.8" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "itoa" +-version = "0.4.2" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- + [[package]] + name = "lazy_static" + version = "1.0.0" +@@ -347,19 +179,6 @@ dependencies = [ + "zip32 0.0.0", + ] + +-[[package]] +-name = "matches" +-version = "0.1.8" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "memchr" +-version = "2.0.2" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- + [[package]] + name = "nodrop" + version = "0.1.12" +@@ -405,65 +224,6 @@ name = "pairing" + version = "0.14.2" + dependencies = [ + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "clippy 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)", +- "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "percent-encoding" +-version = "1.0.1" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "proc-macro-hack" +-version = "0.4.0" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "proc-macro-hack-impl" +-version = "0.4.0" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "proc-macro2" +-version = "0.4.14" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "pulldown-cmark" +-version = "0.1.2" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", +- "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "quine-mc_cluskey" +-version = "0.2.4" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "quote" +-version = "0.6.8" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "rand" +-version = "0.3.22" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + ] + +@@ -477,66 +237,6 @@ dependencies = [ + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + ] + +-[[package]] +-name = "redox_syscall" +-version = "0.1.40" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "regex" +-version = "1.0.4" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +- "utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "regex-syntax" +-version = "0.6.2" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "rust-crypto" +-version = "0.2.36" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", +- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", +- "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", +- "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +- "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "rustc-demangle" +-version = "0.1.9" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "rustc-serialize" +-version = "0.3.24" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "rustc_version" +-version = "0.2.3" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "ryu" +-version = "0.2.6" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- + [[package]] + name = "sapling-crypto" + version = "0.0.1" +@@ -545,49 +245,8 @@ dependencies = [ + "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pairing 0.14.2", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "semver" +-version = "0.9.0" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "semver-parser" +-version = "0.7.0" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "serde" +-version = "1.0.75" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "serde_derive" +-version = "1.0.75" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", +- "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "serde_json" +-version = "1.0.26" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +- "ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +- "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", + ] + + [[package]] +@@ -598,90 +257,11 @@ dependencies = [ + "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + ] + +-[[package]] +-name = "syn" +-version = "0.14.9" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", +- "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "thread_local" +-version = "0.3.6" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "time" +-version = "0.1.40" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", +- "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "toml" +-version = "0.4.6" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- + [[package]] + name = "typenum" + version = "1.10.0" + source = "registry+https://github.com/rust-lang/crates.io-index" + +-[[package]] +-name = "ucd-util" +-version = "0.1.1" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "unicode-bidi" +-version = "0.3.4" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "unicode-normalization" +-version = "0.1.7" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "unicode-width" +-version = "0.1.5" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "unicode-xid" +-version = "0.1.0" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- +-[[package]] +-name = "url" +-version = "1.7.1" +-source = "registry+https://github.com/rust-lang/crates.io-index" +-dependencies = [ +- "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +- "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +- "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +-] +- +-[[package]] +-name = "utf8-ranges" +-version = "1.0.1" +-source = "registry+https://github.com/rust-lang/crates.io-index" +- + [[package]] + name = "winapi" + version = "0.3.4" +@@ -730,87 +310,33 @@ dependencies = [ + "checksum aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6fb1737cdc8da3db76e90ca817a194249a38fcb500c2e6ecec39b29448aa873" + "checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1" + "checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e" +-"checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a" +-"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" + "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +-"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" +-"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" + "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" +-"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" + "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" + "checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "" + "checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4" + "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" + "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" +-"checksum cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0" +-"checksum cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4a6007c146fdd28d4512a794b07ffe9d8e89e6bf86e2e0c4ddff2e1fb54a0007" +-"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" +-"checksum clippy 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)" = "927a1f79af10deb103df108347f23c6b7fa1731c953d6fb24d68be1748a0993f" +-"checksum clippy_lints 0.0.200 (registry+https://github.com/rust-lang/crates.io-index)" = "d2432663f6bdb90255dcf9df5ca504f99b575bb471281591138f62f9d31f863b" + "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" + "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" + "checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603" +-"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" +-"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" + "checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad" + "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" + "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" + "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" +-"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" + "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +-"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" +-"checksum hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95" +-"checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a" +-"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +-"checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec" +-"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" +-"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" + "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" + "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" +-"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +-"checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d" + "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" + "checksum num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3eceac7784c5dc97c2d6edf30259b4e153e6e2b42b3c85e9a6e9f45d06caef6e" + "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" + "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" + "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" + "checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7" +-"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +-"checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0" +-"checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892" +-"checksum proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0" +-"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32" +-"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" +-"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" +-"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" + "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +-"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" +-"checksum regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "67d0301b0c6804eca7e3c275119d0b01ff3b7ab9258a65709e608a66312a1025" +-"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d" +-"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +-"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" +-"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +-"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +-"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7" +-"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +-"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +-"checksum serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "22d340507cea0b7e6632900a176101fea959c7065d93ba555072da90aaaafc87" +-"checksum serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "234fc8b737737b148ccd625175fc6390f5e4dacfdaa543cb93a3430d984a9119" +-"checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae" + "checksum stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab" +-"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" +-"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +-"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" +-"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" + "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" +-"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" +-"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +-"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" +-"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +-"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +-"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" +-"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4" + "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" + "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +diff --git a/pairing/Cargo.toml b/pairing/Cargo.toml +index 98725aa..dedce80 100644 +--- a/pairing/Cargo.toml ++++ b/pairing/Cargo.toml +@@ -14,7 +14,6 @@ repository = "https://github.com/ebfull/pairing" + [dependencies] + rand = "0.4" + byteorder = "1" +-clippy = { version = "0.0.200", optional = true } + + [features] + unstable-features = ["expose-arith"] +diff --git a/sapling-crypto/Cargo.toml b/sapling-crypto/Cargo.toml +index 6e802f2..33e21bf 100644 +--- a/sapling-crypto/Cargo.toml ++++ b/sapling-crypto/Cargo.toml +@@ -22,10 +22,6 @@ byteorder = "1" + git = "https://github.com/gtank/blake2-rfc" + rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" + +-[dev-dependencies] +-hex-literal = "0.1" +-rust-crypto = "0.2" +- + [features] + default = ["u128-support"] + u128-support = ["pairing/u128-support"] 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..1782e7ecf 100644 --- a/doc/authors.md +++ b/doc/authors.md @@ -1,63 +1,82 @@ Zcash Contributors ================== -Jack Grigg (601) -Simon Liu (297) -Sean Bowe (193) -Daira Hopwood (102) -Wladimir J. van der Laan (71) +Jack Grigg (843) +Simon Liu (420) +Sean Bowe (264) +Daira Hopwood (110) +Jay Graber (89) +Wladimir J. van der Laan (81) Taylor Hornby (65) -Jay Graber (61) +Eirik Ogilvie-Wigley (60) +Jonas Schnelli (58) Nathan Wilcox (56) -Jonas Schnelli (49) +Pieter Wuille (50) Kevin Gallagher (38) -Cory Fields (30) -Pieter Wuille (24) +Cory Fields (35) syd (15) +Matt Corallo (13) +Larry Ruane (11) +mdr0id (10) +Paige Peterson (10) +MarcoFalke (10) +Jonathan "Duke" Leto (10) nomnombtc (9) -Paige Peterson (9) -Matt Corallo (9) +kozyilmaz (8) fanquake (8) -MarcoFalke (7) +Jeff Garzik (7) +Gregory Maxwell (7) +Ariel Gabizon (7) Luke Dashjr (6) +David Mercer (6) +Daniel Cousens (6) +Pavel Janík (5) +Karl-Johan Alm (5) Johnathan Corgan (5) -Gregory Maxwell (5) -Ariel Gabizon (5) -kozyilmaz (4) +WO (4) Philip Kaufmann (4) Peter Todd (4) Patrick Strateman (4) -Karl-Johan Alm (4) +Marius Kjærstad (4) +João Barbosa (4) Jorge Timón (4) -Jeff Garzik (4) -David Mercer (4) -Daniel Cousens (4) +Duke Leto (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) +George Tankersley (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) kazcw (1) jc (1) @@ -68,11 +87,18 @@ dexX7 (1) daniel (1) calebogden (1) ayleph (1) +Za Wilcox (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) @@ -81,13 +107,13 @@ Murilo Santana (1) Maxwell Gubler (1) Matt Quinn (1) 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 +121,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 +138,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/verus-cli/linux/README.txt b/doc/man/verus-cli/linux/README.txt new file mode 100644 index 000000000..cb2c10f0f --- /dev/null +++ b/doc/man/verus-cli/linux/README.txt @@ -0,0 +1,13 @@ +VerusCoin Command Line Tools v0.4.0c + +Contents: +komodod - VerusCoin's enhanced Komodo daemon +komodo-cli - VerusCoin's Komodo command line utility +verus - wrapper for komodo-cli that applies the command to the VRSC coin +verusd - wrapper for komodod that sets the VerusCoin parameters to defaults properly + +The first time on a new system you will need to run ./fetch-params before using komodod or verusd. + +Run ./verusd to launch komodod, and use verus to run commands such as: +./verus stop +Which signals komodod (if it is running) to stop running. diff --git a/doc/man/verus-cli/mac/README.txt b/doc/man/verus-cli/mac/README.txt new file mode 100644 index 000000000..367e52fce --- /dev/null +++ b/doc/man/verus-cli/mac/README.txt @@ -0,0 +1,17 @@ +VerusCoin Command Line Tools v0.4.0c +Contents: +komodod - VerusCoin's enhanced Komodo daemon. +komodo-cli - VerusCoin's enhanced Komodo command line utility. +verus - wrapper for komodo-cli that applies the command to the VRSC coin +verusd - wrapper for komodod that sets the VerusCoin parameters to defaults properly +fetch_params.sh - utility to download the zcash parameters needed to start the VerusCoin command line tools and scripts +lib*.dylib - assorted dynamic libraries, dependencies needed by fetch-params.sh, komodod and/or komodo-cli + +Command line tools are run from the terminal. You can launch the terminal on a Mac by using the Finder, selecting Applications and from that select Utilities, finally selecting Terminal from the Utilities folder. +You will need to switch to the directory you extracted the verus-cl into. If you extracted it in the Download folder then the change directory command is +cd ~/Downloads/verus-cli +The first time on a new system you will need to run ./fetch-params before using komodod or verusd. + +Run ./verusd to launch komodod, and use verus to run commands such as: +./verus stop +Which signals komodod (if it is running) to stop running. diff --git a/doc/man/verus-cli/windows/README.txt b/doc/man/verus-cli/windows/README.txt new file mode 100644 index 000000000..aa71d8c3f --- /dev/null +++ b/doc/man/verus-cli/windows/README.txt @@ -0,0 +1,21 @@ +VerusCoin Command Line Tools v0.4.0c +Contents: +komodod.exe - VerusCoin's enhanced Komodo daemon +komodo-cli.exe - VerusCoin's Komodo command line utility +verus.bat - wrapper for komodo-cli that applies the command to the VRSC coin +verusd.bat - wrapper for komodod that sets the VerusCoin parameters to defaults properly + +You need to run a command prompt, for example hit and type cmd +From the command prompt change to the directory where you installed verus-cli. If you downloaded the file to your Downloads directory and extracted it there then the change directory command is +cd \Users\MyName\Downloads\verus-cli +From this directory you can run the Verus command line utilities. +The first time on a new system you will need to run fetch-params before using komodod.exe or verusd. +Many anti-virus products interfere with the VerusCoin tool's ability to open ports and will need to be configured to allow what the scanner says is unsafe behavior. +Extreme cases can result in the virus scanner deleting Agama.exe or moving it to "protect" the system. You will to add the executables to a whitelist and re-extract the verus-cli-windows.zip file if that happens. +Run verusd.bat to launch komodod, and use verus.bat to run commands such as: +verus.bat stop +Which signals komodod.exe (if it is running) to stop running. + +Note that if you pass in command line options to verus.bat or verusd.bat that include an = like -ac_veruspos=50 you must surround it with double quotes like this: +verusd.bat "-ac_veruspos=50" +Otherwise Windows will drop the = and pass the two values in as separate command line options. diff --git a/doc/man/zcash-cli.1 b/doc/man/zcash-cli.1 index a30af6fe6..c1bd12a78 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" "October 2018" "zcash-cli v2.0.1" "User Commands" .SH NAME -zcash-cli \- manual page for zcash-cli v1.0.15 +zcash-cli \- manual page for zcash-cli v2.0.1 .SH DESCRIPTION -Zcash RPC client version v1.0.15 +Zcash RPC client version v2.0.1 .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..110f79de7 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" "October 2018" "zcash-tx v2.0.1" "User Commands" .SH NAME -zcash-tx \- manual page for zcash-tx v1.0.15 +zcash-tx \- manual page for zcash-tx v2.0.1 .SH DESCRIPTION -Zcash zcash\-tx utility version v1.0.15 +Zcash zcash\-tx utility version v2.0.1 .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..3900a29c3 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" "October 2018" "zcashd v2.0.1" "User Commands" .SH NAME -zcashd \- manual page for zcashd v1.0.15 +zcashd \- manual page for zcashd v2.0.1 .SH DESCRIPTION -Zcash Daemon version v1.0.15 +Zcash Daemon version v2.0.1 .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..8737b7dae 100644 --- a/doc/payment-api.md +++ b/doc/payment-api.md @@ -29,17 +29,17 @@ 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: * taddr : Transparent address * zaddr : Private address * address : Accepts both private and transparent addresses. -* amount : JSON format double-precision number with 1 ZC expressed as 1.00000000. +* amount : JSON format decimal number with at most 8 digits of precision, with 1 ZEC expressed as 1.00000000. * memo : Metadata expressed in hexadecimal format. Limited to 512 bytes, the current size of the memo field of a private transaction. Zero padding is automatic. ### Accounting @@ -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/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-notes/release-notes-2.0.1-rc1.md b/doc/release-notes/release-notes-2.0.1-rc1.md new file mode 100644 index 000000000..683d5ed22 --- /dev/null +++ b/doc/release-notes/release-notes-2.0.1-rc1.md @@ -0,0 +1,244 @@ +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) + +Changelog +========= + +David Mercer (2): + libsnark: convert long long and unsigned long to C++11 fixed-width types + libsnark: convert 0ul to UINT64_C(0) + +Eirik Ogilvie-Wigley (22): + Rename map to include sprout + Add sapling spending keys to z_exportwallet + Rename AddZKey to include sprout + Move AddSpendingKeyToWallet + Return more information when adding a spending key + Add sapling support to z_importwallet + Export comment on HDSeed and fingerprint with wallet + Export zip32 metadata with sapling keys + Don't export empty zip32 metadata + Allow more information to be returned when an async rpc fails + Use utility method to wait for async operations + Remove unneeded semicolons + Remove unused imports + Allow passing timeout parameter to wait_and_assert_operationid_status + Add test for signing raw transactions offline + Incorporate APPROX_RELEASE_HEIGHT when determining what consensus branch to sign with + Allow passing branchId when calling signrawtransaction + Remove unused import + Address need not be optional when adding sapling keys + Use max priority for all shielded transfers + Move FIXME comment to where the fix should happen + Add newly discovered sapling addresses to the wallet + +George Tankersley (2): + Refactor ContextualCheckBlock tests (#3187) + Refactor ContextualCheckBlock tests + +Jack Grigg (83): + [ci-workers] Install Python modules in a virtualenv + [ci-workers] Handle user home directories outside /home + [ci-workers] Handle ansible_processor being either a string or a list + [ci-workers] Add support for MacOSX + [ci-workers] Add a tag for updating dependencies + [ci-workers] Add curl and cmake to dependencies + [ci-workers] README cleanups + [ci-workers] Add pkg-config to general dependencies + depends: Correctly configure Rust when cross-compiling + depends: Configure librustzcash for cross-compiling + depends: Fix BDB naming issue when cross-compiling + zcutil/build.sh: Use $HOST to specify the depends prefix + configure: Don't require RELRO and BIND_NOW when cross-compiling + Measure Windows console size for metrics UI + Use -O1 for darwin and mingw32 release builds + Clean up libzcash CPPFLAGS, CXXFLAGS, and LDFLAGS + zcutil/build.sh: Use config.site to set default ./configure settings + zcutil/build.sh: Remove --enable-werror from default configuration + Pass correct compiler, linker, and flags into libsnark + Use boost::filesystem::path::string() instead of path::native() + Metrics UI: Enable virtual terminal sequence processing on Windows + Metrics UI: Tell Windows users how to stop zcashd + depends: Pass correct compiler, linker, and flags into googletest + configure: Don't add -ldl to RUST_LIBS for mingw32 + test: Fix comment in WalletTests.FindMySaplingNotes + Add Sapling support to GetFilteredNotes() and GetUnspentFilteredNotes() + Add Sapling support to z_getbalance and z_gettotalbalance + Metrics UI: Fall back to 80 cols if GetConsoleScreenBufferInfo() fails + libsnark: Adjust SHA256 K value type to match the constant + libsnark: Use mp_limb_t cast instead of uint64_t when masking bigint.data + libsnark: Fix stale comment + rpc: Clarify Sprout shielded addresses in help text + rpc: Clarify ivk balance issues in help text + Move GetSpendingKeyForPaymentAddress visitor into wallet.h + wallet: Add HaveSpendingKeyForPaymentAddress visitor + rpcwallet: Add TransactionBuilder argument to AsyncRPCOperation_sendmany + rpcwallet: Prevent use of both Sprout and Sapling addresses in z_sendmany + rpcwallet: Add Sapling support to z_sendmany + Define additional booleans for readability + Ensure SCOPED_TRACE falls out of scope when necessary + Revert NU activation heights in reverse order + Fix test after refactor to check bacd-cb-height rule on a genesis block + Rename GetFirstBlockTransaction() to GetFirstBlockCoinbaseTx() + libsnark: Force constants used in test comparisons to be unsigned + libsnark: Use format macro constants for printing fixed-width values + Rename z_inputs_ to z_sprout_inputs_ + Minor cleanups + Fix RPC test that checks exact wording of cleaned-up error message + Fix file permissions of wallet_sapling RPC test + Update librustzcash with ZIP 32 APIs + ZIP 32 Sapling structs + Store HDSeed in CBasicKeyStore + Store HDSeed in CCryptoKeyStore + wallet: Store HDSeed and chain data + wallet: Store Sapling key metadata indexed by ivk + wallet: Switch from SaplingSpendingKey to SaplingExtendedSpendingKey + init: Generate a new HD seed on startup + wallet: Comment out HDSeed and CHDChain persistence to disk + Add ZIP 32 usage to release notes + wallet: Don't allow an HDSeed to be overwritten + Bugfix: Use time instead of block height for Sapling key metadata + net: Check against the current epoch's version when rejecting nodes + Extract a helper method for finding the next epoch + net: Check against the next epoch's version when evicting peers + net: Check against the current epoch's version when disconnecting peers + qa: Test both Overwinter and Sapling peer management + Use ovk directly in the TransactionBuilder API instead of fvk + Generate an ovk to encrypt outCiphertext for t-addr senders + Revert "Disable Sapling features on mainnet" + Use the correct empty memo for Sapling outputs + Add Sapling support to z_shieldcoinbase + Revert "Get rid of consensus.fPowAllowMinDifficultyBlocks." + Revert "Remove testnet-only difficulty rules" + Allow minimum-difficulty blocks on testnet and regtest + Only enable min-difficulty blocks on testnet from a particular height + Update wallet_listreceived test for now-correct empty Sapling memos + Rename min-difficulty flag to remove off-by-one in the name + Explicitly check the min-difficulty flag against boost::none + Position PoW.MinDifficultyRules test after rule activates + Fix pyflakes warnings + Store ExtFVK with encrypted Sapling spending key instead of FVK + Persist Sapling payment address to IVK map + Ignore decoding errors during -zapwallettxes + +Jay Graber (5): + s/jsoutindex/outindex for sapling outputs + z_listunspent sapling support - needs refactor + Add rpc test for sprout txs z_listunspent + Modify comments + Modify GetNullifiersForAddresses for Sapling + +Jonas Schnelli (3): + [Wallet] extend CKeyMetadata with HD keypath Zcash: modified for zip32 + [Wallet] print hd masterkeyid in getwalletinfo Zcash: modified for zip32 + [Wallet] ensure CKeyMetadata.hdMasterKeyID will be cleared during SetNull() Zcash: modified for zip32 + +Larry Ruane (5): + generalize mininode.py protocol versioning + Test peer banning logic in both pre- and post-initial block download states + Sapling support for z_listreceivedbyaddress + z_listunspent rpc unit test: add testing for Sapling + fix z_listunspent includeWatchonly logic + +Marius Kjærstad (3): + Fix for license not being valid + Update debian package copyright license + Missing comma in debian package copyright license + +Sean Bowe (1): + Check commitment validity within the decryption API for Sapling note plaintexts. + +Simon Liu (59): + Rename FindMyNotes to FindMySproutNotes. + Rename GetNoteNullifier to GetSproutNoteNullifier. + Rename mapNullifiersToNotes to mapSproutNullifiersToNotes. + Rename CWallet::AddToSpends methods for clarity. + Rename mapTxNullifiers to mapTxSproutNullifiers. + Add ivk member variable and equality comparators to SaplingNoteData class. + Update CWallet::MarkAffectedTransactionsDirty() for Sapling. + Update CWallet::UpdatedNoteData() for Sapling. + Create CWallet::AddToSaplingSpends() to track Sapling nullifiers. + Update test to pass in required cm to SaplingNotePlaintext::decrypt(). + Create CWallet::FindMySaplingNotes() + Rename IsFromMe(nullifier) to IsSproutNullifierFromMe(nullifier). + Create CWallet::IsSaplingNullifierFromMe() + Remove dead code in CWalletTx::GetAmounts() as filed in issue #3434. + Cleanup CWalletTx::GetAmounts() for clarity. No-op. + Update CWalletTx::GetAmounts() to return COutputEntry for Sapling valueBalance. + Add caching and updating of Sapling note nullifier. + Update CWallet::IsSpent() to check Sapling nullifiers. + Clean up names of unit tests in gtest/test_wallet.cpp. + Add test for CWalletTx::SetSaplingNoteData() + Iterate over mapSaplingFullViewingKeys with ivk->fvk mapping (1:1). + Refactor IsSpent(nullifier) for Sprout and Sapling domain separation. + Fix code review nits. + Add two new wallet tests: FindMySaplingNotes, SaplingNullifierIsSpent. + Add new wallet test: NavigateFromSaplingNullifierToNote + Add new wallet test: UpdatedSaplingNoteData. + Add new wallet tests: SpentSaplingNoteIsFromMe. + Rename wallet tests for clarity between Sprout and Sapling. + Fix typo in variable name in test. + Fix inaccurate comments in test. + Fix typo in parameter name. + Update CWallet::GetConflicts for Sapling. + Add new wallet test: SetSaplingNoteAddrsInCWalletTx. + Add new wallet test: GetConflictedSaplingNotes + Add new wallet test: MarkAffectedSaplingTransactionsDirty + Update wallet unit tests to revert upgraded network parameters. + Clean up wallet unit tests: replace .value() with .get() for clarity. + Fix comment in CWallet::SyncMetaData. + Refactor: rename setLockedNotes -> setLockedSproutNotes + Refactor: rename UnlockAllNotes -> UnlockAllSproutNotes + Refactor: rename ListLockedNotes -> ListLockedSproutNotes + Add methods to store SaplingOutPoint in setLockedSaplingNotes + Add unit test SaplingNoteLocking + Update comment for test ContextualCheckBlockTest.BlockSproutRulesRejectOtherTx + Add Sapling fields to JSON RPC output using TxToJSON. + Update qa test to check for Sapling related JSON fields. + Closes #3534. Do not use APPROX_RELEASE_HEIGHT to get consensus branch id when in regtest mode. + For #3533. Replace asserts with JSON errors. + Update qa test as offline regtest nodes need branch id passed in. + Fix rebasing of CWallet::GetNullifiersForAddresses + Cleanup to address review comments. + Add test that Sapling shielded transactions have MAX_PRIORITY + Closes #3560. Update Sapling note data correctly when importing a key. + For #3546. Shielded tx with missing inputs are not treated as orphans. + For #3546. Improve estimated tx size for Sapling outputs. + Fix deadlock from calling CWallet::AddSaplingIncomingViewingKey instead of CBasicKeyStore::AddSaplingIncomingViewingKey + Fix file permissions of QA test wallet_persistence.py + Update wallet_persistence test to verify wallet txs are persisted across restarts. + Update wallet_persistence test to verify spending notes after restart. + +WO (4): + Fix a bug of Windows binary + Add an assert for num_bits function + long -> int64_t + The long data type is replaced with int64_t + +Za Wilcox (1): + Revise help output for z_sendmany + +mdr0id (8): + Resolve final edits for README + Revert "wallet: Comment out HDSeed and CHDChain persistence to disk" + Persist Sapling key material in the wallet to disk + Serialize Sapling data in CWalletTx + Adding in rpc wallet sap for test_bitcoin + Add gtest coverage of Sapling wallet persistence + make-release.py: Versioning changes for 2.0.1-rc1. + make-release.py: Updated manpages for 2.0.1-rc1. + diff --git a/doc/release-notes/release-notes-2.0.1.md b/doc/release-notes/release-notes-2.0.1.md new file mode 100644 index 000000000..b4dad7c25 --- /dev/null +++ b/doc/release-notes/release-notes-2.0.1.md @@ -0,0 +1,276 @@ +Notable changes +=============== + +Enabled Sapling features for mainnet +------------------------------------ +This release adds significant support for Sapling to the wallet and RPC interface. Sapling will activate at block 419200, which is expected to be mined on the 28th of October 2018. Users running v2.0.0 nodes (which are consensus-compatible with Sapling) will follow the network upgrade, but must upgrade to v2.0.1 in order to send or receive Sapling shielded transactions. + +Minimum Difficulty Blocks allowed on testnet +-------------------------------------------- +Sapling activated on testnet at block 280000. Users running v2.0.0 nodes should upgrade to v2.0.1 which introduces a consensus rule change to allow minimum difficulty blocks to be mined from block 299188, thereby splitting the chain. In addition, users running v2.0.1 nodes no longer need to specify `-experimentalfeatures` and `-developersapling` to use Sapling functionality on testnet. + +[Pull request](https://github.com/zcash/zcash/pull/3559) + +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) + +Fix Signing Raw Transactions with Unsynced Offline Nodes +-------------------------------------------------------- +With v2.0.0, in `signrawtransaction` the consensus branch ID (which is used to construct the transaction) was estimated using the chain height. With v2.0.1 this has been improved by also considering the `APPROX_RELEASE_HEIGHT` of the release, and a new parameter to allow the caller to manually override the consensus branch ID that zcashd will use. + +[Pull request](https://github.com/zcash/zcash/pull/3520) + + +Changelog +========= + +David Mercer (2): + libsnark: convert long long and unsigned long to C++11 fixed-width types + libsnark: convert 0ul to UINT64_C(0) + +Eirik Ogilvie-Wigley (24): + Rename map to include sprout + Add sapling spending keys to z_exportwallet + Rename AddZKey to include sprout + Move AddSpendingKeyToWallet + Return more information when adding a spending key + Add sapling support to z_importwallet + Export comment on HDSeed and fingerprint with wallet + Export zip32 metadata with sapling keys + Don't export empty zip32 metadata + Allow more information to be returned when an async rpc fails + Use utility method to wait for async operations + Remove unneeded semicolons + Remove unused imports + Allow passing timeout parameter to wait_and_assert_operationid_status + Add test for signing raw transactions offline + Incorporate APPROX_RELEASE_HEIGHT when determining what consensus branch to sign with + Allow passing branchId when calling signrawtransaction + Remove unused import + Address need not be optional when adding sapling keys + Use max priority for all shielded transfers + Move FIXME comment to where the fix should happen + Add newly discovered sapling addresses to the wallet + Fix HDSeed comment + Better error message when sending to both sprout and sapling + +George Tankersley (2): + Refactor ContextualCheckBlock tests (#3187) + Refactor ContextualCheckBlock tests + +Jack Grigg (83): + [ci-workers] Install Python modules in a virtualenv + [ci-workers] Handle user home directories outside /home + [ci-workers] Handle ansible_processor being either a string or a list + [ci-workers] Add support for MacOSX + [ci-workers] Add a tag for updating dependencies + [ci-workers] Add curl and cmake to dependencies + [ci-workers] README cleanups + [ci-workers] Add pkg-config to general dependencies + depends: Correctly configure Rust when cross-compiling + depends: Configure librustzcash for cross-compiling + depends: Fix BDB naming issue when cross-compiling + zcutil/build.sh: Use $HOST to specify the depends prefix + configure: Don't require RELRO and BIND_NOW when cross-compiling + Measure Windows console size for metrics UI + Use -O1 for darwin and mingw32 release builds + Clean up libzcash CPPFLAGS, CXXFLAGS, and LDFLAGS + zcutil/build.sh: Use config.site to set default ./configure settings + zcutil/build.sh: Remove --enable-werror from default configuration + Pass correct compiler, linker, and flags into libsnark + Use boost::filesystem::path::string() instead of path::native() + Metrics UI: Enable virtual terminal sequence processing on Windows + Metrics UI: Tell Windows users how to stop zcashd + depends: Pass correct compiler, linker, and flags into googletest + configure: Don't add -ldl to RUST_LIBS for mingw32 + test: Fix comment in WalletTests.FindMySaplingNotes + Add Sapling support to GetFilteredNotes() and GetUnspentFilteredNotes() + Add Sapling support to z_getbalance and z_gettotalbalance + Metrics UI: Fall back to 80 cols if GetConsoleScreenBufferInfo() fails + libsnark: Adjust SHA256 K value type to match the constant + libsnark: Use mp_limb_t cast instead of uint64_t when masking bigint.data + libsnark: Fix stale comment + rpc: Clarify Sprout shielded addresses in help text + rpc: Clarify ivk balance issues in help text + Move GetSpendingKeyForPaymentAddress visitor into wallet.h + wallet: Add HaveSpendingKeyForPaymentAddress visitor + rpcwallet: Add TransactionBuilder argument to AsyncRPCOperation_sendmany + rpcwallet: Prevent use of both Sprout and Sapling addresses in z_sendmany + rpcwallet: Add Sapling support to z_sendmany + Define additional booleans for readability + Ensure SCOPED_TRACE falls out of scope when necessary + Revert NU activation heights in reverse order + Fix test after refactor to check bacd-cb-height rule on a genesis block + Rename GetFirstBlockTransaction() to GetFirstBlockCoinbaseTx() + libsnark: Force constants used in test comparisons to be unsigned + libsnark: Use format macro constants for printing fixed-width values + Rename z_inputs_ to z_sprout_inputs_ + Minor cleanups + Fix RPC test that checks exact wording of cleaned-up error message + Fix file permissions of wallet_sapling RPC test + Update librustzcash with ZIP 32 APIs + ZIP 32 Sapling structs + Store HDSeed in CBasicKeyStore + Store HDSeed in CCryptoKeyStore + wallet: Store HDSeed and chain data + wallet: Store Sapling key metadata indexed by ivk + wallet: Switch from SaplingSpendingKey to SaplingExtendedSpendingKey + init: Generate a new HD seed on startup + wallet: Comment out HDSeed and CHDChain persistence to disk + Add ZIP 32 usage to release notes + wallet: Don't allow an HDSeed to be overwritten + Bugfix: Use time instead of block height for Sapling key metadata + net: Check against the current epoch's version when rejecting nodes + Extract a helper method for finding the next epoch + net: Check against the next epoch's version when evicting peers + net: Check against the current epoch's version when disconnecting peers + qa: Test both Overwinter and Sapling peer management + Use ovk directly in the TransactionBuilder API instead of fvk + Generate an ovk to encrypt outCiphertext for t-addr senders + Revert "Disable Sapling features on mainnet" + Use the correct empty memo for Sapling outputs + Add Sapling support to z_shieldcoinbase + Revert "Get rid of consensus.fPowAllowMinDifficultyBlocks." + Revert "Remove testnet-only difficulty rules" + Allow minimum-difficulty blocks on testnet and regtest + Only enable min-difficulty blocks on testnet from a particular height + Update wallet_listreceived test for now-correct empty Sapling memos + Rename min-difficulty flag to remove off-by-one in the name + Explicitly check the min-difficulty flag against boost::none + Position PoW.MinDifficultyRules test after rule activates + Fix pyflakes warnings + Store ExtFVK with encrypted Sapling spending key instead of FVK + Persist Sapling payment address to IVK map + Ignore decoding errors during -zapwallettxes + +Jay Graber (5): + s/jsoutindex/outindex for sapling outputs + z_listunspent sapling support - needs refactor + Add rpc test for sprout txs z_listunspent + Modify comments + Modify GetNullifiersForAddresses for Sapling + +Jonas Schnelli (3): + [Wallet] extend CKeyMetadata with HD keypath Zcash: modified for zip32 + [Wallet] print hd masterkeyid in getwalletinfo Zcash: modified for zip32 + [Wallet] ensure CKeyMetadata.hdMasterKeyID will be cleared during SetNull() Zcash: modified for zip32 + +Jonathan "Duke" Leto (1): + Fix some typos in rpc-tests readme + +Larry Ruane (5): + generalize mininode.py protocol versioning + Test peer banning logic in both pre- and post-initial block download states + Sapling support for z_listreceivedbyaddress + z_listunspent rpc unit test: add testing for Sapling + fix z_listunspent includeWatchonly logic + +Marius Kjærstad (3): + Fix for license not being valid + Update debian package copyright license + Missing comma in debian package copyright license + +Sean Bowe (1): + Check commitment validity within the decryption API for Sapling note plaintexts. + +Simon Liu (68): + Rename FindMyNotes to FindMySproutNotes. + Rename GetNoteNullifier to GetSproutNoteNullifier. + Rename mapNullifiersToNotes to mapSproutNullifiersToNotes. + Rename CWallet::AddToSpends methods for clarity. + Rename mapTxNullifiers to mapTxSproutNullifiers. + Add ivk member variable and equality comparators to SaplingNoteData class. + Update CWallet::MarkAffectedTransactionsDirty() for Sapling. + Update CWallet::UpdatedNoteData() for Sapling. + Create CWallet::AddToSaplingSpends() to track Sapling nullifiers. + Update test to pass in required cm to SaplingNotePlaintext::decrypt(). + Create CWallet::FindMySaplingNotes() + Rename IsFromMe(nullifier) to IsSproutNullifierFromMe(nullifier). + Create CWallet::IsSaplingNullifierFromMe() + Remove dead code in CWalletTx::GetAmounts() as filed in issue #3434. + Cleanup CWalletTx::GetAmounts() for clarity. No-op. + Update CWalletTx::GetAmounts() to return COutputEntry for Sapling valueBalance. + Add caching and updating of Sapling note nullifier. + Update CWallet::IsSpent() to check Sapling nullifiers. + Clean up names of unit tests in gtest/test_wallet.cpp. + Add test for CWalletTx::SetSaplingNoteData() + Iterate over mapSaplingFullViewingKeys with ivk->fvk mapping (1:1). + Refactor IsSpent(nullifier) for Sprout and Sapling domain separation. + Fix code review nits. + Add two new wallet tests: FindMySaplingNotes, SaplingNullifierIsSpent. + Add new wallet test: NavigateFromSaplingNullifierToNote + Add new wallet test: UpdatedSaplingNoteData. + Add new wallet tests: SpentSaplingNoteIsFromMe. + Rename wallet tests for clarity between Sprout and Sapling. + Fix typo in variable name in test. + Fix inaccurate comments in test. + Fix typo in parameter name. + Update CWallet::GetConflicts for Sapling. + Add new wallet test: SetSaplingNoteAddrsInCWalletTx. + Add new wallet test: GetConflictedSaplingNotes + Add new wallet test: MarkAffectedSaplingTransactionsDirty + Update wallet unit tests to revert upgraded network parameters. + Clean up wallet unit tests: replace .value() with .get() for clarity. + Fix comment in CWallet::SyncMetaData. + Refactor: rename setLockedNotes -> setLockedSproutNotes + Refactor: rename UnlockAllNotes -> UnlockAllSproutNotes + Refactor: rename ListLockedNotes -> ListLockedSproutNotes + Add methods to store SaplingOutPoint in setLockedSaplingNotes + Add unit test SaplingNoteLocking + Update comment for test ContextualCheckBlockTest.BlockSproutRulesRejectOtherTx + Add Sapling fields to JSON RPC output using TxToJSON. + Update qa test to check for Sapling related JSON fields. + Closes #3534. Do not use APPROX_RELEASE_HEIGHT to get consensus branch id when in regtest mode. + For #3533. Replace asserts with JSON errors. + Update qa test as offline regtest nodes need branch id passed in. + Fix rebasing of CWallet::GetNullifiersForAddresses + Cleanup to address review comments. + Add test that Sapling shielded transactions have MAX_PRIORITY + Closes #3560. Update Sapling note data correctly when importing a key. + For #3546. Shielded tx with missing inputs are not treated as orphans. + For #3546. Improve estimated tx size for Sapling outputs. + Fix deadlock from calling CWallet::AddSaplingIncomingViewingKey instead of CBasicKeyStore::AddSaplingIncomingViewingKey + Fix file permissions of QA test wallet_persistence.py + Update wallet_persistence test to verify wallet txs are persisted across restarts. + Update wallet_persistence test to verify spending notes after restart. + Resolves Sapling nullifier persistence issue when importing a key. + Update test to verify Sapling nullifiers and witnesses persist correctly. + For #3359. RPCs transferring funds return error if Sapling addresses are used before Sapling activation. + For #3359. Return error if Sapling addresses passed to RPC z_mergetoaddress. + Update mainnet checkpoint for block 410100. + Update release notes for v2.0.1 + Update release-notes.md for clarity. + make-release.py: Versioning changes for 2.0.1. + make-release.py: Updated manpages for 2.0.1. + +WO (4): + Fix a bug of Windows binary + Add an assert for num_bits function + long -> int64_t + The long data type is replaced with int64_t + +Za Wilcox (1): + Revise help output for z_sendmany + +mdr0id (9): + Resolve final edits for README + Revert "wallet: Comment out HDSeed and CHDChain persistence to disk" + Persist Sapling key material in the wallet to disk + Serialize Sapling data in CWalletTx + Adding in rpc wallet sap for test_bitcoin + Add gtest coverage of Sapling wallet persistence + make-release.py: Versioning changes for 2.0.1-rc1. + make-release.py: Updated manpages for 2.0.1-rc1. + make-release.py: Updated release notes and changelog for 2.0.1-rc1. + 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/libsnark.mk.patch b/libsnark.mk.patch index 28a60c8b6..acb306b04 100644 --- a/libsnark.mk.patch +++ b/libsnark.mk.patch @@ -4,7 +4,7 @@ *** 1,30 **** package=libsnark $(package)_version=0.1 -! $(package)_download_path=https://github.com/radix42/$(package)/archive/ +! $(package)_download_path=https://github.com/radix42/$(package)/archive $(package)_file_name=$(package)-$($(package)_git_commit).tar.gz $(package)_download_file=$($(package)_git_commit).tar.gz ! $(package)_sha256_hash=9dbd5b44d3443e86463e934bfe1023cab4ca5948f8d74c23a67d9535c28d2584 @@ -18,7 +18,7 @@ - endef - else define $(package)_build_cmds - CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64" + CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64 -g " endef - @@ -35,7 +35,7 @@ --- 1,17 ---- package=libsnark $(package)_version=0.1 -! $(package)_download_path=https://github.com/zcash/$(package)/archive/ +! $(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=9422b1a2a94e6b8be61f07af7f146087c2a7d70b208d07ad076622225aa7f0e4 @@ -44,7 +44,7 @@ $(package)_dependencies=libgmp libsodium define $(package)_build_cmds - CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64" + CXXFLAGS="-fPIC -DBINARY_OUTPUT -DNO_PT_COMPRESSION=1" $(MAKE) lib DEPINST=$(host_prefix) CURVE=ALT_BN128 MULTICORE=1 NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 STATIC=1 NO_SUPERCOP=1 FEATUREFLAGS=-DMONTGOMERY_OUTPUT OPTFLAGS="-O2 -march=x86-64 -g " endef define $(package)_stage_cmds diff --git a/makeDistrib.sh b/makeDistrib.sh deleted file mode 100755 index ad72fbb16..000000000 --- a/makeDistrib.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -TMP_DIR=~/tmp/komodo - -# make a tmp directory -mkdir -p $TMP_DIR -echo "making $TMP_DIR" - -binaries=("komodo-cli" "komodod") - -for binary in "${binaries[@]}"; -do - echo "copying $binary to $TMP_DIR" - - cp src/$binary $TMP_DIR - - # find the dylibs to copy for komodod - DYLIBS=`otool -L $TMP_DIR/$binary | grep "/usr/local" | awk -F' ' '{ print $1 }'` - echo "copying $DYLIBS to $TMP_DIR" - - # copy the dylibs to the tmpdir - for dylib in $DYLIBS; do cp -rf $dylib $TMP_DIR/; done - - # modify komodod to point to dylibs - echo "modifying $binary to use local libraries" - for dylib in $DYLIBS; do install_name_tool -change $dylib @executable_path/`basename $dylib` $TMP_DIR/$binary; done; -done - - - - - - - - diff --git a/makeRelease.sh b/makeRelease.sh deleted file mode 100755 index 5d68f0b03..000000000 --- a/makeRelease.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -binaries=("komodo-cli" "komodod") - -for binary in "${binaries[@]}"; -do - # find the dylibs to copy for komodod - DYLIBS=`otool -L src/$binary | grep "/usr/local" | awk -F' ' '{ print $1 }'` - echo "copying $DYLIBS to $src" - # copy the dylibs to the srcdir - for dylib in $DYLIBS; do cp -rf $dylib src/; done - - # modify komodod to point to dylibs - echo "modifying $binary to use local libraries" - for dylib in $DYLIBS; do install_name_tool -change $dylib @executable_path/`basename $dylib` src/$binary; done; - chmod +x src/$binary -done diff --git a/makeReleaseMac.sh b/makeReleaseMac.sh new file mode 100755 index 000000000..2ecf271cc --- /dev/null +++ b/makeReleaseMac.sh @@ -0,0 +1,76 @@ +#!/bin/sh + +KMD_DIR=verus-cli +mkdir ${KMD_DIR} + +cp src/fiat/verus \ + src/verusd \ + doc/man/verus-cli/mac/README.txt \ + zcutil/fetch-params.sh \ + verus-cli +mv verus-cli/fetch-params.sh verus-cli/fetch-params +chmod +x ${KMD_DIR}/fetch-params +chmod +x ${KMD_DIR}/verus +chmod +x ${KMD_DIR}/verusd + +binaries=("komodo-cli" "komodod") +alllibs=() +for binary in "${binaries[@]}"; +do + # do the work in the destination directory + cp src/${binary} ${KMD_DIR} + # find the dylibs to copy for komodod + DYLIBS=`otool -L ${KMD_DIR}/${binary} | grep "/usr/local" | awk -F' ' '{ print $1 }'` + echo "copying ${DYLIBS} to ${KMD_DIR}" + # copy the dylibs to the srcdir + for dylib in ${DYLIBS}; do cp -rf ${dylib} ${KMD_DIR}; done +done + +libraries=("libgcc_s.1.dylib" "libgomp.1.dylib" "libidn2.0.dylib" "libstdc++.6.dylib") + +for binary in "${libraries[@]}"; +do + # find the dylibs to copy for komodod + DYLIBS=`otool -L ${KMD_DIR}/${binary} | grep "/usr/local" | awk -F' ' '{ print $1 }'` + echo "copying ${DYLIBS} to ${KMD_DIR}" + # copy the dylibs to the srcdir + for dylib in ${DYLIBS}; do cp -rf ${dylib} ${KMD_DIR}; alllibs+=(${dylib}); done +done + +indirectlibraries=("libintl.8.dylib" "libunistring.2.dylib") + +for binary in "${indirectlibraries[@]}"; +do + # Need to undo this for the dylibs when we are done + chmod 755 src/${binary} + # find the dylibs to copy for komodod + DYLIBS=`otool -L ${KMD_DIR}/${binary} | grep "/usr/local" | awk -F' ' '{ print $1 }'` + echo "copying indirect ${DYLIBS} to ${KMD_DIR}" + # copy the dylibs to the dest dir + for dylib in ${DYLIBS}; do cp -rf ${dylib} ${KMD_DIR}; alllibs+=(${dylib}); done +done + +for binary in "${binaries[@]}"; +do + # modify komodod to point to dylibs + echo "modifying ${binary} to use local libraries" + for dylib in "${alllibs[@]}" + do + echo "Next lib is ${dylib} " + install_name_tool -change ${dylib} @executable_path/`basename ${dylib}` ${KMD_DIR}/${binary} + done + chmod +x ${KMD_DIR}/${binary} +done + +for binary in "${libraries[@]}"; +do + # modify libraries to point to dylibs + echo "modifying ${binary} to use local libraries" + for dylib in "${alllibs[@]}" + do + echo "Next lib is ${dylib} " + install_name_tool -change ${dylib} @executable_path/`basename ${dylib}` ${KMD_DIR}/${binary} + done +done + + diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index fb4ff99a7..bc83f9880 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -11,18 +11,28 @@ export BITCOIND=${REAL_BITCOIND} #Run the tests testScripts=( + 'ac_private.py' + 'verushash.py' 'cryptoconditions.py' 'paymentdisclosure.py' 'prioritisetransaction.py' 'wallet_treestate.py' 'wallet_anchorfork.py' + 'wallet_changeindicator.py' + 'wallet_import_export.py' 'wallet_protectcoinbase.py' - 'wallet_shieldcoinbase.py' + 'wallet_shieldcoinbase_sprout.py' + 'wallet_shieldcoinbase_sapling.py' + 'wallet_listreceived.py' 'wallet_mergetoaddress.py' 'wallet.py' 'wallet_overwintertx.py' + 'wallet_persistence.py' 'wallet_nullifiers.py' 'wallet_1941.py' + 'wallet_addresses.py' + 'wallet_sapling.py' + 'wallet_listnotes.py' 'listtransactions.py' 'mempool_resurrect_test.py' 'txn_doublespend.py' @@ -41,6 +51,7 @@ testScripts=( 'merkle_blocks.py' 'fundrawtransaction.py' 'signrawtransactions.py' + 'signrawtransaction_offline.py' 'walletbackup.py' 'key_import_export.py' 'nodehandling.py' @@ -49,6 +60,7 @@ testScripts=( 'timestampindex.py' 'spentindex.py' 'decodescript.py' + 'blockchain.py' 'disablewallet.py' 'zcjoinsplit.py' 'zcjoinsplitdoublespend.py' @@ -57,7 +69,12 @@ testScripts=( 'getblocktemplate.py' 'bip65-cltv-p2p.py' 'bipdersig-p2p.py' - 'overwinter_peer_management.py' + 'p2p_nu_peer_management.py' + 'rewind_index.py' + 'p2p_txexpiry_dos.py' + 'p2p_node_bloom.py' + 'regtest_signrawtransaction.py' + 'finalsaplingroot.py' ); testScriptsExt=( 'getblocktemplate_longpoll.py' diff --git a/qa/rpc-tests/ac_private.py b/qa/rpc-tests/ac_private.py new file mode 100755 index 000000000..fafc4b4cd --- /dev/null +++ b/qa/rpc-tests/ac_private.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 SuperNET 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.authproxy import JSONRPCException +from test_framework.util import assert_equal, assert_greater_than, \ + initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \ + stop_nodes, sync_blocks, sync_mempools, wait_bitcoinds, rpc_port, assert_raises + +import time +from decimal import Decimal +from random import choice +from string import ascii_uppercase + +def assert_success(result): + assert_equal(result['result'], 'success') + +def assert_error(result): + assert_equal(result['result'], 'error') + +def generate_random_string(length): + random_string = ''.join(choice(ascii_uppercase) for i in range(length)) + return random_string + + +class AssetChainPrivateTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing VerusHash test directory "+self.options.tmpdir) + self.num_nodes = 1 + initialize_chain_clean(self.options.tmpdir, self.num_nodes) + + def setup_network(self, split = False): + print("Setting up network...") + # These nodes simulate the ARRR asset chain parameters + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, + extra_args=[[ + # always give -ac_name as first extra_arg and port as third + '-ac_name=REGTEST', + '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', + '-port=64367', + '-rpcport=64368', + '-regtest', + '-addressindex=1', + '-spentindex=1', + '-ac_supply=0', + '-ac_reward=25600000000', + '-ac_private=1', + '-whitelist=127.0.0.1', + '-debug', + '--daemon', + '-rpcuser=rt', + '-rpcpassword=rt' + ]] + ) + self.is_network_split = split + self.rpc = self.nodes[0] + self.sync_all() + print("Done setting up network") + + def send_and_mine(self, xtn, rpc_connection): + txid = rpc_connection.sendrawtransaction(xtn) + assert txid, 'got txid' + # we need the tx above to be confirmed in the next block + rpc_connection.generate(1) + return txid + + def run_test (self): + print("Mining blocks...") + rpc = self.nodes[0] + # utxos from block 1 become mature in block 101 + rpc.generate(101) + self.sync_all() + rpc.getinfo() + rpc.getwalletinfo() + + taddr = rpc.getnewaddress() + print "Sending to " + taddr + # sending to arbitrary non-notary transparent address is not allowed + assert_raises(JSONRPCException, rpc.sendtoaddress, taddr,1) + + # this is a current notary address + # TODO: keep in sync when notaries change + #dev1_jl777 = "RNJmgYaFF5DbnrNUX6pMYz9rcnDKC2tuAc" + # taddr vout is only allowed if it is a notary address + #txid = rpc.sendtoaddress(dev1_jl777, 7) + #assert txid, 'got txid' + +if __name__ == '__main__': + AssetChainPrivateTest ().main() 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/cryptoconditions.py b/qa/rpc-tests/cryptoconditions.py index 1d2f68777..ee119b75a 100755 --- a/qa/rpc-tests/cryptoconditions.py +++ b/qa/rpc-tests/cryptoconditions.py @@ -30,7 +30,7 @@ class CryptoConditionsTest (BitcoinTestFramework): def setup_chain(self): print("Initializing CC test directory "+self.options.tmpdir) - self.num_nodes = 1 + self.num_nodes = 2 initialize_chain_clean(self.options.tmpdir, self.num_nodes) def setup_network(self, split = False): @@ -38,9 +38,12 @@ class CryptoConditionsTest (BitcoinTestFramework): self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D" self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf" self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9" + self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp" + self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0" + self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi" self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[ - # always give -ac_name as first extra_arg + # always give -ac_name as first extra_arg and port as third '-ac_name=REGTEST', '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', '-port=64367', @@ -49,30 +52,49 @@ class CryptoConditionsTest (BitcoinTestFramework): '-addressindex=1', '-spentindex=1', '-ac_supply=5555555', - '-ac_reward=10000000', + '-ac_reward=10000000000000', '-pubkey=' + self.pubkey, '-ac_cc=2', '-whitelist=127.0.0.1', '-debug', - '-daemon', + '--daemon', '-rpcuser=rt', '-rpcpassword=rt' - ]] + ], + ['-ac_name=REGTEST', + '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', + '-port=64365', + '-rpcport=64366', + '-regtest', + '-addressindex=1', + '-spentindex=1', + '-ac_supply=5555555', + '-ac_reward=10000000000000', + '-pubkey=' + self.pubkey1, + '-ac_cc=2', + '-whitelist=127.0.0.1', + '-debug', + '-addnode=127.0.0.1:64367', + '--daemon', + '-rpcuser=rt', + '-rpcpassword=rt']] ) self.is_network_split = split self.rpc = self.nodes[0] + self.rpc1 = self.nodes[1] self.sync_all() print("Done setting up network") - def send_and_mine(self, xtn): - txid = self.rpc.sendrawtransaction(xtn) + def send_and_mine(self, xtn, rpc_connection): + txid = rpc_connection.sendrawtransaction(xtn) assert txid, 'got txid' # we need the tx above to be confirmed in the next block - self.rpc.generate(1) + rpc_connection.generate(1) return txid def run_faucet_tests(self): rpc = self.rpc + rpc1 = self.rpc1 # basic sanity tests result = rpc.getwalletinfo() @@ -117,9 +139,11 @@ class CryptoConditionsTest (BitcoinTestFramework): # we need the tx above to be confirmed in the next block rpc.generate(1) + self.sync_all() result = rpc.getwalletinfo() - balance2 = result['balance'] + # minus one block reward + balance2 = result['balance'] - 100000 # make sure our balance is less now assert_greater_than(balance, balance2) @@ -127,21 +151,31 @@ class CryptoConditionsTest (BitcoinTestFramework): assert_success(result) assert_greater_than( result['funding'], 0 ) - result = rpc.faucetget() - assert_success(result) - assert result['hex'], "hex key found" + # claiming faucet on second node + faucetgethex = rpc1.faucetget() + assert_success(faucetgethex) + assert faucetgethex['hex'], "hex key found" - # try to broadcast the xtn, but we will get 'faucet is only for brand new addresses' - assert_raises(JSONRPCException, rpc.sendrawtransaction, [ result['hex'] ]) + balance1 = rpc1.getwalletinfo()['balance'] - newaddr = rpc.getnewaddress() - assert newaddr, "got a new address" - result = rpc.validateaddress(newaddr) - newpubkey = result['pubkey'] - assert newpubkey, "got a pubkey for new address" + # try to broadcast the faucetget transaction + result = self.send_and_mine(faucetgethex['hex'], rpc1) + assert txid, "transaction broadcasted" + + balance2 = rpc1.getwalletinfo()['balance'] + assert_greater_than(balance2, balance1) + + self.sync_all() def run_dice_tests(self): rpc = self.nodes[0] + rpc1 = self.nodes[1] + self.sync_all() + + # have to generate few blocks on second node to be able to place bets + rpc1.generate(10) + result = rpc1.getbalance() + assert_greater_than(result, 100000) dice = rpc.diceaddress() assert_equal(dice['result'], 'success') @@ -171,7 +205,7 @@ class CryptoConditionsTest (BitcoinTestFramework): # creating dice plan dicefundtx = rpc.dicefund("LUCKY","1000","1","800","10","5") - diceid = self.send_and_mine(dicefundtx['hex']) + diceid = self.send_and_mine(dicefundtx['hex'], rpc) # checking if it in plans list now result = rpc.dicelist() @@ -190,7 +224,7 @@ class CryptoConditionsTest (BitcoinTestFramework): # adding funds to plan addfundstx = rpc.diceaddfunds(dicename,diceid,"1100") - result = self.send_and_mine(addfundstx['hex']) + result = self.send_and_mine(addfundstx['hex'], rpc) # checking if funds added to plan result = rpc.diceinfo(diceid) @@ -201,92 +235,99 @@ class CryptoConditionsTest (BitcoinTestFramework): assert_error(result) # placing 0 amount bet - result = rpc.dicebet(dicename,diceid,"0","1") + result = rpc1.dicebet(dicename,diceid,"0","2") assert_error(result) # placing negative amount bet - result = rpc.dicebet(dicename,diceid,"-1","1") + result = rpc1.dicebet(dicename,diceid,"-1","2") assert_error(result) # placing bet more than maxbet - result = rpc.dicebet(dicename,diceid,"900","1") + result = rpc1.dicebet(dicename,diceid,"900","2") assert_error(result) # placing bet with amount more than funding - result = rpc.dicebet(dicename,diceid,"3000","1") + result = rpc1.dicebet(dicename,diceid,"3000","2") assert_error(result) # placing bet with potential won more than funding - result = rpc.dicebet(dicename,diceid,"750","9") + result = rpc1.dicebet(dicename,diceid,"750","9") assert_error(result) # placing 0 odds bet - result = rpc.dicebet(dicename,diceid,"1","0") + result = rpc1.dicebet(dicename,diceid,"1","0") assert_error(result) # placing negative odds bet - result = rpc.dicebet(dicename,diceid,"1","-1") + result = rpc1.dicebet(dicename,diceid,"1","-1") assert_error(result) # placing bet with odds more than allowed - result = rpc.dicebet(dicename,diceid,"1","11") + result = rpc1.dicebet(dicename,diceid,"1","11") assert_error(result) # placing bet with not correct dice name - result = rpc.dicebet("nope",diceid,"100","1") + result = rpc1.dicebet("nope",diceid,"100","2") assert_error(result) # placing bet with not correct dice id - result = rpc.dicebet(dicename,self.pubkey,"100","1") + result = rpc1.dicebet(dicename,self.pubkey,"100","2") assert_error(result) - # valid bet placing - placebet = rpc.dicebet(dicename,diceid,"100","1") - betid = self.send_and_mine(placebet["hex"]) - assert result, "bet placed" - - # check bet status - result = rpc.dicestatus(dicename,diceid,betid) - assert_success(result) - # have to make some entropy for the next test entropytx = 0 fundingsum = 1 - while entropytx < 10: + while entropytx < 110: fundingsuminput = str(fundingsum) fundinghex = rpc.diceaddfunds(dicename,diceid,fundingsuminput) - result = self.send_and_mine(fundinghex['hex']) + result = self.send_and_mine(fundinghex['hex'], rpc) entropytx = entropytx + 1 fundingsum = fundingsum + 1 rpc.generate(2) + self.sync_all() + + # valid bet placing + placebet = rpc1.dicebet(dicename,diceid,"100","2") + betid = self.send_and_mine(placebet["hex"], rpc1) + assert result, "bet placed" + + # check bet status + result = rpc1.dicestatus(dicename,diceid,betid) + assert_success(result) # note initial dice funding state at this point. # TODO: track player balance somehow (hard to do because of mining and fees) diceinfo = rpc.diceinfo(diceid) funding = float(diceinfo['funding']) - # placing same amount bets with amount 1 and odds 1:2, checking if balance changed correct - losscounter = 0 - wincounter = 0 - betcounter = 0 - - while (betcounter < 10): - placebet = rpc.dicebet(dicename,diceid,"1","1") - betid = self.send_and_mine(placebet["hex"]) - finish = rpc.dicefinish(dicename,diceid,betid) - self.send_and_mine(finish["hex"]) - betresult = rpc.dicestatus(dicename,diceid,betid) - betcounter = betcounter + 1 - if betresult["status"] == "loss": - losscounter = losscounter + 1 - elif betresult["status"] == "win": - wincounter = wincounter + 1 - - # funding balance should increase if player loss, decrease if player won - fundbalanceguess = funding + losscounter - wincounter - fundinfoactual = rpc.diceinfo(diceid) - assert_equal(round(fundbalanceguess),round(float(fundinfoactual['funding']))) + # # placing same amount bets with amount 1 and odds 1:3, checking if balance changed correct + # losscounter = 0 + # wincounter = 0 + # betcounter = 0 + # + # while (betcounter < 10): + # placebet = rpc1.dicebet(dicename,diceid,"1","2") + # betid = self.send_and_mine(placebet["hex"], rpc1) + # time.sleep(3) + # self.sync_all() + # finish = rpc.dicefinish(dicename,diceid,betid) + # self.send_and_mine(finish["hex"], rpc1) + # self.sync_all() + # time.sleep(3) + # betresult = rpc1.dicestatus(dicename,diceid,betid) + # betcounter = betcounter + 1 + # if betresult["status"] == "loss": + # losscounter = losscounter + 1 + # elif betresult["status"] == "win": + # wincounter = wincounter + 1 + # else: + # pass + # + # # funding balance should increase if player loss, decrease if player won + # fundbalanceguess = funding + losscounter - wincounter * 2 + # fundinfoactual = rpc.diceinfo(diceid) + # assert_equal(round(fundbalanceguess),round(float(fundinfoactual['funding']))) def run_token_tests(self): rpc = self.nodes[0] @@ -315,7 +356,7 @@ class CryptoConditionsTest (BitcoinTestFramework): result = rpc.tokencreate("DUKE", "1987.420", "Duke's custom token") assert_success(result) - tokenid = self.send_and_mine(result['hex']) + tokenid = self.send_and_mine(result['hex'], rpc) result = rpc.tokenlist() assert_equal(result[0], tokenid) @@ -379,7 +420,7 @@ class CryptoConditionsTest (BitcoinTestFramework): # valid ask tokenask = rpc.tokenask("100", tokenid, "7.77") tokenaskhex = tokenask['hex'] - tokenaskid = self.send_and_mine(tokenask['hex']) + tokenaskid = self.send_and_mine(tokenask['hex'], rpc) result = rpc.tokenorders() order = result[0] assert order, "found order" @@ -394,7 +435,7 @@ class CryptoConditionsTest (BitcoinTestFramework): # valid ask fillunits fillask = rpc.tokenfillask(tokenid, tokenaskid, "777") - result = self.send_and_mine(fillask['hex']) + result = self.send_and_mine(fillask['hex'], rpc) txid = result[0] assert txid, "found txid" @@ -404,9 +445,9 @@ class CryptoConditionsTest (BitcoinTestFramework): # checking ask cancellation testorder = rpc.tokenask("100", tokenid, "7.77") - testorderid = self.send_and_mine(testorder['hex']) + testorderid = self.send_and_mine(testorder['hex'], rpc) cancel = rpc.tokencancelask(tokenid, testorderid) - self.send_and_mine(cancel["hex"]) + self.send_and_mine(cancel["hex"], rpc) result = rpc.tokenorders() assert_equal(result, []) @@ -432,7 +473,7 @@ class CryptoConditionsTest (BitcoinTestFramework): tokenbid = rpc.tokenbid("100", tokenid, "10") tokenbidhex = tokenbid['hex'] - tokenbidid = self.send_and_mine(tokenbid['hex']) + tokenbidid = self.send_and_mine(tokenbid['hex'], rpc) result = rpc.tokenorders() order = result[0] assert order, "found order" @@ -447,7 +488,7 @@ class CryptoConditionsTest (BitcoinTestFramework): # valid bid fillunits fillbid = rpc.tokenfillbid(tokenid, tokenbidid, "1000") - result = self.send_and_mine(fillbid['hex']) + result = self.send_and_mine(fillbid['hex'], rpc) txid = result[0] assert txid, "found txid" @@ -457,9 +498,9 @@ class CryptoConditionsTest (BitcoinTestFramework): # checking bid cancellation testorder = rpc.tokenbid("100", tokenid, "7.77") - testorderid = self.send_and_mine(testorder['hex']) + testorderid = self.send_and_mine(testorder['hex'], rpc) cancel = rpc.tokencancelbid(tokenid, testorderid) - self.send_and_mine(cancel["hex"]) + self.send_and_mine(cancel["hex"], rpc) result = rpc.tokenorders() assert_equal(result, []) @@ -474,7 +515,7 @@ class CryptoConditionsTest (BitcoinTestFramework): # valid token transfer sendtokens = rpc.tokentransfer(tokenid,randompubkey,"1") - self.send_and_mine(sendtokens["hex"]) + self.send_and_mine(sendtokens["hex"], rpc) result = rpc.tokenbalance(tokenid,randompubkey) assert_equal(result["balance"], 1) @@ -548,7 +589,7 @@ class CryptoConditionsTest (BitcoinTestFramework): # adding valid funding result = rpc.rewardsaddfunding("STUFF", fundingtxid, "555") - addfundingtxid = self.send_and_mine(result['hex']) + addfundingtxid = self.send_and_mine(result['hex'], rpc) assert addfundingtxid, 'got funding txid' # checking if funding added to rewardsplan @@ -590,6 +631,10 @@ class CryptoConditionsTest (BitcoinTestFramework): def run_oracles_tests(self): rpc = self.nodes[0] + rpc1 = self.nodes[1] + + result = rpc1.oraclesaddress() + result = rpc.oraclesaddress() assert_success(result) for x in ['OraclesCCaddress', 'Oraclesmarker', 'myCCaddress', 'myaddress']: @@ -621,36 +666,36 @@ class CryptoConditionsTest (BitcoinTestFramework): too_long_description = generate_random_string(4100) result = rpc.oraclescreate("Test", too_long_description, "s") assert_error(result) - - # valid creating oracles of different types - # using such naming to re-use it for data publishing / reading (e.g. oracle_s for s type) - valid_formats = ["s", "S", "d", "D", "c", "C", "t", "T", "i", "I", "l", "L", "h", "Ihh"] - for f in valid_formats: - result = rpc.oraclescreate("Test", "Test", f) - assert_success(result) - globals()["oracle_{}".format(f)] = self.send_and_mine(result['hex']) - - - + # # valid creating oracles of different types + # # using such naming to re-use it for data publishing / reading (e.g. oracle_s for s type) + # valid_formats = ["s", "S", "d", "D", "c", "C", "t", "T", "i", "I", "l", "L", "h", "Ihh"] + # for f in valid_formats: + # result = rpc.oraclescreate("Test", "Test", f) + # assert_success(result) + # globals()["oracle_{}".format(f)] = self.send_and_mine(result['hex'], rpc) def run_test (self): print("Mining blocks...") rpc = self.nodes[0] - + rpc1 = self.nodes[1] # utxos from block 1 become mature in block 101 rpc.generate(101) self.sync_all() - + rpc.getinfo() + rpc1.getinfo() # this corresponds to -pubkey above - print("Importing privkey") + print("Importing privkeys") rpc.importprivkey(self.privkey) - - #self.run_faucet_tests() - self.run_rewards_tests() - self.run_dice_tests() - self.run_token_tests() + rpc1.importprivkey(self.privkey1) self.run_faucet_tests() + self.sync_all() + self.run_rewards_tests() + self.sync_all() + self.run_dice_tests() + self.sync_all() + self.run_token_tests() + self.sync_all() self.run_oracles_tests() 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/finalsaplingroot.py b/qa/rpc-tests/finalsaplingroot.py new file mode 100755 index 000000000..83f16edec --- /dev/null +++ b/qa/rpc-tests/finalsaplingroot.py @@ -0,0 +1,150 @@ +#!/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, + connect_nodes_bi, + initialize_chain_clean, + start_nodes, + wait_and_assert_operationid_status, +) + +from decimal import Decimal + +SAPLING_TREE_EMPTY_ROOT = "3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb" +NULL_FIELD = "0000000000000000000000000000000000000000000000000000000000000000" + +# Verify block header field 'hashFinalSaplingRoot' (returned in rpc as 'finalsaplingroot') +# is updated when Sapling transactions with outputs (commitments) are mined into a block. +class FinalSaplingRootTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def setup_network(self, split=False): + self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[[ + '-nuparams=5ba81b19:100', # Overwinter + '-nuparams=76b809bb:200', # Sapling + '-txindex' # Avoid JSONRPC error: No information available about transaction + ]] * 4 ) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + connect_nodes_bi(self.nodes,0,3) + self.is_network_split=False + self.sync_all() + + def run_test(self): + # Activate Overwinter and Sapling + self.nodes[0].generate(200) + self.sync_all() + + # Verfify genesis block contains null field for what is now called the final sapling root field. + blk = self.nodes[0].getblock("0") + assert_equal(blk["finalsaplingroot"], NULL_FIELD) + + # Verify all generated blocks contain the empty root of the Sapling tree. + blockcount = self.nodes[0].getblockcount() + for height in xrange(1, blockcount + 1): + blk = self.nodes[0].getblock(str(height)) + assert_equal(blk["finalsaplingroot"], SAPLING_TREE_EMPTY_ROOT) + + # Node 0 shields some funds + taddr0 = self.nodes[0].getnewaddress() + saplingAddr0 = self.nodes[0].z_getnewaddress('sapling') + recipients = [] + recipients.append({"address": saplingAddr0, "amount": Decimal('20')}) + myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) + mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) + + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + # Verify the final Sapling root has changed + blk = self.nodes[0].getblock("201") + root = blk["finalsaplingroot"] + assert(root is not SAPLING_TREE_EMPTY_ROOT) + assert(root is not NULL_FIELD) + + # Verify there is a Sapling output description (its commitment was added to tree) + result = self.nodes[0].getrawtransaction(mytxid, 1) + assert_equal(len(result["vShieldedOutput"]), 1) + + # Mine an empty block and verify the final Sapling root does not change + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + assert_equal(root, self.nodes[0].getblock("202")["finalsaplingroot"]) + + # Mine a block with a transparent tx and verify the final Sapling root does not change + taddr1 = self.nodes[1].getnewaddress() + self.nodes[0].sendtoaddress(taddr1, Decimal("1.23")) + + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + assert_equal(len(self.nodes[0].getblock("203")["tx"]), 2) + assert_equal(self.nodes[1].z_getbalance(taddr1), Decimal("1.23")) + assert_equal(root, self.nodes[0].getblock("203")["finalsaplingroot"]) + + # Mine a block with a Sprout shielded tx and verify the final Sapling root does not change + zaddr1 = self.nodes[1].z_getnewaddress() + recipients = [] + recipients.append({"address": zaddr1, "amount": Decimal('10')}) + myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0) + wait_and_assert_operationid_status(self.nodes[0], myopid) + + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + assert_equal(len(self.nodes[0].getblock("204")["tx"]), 2) + assert_equal(self.nodes[1].z_getbalance(zaddr1), Decimal("10")) + assert_equal(root, self.nodes[0].getblock("204")["finalsaplingroot"]) + + # Mine a block with a Sapling shielded recipient and verify the final Sapling root changes + saplingAddr1 = self.nodes[1].z_getnewaddress("sapling") + recipients = [] + recipients.append({"address": saplingAddr1, "amount": Decimal('12.34')}) + myopid = self.nodes[0].z_sendmany(saplingAddr0, recipients, 1, 0) + mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) + + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + assert_equal(len(self.nodes[0].getblock("205")["tx"]), 2) + assert_equal(self.nodes[1].z_getbalance(saplingAddr1), Decimal("12.34")) + assert(root is not self.nodes[0].getblock("205")["finalsaplingroot"]) + + # Verify there is a Sapling output description (its commitment was added to tree) + result = self.nodes[0].getrawtransaction(mytxid, 1) + assert_equal(len(result["vShieldedOutput"]), 2) # there is Sapling shielded change + + # Mine a block with a Sapling shielded sender and transparent recipient and verify the final Sapling root doesn't change + taddr2 = self.nodes[0].getnewaddress() + recipients = [] + recipients.append({"address": taddr2, "amount": Decimal('12.34')}) + myopid = self.nodes[1].z_sendmany(saplingAddr1, recipients, 1, 0) + mytxid = wait_and_assert_operationid_status(self.nodes[1], myopid) + + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + assert_equal(len(self.nodes[0].getblock("206")["tx"]), 2) + assert_equal(self.nodes[0].z_getbalance(taddr2), Decimal("12.34")) + + blk = self.nodes[0].getblock("206") + root = blk["finalsaplingroot"] + assert_equal(root, self.nodes[0].getblock("205")["finalsaplingroot"]) + + +if __name__ == '__main__': + FinalSaplingRootTest().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..9a7131cfe 100755 --- a/qa/rpc-tests/mempool_tx_input_limit.py +++ b/qa/rpc-tests/mempool_tx_input_limit.py @@ -8,7 +8,6 @@ from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, initialize_chain_clean, \ start_node, connect_nodes, wait_and_assert_operationid_status -import time from decimal import Decimal # Test -mempooltxinputlimit @@ -17,7 +16,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)) @@ -49,27 +48,13 @@ class MempoolTxInputLimitTest(BitcoinTestFramework): node0_zaddr = self.nodes[0].z_getnewaddress() # Send three inputs from node 0 taddr to zaddr to get out of coinbase - node0_taddr = self.nodes[0].getnewaddress(); + node0_taddr = self.nodes[0].getnewaddress() 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) - opids = [] - opids.append(myopid) - # Spend should fail due to -mempooltxinputlimit - timeout = 120 - status = None - for x in xrange(1, timeout): - results = self.nodes[0].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - msg = results[0]["error"]["message"] - assert_equal("failed", status) - assert_equal("Too many transparent inputs 3 > limit 2", msg) - break + wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "Too many transparent inputs 3 > limit 2", 120) # Mempool should be empty. assert_equal(set(self.nodes[0].getrawmempool()), set()) @@ -100,6 +85,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 +106,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 deleted file mode 100755 index 6c59e47ba..000000000 --- a/qa/rpc-tests/overwinter_peer_management.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/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_ping, MY_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 - -import time - -# -# In this test we connect Sprout and Overwinter mininodes to a Zcashd node -# which will activate Overwinter at block 10. -# -# We test: -# 1. the mininodes stay connected to Zcash with Sprout consensus rules -# 2. when Overwinter activates, the Sprout mininodes are dropped -# 3. new Overwinter nodes can connect to Zcash -# 4. new Sprout nodes cannot connect to Zcash -# -# This test *does not* verify that prior to Overwinter activation, the Zcashd -# node will prefer connections with Overwinter nodes, with an eviction process -# that prioritizes Sprout connections. -# - - -class TestManager(NodeConnCB): - def __init__(self): - NodeConnCB.__init__(self) - self.create_callback_map() - - def on_close(self, conn): - pass - - def on_reject(self, conn, message): - conn.rejectMessage = message - - -class OverwinterPeerManagementTest(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', '-debug', '-whitelist=127.0.0.1']]) - - def run_test(self): - test = TestManager() - - # 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)) - - # Start up network handling in another thread - NetworkThread().start() - - # Sprout consensus rules apply at block height 9 - self.nodes[0].generate(9) - assert_equal(9, self.nodes[0].getblockcount()) - - # 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(OVERWINTER_PROTO_VERSION)) - - # Overwinter consensus rules activate at block height 10 - self.nodes[0].generate(1) - assert_equal(10, self.nodes[0].getblockcount()) - - # Mininodes send ping message to zcashd node. - pingCounter = 1 - for node in nodes: - node.send_message(msg_ping(pingCounter)) - pingCounter = pingCounter + 1 - - time.sleep(3) - - # 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(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)) - 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) - nodes.append(sprout) - time.sleep(3) - assert("Version must be 170003 or greater" in str(sprout.rejectMessage)) - - # 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(11, versions.count(OVERWINTER_PROTO_VERSION)) - - for node in nodes: - node.disconnect_node() - -if __name__ == '__main__': - OverwinterPeerManagementTest().main() 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_nu_peer_management.py b/qa/rpc-tests/p2p_nu_peer_management.py new file mode 100755 index 000000000..6cedf66bb --- /dev/null +++ b/qa/rpc-tests/p2p_nu_peer_management.py @@ -0,0 +1,192 @@ +#!/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_ping, + SPROUT_PROTO_VERSION, + OVERWINTER_PROTO_VERSION, + SAPLING_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 + +# +# In this test we connect Sprout, Overwinter, and Sapling mininodes to a Zcashd +# node which will activate Overwinter at block 10 and Sapling at block 15. +# +# We test: +# 1. the mininodes stay connected to Zcash with Sprout consensus rules +# 2. when Overwinter activates, the Sprout mininodes are dropped +# 3. new Overwinter and Sapling nodes can connect to Zcash +# 4. new Sprout nodes cannot connect to Zcash +# 5. when Sapling activates, the Overwinter mininodes are dropped +# 6. new Sapling nodes can connect to Zcash +# 7. new Sprout and Overwinter nodes cannot connect to Zcash +# +# This test *does not* verify that prior to each activation, the Zcashd +# node will prefer connections with NU-aware nodes, with an eviction process +# that prioritizes non-NU-aware connections. +# + + +class TestManager(NodeConnCB): + def __init__(self): + NodeConnCB.__init__(self) + self.create_callback_map() + + def on_close(self, conn): + pass + + def on_reject(self, conn, message): + conn.rejectMessage = message + + +class NUPeerManagementTest(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', # Overwinter + '-nuparams=76b809bb:15', # Sapling + '-debug', + '-whitelist=127.0.0.1', + ]]) + + def run_test(self): + test = TestManager() + + # Launch Sprout, Overwinter, and Sapling mininodes + nodes = [] + for x in xrange(10): + 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)) + nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], + test, "regtest", SAPLING_PROTO_VERSION)) + + # Start up network handling in another thread + NetworkThread().start() + + # Sprout consensus rules apply at block height 9 + self.nodes[0].generate(9) + assert_equal(9, self.nodes[0].getblockcount()) + + # 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(SPROUT_PROTO_VERSION)) + assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION)) + assert_equal(10, versions.count(SAPLING_PROTO_VERSION)) + + # Overwinter consensus rules activate at block height 10 + self.nodes[0].generate(1) + assert_equal(10, self.nodes[0].getblockcount()) + print('Overwinter active') + + # Mininodes send ping message to zcashd node. + pingCounter = 1 + for node in nodes: + node.send_message(msg_ping(pingCounter)) + pingCounter = pingCounter + 1 + + time.sleep(3) + + # Verify Sprout mininodes have been dropped, while Overwinter and + # Sapling mininodes are still connected. + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) + assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION)) + assert_equal(10, versions.count(SAPLING_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", OVERWINTER_PROTO_VERSION)) + time.sleep(3) + assert_equal(21, len(self.nodes[0].getpeerinfo())) + + # Connect a new Sapling mininode to the zcashd node, which is accepted. + nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SAPLING_PROTO_VERSION)) + time.sleep(3) + assert_equal(22, 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", SPROUT_PROTO_VERSION) + nodes.append(sprout) + time.sleep(3) + assert("Version must be 170003 or greater" in str(sprout.rejectMessage)) + + # Verify that only Overwinter and Sapling mininodes are connected. + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) + assert_equal(11, versions.count(OVERWINTER_PROTO_VERSION)) + assert_equal(11, versions.count(SAPLING_PROTO_VERSION)) + + # Sapling consensus rules activate at block height 15 + self.nodes[0].generate(4) + assert_equal(15, self.nodes[0].getblockcount()) + print('Sapling active') + + # Mininodes send ping message to zcashd node. + pingCounter = 1 + for node in nodes: + node.send_message(msg_ping(pingCounter)) + pingCounter = pingCounter + 1 + + time.sleep(3) + + # Verify Sprout and Overwinter mininodes have been dropped, while + # Sapling mininodes are still connected. + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) + assert_equal(0, versions.count(OVERWINTER_PROTO_VERSION)) + assert_equal(11, versions.count(SAPLING_PROTO_VERSION)) + + # Extend the Sapling chain with another block. + self.nodes[0].generate(1) + + # Connect a new Sapling mininode to the zcashd node, which is accepted. + nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SAPLING_PROTO_VERSION)) + time.sleep(3) + assert_equal(12, 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", SPROUT_PROTO_VERSION) + nodes.append(sprout) + time.sleep(3) + assert("Version must be 170006 or greater" in str(sprout.rejectMessage)) + + # Try to connect a new Overwinter mininode to the zcashd node, which is rejected. + sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", OVERWINTER_PROTO_VERSION) + nodes.append(sprout) + time.sleep(3) + assert("Version must be 170006 or greater" in str(sprout.rejectMessage)) + + # Verify that only Sapling mininodes are connected. + peerinfo = self.nodes[0].getpeerinfo() + versions = [x["version"] for x in peerinfo] + assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) + assert_equal(0, versions.count(OVERWINTER_PROTO_VERSION)) + assert_equal(12, versions.count(SAPLING_PROTO_VERSION)) + + for node in nodes: + node.disconnect_node() + +if __name__ == '__main__': + NUPeerManagementTest().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/regtest_signrawtransaction.py b/qa/rpc-tests/regtest_signrawtransaction.py new file mode 100755 index 000000000..2e0273677 --- /dev/null +++ b/qa/rpc-tests/regtest_signrawtransaction.py @@ -0,0 +1,34 @@ +#!/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 start_nodes, wait_and_assert_operationid_status + +class RegtestSignrawtransactionTest (BitcoinTestFramework): + + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir, [[ + "-nuparams=5ba81b19:200", # Overwinter + "-nuparams=76b809bb:204", # Sapling + ]] * 4) + + def run_test(self): + self.nodes[0].generate(1) + self.sync_all() + taddr = self.nodes[1].getnewaddress() + zaddr1 = self.nodes[1].z_getnewaddress('sprout') + + self.nodes[0].sendtoaddress(taddr, 2.0) + self.nodes[0].generate(1) + self.sync_all() + + # Create and sign Overwinter transaction. + # If the incorrect consensus branch id is selected, there will be a signing error. + opid = self.nodes[1].z_sendmany(taddr, + [{'address': zaddr1, 'amount': 1}]) + wait_and_assert_operationid_status(self.nodes[1], opid) + +if __name__ == '__main__': + RegtestSignrawtransactionTest().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/signrawtransaction_offline.py b/qa/rpc-tests/signrawtransaction_offline.py new file mode 100755 index 000000000..0d7def43b --- /dev/null +++ b/qa/rpc-tests/signrawtransaction_offline.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python2 + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_true, initialize_chain_clean, start_node +from test_framework.authproxy import JSONRPCException + +class SignOfflineTest (BitcoinTestFramework): + # Setup Methods + 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_node(0, self.options.tmpdir, ["-nuparams=5ba81b19:10"]) ] + self.is_network_split = False + self.sync_all() + + # Tests + def run_test(self): + print "Mining blocks..." + self.nodes[0].generate(101) + + offline_node = start_node(1, self.options.tmpdir, ["-maxconnections=0", "-nuparams=5ba81b19:10"]) + self.nodes.append(offline_node) + + assert_equal(0, len(offline_node.getpeerinfo())) # make sure node 1 has no peers + + privkeys = [self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress())] + taddr = self.nodes[0].getnewaddress() + + tx = self.nodes[0].listunspent()[0] + txid = tx['txid'] + scriptpubkey = tx['scriptPubKey'] + + create_inputs = [{'txid': txid, 'vout': 0}] + sign_inputs = [{'txid': txid, 'vout': 0, 'scriptPubKey': scriptpubkey, 'amount': 10}] + + create_hex = self.nodes[0].createrawtransaction(create_inputs, {taddr: 9.9999}) + + # An offline regtest node does not rely on the approx release height of the software + # to determine the consensus rules to be used for signing. + try: + signed_tx = offline_node.signrawtransaction(create_hex, sign_inputs, privkeys) + self.nodes[0].sendrawtransaction(signed_tx['hex']) + assert(False) + except JSONRPCException: + pass + + # Passing in the consensus branch id resolves the issue for offline regtest nodes. + signed_tx = offline_node.signrawtransaction(create_hex, sign_inputs, privkeys, "ALL", "5ba81b19") + + # If we return the transaction hash, then we have have not thrown an error (success) + online_tx_hash = self.nodes[0].sendrawtransaction(signed_tx['hex']) + assert_true(len(online_tx_hash) > 0) + +if __name__ == '__main__': + SignOfflineTest().main() \ No newline at end of file diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index 3c9821259..cd29c1791 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -41,9 +41,12 @@ 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 +SAPLING_PROTO_VERSION = 170006 MY_SUBVERSION = "/python-mininode-tester:0.0.1/" +OVERWINTER_VERSION_GROUP_ID = 0x03C48270 + MAX_INV_SZ = 50000 @@ -328,7 +331,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 +568,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 +595,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 +659,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 +902,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 +1260,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 +1331,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 +1392,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,14 +1409,14 @@ 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" vt.addrFrom.port = 0 self.send_message(vt, True) print 'MiniNode: Connecting to Bitcoin Node IP # ' + dstaddr + ':' \ - + str(dstport) + + str(dstport) + ' using version ' + str(protocol_version) try: self.connect((dstaddr, dstport)) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 5cb0d1b10..e9130171b 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -198,6 +198,21 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary= Start a komodod and return RPC connection to it """ datadir = os.path.join(dirname, "node"+str(i)) + # creating special config in case of cryptocondition asset chain test + if extra_args[0] == '-ac_name=REGTEST': + configpath = datadir + "/REGTEST.conf" + with open(configpath, "w+") as config: + config.write("regtest=1\n") + config.write("rpcuser=rt\n") + config.write("rpcpassword=rt\n") + port = extra_args[3] + config.write("rpcport=" + (port[9:]) + "\n") + config.write("server=1\n") + config.write("txindex=1\n") + config.write("rpcworkqueue=256\n") + config.write("rpcallowip=127.0.0.1\n") + config.write("bind=127.0.0.1\n") + config.write("rpcbind=127.0.0.1") if binary is None: binary = os.getenv("BITCOIND", "komodod") args = [ binary, "-datadir="+datadir, "-keypool=1", "-discover=0", "-rest" ] @@ -223,10 +238,8 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary= if os.getenv("PYTHON_DEBUG", ""): print "start_node: calling komodo-cli -rpcwait getblockcount returned" devnull.close() - if extra_args[0] == '-ac_name=REGTEST': - url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', 64368) - else: - url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i)) + port = extra_args[3] + url = "http://rt:rt@%s:%d" % (rpchost or '127.0.0.1', int(port[9:])) print("connecting to " + url) if timewait is not None: proxy = AuthServiceProxy(url, timeout=timewait) @@ -389,9 +402,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("(left == right)%s\n left: <%s>\n right: <%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: @@ -408,31 +430,36 @@ def assert_raises(exc, fun, *args, **kwds): raise AssertionError("No exception raised") # Returns txid if operation was a success or None -def wait_and_assert_operationid_status(node, myopid, in_status='success', in_errormsg=None): +def wait_and_assert_operationid_status(node, myopid, in_status='success', in_errormsg=None, timeout=300): print('waiting for async operation {}'.format(myopid)) - opids = [] - opids.append(myopid) - timeout = 300 - status = None - errormsg = None - txid = None - for x in xrange(1, timeout): - results = node.z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - if status == "failed": - errormsg = results[0]['error']['message'] - elif status == "success": - txid = results[0]['result']['txid'] + result = None + for _ in xrange(1, timeout): + results = node.z_getoperationresult([myopid]) + if len(results) > 0: + result = results[0] break - assert_equal(in_status, status) - if errormsg is not None: - assert(in_errormsg is not None) - assert_equal(in_errormsg in errormsg, True) + time.sleep(1) + + assert_true(result is not None, "timeout occured") + status = result['status'] + + txid = None + errormsg = None + if status == "failed": + errormsg = result['error']['message'] + elif status == "success": + txid = result['result']['txid'] + if os.getenv("PYTHON_DEBUG", ""): print('...returned status: {}'.format(status)) if errormsg is not None: print('...returned error: {}'.format(errormsg)) - return txid + + assert_equal(in_status, status, "Operation returned mismatched status. Error Message: {}".format(errormsg)) + + if errormsg is not None: + assert_true(in_errormsg is not None, "No error retured. Expected: {}".format(errormsg)) + assert_true(in_errormsg in errormsg, "Error returned: {}. Error expected: {}".format(errormsg, in_errormsg)) + return result # if there was an error return the result + else: + return txid # otherwise return the txid diff --git a/qa/rpc-tests/verushash.py b/qa/rpc-tests/verushash.py new file mode 100755 index 000000000..db1ab20e9 --- /dev/null +++ b/qa/rpc-tests/verushash.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 SuperNET 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.authproxy import JSONRPCException +from test_framework.util import assert_equal, assert_greater_than, \ + initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \ + stop_nodes, sync_blocks, sync_mempools, wait_bitcoinds, rpc_port, assert_raises + +import time +from decimal import Decimal +from random import choice +from string import ascii_uppercase + +def assert_success(result): + assert_equal(result['result'], 'success') + +def assert_error(result): + assert_equal(result['result'], 'error') + +def generate_random_string(length): + random_string = ''.join(choice(ascii_uppercase) for i in range(length)) + return random_string + + +class VerusHashTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing VerusHash test directory "+self.options.tmpdir) + self.num_nodes = 2 + initialize_chain_clean(self.options.tmpdir, self.num_nodes) + + def setup_network(self, split = False): + print("Setting up network...") + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, + extra_args=[[ + # always give -ac_name as first extra_arg and port as third + '-ac_name=REGTEST', + '-conf='+self.options.tmpdir+'/node0/REGTEST.conf', + '-port=64367', + '-rpcport=64368', + '-regtest', + '-addressindex=1', + '-spentindex=1', + '-ac_supply=5555555', + '-ac_reward=10000000000000', + '-ac_algo=verushash', + '-ac_cc=2', + '-whitelist=127.0.0.1', + '-debug', + '--daemon', + '-rpcuser=rt', + '-rpcpassword=rt' + ], + ['-ac_name=REGTEST', + '-conf='+self.options.tmpdir+'/node1/REGTEST.conf', + '-port=64365', + '-rpcport=64366', + '-regtest', + '-addressindex=1', + '-spentindex=1', + '-ac_supply=5555555', + '-ac_reward=10000000000000', + '-ac_algo=verushash', + '-ac_cc=2', + '-whitelist=127.0.0.1', + '-debug', + '-addnode=127.0.0.1:64367', + '--daemon', + '-rpcuser=rt', + '-rpcpassword=rt']] + ) + self.is_network_split = split + self.rpc = self.nodes[0] + self.rpc1 = self.nodes[1] + self.sync_all() + print("Done setting up network") + + def send_and_mine(self, xtn, rpc_connection): + txid = rpc_connection.sendrawtransaction(xtn) + assert txid, 'got txid' + # we need the tx above to be confirmed in the next block + rpc_connection.generate(1) + return txid + + def run_test (self): + print("Mining blocks...") + rpc = self.nodes[0] + rpc1 = self.nodes[1] + # utxos from block 1 become mature in block 101 + rpc.generate(101) + self.sync_all() + rpc.getinfo() + rpc1.getinfo() + +if __name__ == '__main__': + VerusHashTest ().main() diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 12dfac0e4..5d221a28c 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -8,9 +8,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.authproxy import JSONRPCException from test_framework.util import assert_equal, assert_greater_than, \ initialize_chain_clean, start_nodes, start_node, connect_nodes_bi, \ - stop_nodes, sync_blocks, sync_mempools, wait_bitcoinds + stop_nodes, sync_blocks, sync_mempools, wait_and_assert_operationid_status, \ + wait_bitcoinds -import time from decimal import Decimal class WalletTest (BitcoinTestFramework): @@ -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: @@ -199,7 +219,7 @@ class WalletTest (BitcoinTestFramework): for uTx in unspentTxs: if uTx['txid'] == zeroValueTxid: found = True - assert_equal(uTx['amount'], Decimal('0.00000000')); + assert_equal(uTx['amount'], Decimal('0.00000000')) assert(found) #do some -walletbroadcast tests @@ -211,13 +231,13 @@ class WalletTest (BitcoinTestFramework): connect_nodes_bi(self.nodes,0,2) self.sync_all() - txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2); + txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) self.sync_all() self.nodes[1].generate(1) #mine a block, tx should not be in there self.sync_all() - assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000')); #should not be changed because tx was not broadcasted - assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000')); #should not be changed because tx was not broadcasted + assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000')) #should not be changed because tx was not broadcasted + assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000')) #should not be changed because tx was not broadcasted #now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex']) @@ -225,11 +245,11 @@ class WalletTest (BitcoinTestFramework): self.nodes[1].generate(1) self.sync_all() txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) - assert_equal(self.nodes[2].getbalance(), Decimal('11.99800000')); #should not be - assert_equal(self.nodes[2].getbalance("*"), Decimal('11.99800000')); #should not be + assert_equal(self.nodes[2].getbalance(), Decimal('11.99800000')) #should not be + assert_equal(self.nodes[2].getbalance("*"), Decimal('11.99800000')) #should not be #create another tx - txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2); + txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) #restart the nodes with -walletbroadcast=1 stop_nodes(self.nodes) @@ -244,18 +264,18 @@ class WalletTest (BitcoinTestFramework): sync_blocks(self.nodes) #tx should be added to balance because after restarting the nodes tx should be broadcastet - assert_equal(self.nodes[2].getbalance(), Decimal('13.99800000')); #should not be - assert_equal(self.nodes[2].getbalance("*"), Decimal('13.99800000')); #should not be + assert_equal(self.nodes[2].getbalance(), Decimal('13.99800000')) #should not be + assert_equal(self.nodes[2].getbalance("*"), Decimal('13.99800000')) #should not be # send from node 0 to node 2 taddr - mytaddr = self.nodes[2].getnewaddress(); - mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0); + mytaddr = self.nodes[2].getnewaddress() + mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0) self.sync_all() self.nodes[0].generate(1) self.sync_all() mybalance = self.nodes[2].z_getbalance(mytaddr) - assert_equal(mybalance, Decimal('10.0')); + assert_equal(mybalance, Decimal('10.0')) mytxdetails = self.nodes[2].gettransaction(mytxid) myvjoinsplits = mytxdetails["vjoinsplit"] @@ -328,23 +348,9 @@ class WalletTest (BitcoinTestFramework): # send node 2 taddr to zaddr recipients = [] recipients.append({"address":myzaddr, "amount":7}) - myopid = self.nodes[2].z_sendmany(mytaddr, recipients) - opids = [] - opids.append(myopid) + mytxid = wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany(mytaddr, recipients)) - timeout = 300 - status = None - for x in xrange(1, timeout): - results = self.nodes[2].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - mytxid = results[0]["result"]["txid"] - break - - assert_equal("success", status) self.sync_all() self.nodes[2].generate(1) self.sync_all() @@ -358,7 +364,7 @@ class WalletTest (BitcoinTestFramework): assert_equal(self.nodes[2].getbalance("*"), node2utxobalance) # check zaddr balance - assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue); + assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue) # check via z_gettotalbalance resp = self.nodes[2].z_gettotalbalance() @@ -379,7 +385,6 @@ class WalletTest (BitcoinTestFramework): assert("randomSeed" in myjoinsplit.keys()) assert("ciphertexts" in myjoinsplit.keys()) - # send from private note to node 0 and node 2 node0balance = self.nodes[0].getbalance() # 25.99794745 node2balance = self.nodes[2].getbalance() # 16.99790000 @@ -387,20 +392,9 @@ class WalletTest (BitcoinTestFramework): recipients = [] recipients.append({"address":self.nodes[0].getnewaddress(), "amount":1}) recipients.append({"address":self.nodes[2].getnewaddress(), "amount":1.0}) - myopid = self.nodes[2].z_sendmany(myzaddr, recipients) + + wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany(myzaddr, recipients)) - status = None - opids = [] - opids.append(myopid) - for x in xrange(1, timeout): - results = self.nodes[2].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - break - - assert_equal("success", status) self.sync_all() self.nodes[2].generate(1) self.sync_all() @@ -433,7 +427,7 @@ class WalletTest (BitcoinTestFramework): except JSONRPCException,e: errorString = e.error['message'] - assert_equal("Invalid amount" in errorString, True); + assert_equal("Invalid amount" in errorString, True) errorString = "" try: @@ -441,7 +435,63 @@ class WalletTest (BitcoinTestFramework): except JSONRPCException,e: errorString = e.error['message'] - assert_equal("not an integer" in errorString, True); + 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__': 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_import_export.py b/qa/rpc-tests/wallet_import_export.py new file mode 100755 index 000000000..cdcc01d1f --- /dev/null +++ b/qa/rpc-tests/wallet_import_export.py @@ -0,0 +1,84 @@ +#!/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, start_nodes + +class WalletImportExportTest (BitcoinTestFramework): + def setup_network(self, split=False): + num_nodes = 3 + extra_args = [["-exportdir={}/export{}".format(self.options.tmpdir, i)] for i in range(num_nodes)] + self.nodes = start_nodes(num_nodes, self.options.tmpdir, extra_args) + + def run_test(self): + sapling_address2 = self.nodes[2].z_getnewaddress('sapling') + privkey2 = self.nodes[2].z_exportkey(sapling_address2) + self.nodes[0].z_importkey(privkey2) + + sprout_address0 = self.nodes[0].z_getnewaddress('sprout') + sapling_address0 = self.nodes[0].z_getnewaddress('sapling') + + # node 0 should have the keys + dump_path0 = self.nodes[0].z_exportwallet('walletdump') + (t_keys0, sprout_keys0, sapling_keys0) = parse_wallet_file(dump_path0) + + sapling_line_lengths = [len(sapling_key0.split(' #')[0].split()) for sapling_key0 in sapling_keys0.splitlines()] + assert_equal(2, len(sapling_line_lengths), "Should have 2 sapling keys") + assert_true(2 in sapling_line_lengths, "Should have a key with 2 parameters") + assert_true(4 in sapling_line_lengths, "Should have a key with 4 parameters") + + assert_true(sprout_address0 in sprout_keys0) + assert_true(sapling_address0 in sapling_keys0) + assert_true(sapling_address2 in sapling_keys0) + + # node 1 should not have the keys + dump_path1 = self.nodes[1].z_exportwallet('walletdumpbefore') + (t_keys1, sprout_keys1, sapling_keys1) = parse_wallet_file(dump_path1) + + assert_true(sprout_address0 not in sprout_keys1) + assert_true(sapling_address0 not in sapling_keys1) + + # import wallet to node 1 + self.nodes[1].z_importwallet(dump_path0) + + # node 1 should now have the keys + dump_path1 = self.nodes[1].z_exportwallet('walletdumpafter') + (t_keys1, sprout_keys1, sapling_keys1) = parse_wallet_file(dump_path1) + + assert_true(sprout_address0 in sprout_keys1) + assert_true(sapling_address0 in sapling_keys1) + assert_true(sapling_address2 in sapling_keys1) + + # make sure we have perserved the metadata + for sapling_key0 in sapling_keys0.splitlines(): + assert_true(sapling_key0 in sapling_keys1) + +# Helper functions +def parse_wallet_file(dump_path): + file_lines = open(dump_path, "r").readlines() + # We expect information about the HDSeed and fingerpring in the header + assert_true("HDSeed" in file_lines[4], "Expected HDSeed") + assert_true("fingerprint" in file_lines[4], "Expected fingerprint") + seed_comment_line = file_lines[4][2:].split() # ["HDSeed=...", "fingerprint=..."] + assert_true(seed_comment_line[0].split("=")[1] != seed_comment_line[1].split("=")[1], "The seed should not equal the fingerprint") + (t_keys, i) = parse_wallet_file_lines(file_lines, 0) + (sprout_keys, i) = parse_wallet_file_lines(file_lines, i) + (sapling_keys, i) = parse_wallet_file_lines(file_lines, i) + + return (t_keys, sprout_keys, sapling_keys) + +def parse_wallet_file_lines(file_lines, i): + keys = [] + # skip blank lines and comments + while i < len(file_lines) and (file_lines[i] == '\n' or file_lines[i].startswith("#")): + i += 1 + # add keys until we hit another blank line or comment + while i < len(file_lines) and not (file_lines[i] == '\n' or file_lines[i].startswith("#")): + keys.append(file_lines[i]) + i += 1 + return ("".join(keys), i) + +if __name__ == '__main__': + WalletImportExportTest().main() \ No newline at end of file diff --git a/qa/rpc-tests/wallet_listnotes.py b/qa/rpc-tests/wallet_listnotes.py new file mode 100755 index 000000000..5cd89c661 --- /dev/null +++ b/qa/rpc-tests/wallet_listnotes.py @@ -0,0 +1,168 @@ +#!/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 z_listunspent behaviour across network upgrades +class WalletListNotes(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): + # Current height = 200 -> Sprout + assert_equal(200, self.nodes[0].getblockcount()) + sproutzaddr = self.nodes[0].z_getnewaddress('sprout') + + # test that we can create a sapling zaddr before sapling activates + saplingzaddr = self.nodes[0].z_getnewaddress('sapling') + + # we've got lots of coinbase (taddr) but no shielded funds yet + assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private'])) + + # Set current height to 201 -> Sprout + self.nodes[0].generate(1) + self.sync_all() + assert_equal(201, self.nodes[0].getblockcount()) + + mining_addr = self.nodes[0].listunspent()[0]['address'] + + # Shield coinbase funds (must be a multiple of 10, no change allowed pre-sapling) + receive_amount_10 = Decimal('10.0') - Decimal('0.0001') + recipients = [{"address":sproutzaddr, "amount":receive_amount_10}] + myopid = self.nodes[0].z_sendmany(mining_addr, recipients) + txid_1 = wait_and_assert_operationid_status(self.nodes[0], myopid) + self.sync_all() + + # No funds (with (default) one or more confirmations) in sproutzaddr yet + assert_equal(0, len(self.nodes[0].z_listunspent())) + assert_equal(0, len(self.nodes[0].z_listunspent(1))) + + # no private balance because no confirmations yet + assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private'])) + + # list private unspent, this time allowing 0 confirmations + unspent_cb = self.nodes[0].z_listunspent(0) + assert_equal(1, len(unspent_cb)) + assert_equal(False, unspent_cb[0]['change']) + assert_equal(txid_1, unspent_cb[0]['txid']) + assert_equal(True, unspent_cb[0]['spendable']) + assert_equal(sproutzaddr, unspent_cb[0]['address']) + assert_equal(receive_amount_10, unspent_cb[0]['amount']) + + # list unspent, filtering by address, should produce same result + unspent_cb_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr]) + assert_equal(unspent_cb, unspent_cb_filter) + + # Generate a block to confirm shield coinbase tx + self.nodes[0].generate(1) + self.sync_all() + + # Current height = 202 -> Overwinter. Default address type remains Sprout + assert_equal(202, self.nodes[0].getblockcount()) + + # Send 1.0 (actually 0.9999) from sproutzaddr to a new zaddr + sproutzaddr2 = self.nodes[0].z_getnewaddress() + receive_amount_1 = Decimal('1.0') - Decimal('0.0001') + change_amount_9 = receive_amount_10 - Decimal('1.0') + assert_equal('sprout', self.nodes[0].z_validateaddress(sproutzaddr2)['type']) + recipients = [{"address": sproutzaddr2, "amount":receive_amount_1}] + myopid = self.nodes[0].z_sendmany(sproutzaddr, recipients) + txid_2 = wait_and_assert_operationid_status(self.nodes[0], myopid) + self.sync_all() + + # list unspent, allowing 0conf txs + unspent_tx = self.nodes[0].z_listunspent(0) + assert_equal(len(unspent_tx), 2) + # sort low-to-high by amount (order of returned entries is not guaranteed) + unspent_tx = sorted(unspent_tx, key=lambda k: k['amount']) + assert_equal(False, unspent_tx[0]['change']) + assert_equal(txid_2, unspent_tx[0]['txid']) + assert_equal(True, unspent_tx[0]['spendable']) + assert_equal(sproutzaddr2, unspent_tx[0]['address']) + assert_equal(receive_amount_1, unspent_tx[0]['amount']) + + assert_equal(True, unspent_tx[1]['change']) + assert_equal(txid_2, unspent_tx[1]['txid']) + assert_equal(True, unspent_tx[1]['spendable']) + assert_equal(sproutzaddr, unspent_tx[1]['address']) + assert_equal(change_amount_9, unspent_tx[1]['amount']) + + unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr2]) + assert_equal(1, len(unspent_tx_filter)) + assert_equal(unspent_tx[0], unspent_tx_filter[0]) + + unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr]) + assert_equal(1, len(unspent_tx_filter)) + assert_equal(unspent_tx[1], unspent_tx_filter[0]) + + # Set current height to 204 -> Sapling + self.nodes[0].generate(2) + self.sync_all() + assert_equal(204, self.nodes[0].getblockcount()) + + # No funds in saplingzaddr yet + assert_equal(0, len(self.nodes[0].z_listunspent(0, 9999, False, [saplingzaddr]))) + + # Send 0.9999 to our sapling zaddr + # (sending from a sprout zaddr to a sapling zaddr is disallowed, + # so send from coin base) + receive_amount_2 = Decimal('2.0') - Decimal('0.0001') + recipients = [{"address": saplingzaddr, "amount":receive_amount_2}] + myopid = self.nodes[0].z_sendmany(mining_addr, recipients) + txid_3 = wait_and_assert_operationid_status(self.nodes[0], myopid) + self.sync_all() + unspent_tx = self.nodes[0].z_listunspent(0) + assert_equal(3, len(unspent_tx)) + + # low-to-high in amount + unspent_tx = sorted(unspent_tx, key=lambda k: k['amount']) + + assert_equal(False, unspent_tx[0]['change']) + assert_equal(txid_2, unspent_tx[0]['txid']) + assert_equal(True, unspent_tx[0]['spendable']) + assert_equal(sproutzaddr2, unspent_tx[0]['address']) + assert_equal(receive_amount_1, unspent_tx[0]['amount']) + + assert_equal(False, unspent_tx[1]['change']) + assert_equal(txid_3, unspent_tx[1]['txid']) + assert_equal(True, unspent_tx[1]['spendable']) + assert_equal(saplingzaddr, unspent_tx[1]['address']) + assert_equal(receive_amount_2, unspent_tx[1]['amount']) + + assert_equal(True, unspent_tx[2]['change']) + assert_equal(txid_2, unspent_tx[2]['txid']) + assert_equal(True, unspent_tx[2]['spendable']) + assert_equal(sproutzaddr, unspent_tx[2]['address']) + assert_equal(change_amount_9, unspent_tx[2]['amount']) + + unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [saplingzaddr]) + assert_equal(1, len(unspent_tx_filter)) + assert_equal(unspent_tx[1], unspent_tx_filter[0]) + + # test that pre- and post-sapling can be filtered in a single call + unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, + [sproutzaddr, saplingzaddr]) + assert_equal(2, len(unspent_tx_filter)) + unspent_tx_filter = sorted(unspent_tx_filter, key=lambda k: k['amount']) + assert_equal(unspent_tx[1], unspent_tx_filter[0]) + assert_equal(unspent_tx[2], unspent_tx_filter[1]) + + # so far, this node has no watchonly addresses, so results are the same + unspent_tx_watchonly = self.nodes[0].z_listunspent(0, 9999, True) + unspent_tx_watchonly = sorted(unspent_tx_watchonly, key=lambda k: k['amount']) + assert_equal(unspent_tx, unspent_tx_watchonly) + + # TODO: use z_exportviewingkey, z_importviewingkey to test includeWatchonly + # but this requires Sapling support for those RPCs + +if __name__ == '__main__': + WalletListNotes().main() diff --git a/qa/rpc-tests/wallet_listreceived.py b/qa/rpc-tests/wallet_listreceived.py new file mode 100755 index 000000000..9ece27772 --- /dev/null +++ b/qa/rpc-tests/wallet_listreceived.py @@ -0,0 +1,98 @@ +#!/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 +from test_framework.util import start_nodes, wait_and_assert_operationid_status +from decimal import Decimal + +my_memo = 'c0ffee' # stay awake +my_memo = my_memo + '0'*(1024-len(my_memo)) + +no_memo = 'f6' + ('0'*1022) # see section 5.5 of the protocol spec + +fee = Decimal('0.0001') + +class ListReceivedTest (BitcoinTestFramework): + + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir, [[ + "-nuparams=5ba81b19:201", # Overwinter + "-nuparams=76b809bb:204", # Sapling + ]] * 4) + + def generate_and_sync(self, new_height): + self.nodes[0].generate(1) + self.sync_all() + assert_equal(new_height, self.nodes[0].getblockcount()) + + def run_test_release(self, release, expected_memo, height): + self.generate_and_sync(height+1) + taddr = self.nodes[1].getnewaddress() + zaddr1 = self.nodes[1].z_getnewaddress(release) + + self.nodes[0].sendtoaddress(taddr, 2.0) + self.generate_and_sync(height+2) + + # Send 1 ZEC to zaddr1 + opid = self.nodes[1].z_sendmany(taddr, + [{'address': zaddr1, 'amount': 1, 'memo': my_memo}]) + txid = wait_and_assert_operationid_status(self.nodes[1], opid) + self.sync_all() + r = self.nodes[1].z_listreceivedbyaddress(zaddr1) + assert_equal(0, len(r), "Should have received no confirmed note") + + # No confirmation required, one note should be present + r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) + assert_equal(1, len(r), "Should have received one (unconfirmed) note") + assert_equal(txid, r[0]['txid']) + assert_equal(1, r[0]['amount']) + assert_false(r[0]['change'], "Note should not be change") + assert_equal(my_memo, r[0]['memo']) + + # Confirm transaction (1 ZEC from taddr to zaddr1) + self.generate_and_sync(height+3) + + # Require one confirmation, note should be present + assert_equal(r, self.nodes[1].z_listreceivedbyaddress(zaddr1)) + + # Generate some change by sending part of zaddr1 to zaddr2 + zaddr2 = self.nodes[1].z_getnewaddress(release) + opid = self.nodes[1].z_sendmany(zaddr1, + [{'address': zaddr2, 'amount': 0.6, 'memo': my_memo}]) + txid = wait_and_assert_operationid_status(self.nodes[1], opid) + self.sync_all() + self.generate_and_sync(height+4) + + # zaddr1 should have a note with change + r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0) + r = sorted(r, key = lambda received: received['amount']) + assert_equal(2, len(r), "zaddr1 Should have received 2 notes") + + assert_equal(txid, r[0]['txid']) + assert_equal(Decimal('0.4')-fee, r[0]['amount']) + assert_true(r[0]['change'], "Note valued at (0.4-fee) should be change") + assert_equal(expected_memo, r[0]['memo']) + + # The old note still exists (it's immutable), even though it is spent + assert_equal(Decimal('1.0'), r[1]['amount']) + assert_false(r[1]['change'], "Note valued at 1.0 should not be change") + assert_equal(expected_memo, r[0]['memo']) + + # zaddr2 should not have change + r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0) + r = sorted(r, key = lambda received: received['amount']) + assert_equal(1, len(r), "zaddr2 Should have received 1 notes") + assert_equal(txid, r[0]['txid']) + assert_equal(Decimal('0.6'), r[0]['amount']) + assert_false(r[0]['change'], "Note valued at 0.6 should not be change") + assert_equal(my_memo, r[0]['memo']) + + def run_test(self): + self.run_test_release('sprout', no_memo, 200) + self.run_test_release('sapling', no_memo, 204) + +if __name__ == '__main__': + ListReceivedTest().main() diff --git a/qa/rpc-tests/wallet_nullifiers.py b/qa/rpc-tests/wallet_nullifiers.py index 207631efb..9b4e5649c 100755 --- a/qa/rpc-tests/wallet_nullifiers.py +++ b/qa/rpc-tests/wallet_nullifiers.py @@ -5,10 +5,9 @@ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, start_node, \ - start_nodes, connect_nodes_bi, bitcoind_processes +from test_framework.util import assert_equal, assert_true, bitcoind_processes, \ + connect_nodes_bi, start_node, start_nodes, wait_and_assert_operationid_status -import time from decimal import Decimal class WalletNullifiersTest (BitcoinTestFramework): @@ -22,25 +21,11 @@ class WalletNullifiersTest (BitcoinTestFramework): myzaddr0 = self.nodes[0].z_getnewaddress() # send node 0 taddr to zaddr to get out of coinbase - mytaddr = self.nodes[0].getnewaddress(); + mytaddr = self.nodes[0].getnewaddress() recipients = [] recipients.append({"address":myzaddr0, "amount":Decimal('10.0')-Decimal('0.0001')}) # utxo amount less fee - myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - - opids = [] - opids.append(myopid) - - timeout = 120 - status = None - for x in xrange(1, timeout): - results = self.nodes[0].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - assert_equal("success", status) - mytxid = results[0]["result"]["txid"] - break + + wait_and_assert_operationid_status(self.nodes[0], self.nodes[0].z_sendmany(mytaddr, recipients), timeout=120) self.sync_all() self.nodes[0].generate(1) @@ -66,22 +51,8 @@ class WalletNullifiersTest (BitcoinTestFramework): # send node 0 zaddr to note 2 zaddr recipients = [] recipients.append({"address":myzaddr, "amount":7.0}) - myopid = self.nodes[0].z_sendmany(myzaddr0, recipients) - - opids = [] - opids.append(myopid) - - timeout = 120 - status = None - for x in xrange(1, timeout): - results = self.nodes[0].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - assert_equal("success", status) - mytxid = results[0]["result"]["txid"] - break + + wait_and_assert_operationid_status(self.nodes[0], self.nodes[0].z_sendmany(myzaddr0, recipients), timeout=120) self.sync_all() self.nodes[0].generate(1) @@ -98,22 +69,8 @@ class WalletNullifiersTest (BitcoinTestFramework): # send node 2 zaddr to note 3 zaddr recipients = [] recipients.append({"address":myzaddr3, "amount":2.0}) - myopid = self.nodes[2].z_sendmany(myzaddr, recipients) - opids = [] - opids.append(myopid) - - timeout = 120 - status = None - for x in xrange(1, timeout): - results = self.nodes[2].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - assert_equal("success", status) - mytxid = results[0]["result"]["txid"] - break + wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany(myzaddr, recipients), timeout=120) self.sync_all() self.nodes[2].generate(1) @@ -136,26 +93,11 @@ class WalletNullifiersTest (BitcoinTestFramework): # This requires that node 1 be unlocked, which triggers caching of # uncached nullifiers. self.nodes[1].walletpassphrase("test", 600) - mytaddr1 = self.nodes[1].getnewaddress(); + mytaddr1 = self.nodes[1].getnewaddress() recipients = [] recipients.append({"address":mytaddr1, "amount":1.0}) - myopid = self.nodes[1].z_sendmany(myzaddr, recipients) - - opids = [] - opids.append(myopid) - - timeout = 120 - status = None - for x in xrange(1, timeout): - results = self.nodes[1].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - assert_equal("success", status) - mytxid = results[0]["result"]["txid"] - [mytxid] # hush pyflakes - break + + wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(myzaddr, recipients), timeout=120) self.sync_all() self.nodes[1].generate(1) @@ -188,10 +130,23 @@ 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_persistence.py b/qa/rpc-tests/wallet_persistence.py new file mode 100755 index 000000000..f6c227d2a --- /dev/null +++ b/qa/rpc-tests/wallet_persistence.py @@ -0,0 +1,131 @@ +#!/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, + start_nodes, stop_nodes, + initialize_chain_clean, connect_nodes_bi, wait_bitcoinds, + wait_and_assert_operationid_status +) +from decimal import Decimal + +class WalletPersistenceTest (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): + self.nodes = start_nodes(3, self.options.tmpdir, + extra_args=[[ + '-nuparams=5ba81b19:100', # Overwinter + '-nuparams=76b809bb:201', # Sapling + ]] * 3) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + self.is_network_split=False + self.sync_all() + + def run_test(self): + # Sanity-check the test harness + self.nodes[0].generate(200) + assert_equal(self.nodes[0].getblockcount(), 200) + self.sync_all() + + # Verify Sapling address is persisted in wallet (even when Sapling is not yet active) + sapling_addr = self.nodes[0].z_getnewaddress('sapling') + + # Make sure the node has the addresss + addresses = self.nodes[0].z_listaddresses() + assert_true(sapling_addr in addresses, "Should contain address before restart") + + # Restart the nodes + stop_nodes(self.nodes) + wait_bitcoinds() + self.setup_network() + + # Make sure we still have the address after restarting + addresses = self.nodes[0].z_listaddresses() + assert_true(sapling_addr in addresses, "Should contain address after restart") + + # Activate Sapling + self.nodes[0].generate(1) + self.sync_all() + + # Node 0 shields funds to Sapling address + taddr0 = self.nodes[0].getnewaddress() + recipients = [] + recipients.append({"address": sapling_addr, "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[0].generate(1) + self.sync_all() + + # Verify shielded balance + assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20')) + + # Restart the nodes + stop_nodes(self.nodes) + wait_bitcoinds() + self.setup_network() + + # Node 0 sends some shielded funds to Node 1 + dest_addr = self.nodes[1].z_getnewaddress('sapling') + recipients = [] + recipients.append({"address": dest_addr, "amount": Decimal('15')}) + myopid = self.nodes[0].z_sendmany(sapling_addr, recipients, 1, 0) + wait_and_assert_operationid_status(self.nodes[0], myopid) + + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + # Verify balances + assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5')) + assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15')) + + # Restart the nodes + stop_nodes(self.nodes) + wait_bitcoinds() + self.setup_network() + + # Verify balances + assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5')) + assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15')) + + # Verify importing a spending key will update and persist the nullifiers and witnesses correctly + sk0 = self.nodes[0].z_exportkey(sapling_addr) + self.nodes[2].z_importkey(sk0, "yes") + assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5')) + + # Restart the nodes + stop_nodes(self.nodes) + wait_bitcoinds() + self.setup_network() + + # Verify nullifiers persisted correctly by checking balance + # Prior to PR #3590, there will be an error as spent notes are considered unspent: + # Assertion failed: expected: <25.00000000> but was: <5> + assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5')) + + # Verity witnesses persisted correctly by sending shielded funds + recipients = [] + recipients.append({"address": dest_addr, "amount": Decimal('1')}) + myopid = self.nodes[2].z_sendmany(sapling_addr, recipients, 1, 0) + wait_and_assert_operationid_status(self.nodes[2], myopid) + + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + # Verify balances + assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('4')) + assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16')) + +if __name__ == '__main__': + WalletPersistenceTest().main() \ No newline at end of file diff --git a/qa/rpc-tests/wallet_protectcoinbase.py b/qa/rpc-tests/wallet_protectcoinbase.py index afe851a16..71512840d 100755 --- a/qa/rpc-tests/wallet_protectcoinbase.py +++ b/qa/rpc-tests/wallet_protectcoinbase.py @@ -8,10 +8,9 @@ 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 import timeit from decimal import Decimal @@ -82,52 +81,29 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework): self.nodes[3].importaddress(mytaddr) recipients= [{"address":myzaddr, "amount": Decimal('1')}] myopid = self.nodes[3].z_sendmany(mytaddr, recipients) - errorString="" - status = None - opids = [myopid] - timeout = 10 - for x in xrange(1, timeout): - results = self.nodes[3].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - errorString = results[0]["error"]["message"] - 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() + + wait_and_assert_operationid_status(self.nodes[3], myopid, "failed", "no UTXOs found for taddr from address", 10) # 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. recipients = [] recipients.append({"address":myzaddr, "amount":Decimal('1.23456789')}) - errorString = "" + myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - opids = [] - opids.append(myopid) - timeout = 10 - status = None - for x in xrange(1, timeout): - results = self.nodes[0].z_getoperationresult(opids) - if len(results)==0: - time.sleep(1) - else: - status = results[0]["status"] - errorString = results[0]["error"]["message"] + error_result = wait_and_assert_operationid_status(self.nodes[0], myopid, "failed", "wallet does not allow any change", 10) - # Test that the returned status object contains a params field with the operation's input parameters - assert_equal(results[0]["method"], "z_sendmany") - params =results[0]["params"] - assert_equal(params["fee"], Decimal('0.0001')) # default - assert_equal(params["minconf"], Decimal('1')) # default - assert_equal(params["fromaddress"], mytaddr) - assert_equal(params["amounts"][0]["address"], myzaddr) - assert_equal(params["amounts"][0]["amount"], Decimal('1.23456789')) - break - assert_equal("failed", status) - assert_equal("wallet does not allow any change" in errorString, True) + # Test that the returned status object contains a params field with the operation's input parameters + assert_equal(error_result["method"], "z_sendmany") + params = error_result["params"] + assert_equal(params["fee"], Decimal('0.0001')) # default + assert_equal(params["minconf"], Decimal('1')) # default + assert_equal(params["fromaddress"], mytaddr) + assert_equal(params["amounts"][0]["address"], myzaddr) + assert_equal(params["amounts"][0]["amount"], Decimal('1.23456789')) + + # 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') @@ -136,9 +112,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 +236,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 +343,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..1abb1e8dc --- /dev/null +++ b/qa/rpc-tests/wallet_sapling.py @@ -0,0 +1,202 @@ +#!/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.authproxy import JSONRPCException +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:203', # Sapling + '-experimentalfeatures', '-zmergetoaddress', + ]] * 4) + + def run_test(self): + # Sanity-check the test harness + assert_equal(self.nodes[0].getblockcount(), 200) + + # Activate Overwinter + self.nodes[2].generate(1) + self.sync_all() + + # Verify RPCs disallow Sapling value transfer if Sapling is not active + tmp_taddr = self.nodes[3].getnewaddress() + tmp_zaddr = self.nodes[3].z_getnewaddress('sapling') + try: + recipients = [] + recipients.append({"address": tmp_zaddr, "amount": Decimal('20')}) + self.nodes[3].z_sendmany(tmp_taddr, recipients, 1, 0) + raise AssertionError("Should have thrown an exception") + except JSONRPCException as e: + assert_equal("Invalid parameter, Sapling has not activated", e.error['message']) + try: + recipients = [] + recipients.append({"address": tmp_taddr, "amount": Decimal('20')}) + self.nodes[3].z_sendmany(tmp_zaddr, recipients, 1, 0) + raise AssertionError("Should have thrown an exception") + except JSONRPCException as e: + assert_equal("Invalid parameter, Sapling has not activated", e.error['message']) + try: + self.nodes[3].z_shieldcoinbase(tmp_taddr, tmp_zaddr) + raise AssertionError("Should have thrown an exception") + except JSONRPCException as e: + assert_equal("Invalid parameter, Sapling has not activated", e.error['message']) + + # Verify z_mergetoaddress RPC does not support Sapling yet + try: + self.nodes[3].z_mergetoaddress([tmp_taddr], tmp_zaddr) + raise AssertionError("Should have thrown an exception") + except JSONRPCException as e: + assert_equal("Invalid parameter, Sapling is not supported yet by z_mergetoadress", e.error['message']) + try: + self.nodes[3].z_mergetoaddress([tmp_zaddr], tmp_taddr) + raise AssertionError("Should have thrown an exception") + except JSONRPCException as e: + assert_equal("Invalid parameter, Sapling is not supported yet by z_mergetoadress", e.error['message']) + + # Activate Sapling + self.nodes[2].generate(2) + 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) + mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) + + self.sync_all() + + # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000) + mempool = self.nodes[0].getrawmempool(True) + assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16')) + + 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) + mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid) + + self.sync_all() + + # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000) + mempool = self.nodes[0].getrawmempool(True) + assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16')) + + 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) + mytxid = wait_and_assert_operationid_status(self.nodes[1], myopid) + + self.sync_all() + + # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000) + mempool = self.nodes[1].getrawmempool(True) + assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16')) + + 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')) + + # Verify existence of Sapling related JSON fields + resp = self.nodes[0].getrawtransaction(mytxid, 1) + assert_equal(resp['valueBalance'], Decimal('5')) + assert(len(resp['vShieldedSpend']) == 1) + assert(len(resp['vShieldedOutput']) == 2) + assert('bindingSig' in resp) + shieldedSpend = resp['vShieldedSpend'][0] + assert('cv' in shieldedSpend) + assert('anchor' in shieldedSpend) + assert('nullifier' in shieldedSpend) + assert('rk' in shieldedSpend) + assert('proof' in shieldedSpend) + assert('spendAuthSig' in shieldedSpend) + shieldedOutput = resp['vShieldedOutput'][0] + assert('cv' in shieldedOutput) + assert('cmu' in shieldedOutput) + assert('ephemeralKey' in shieldedOutput) + assert('encCiphertext' in shieldedOutput) + assert('outCiphertext' in shieldedOutput) + assert('proof' in shieldedOutput) + + # Verify importing a spending key will update the nullifiers and witnesses correctly + sk0 = self.nodes[0].z_exportkey(saplingAddr0) + self.nodes[2].z_importkey(sk0, "yes") + assert_equal(self.nodes[2].z_getbalance(saplingAddr0), Decimal('10')) + sk1 = self.nodes[1].z_exportkey(saplingAddr1) + self.nodes[2].z_importkey(sk1, "yes") + assert_equal(self.nodes[2].z_getbalance(saplingAddr1), Decimal('5')) + + # Make sure we get a useful error when trying to send to both sprout and sapling + node4_sproutaddr = self.nodes[3].z_getnewaddress('sprout') + node4_saplingaddr = self.nodes[3].z_getnewaddress('sapling') + try: + self.nodes[1].z_sendmany( + taddr1, + [{'address': node4_sproutaddr, 'amount': 2.5}, {'address': node4_saplingaddr, 'amount': 2.4999}], + 1, 0.0001 + ) + raise AssertionError("Should have thrown an exception") + except JSONRPCException as e: + assert_equal("Cannot send to both Sprout and Sapling addresses using z_sendmany", e.error['message']) + +if __name__ == '__main__': + WalletSaplingTest().main() diff --git a/qa/rpc-tests/wallet_shieldcoinbase.py b/qa/rpc-tests/wallet_shieldcoinbase.py index b77fedcf0..d8366c81d 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase.py +++ b/qa/rpc-tests/wallet_shieldcoinbase.py @@ -12,6 +12,9 @@ from test_framework.util import assert_equal, initialize_chain_clean, \ from decimal import Decimal class WalletShieldCoinbaseTest (BitcoinTestFramework): + def __init__(self, addr_type): + super(WalletShieldCoinbaseTest, self).__init__() + self.addr_type = addr_type def setup_chain(self): print("Initializing test directory "+self.options.tmpdir) @@ -19,10 +22,17 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): def setup_network(self, split=False): args = ['-regtestprotectcoinbase', '-debug=zrpcunsafe'] + args2 = ['-regtestprotectcoinbase', '-debug=zrpcunsafe', "-mempooltxinputlimit=7"] + if self.addr_type != 'sprout': + nu = [ + '-nuparams=5ba81b19:0', # Overwinter + '-nuparams=76b809bb:1', # Sapling + ] + args.extend(nu) + args2 = args self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, args)) self.nodes.append(start_node(1, self.options.tmpdir, args)) - args2 = ['-regtestprotectcoinbase', '-debug=zrpcunsafe', "-mempooltxinputlimit=7"] self.nodes.append(start_node(2, self.options.tmpdir, args2)) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) @@ -55,7 +65,7 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): # Prepare to send taddr->zaddr mytaddr = self.nodes[0].getnewaddress() - myzaddr = self.nodes[0].z_getnewaddress() + myzaddr = self.nodes[0].z_getnewaddress(self.addr_type) # Shielding will fail when trying to spend from watch-only address self.nodes[2].importaddress(mytaddr) @@ -135,26 +145,33 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): self.sync_all() mytaddr = self.nodes[0].getnewaddress() - # Shielding the 800 utxos will occur over two transactions, since max tx size is 100,000 bytes. - # We don't verify shieldingValue as utxos are not selected in any specific order, so value can change on each test run. - # We set an unrealistically high limit parameter of 99999, to verify that max tx size will constrain the number of utxos. - result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, 99999) - assert_equal(result["shieldingUTXOs"], Decimal('662')) - assert_equal(result["remainingUTXOs"], Decimal('138')) - remainingValue = result["remainingValue"] - opid1 = result['opid'] + def verify_locking(first, second, limit): + result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, limit) + assert_equal(result["shieldingUTXOs"], Decimal(first)) + assert_equal(result["remainingUTXOs"], Decimal(second)) + remainingValue = result["remainingValue"] + opid1 = result['opid'] - # Verify that utxos are locked (not available for selection) by queuing up another shielding operation - result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, 0) - assert_equal(result["shieldingValue"], Decimal(remainingValue)) - assert_equal(result["shieldingUTXOs"], Decimal('138')) - assert_equal(result["remainingValue"], Decimal('0')) - assert_equal(result["remainingUTXOs"], Decimal('0')) - opid2 = result['opid'] + # Verify that utxos are locked (not available for selection) by queuing up another shielding operation + result = self.nodes[0].z_shieldcoinbase(mytaddr, myzaddr, 0, 0) + assert_equal(result["shieldingValue"], Decimal(remainingValue)) + assert_equal(result["shieldingUTXOs"], Decimal(second)) + assert_equal(result["remainingValue"], Decimal('0')) + assert_equal(result["remainingUTXOs"], Decimal('0')) + opid2 = result['opid'] - # wait for both aysnc operations to complete - wait_and_assert_operationid_status(self.nodes[0], opid1) - wait_and_assert_operationid_status(self.nodes[0], opid2) + # wait for both aysnc operations to complete + wait_and_assert_operationid_status(self.nodes[0], opid1) + wait_and_assert_operationid_status(self.nodes[0], opid2) + + if self.addr_type == 'sprout': + # Shielding the 800 utxos will occur over two transactions, since max tx size is 100,000 bytes. + # We don't verify shieldingValue as utxos are not selected in any specific order, so value can change on each test run. + # We set an unrealistically high limit parameter of 99999, to verify that max tx size will constrain the number of utxos. + verify_locking('662', '138', 99999) + else: + # Shield the 800 utxos over two transactions + verify_locking('500', '300', 500) # sync_all() invokes sync_mempool() but node 2's mempool limit will cause tx1 and tx2 to be rejected. # So instead, we sync on blocks and mempool for node 0 and node 1, and after a new block is generated @@ -164,16 +181,17 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): self.nodes[1].generate(1) self.sync_all() - # Verify maximum number of utxos which node 2 can shield is limited by option -mempooltxinputlimit - # This option is used when the limit parameter is set to 0. - mytaddr = self.nodes[2].getnewaddress() - result = self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001'), 0) - assert_equal(result["shieldingUTXOs"], Decimal('7')) - assert_equal(result["remainingUTXOs"], Decimal('13')) - wait_and_assert_operationid_status(self.nodes[2], result['opid']) - self.sync_all() - self.nodes[1].generate(1) - self.sync_all() + if self.addr_type == 'sprout': + # Verify maximum number of utxos which node 2 can shield is limited by option -mempooltxinputlimit + # This option is used when the limit parameter is set to 0. + mytaddr = self.nodes[2].getnewaddress() + result = self.nodes[2].z_shieldcoinbase(mytaddr, myzaddr, Decimal('0.0001'), 0) + assert_equal(result["shieldingUTXOs"], Decimal('7')) + assert_equal(result["remainingUTXOs"], Decimal('13')) + wait_and_assert_operationid_status(self.nodes[2], result['opid']) + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() # Verify maximum number of utxos which node 0 can shield is set by default limit parameter of 50 self.nodes[0].generate(200) @@ -194,6 +212,3 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): sync_mempools(self.nodes[:2]) self.nodes[1].generate(1) self.sync_all() - -if __name__ == '__main__': - WalletShieldCoinbaseTest().main() diff --git a/qa/rpc-tests/wallet_shieldcoinbase_sapling.py b/qa/rpc-tests/wallet_shieldcoinbase_sapling.py new file mode 100755 index 000000000..d5d130329 --- /dev/null +++ b/qa/rpc-tests/wallet_shieldcoinbase_sapling.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python2 +import inspect +import os + +# To keep pyflakes happy +WalletShieldCoinbaseTest = object + +cwd = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +execfile(os.path.join(cwd, 'wallet_shieldcoinbase.py')) + +class WalletShieldCoinbaseSapling(WalletShieldCoinbaseTest): + def __init__(self): + super(WalletShieldCoinbaseSapling, self).__init__('sapling') + +if __name__ == '__main__': + WalletShieldCoinbaseSapling().main() diff --git a/qa/rpc-tests/wallet_shieldcoinbase_sprout.py b/qa/rpc-tests/wallet_shieldcoinbase_sprout.py new file mode 100755 index 000000000..619ae7caf --- /dev/null +++ b/qa/rpc-tests/wallet_shieldcoinbase_sprout.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python2 +import inspect +import os + +# To keep pyflakes happy +WalletShieldCoinbaseTest = object + +cwd = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +execfile(os.path.join(cwd, 'wallet_shieldcoinbase.py')) + +class WalletShieldCoinbaseSprout(WalletShieldCoinbaseTest): + def __init__(self): + super(WalletShieldCoinbaseSprout, self).__init__('sprout') + +if __name__ == '__main__': + WalletShieldCoinbaseSprout().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/verus-cli-tests/verus-cli-tester.py b/qa/verus-cli-tests/verus-cli-tester.py new file mode 100644 index 000000000..147686110 --- /dev/null +++ b/qa/verus-cli-tests/verus-cli-tester.py @@ -0,0 +1,39 @@ +from subprocess import Popen, check_output, call +from time import sleep +from os import environ, path + +daemon_wrapper = "verusd" +cli_wrapper = "verus" +daemon_runtime_seconds = 600 +cli_commands = ["getblockchaininfo", "getmininginfo", "getwalletinfo", "stop"] + + +def start_daemon(daemon_wrapper): + try: + Popen(daemon_wrapper, shell=True, close_fds=True) + except: + exit(1) + + +def fetch_zcash_params(): + try: + call("fetch-params", shell=True) + except: + exit(1) + + +def run_cli_commands(cli_wrapper, commands): + for command in commands: + command = "%(cli_wrapper)s %(command)s" % locals() + try: + with open(path.join(environ["CI_PROJECT_DIR"], "log.txt"), "a") as log: + command_output = check_output(command, shell=True) + log.write("%(command_output)s\n" % locals()) + except: + exit(1) + + +fetch_zcash_params() +start_daemon(daemon_wrapper) +sleep(daemon_runtime_seconds) +run_cli_commands(cli_wrapper, cli_commands) 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 2bd18df4d..35b9b0120 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,10 +21,12 @@ $(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 +BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/src +BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/src/asn BITCOIN_INCLUDES += -I$(srcdir)/snark BITCOIN_INCLUDES += -I$(srcdir)/snark/libsnark BITCOIN_INCLUDES += -I$(srcdir)/univalue/include @@ -34,7 +37,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 @@ -42,59 +45,74 @@ LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a +LIBVERUS_CRYPTO=crypto/libverus_crypto.a +LIBVERUS_PORTABLE_CRYPTO=crypto/libverus_portable_crypto.a 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) + $(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" + $(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" + $(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/ + $(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) + $(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 \ - libbitcoin_util.a \ - libbitcoin_common.a \ - libbitcoin_server.a \ - libbitcoin_cli.a \ - libzcash.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 = @@ -121,7 +139,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 # @@ -140,6 +159,7 @@ BITCOIN_CORE_H = \ asyncrpcoperation.h \ asyncrpcqueue.h \ base58.h \ + bech32.h \ bloom.h \ cc/eval.h \ chain.h \ @@ -162,14 +182,18 @@ BITCOIN_CORE_H = \ consensus/validation.h \ core_io.h \ core_memusage.h \ + crypto/haraka.h \ + crypto/haraka_portable.h \ + crypto/verus_hash.h \ deprecation.h \ hash.h \ httprpc.h \ httpserver.h \ init.h \ key.h \ + key_io.h \ keystore.h \ - leveldbwrapper.h \ + dbwrapper.h \ limitedmap.h \ main.h \ memusage.h \ @@ -185,15 +209,18 @@ BITCOIN_CORE_H = \ paymentdisclosuredb.h \ policy/fees.h \ pow.h \ + prevector.h \ primitives/block.h \ primitives/transaction.h \ + primitives/nonce.h \ protocol.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 \ @@ -213,6 +240,7 @@ BITCOIN_CORE_H = \ timedata.h \ tinyformat.h \ torcontrol.h \ + transaction_builder.h \ txdb.h \ txmempool.h \ ui_interface.h \ @@ -230,9 +258,11 @@ 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 \ + veruslaunch.h \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h\ zmq/zmqnotificationinterface.h \ @@ -281,15 +311,19 @@ libbitcoin_server_a_SOURCES = \ chain.cpp \ checkpoints.cpp \ crosschain.cpp \ - crosschain_authority.cpp \ + crosschain_authority.cpp \ + crypto/haraka.h \ + crypto/haraka_portable.h \ + crypto/verus_hash.h \ + crypto/verus_hash.cpp \ deprecation.cpp \ httprpc.cpp \ httpserver.cpp \ init.cpp \ - leveldbwrapper.cpp \ + dbwrapper.cpp \ main.cpp \ merkleblock.cpp \ - metrics.cpp \ + metrics.h \ miner.cpp \ net.cpp \ notaries_staked.cpp \ @@ -300,14 +334,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 \ @@ -317,8 +352,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 = \ @@ -328,8 +361,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 = \ @@ -353,6 +384,7 @@ libbitcoin_wallet_a_SOURCES = \ wallet/db.cpp \ paymentdisclosure.cpp \ paymentdisclosuredb.cpp \ + transaction_builder.cpp \ wallet/rpcdisclosure.cpp \ wallet/rpcdump.cpp \ cc/CCassetstx.cpp \ @@ -361,6 +393,7 @@ libbitcoin_wallet_a_SOURCES = \ wallet/wallet.cpp \ wallet/wallet_ismine.cpp \ wallet/walletdb.cpp \ + zcash/zip32.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) @@ -368,22 +401,26 @@ libbitcoin_wallet_a_SOURCES = \ crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES) crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crypto_libbitcoin_crypto_a_SOURCES = \ - crypto/common.h \ - crypto/equihash.cpp \ - crypto/equihash.h \ - crypto/equihash.tcc \ - crypto/hmac_sha256.cpp \ - crypto/hmac_sha256.h \ - crypto/hmac_sha512.cpp \ - crypto/hmac_sha512.h \ - crypto/ripemd160.cpp \ - crypto/ripemd160.h \ - crypto/sha1.cpp \ - crypto/sha1.h \ - crypto/sha256.cpp \ - crypto/sha256.h \ - crypto/sha512.cpp \ - crypto/sha512.h + crypto/common.h \ + crypto/equihash.cpp \ + crypto/equihash.h \ + crypto/equihash.tcc \ + crypto/hmac_sha256.cpp \ + crypto/hmac_sha256.h \ + crypto/hmac_sha512.cpp \ + crypto/hmac_sha512.h \ + crypto/ripemd160.cpp \ + crypto/ripemd160.h \ + crypto/sha1.cpp \ + crypto/sha1.h \ + crypto/sha256.cpp \ + crypto/sha256.h \ + crypto/sha512.cpp \ + crypto/sha512.h \ + crypto/haraka.h \ + crypto/haraka_portable.h \ + crypto/verus_hash.h \ + crypto/verus_hash.cpp if ENABLE_MINING EQUIHASH_TROMP_SOURCES = \ @@ -397,35 +434,60 @@ crypto_libbitcoin_crypto_a_SOURCES += \ ${EQUIHASH_TROMP_SOURCES} endif +# Verus hash specific library - optimized +crypto_libverus_crypto_a_CPPFLAGS = -O3 -Wint-conversion -march=x86-64 -msse4 -msse4.1 -msse4.2 -mssse3 -mavx -maes -g -funroll-loops -fomit-frame-pointer -fPIC $(AM_CPPFLAGS) +crypto_libverus_crypto_a_CXXFLAGS = -O3 -Wint-conversion -march=x86-64 -msse4 -msse4.1 -msse4.2 -mssse3 -mavx -maes -g -funroll-loops -fomit-frame-pointer -fPIC $(AM_CXXFLAGS) +crypto_libverus_crypto_a_SOURCES = \ + crypto/haraka.h \ + crypto/haraka.c + +# Verus hash specific library - portable +crypto_libverus_portable_crypto_a_CPPFLAGS = -O3 -Wint-conversion -march=x86-64 -g -funroll-loops -fomit-frame-pointer -fPIC $(AM_CPPFLAGS) +crypto_libverus_portable_crypto_a_CXXFLAGS = -O3 -Wint-conversion -march=x86-64 -g -funroll-loops -fomit-frame-pointer -fPIC $(AM_CXXFLAGS) +crypto_libverus_portable_crypto_a_SOURCES = \ + crypto/haraka_portable.h \ + crypto/haraka_portable.c + # common: shared between zcashd and non-server tools -libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +libbitcoin_common_a_CPPFLAGS = -fPIC $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_common_a_CXXFLAGS = -fPIC $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_common_a_SOURCES = \ amount.cpp \ arith_uint256.cpp \ base58.cpp \ + bech32.cpp \ chainparams.cpp \ coins.cpp \ compressor.cpp \ consensus/upgrades.cpp \ core_read.cpp \ core_write.cpp \ + crypto/haraka.h \ + crypto/haraka_portable.h \ + crypto/verus_hash.h \ + crypto/verus_hash.cpp \ hash.cpp \ importcoin.cpp \ key.cpp \ + key_io.cpp \ keystore.cpp \ netbase.cpp \ + metrics.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ + primitives/nonce.cpp \ protocol.cpp \ pubkey.cpp \ scheduler.cpp \ script/cc.cpp \ script/interpreter.cpp \ script/script.cpp \ + script/script_ext.cpp \ script/script_error.cpp \ script/sign.cpp \ script/standard.cpp \ + veruslaunch.cpp \ + transaction_builder.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) @@ -435,23 +497,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 @@ -461,9 +523,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 # @@ -483,7 +545,11 @@ komodod_LDADD = \ $(LIBBITCOIN_COMMON) \ $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ + $(LIBBITCOIN_ZMQ) \ + $(LIBBITCOIN_PROTON) \ $(LIBBITCOIN_CRYPTO) \ + $(LIBVERUS_CRYPTO) \ + $(LIBVERUS_PORTABLE_CRYPTO) \ $(LIBZCASH) \ $(LIBSNARK) \ $(LIBLEVELDB) \ @@ -491,12 +557,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 += \ @@ -506,7 +568,11 @@ komodod_LDADD += \ $(CRYPTO_LIBS) \ $(EVENT_PTHREADS_LIBS) \ $(EVENT_LIBS) \ + $(ZMQ_LIBS) \ + $(PROTON_LIBS) \ $(LIBBITCOIN_CRYPTO) \ + $(LIBVERUS_CRYPTO) \ + $(LIBVERUS_PORTABLE_CRYPTO) \ $(LIBZCASH_LIBS) if ENABLE_PROTON @@ -541,6 +607,8 @@ komodo_cli_LDADD = \ $(EVENT_LIBS) \ $(LIBZCASH) \ $(LIBBITCOIN_CRYPTO) \ + $(LIBVERUS_CRYPTO) \ + $(LIBVERUS_PORTABLE_CRYPTO) \ $(LIBZCASH_LIBS) if ENABLE_WALLET @@ -548,6 +616,8 @@ wallet_utility_LDADD = \ libbitcoin_wallet.a \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_CRYPTO) \ + $(LIBVERUS_CRYPTO) \ + $(LIBVERUS_PORTABLE_CRYPTO) \ $(LIBSECP256K1) \ $(LIBBITCOIN_UTIL) \ $(BOOST_LIBS) \ @@ -578,6 +648,8 @@ komodo_tx_LDADD = \ $(LIBZCASH) \ $(LIBSNARK) \ $(LIBBITCOIN_CRYPTO) \ + $(LIBVERUS_CRYPTO) \ + $(LIBVERUS_PORTABLE_CRYPTO) \ $(LIBZCASH_LIBS) \ $(LIBCRYPTOCONDITIONS) @@ -594,6 +666,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 \ @@ -603,6 +676,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 @@ -619,6 +696,7 @@ libzcashconsensus_la_SOURCES = \ crypto/sha512.cpp \ hash.cpp \ primitives/transaction.cpp \ + primitives/nonce.cpp \ pubkey.cpp \ script/zcashconsensus.cpp \ script/interpreter.cpp \ @@ -648,6 +726,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 @@ -680,5 +759,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 f70672052..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 @@ -49,7 +54,7 @@ endif komodo_gtest_CPPFLAGS = $(AM_CPPFLAGS) -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES) komodo_gtest_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -komodo_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ +komodo_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) if ENABLE_ZMQ zcash_gtest_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index c21016737..6afc3a707 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -361,7 +361,7 @@ qt_komodo_qt_LDADD = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER) if ENABLE_WALLET qt_komodo_qt_LDADD += $(LIBBITCOIN_WALLET) endif -qt_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ +qt_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBZCASH_LIBS) qt_komodo_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) qt_komodo_qt_LIBTOOLFLAGS = --tag CXX diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 3e57a8926..2d56d07e3 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -30,7 +30,7 @@ qt_test_test_komodo_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER) if ENABLE_WALLET qt_test_test_komodo_qt_LDADD += $(LIBBITCOIN_WALLET) endif -qt_test_test_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \ +qt_test_test_komodo_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \ $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBZCASH_LIBS) qt_test_test_komodo_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index a52b66335..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 += \ @@ -102,12 +113,15 @@ endif test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS) -test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ +test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBVERUS_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) 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/Makefile.zcash.include b/src/Makefile.zcash.include index da5b4344d..4302b2e0d 100644 --- a/src/Makefile.zcash.include +++ b/src/Makefile.zcash.include @@ -24,6 +24,7 @@ zcash_CreateJoinSplit_LDADD = \ $(LIBSNARK) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ + $(LIBVERUS_CRYPTO) \ $(BOOST_LIBS) \ $(LIBZCASH_LIBS) \ $(LIBCRYPTOCONDITIONS) \ 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/assetchains.json b/src/assetchains.json index 447de4ca6..2e2f38a8f 100644 --- a/src/assetchains.json +++ b/src/assetchains.json @@ -66,18 +66,6 @@ "190.114.254.104" ] }, - { - "ac_name": "KMDICE", - "ac_supply": "10500000", - "ac_reward": "2500000000", - "ac_halving": "210000", - "ac_cc": "2", - "addressindex": "1", - "spentindex": "1", - "addnode": [ - "144.76.217.232" - ] - }, { "ac_name": "DION", "ac_supply": "3900000000", 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 c086cc854..12978fa1c 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(); @@ -215,6 +213,7 @@ public: CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {} bool operator()(const CKeyID& id) const { return addr->Set(id); } + bool operator()(const CPubKey& key) const { return addr->Set(key); } bool operator()(const CScriptID& id) const { return addr->Set(id); } bool operator()(const CNoDestination& no) const { return false; } }; @@ -227,6 +226,13 @@ bool CBitcoinAddress::Set(const CKeyID& id) return true; } +bool CBitcoinAddress::Set(const CPubKey& key) +{ + CKeyID id = key.GetID(); + SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); + return true; +} + bool CBitcoinAddress::Set(const CScriptID& id) { SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); @@ -302,6 +308,14 @@ bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const return true; } +bool CBitcoinAddress::GetKeyID_NoCheck(CKeyID& keyID) const +{ + uint160 id; + memcpy(&id, &vchData[0], 20); + keyID = CKeyID(id); + return true; +} + bool CBitcoinAddress::IsScript() const { return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); @@ -373,27 +387,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 73e1c4d94..66cb7e7a0 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. @@ -149,6 +116,7 @@ public: class CBitcoinAddress : public CBase58Data { public: bool Set(const CKeyID &id); + bool Set(const CPubKey &key); bool Set(const CScriptID &id); bool Set(const CTxDestination &dest); bool IsValid() const; @@ -163,6 +131,7 @@ public: CTxDestination Get() const; bool GetKeyID(CKeyID &keyID) const; + bool GetKeyID_NoCheck(CKeyID& keyID) const; bool GetIndexKey(uint160& hashBytes, int& type) const; bool IsScript() const; }; 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 d7c906669..31cfd9a3d 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" @@ -22,14 +22,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")); @@ -43,6 +41,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; } @@ -90,8 +89,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 // @@ -111,29 +118,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; } @@ -202,7 +213,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()); @@ -217,7 +228,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 @@ -227,7 +238,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())); @@ -260,26 +271,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 @@ -287,15 +298,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); @@ -347,7 +360,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 (...) { @@ -366,12 +379,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 80fef2c0f..34e1b5d91 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 @@ -42,6 +41,7 @@ */ static bool fDaemon; +#include "komodo_defs.h" #define KOMODO_ASSETCHAIN_MAXLEN 65 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; void komodo_passport_iteration(); @@ -115,7 +115,7 @@ bool AppInit(int argc, char* argv[]) } fprintf(stdout, "%s", strUsage.c_str()); - return false; + return true; } try @@ -179,7 +179,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 +236,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/CC made easy b/src/cc/CC made easy.md similarity index 100% rename from src/cc/CC made easy rename to src/cc/CC made easy.md diff --git a/src/cc/CCGateways.h b/src/cc/CCGateways.h index e82add62b..2470665d4 100644 --- a/src/cc/CCGateways.h +++ b/src/cc/CCGateways.h @@ -20,15 +20,18 @@ #include "CCinclude.h" #include "../merkleblock.h" -bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector pubkeys); std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount); std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount); std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount); +std::string GatewaysPartialSign(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex); +std::string GatewaysCompleteSigning(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex); +std::string GatewaysMarkDone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin); UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin); -std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,uint256 cointxid); +UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin); UniValue GatewaysMultisig(char *txidaddr); -std::string GatewaysPartialSign(uint64_t txfee,uint256 txidaddr,std::string refcoin, std::string hex); + // CCcustom UniValue GatewaysInfo(uint256 bindtxid); diff --git a/src/cc/CCHeir.h b/src/cc/CCHeir.h index c86bf3b6b..9a8193428 100644 --- a/src/cc/CCHeir.h +++ b/src/cc/CCHeir.h @@ -21,7 +21,7 @@ #define EVAL_HEIR 0xea -bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); // CCcustom UniValue HeirInfo(); diff --git a/src/cc/CCOracles.h b/src/cc/CCOracles.h index 41409d5c5..5e2fcc8b9 100644 --- a/src/cc/CCOracles.h +++ b/src/cc/CCOracles.h @@ -19,7 +19,7 @@ #include "CCinclude.h" -bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format); std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee); std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount); diff --git a/src/cc/CCPayments.h b/src/cc/CCPayments.h index 7e7a0e681..18f6cb7ef 100644 --- a/src/cc/CCPayments.h +++ b/src/cc/CCPayments.h @@ -19,7 +19,7 @@ #include "CCinclude.h" -bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); // CCcustom UniValue PaymentsInfo(); diff --git a/src/cc/CCPegs.h b/src/cc/CCPegs.h index 296e0c272..0e20d278f 100644 --- a/src/cc/CCPegs.h +++ b/src/cc/CCPegs.h @@ -19,7 +19,7 @@ #include "CCinclude.h" -bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); // CCcustom UniValue PegsInfo(); diff --git a/src/cc/CCPrices.h b/src/cc/CCPrices.h index f375ee10a..55877cce0 100644 --- a/src/cc/CCPrices.h +++ b/src/cc/CCPrices.h @@ -19,7 +19,7 @@ #include "CCinclude.h" -bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); // CCcustom UniValue PricesList(); diff --git a/src/cc/CCTriggers.h b/src/cc/CCTriggers.h index 4e9881c52..bd243842f 100644 --- a/src/cc/CCTriggers.h +++ b/src/cc/CCTriggers.h @@ -19,7 +19,7 @@ #include "CCinclude.h" -bool TriggersValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool TriggersValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); // CCcustom UniValue TriggersInfo(); diff --git a/src/cc/CCassets.h b/src/cc/CCassets.h index 4d4f30b3b..a48195970 100644 --- a/src/cc/CCassets.h +++ b/src/cc/CCassets.h @@ -26,7 +26,7 @@ #include "CCinclude.h" // CCcustom -bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); // CCassetsCore //CTxOut MakeAssetsVout(CAmount nValue,CPubKey pk); diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 64b380900..ef208f87c 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -56,7 +56,8 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK int64_t GetAssetBalance(CPubKey pk,uint256 tokenid) { - CMutableTransaction mtx; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_ASSETS); return(AddAssetInputs(cp,mtx,pk,tokenid,0,0)); } @@ -186,7 +187,8 @@ UniValue AssetOrders(uint256 refassetid) std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description) { - CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; struct CCcontract_info *cp,C; if ( assetsupply < 0 ) { fprintf(stderr,"negative assetsupply %lld\n",(long long)assetsupply); @@ -212,7 +214,8 @@ std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std:: std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total) { - CMutableTransaction mtx; CPubKey mypk; uint64_t mask; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; uint64_t mask; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C; if ( total < 0 ) { fprintf(stderr,"negative total %lld\n",(long long)total); @@ -222,7 +225,7 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector des if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { /*n = outputs.size(); if ( n == amounts.size() ) @@ -247,7 +250,8 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector des std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total,int32_t evalcode) { - CMutableTransaction mtx; CPubKey mypk; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C; if ( total < 0 ) { fprintf(stderr,"negative total %lld\n",(long long)total); @@ -257,7 +261,7 @@ std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector dest if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 ) { @@ -273,7 +277,8 @@ std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector dest std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal) { - CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx; std::vector origpubkey; std::string name,description; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx; std::vector origpubkey; std::string name,description; if ( bidamount < 0 || pricetotal < 0 ) { fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n",(long long)bidamount,(long long)pricetotal); @@ -303,7 +308,8 @@ std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64 std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal) { - CMutableTransaction mtx; CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C; if ( askamount < 0 || pricetotal < 0 ) { fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount); @@ -313,7 +319,7 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { mask = ~((1LL << mtx.vin.size()) - 1); if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 ) @@ -335,7 +341,8 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 assetid2,int64_t pricetotal) { - CMutableTransaction mtx; CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C; fprintf(stderr,"asset swaps disabled\n"); return(""); if ( askamount < 0 || pricetotal < 0 ) @@ -347,7 +354,7 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { mask = ~((1LL << mtx.vin.size()) - 1); if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 ) @@ -374,12 +381,13 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) { - CMutableTransaction mtx; CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t bidamount; CPubKey mypk; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t bidamount; CPubKey mypk; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_ASSETS); if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { mask = ~((1LL << mtx.vin.size()) - 1); if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 ) @@ -395,12 +403,13 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) { - CMutableTransaction mtx; CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_ASSETS); if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { mask = ~((1LL << mtx.vin.size()) - 1); if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 ) @@ -416,7 +425,8 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount) { - CTransaction vintx; uint256 hashBlock; CMutableTransaction mtx; CPubKey mypk; std::vector origpubkey; int32_t bidvout=0; uint64_t mask; int64_t origprice,bidamount,paid_amount,remaining_required,inputs,CCchange=0; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction vintx; uint256 hashBlock; CPubKey mypk; std::vector origpubkey; int32_t bidvout=0; uint64_t mask; int64_t origprice,bidamount,paid_amount,remaining_required,inputs,CCchange=0; struct CCcontract_info *cp,C; if ( fillamount < 0 ) { fprintf(stderr,"negative fillamount %lld\n",(long long)fillamount); @@ -426,7 +436,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { mask = ~((1LL << mtx.vin.size()) - 1); if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 ) @@ -456,7 +466,8 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillunits) { - CTransaction vintx,filltx; uint256 hashBlock; CMutableTransaction mtx; CPubKey mypk; std::vector origpubkey; double dprice; uint64_t mask; int32_t askvout=0; int64_t received_assetoshis,total_nValue,orig_assetoshis,paid_nValue,remaining_nValue,inputs,CCchange=0; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction vintx,filltx; uint256 hashBlock; CPubKey mypk; std::vector origpubkey; double dprice; uint64_t mask; int32_t askvout=0; int64_t received_assetoshis,total_nValue,orig_assetoshis,paid_nValue,remaining_nValue,inputs,CCchange=0; struct CCcontract_info *cp,C; if ( fillunits < 0 ) { CCerror = strprintf("negative fillunits %lld\n",(long long)fillunits); @@ -474,7 +485,7 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { mask = ~((1LL << mtx.vin.size()) - 1); if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 ) diff --git a/src/cc/CCauction.h b/src/cc/CCauction.h index 855cdf72e..be636e76b 100644 --- a/src/cc/CCauction.h +++ b/src/cc/CCauction.h @@ -21,7 +21,7 @@ #define EVAL_AUCTION 0xe8 -bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); std::string AuctionPost(uint64_t txfee,uint256 itemhash,int64_t minbid,char *title,char *description); std::string AuctionBid(uint64_t txfee,uint256 itemhash,int64_t amount); diff --git a/src/cc/CCchannels.h b/src/cc/CCchannels.h index f67ef9a6c..7715a31b8 100644 --- a/src/cc/CCchannels.h +++ b/src/cc/CCchannels.h @@ -20,7 +20,7 @@ #include "CCinclude.h" #define CHANNELS_MAXPAYMENTS 1000 -bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment); std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint256 secret); std::string ChannelClose(uint64_t txfee,uint256 opentxid); diff --git a/src/cc/CCcustom.cpp b/src/cc/CCcustom.cpp index 3cd3625e7..b17a7cd89 100644 --- a/src/cc/CCcustom.cpp +++ b/src/cc/CCcustom.cpp @@ -13,6 +13,7 @@ * * ******************************************************************************/ +#include "key_io.h" #include "CCinclude.h" #include "CCassets.h" #include "CCfaucet.h" @@ -221,7 +222,7 @@ uint8_t GatewaysCCpriv[32] = { 0xf7, 0x4b, 0x5b, 0xa2, 0x7a, 0x5e, 0x9c, 0xda, 0 #undef FUNCNAME #undef EVALCODE -struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode) +struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode) { cp->evalcode = evalcode; switch ( evalcode ) diff --git a/src/cc/CCdice.h b/src/cc/CCdice.h index 4a526bfcf..cb0398129 100644 --- a/src/cc/CCdice.h +++ b/src/cc/CCdice.h @@ -21,7 +21,7 @@ #define EVAL_DICE 0xe6 -bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds); std::string DiceBetFinish(uint8_t &funcid,uint256 &entropyused,int32_t &entropyvout,int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout,uint256 vin0txid,int32_t vin0vout); diff --git a/src/cc/CCfaucet.h b/src/cc/CCfaucet.h index 39930cb20..895327d09 100644 --- a/src/cc/CCfaucet.h +++ b/src/cc/CCfaucet.h @@ -22,7 +22,7 @@ #define EVAL_FAUCET 0xe4 #define FAUCETSIZE (COIN / 10) -bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); // CCcustom std::string FaucetFund(uint64_t txfee,int64_t funds); diff --git a/src/cc/CCfsm.h b/src/cc/CCfsm.h index c6ea17024..0aafdb6b9 100644 --- a/src/cc/CCfsm.h +++ b/src/cc/CCfsm.h @@ -21,7 +21,7 @@ #define EVAL_FSM 0xe7 -bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); std::string FSMList(); std::string FSMInfo(uint256 fsmtxid); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 6c404cc17..73400e381 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -57,12 +57,13 @@ extern char ASSETCHAINS_SYMBOL[]; extern std::string CCerror; #define SMALLVAL 0.000000000000001 -#define MIN_NOTARIZATION_CONFIRMS 2 #ifndef _BITS256 #define _BITS256 -union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; -typedef union _bits256 bits256; + union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; + typedef union _bits256 bits256; #endif + + struct CC_utxo { uint256 txid; @@ -70,13 +71,23 @@ struct CC_utxo int32_t vout; }; +// these are the parameters stored after Verus crypto-condition vouts. new versions may change +// the format +struct CC_meta +{ + std::vector version; + uint8_t evalCode; + bool is1of2; + uint8_t numDestinations; + // followed by address destinations +}; + struct CCcontract_info { - uint256 prevtxid; char unspendableCCaddr[64],CChexstr[72],normaladdr[64],unspendableaddr2[64],unspendableaddr3[64]; uint8_t CCpriv[32],unspendablepriv2[32],unspendablepriv3[32]; CPubKey unspendablepk2,unspendablepk3; - bool (*validate)(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); + bool (*validate)(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn); bool (*ismyvin)(CScript const& scriptSig); uint8_t evalcode,evalcode2,evalcode3,didinit; }; @@ -93,11 +104,13 @@ struct oracleprice_info extern CWallet* pwalletMain; #endif bool GetAddressUnspent(uint160 addressHash, int type,std::vector > &unspentOutputs); +CBlockIndex *komodo_getblockindex(uint256 hash); +int32_t komodo_nextheight(); static const uint256 zeroid; bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock); int32_t is_hexstr(char *str,int32_t n); -bool myAddtomempool(CTransaction &tx); +bool myAddtomempool(CTransaction &tx, CValidationState *pstate = NULL); //uint64_t myGettxout(uint256 hash,int32_t n); bool myIsutxo_spentinmempool(uint256 txid,int32_t vout); bool mytxid_inmempool(uint256 txid); @@ -108,6 +121,8 @@ int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t * CScript GetScriptForMultisig(int nRequired, const std::vector& keys); int64_t CCaddress_balance(char *coinaddr); CPubKey CCtxidaddr(char *txidaddr,uint256 txid); +bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn, + CTransaction &txOut, std::vector> &preConditions, std::vector> ¶ms); int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format); uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format); @@ -156,8 +171,9 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey); std::vector Mypubkey(); bool Myprivkey(uint8_t myprivkey[]); int64_t CCduration(int32_t &numblocks,uint256 txid); -bool isCCTxNotarizedConfirmed(uint256 txid); +bool komodo_txnotarizedconfirmed(uint256 txid); // CCtx +bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey); std::string FinalizeCCTx(uint64_t skipmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret); void SetCCunspents(std::vector > &unspentOutputs,char *coinaddr); void SetCCtxids(std::vector > &addressIndex,char *coinaddr); diff --git a/src/cc/CClotto.h b/src/cc/CClotto.h index 784441c57..838aac338 100644 --- a/src/cc/CClotto.h +++ b/src/cc/CClotto.h @@ -21,7 +21,7 @@ #define EVAL_LOTTO 0xe9 -bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); UniValue LottoInfo(uint256 lottoid); UniValue LottoList(); diff --git a/src/cc/CCrewards.h b/src/cc/CCrewards.h index ef675797c..ac90423b2 100644 --- a/src/cc/CCrewards.h +++ b/src/cc/CCrewards.h @@ -22,7 +22,7 @@ #define EVAL_REWARDS 0xe5 #define REWARDSCC_MAXAPR (COIN * 25) -bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); UniValue RewardsInfo(uint256 rewardid); UniValue RewardsList(); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index d927119d6..b94e1372c 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. @@ -348,7 +349,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3 LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos)); - threshold = total/maxinputs; + threshold = total/(maxinputs+1); if ( maxinputs > maxutxos ) maxutxos = maxinputs; sum = 0; diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index cbd4fba7a..e10d97224 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -13,11 +13,20 @@ * * ******************************************************************************/ -#include "CCinclude.h" - /* CCutils has low level functions that are universally useful for all contracts. */ +#include "CCinclude.h" +#include "komodo_structs.h" + +#ifdef TESTMODE + #define MIN_NON_NOTARIZED_CONFIRMS 2 +#else + #define MIN_NON_NOTARIZED_CONFIRMS 101 +#endif // TESTMODE +int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); +struct komodo_state *komodo_stateptr(char *symbol,char *dest); +extern uint32_t KOMODO_DPOWCONFS; void endiancpy(uint8_t *dest,uint8_t *src,int32_t len) { @@ -198,6 +207,48 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey) return(false); } +bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn, + CTransaction &txOut, std::vector> &preConditions, std::vector> ¶ms) +{ + uint256 blockHash; + + if (myGetTransaction(tx.vin[nIn].prevout.hash, txOut, blockHash) && txOut.vout.size() > tx.vin[nIn].prevout.n) + { + CBlockIndex index; + if (eval->GetBlock(blockHash, index)) + { + // read preconditions + CScript subScript = CScript(); + preConditions.clear(); + if (txOut.vout[tx.vin[nIn].prevout.n].scriptPubKey.IsPayToCryptoCondition(&subScript, preConditions)) + { + // read any available parameters in the output transaction + params.clear(); + if (tx.vout.size() > 0 && tx.vout[tx.vout.size() - 1].scriptPubKey.IsOpReturn()) + { + if (tx.vout[tx.vout.size() - 1].scriptPubKey.GetOpretData(params) && params.size() == 1) + { + CScript scr = CScript(params[0].begin(), params[0].end()); + + // printf("Script decoding inner:\n%s\nouter:\n%s\n", scr.ToString().c_str(), tx.vout[tx.vout.size() - 1].scriptPubKey.ToString().c_str()); + + if (!scr.GetPushedData(scr.begin(), params)) + { + return false; + } + else return true; + } + else return false; + } + else return true; + } + } + } + return false; + //fprintf(stderr,"ExtractDestination failed\n"); + return(false); +} + bool pubkey2addr(char *destaddr,uint8_t *pubkey33) { std::vectorpk; int32_t i; @@ -368,9 +419,9 @@ bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector param cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0; if ( paramsNull.size() != 0 ) // Don't expect params return eval->Invalid("Cannot have params"); - else if ( ctx.vout.size() == 0 ) - return eval->Invalid("no-vouts"); - else if ( (*cp->validate)(cp,eval,ctx) != 0 ) + //else if ( ctx.vout.size() == 0 ) // spend can go to z-addresses + // return eval->Invalid("no-vouts"); + else if ( (*cp->validate)(cp,eval,ctx,nIn) != 0 ) { //fprintf(stderr,"done CC %02x\n",cp->evalcode); //cp->prevtxid = txid; @@ -394,29 +445,60 @@ int64_t CCduration(int32_t &numblocks,uint256 txid) //fprintf(stderr,"CCduration no hashBlock for txid %s\n",uint256_str(str,txid)); return(0); } - else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txtime= pindex->nTime) == 0 || (txheight= pindex->nHeight) <= 0 ) + else if ( (pindex= komodo_getblockindex(hashBlock)) == 0 || (txtime= pindex->nTime) == 0 || (txheight= pindex->GetHeight()) <= 0 ) { fprintf(stderr,"CCduration no txtime %u or txheight.%d %p for txid %s\n",txtime,txheight,pindex,uint256_str(str,txid)); return(0); } - else if ( (pindex= chainActive.LastTip()) == 0 || pindex->nTime < txtime || pindex->nHeight <= txheight ) + else if ( (pindex= chainActive.LastTip()) == 0 || pindex->nTime < txtime || pindex->GetHeight() <= txheight ) { if ( pindex->nTime < txtime ) - fprintf(stderr,"CCduration backwards timestamps %u %u for txid %s hts.(%d %d)\n",(uint32_t)pindex->nTime,txtime,uint256_str(str,txid),txheight,(int32_t)pindex->nHeight); + fprintf(stderr,"CCduration backwards timestamps %u %u for txid %s hts.(%d %d)\n",(uint32_t)pindex->nTime,txtime,uint256_str(str,txid),txheight,(int32_t)pindex->GetHeight()); return(0); } - numblocks = (pindex->nHeight - txheight); + numblocks = (pindex->GetHeight() - txheight); duration = (pindex->nTime - txtime); - //fprintf(stderr,"duration %d (%u - %u) numblocks %d (%d - %d)\n",(int32_t)duration,(uint32_t)pindex->nTime,txtime,numblocks,pindex->nHeight,txheight); + //fprintf(stderr,"duration %d (%u - %u) numblocks %d (%d - %d)\n",(int32_t)duration,(uint32_t)pindex->nTime,txtime,numblocks,pindex->GetHeight(),txheight); return(duration); } -bool isCCTxNotarizedConfirmed(uint256 txid) +bool komodo_txnotarizedconfirmed(uint256 txid) { - int32_t confirms; + char str[65]; + uint32_t confirms,notarized=0,txheight; + CTransaction tx; + uint256 hashBlock; + CBlockIndex *pindex; + char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; - CCduration(confirms,txid); - if (confirms >= MIN_NOTARIZATION_CONFIRMS) + if ( myGetTransaction(txid,tx,hashBlock) == 0 ) + { + fprintf(stderr,"komodo_txnotarizedconfirmed cant find txid %s\n",txid.ToString().c_str()); + return(0); + } + else if ( hashBlock == zeroid ) + { + fprintf(stderr,"komodo_txnotarizedconfirmed no hashBlock for txid %s\n",txid.ToString().c_str()); + return(0); + } + else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txheight= pindex->GetHeight()) <= 0 ) + { + fprintf(stderr,"komodo_txnotarizedconfirmed no txheight.%d %p for txid %s\n",txheight,pindex,txid.ToString().c_str()); + return(0); + } + else if ( (pindex= chainActive.LastTip()) == 0 || pindex->GetHeight() < txheight ) + { + fprintf(stderr,"komodo_txnotarizedconfirmed backwards heights for txid %s hts.(%d %d)\n",txid.ToString().c_str(),txheight,(int32_t)pindex->GetHeight()); + return(0); + } + confirms=1 + pindex->GetHeight() - txheight; + if ((sp= komodo_stateptr(symbol,dest)) != 0 && (notarized=sp->NOTARIZED_HEIGHT) > 0 && txheight > sp->NOTARIZED_HEIGHT) notarized=0; +#ifdef TESTMODE + notarized=0; +#endif //TESTMODE + if (notarized>0 && confirms > 1) + return (true); + else if (notarized==0 && confirms >= MIN_NON_NOTARIZED_CONFIRMS) return (true); return (false); } diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index a421f9e44..41a0ed7b1 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -129,7 +129,7 @@ vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey] */ -bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { static uint256 zero; CTxDestination address; CTransaction vinTx,createTx; uint256 hashBlock,assetid,assetid2; int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts; int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector origpubkey,tmporigpubkey,ignorepubkey; uint8_t funcid; char destaddr[64],origaddr[64],CCaddr[64]; diff --git a/src/cc/auction.cpp b/src/cc/auction.cpp index d0d8db0bb..1bc8533ec 100644 --- a/src/cc/auction.cpp +++ b/src/cc/auction.cpp @@ -70,7 +70,7 @@ bool AuctionExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransactio else return(true); } -bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval; return(false); // reject any auction CC for now @@ -150,7 +150,8 @@ int64_t AddAuctionInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPu std::string AuctionBid(uint64_t txfee,uint256 itemhash,int64_t amount) { - CMutableTransaction mtx; CPubKey mypk,Auctionpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,Auctionpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_AUCTION); if ( txfee == 0 ) txfee = 10000; @@ -170,7 +171,8 @@ std::string AuctionBid(uint64_t txfee,uint256 itemhash,int64_t amount) std::string AuctionDeliver(uint64_t txfee,uint256 itemhash,uint256 bidtxid) { - CMutableTransaction mtx; CPubKey mypk,Auctionpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,Auctionpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_AUCTION); if ( txfee == 0 ) txfee = 10000; @@ -190,7 +192,8 @@ std::string AuctionDeliver(uint64_t txfee,uint256 itemhash,uint256 bidtxid) std::string AuctionPost(uint64_t txfee,uint256 itemhash,int64_t minbid,char *title,char *description) { - CMutableTransaction mtx; CPubKey mypk,Auctionpk; int64_t funds = 0; CScript opret; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,Auctionpk; int64_t funds = 0; CScript opret; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_AUCTION); if ( txfee == 0 ) txfee = 10000; diff --git a/src/cc/betprotocol.cpp b/src/cc/betprotocol.cpp index a6ccfc972..3efa4ae37 100644 --- a/src/cc/betprotocol.cpp +++ b/src/cc/betprotocol.cpp @@ -25,6 +25,7 @@ #include "cc/utils.h" #include "primitives/transaction.h" +int32_t komodo_nextheight(); std::vector BetProtocol::PlayerConditions() { @@ -53,7 +54,7 @@ CC* BetProtocol::MakeDisputeCond() */ CMutableTransaction BetProtocol::MakeSessionTx(CAmount spendFee) { - CMutableTransaction mtx; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CC *disputeCond = MakeDisputeCond(); mtx.vout.push_back(CTxOut(spendFee, CCPubKey(disputeCond))); @@ -70,7 +71,7 @@ CMutableTransaction BetProtocol::MakeSessionTx(CAmount spendFee) CMutableTransaction BetProtocol::MakeDisputeTx(uint256 signedSessionTxHash, uint256 vmResultHash) { - CMutableTransaction mtx; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CC *disputeCond = MakeDisputeCond(); mtx.vin.push_back(CTxIn(signedSessionTxHash, 0, CScript())); @@ -84,7 +85,7 @@ CMutableTransaction BetProtocol::MakeDisputeTx(uint256 signedSessionTxHash, uint CMutableTransaction BetProtocol::MakePostEvidenceTx(uint256 signedSessionTxHash, int playerIdx, std::vector state) { - CMutableTransaction mtx; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); mtx.vin.push_back(CTxIn(signedSessionTxHash, playerIdx+1, CScript())); mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << state)); @@ -115,7 +116,7 @@ CC* BetProtocol::MakePayoutCond(uint256 signedSessionTxHash) CMutableTransaction BetProtocol::MakeStakeTx(CAmount totalPayout, uint256 signedSessionTxHash) { - CMutableTransaction mtx; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CC *payoutCond = MakePayoutCond(signedSessionTxHash); mtx.vout.push_back(CTxOut(totalPayout, CCPubKey(payoutCond))); @@ -128,7 +129,7 @@ CMutableTransaction BetProtocol::MakeStakeTx(CAmount totalPayout, uint256 signed CMutableTransaction BetProtocol::MakeAgreePayoutTx(std::vector payouts, uint256 signedStakeTxHash) { - CMutableTransaction mtx; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); mtx.vout = payouts; return mtx; @@ -138,7 +139,7 @@ CMutableTransaction BetProtocol::MakeAgreePayoutTx(std::vector payouts, CMutableTransaction BetProtocol::MakeImportPayoutTx(std::vector payouts, CTransaction signedDisputeTx, uint256 signedStakeTxHash, MoMProof momProof) { - CMutableTransaction mtx; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); mtx.vout = payouts; CScript proofData; @@ -263,7 +264,7 @@ bool Eval::DisputePayout(AppVM &vm, std::vector params, const CTransact if (!GetTxConfirmed(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlock)) return Error("couldnt-get-parent"); - if (GetCurrentHeight() < sessionBlock.nHeight + waitBlocks) + if (GetCurrentHeight() < sessionBlock.GetHeight() + waitBlocks) return Invalid("dispute-too-soon"); // Not yet } 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/channels.cpp b/src/cc/channels.cpp index a03a602d5..60f907c27 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -151,7 +151,7 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti else return(true); } -bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,p1,param1; bool retval; uint256 txid,hashblock,p3,param3,opentxid,tmp_txid,genhashchain,hashchain; @@ -199,7 +199,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.3: normal output of payment amount to receiver pubkey //vout.n-2: normal change //vout.n-1: opreturn - 'P' opentxid senderspubkey receiverspubkey depth numpayments secret - if (isCCTxNotarizedConfirmed(opentxid) == 0) + if (komodo_txnotarizedconfirmed(opentxid) == 0) return eval->Invalid("channelOpen is not yet confirmed(notarised)!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelPayment!"); @@ -261,7 +261,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.2: CC vout marker to receiver pubkey //vout.n-2: normal change //vout.n-1: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0 - if (isCCTxNotarizedConfirmed(opentxid) == 0) + if (komodo_txnotarizedconfirmed(opentxid) == 0) return eval->Invalid("channelOpen is not yet confirmed(notarised)!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelClose!"); @@ -304,9 +304,9 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.2: normal output of CC input to senders pubkey //vout.n-2: normal change //vout.n-1: opreturn - 'R' opentxid senderspubkey receiverspubkey numpayments payment closetxid - if (isCCTxNotarizedConfirmed(opentxid) == 0) + if (komodo_txnotarizedconfirmed(opentxid) == 0) return eval->Invalid("channelOpen is not yet confirmed(notarised)!"); - else if (isCCTxNotarizedConfirmed(param3) == 0) + else if (komodo_txnotarizedconfirmed(param3) == 0) return eval->Invalid("channelClose is not yet confirmed(notarised)!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelRefund!"); @@ -430,7 +430,8 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment) { - CMutableTransaction mtx; uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy; CPubKey mypk; struct CCcontract_info *cp,C; if ( numpayments <= 0 || payment <= 0 || numpayments > CHANNELS_MAXPAYMENTS ) @@ -464,7 +465,8 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint256 secret) { - CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,gensecret,hashblock,entropy,hentropy,prevtxid,param3; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,gensecret,hashblock,entropy,hentropy,prevtxid,param3; struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,numpayments,totalnumpayments; int64_t payment,change,funds,param2; uint8_t hash[32],hashdest[32]; @@ -479,7 +481,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2 fprintf(stderr, "invalid channel open txid\n"); return (""); } - if (AddNormalinputs(mtx,mypk,2*txfee,1) > 0) + if (AddNormalinputs(mtx,mypk,2*txfee,3) > 0) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount-txfee)>=0) { @@ -569,7 +571,8 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2 std::string ChannelClose(uint64_t txfee,uint256 opentxid) { - CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,srcpub,destpub; struct CCcontract_info *cp,C; CTransaction channelOpenTx; uint256 hashblock,tmp_txid,prevtxid,hashchain; int32_t numvouts,numpayments; @@ -595,7 +598,7 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) fprintf(stderr,"cannot close, you are not channel owner\n"); return(""); } - if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && funds-txfee>0) { @@ -616,7 +619,8 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) { - CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; int64_t funds,payment,param2; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; struct CCcontract_info *cp,C; int64_t funds,payment,param2; int32_t i,numpayments,numvouts,param1; uint256 hashchain,hashblock,txid,prevtxid,param3,entropy,hentropy,secret; CTransaction channelOpenTx,channelCloseTx,prevTx; @@ -658,7 +662,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) fprintf(stderr,"cannot refund, you are not the channel owenr\n"); return(""); } - if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && funds-txfee>0) { diff --git a/src/cc/dapps/makedapps b/src/cc/dapps/makedapps new file mode 100755 index 000000000..3a86f68da --- /dev/null +++ b/src/cc/dapps/makedapps @@ -0,0 +1,2 @@ +gcc -o oraclefeed cc/dapps/oraclefeed.c -lm +gcc -o zmigrate cc/dapps/zmigrate.c -lm diff --git a/src/cc/dapps/oraclefeed.c b/src/cc/dapps/oraclefeed.c index a0930bae4..68c02310b 100644 --- a/src/cc/dapps/oraclefeed.c +++ b/src/cc/dapps/oraclefeed.c @@ -328,13 +328,18 @@ cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char { sprintf(cmdstr,"%s %s %s %s %s %s > %s\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,fname); printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr); - } + } +#ifdef TESTMODE + fprintf(stderr,"cmd: %s\n",cmdstr); +#endif // TESTMODE system(cmdstr); *retstrp = 0; if ( (jsonstr= filestr(&fsize,fname)) != 0 ) { jsonstr[strlen(jsonstr)-1]='\0'; - //fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr); +#ifdef TESTMODE + fprintf(stderr,"jsonstr.(%s)\n",jsonstr); +#endif // TESTMODE if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 ) *retstrp = jsonstr; else free(jsonstr); @@ -483,6 +488,22 @@ cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr) return(0); } +cJSON *get_gatewaysprocessed(char *refcoin,char *acname,char *bindtxidstr) +{ + cJSON *retjson; char *retstr; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysprocessed",bindtxidstr,refcoin,"","")) != 0 ) + { + //printf("pending.(%s)\n",jprint(retjson,0)); + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"%s get_gatewaysprocessed.(%s) error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + cJSON *get_rawmempool(char *refcoin,char *acname) { cJSON *retjson; char *retstr; @@ -550,10 +571,12 @@ int32_t validateaddress(char *refcoin,char *acname,char *depositaddr, char* comp return (res); } -void importaddress(char *refcoin,char *acname,char *depositaddr) +void importaddress(char *refcoin,char *acname,char *depositaddr, char *label,int rescan) { - cJSON *retjson; char *retstr; - if ( (retjson= get_komodocli(refcoin,&retstr,acname,"importaddress",depositaddr,"","true","")) != 0 ) + cJSON *retjson; char *retstr; char rescanstr[10]; + if (rescan) strcpy(rescanstr,"true"); + else strcpy(rescanstr,"false"); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"importaddress",depositaddr,label,rescanstr,"")) != 0 ) { printf("importaddress.(%s)\n",jprint(retjson,0)); free_json(retjson); @@ -610,7 +633,7 @@ cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required) return(vins); } -char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signeraddr,char *withdrawaddr,int64_t satoshis) +char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawaddr,char *txidaddr,int64_t satoshis) { char *retstr,*retstr2,array[128],*txstr = 0; cJSON *retjson2,*retjson,*vins,*vouts; int64_t txfee,total,change = 0; if ( strcmp(refcoin,"BTC") == 0 ) @@ -618,7 +641,7 @@ char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signerad else txfee = 10000; if ( satoshis < txfee ) { - printf("createmultisig satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN); + printf("createrawtx satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN); return(0); } satoshis -= txfee; @@ -631,8 +654,9 @@ char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signerad if ( total >= satoshis ) { vouts = cJSON_CreateObject(); - jaddnum(vouts,withdrawaddr,(double)satoshis/SATOSHIDEN); - if ( total > satoshis+txfee ) + jaddnum(vouts,withdrawaddr,(double)(satoshis-2*txfee)/SATOSHIDEN); + jaddnum(vouts,txidaddr,(double)txfee/SATOSHIDEN); + if ( total > satoshis) { change = (total - satoshis); jaddnum(vouts,depositaddr,(double)change/SATOSHIDEN); @@ -645,29 +669,30 @@ char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signerad sprintf(argB,"\'%s\'",tmpB); if ( (retjson2= get_komodocli(refcoin,&txstr,acname,"createrawtransaction",argA,argB,"","")) != 0 ) { - printf("createmultisig: unexpected JSON2.(%s)\n",jprint(retjson2,0)); + printf("createrawtx: unexpected JSON2.(%s)\n",jprint(retjson2,0)); free_json(retjson2); } else if ( txstr == 0 ) - printf("createmultisig: null txstr and JSON2\n"); + printf("createrawtx: null txstr and JSON2\n"); free(tmpA); free(tmpB); free(argA); free(argB); } + else printf("not enough funds to create withdraw tx\n"); } free_json(retjson); } else if ( retstr != 0 ) { - printf("createmultisig: unexpected null JSON, retstr.(%s)\n",retstr); + printf("createrawtx: unexpected null JSON, retstr.(%s)\n",retstr); free(retstr); } - else printf("createmultisig: null retstr and JSON\n"); + else printf("createrawtx: null retstr and JSON\n"); return(txstr); } -cJSON *addmultisignature(char *refcoin,char *acname,char *signeraddr,char *rawtx) +cJSON *addsignature(char *refcoin,char *acname,char *rawtx) { char *retstr,*hexstr; cJSON *retjson; if ( (retjson= get_komodocli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 ) @@ -681,6 +706,11 @@ cJSON *addmultisignature(char *refcoin,char *acname,char *signeraddr,char *rawtx } free_json(retjson); } + else if ( retstr != 0 ) + { + printf("error parsing signrawtransaction.(%s)\n",retstr); + free(retstr); + } return(0); } @@ -696,6 +726,11 @@ char *get_gatewaysmultisig(char *refcoin,char *acname,char *txidaddr,int32_t *K) *K=jint(retjson,"number_of_signs"); free_json(retjson); } + else if ( retstr != 0 ) + { + printf("error parsing gatewaysmultisig.(%s)\n",retstr); + free(retstr); + } return(hex); } @@ -714,11 +749,27 @@ bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex) return (zeroid); } -void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin,bits256 cointxid) +void gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char *coin,char *hex) { char str[65],str2[65],*retstr; cJSON *retjson; printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid)); - if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),coin,bits256_str(str2,cointxid),"")) != 0 ) + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayscompletesigning",bits256_str(str,withtxid),coin,hex,"")) != 0 ) + { + komodobroadcast(refcoin,acname,retjson); + free_json(retjson); + } + else if ( retstr != 0 ) + { + printf("error parsing gatewayscompletesigning.(%s)\n",retstr); + free(retstr); + } +} + +void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin) +{ + char str[65],str2[65],*retstr; cJSON *retjson; + printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid)); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),coin,"","")) != 0 ) { komodobroadcast(refcoin,acname,retjson); free_json(retjson); @@ -771,6 +822,22 @@ int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *M else return(0); } +int32_t tx_notarizedconfirmed(char *refcoin,char *acname,bits256 txid) +{ + char *retstr,str[65]; cJSON *retjson; int32_t result; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"txnotarizedconfirmed",bits256_str(str,txid),"","","")) != 0 ) + { + if (is_cJSON_True(jobj(retjson,"result")) != 0 ) result=1; + else result=0; + free_json(retjson); + } + else if ( retstr != 0 ) + { + printf("error parsing txnotarizedconfirmed.(%s)\n",retstr); + free(retstr); + } +} + int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinaddr) { cJSON *txobj,*vouts,*vout,*vins,*vin,*sobj,*addresses; char *addr,str[65]; int32_t i,j,n,numarray,retval = 0, hasvout=0; @@ -788,8 +855,7 @@ int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinadd { addr = jstri(addresses,j); if ( strcmp(addr,coinaddr) == 0 ) - { - //fprintf(stderr,"found %s in %s v%d\n",coinaddr,bits256_str(str,txid),i); + { hasvout = 1; break; } @@ -798,23 +864,44 @@ int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinadd } if (hasvout==1) break; } - } - // if (hasvout==1 && (vins=jarray(&numarray,txobj,"vin"))!=0) - // { - // for (int i=0;i 0 ) + { + num = 1; + break; + } + } + } + free_json(array); + } + } + fprintf(stderr,"Num=%d\n",num); + return(num); + +} int32_t markerfromthisnodeorunconfirmed(char *refcoin,char *acname,char *coinaddr) { cJSON *array,*item,*rawtx,*vins,*vin; bits256 txid,tmptxid; int32_t i,n,m,num=0; char *retstr; @@ -887,54 +974,42 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t //process item.0 {"txid":"10ec8f4dad6903df6b249b361b879ac77b0617caad7629b97e10f29fa7e99a9b","txidaddr":"RMbite4TGugVmkGmu76ytPHDEQZQGSUjxz","withdrawaddr":"RNJmgYaFF5DbnrNUX6pMYz9rcnDKC2tuAc","amount":"1.00000000","depositaddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","signeraddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj"} if ( (txidaddr= jstr(item,"txidaddr")) != 0 && (withdrawaddr= jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 ) { - if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && markerfromthisnodeorunconfirmed("KMD",acname,txidaddr) == 0) - { - // the actual withdraw + if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0 && markerfromthisnodeorunconfirmed("KMD",acname,txidaddr) == 0) + { if ( strcmp(depositaddr,signeraddr) == 0 ) - { - txid= sendtoaddress("KMD",acname,txidaddr,10000); - if (bits256_nonz(txid) != 0) + { + rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis); + if ( rawtx != 0 ) { - cointxid = sendtoaddress(refcoin,"",withdrawaddr,satoshis); - if ( bits256_nonz(cointxid) != 0) - { - fprintf(stderr,"withdraw %s %s %s %.8f processed\n",refcoin,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); - gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid); - processed++; + if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0) + { + gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex")); + fprintf(stderr,"withdraw %.8f %s to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,withdrawaddr); + free_json(clijson); } - else - { - fprintf(stderr,"ERROR withdraw %s %s %s %.8f processed\n",refcoin,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); - } - } - else - { - fprintf(stderr,"ERROR sending withdraw marker %s %s to %s %.8f processed\n",refcoin,bits256_str(str,cointxid),txidaddr,(double)10000/SATOSHIDEN); - } + processed++; + free(rawtx); + } else fprintf(stderr,"couldnt create rawtx\n"); } else { if ( (rawtx= get_gatewaysmultisig(refcoin,acname,txidaddr,&K)) == 0) { - rawtx = createmultisig(refcoin,"",depositaddr,signeraddr,withdrawaddr,satoshis); + rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis); } if ( rawtx != 0 ) { - if ( (clijson= addmultisignature(refcoin,"",signeraddr,rawtx)) != 0 ) + if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 ) { if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) - { - cointxid = komodobroadcast(refcoin,"",clijson); - if ( bits256_nonz(cointxid) != 0 ) - { - fprintf(stderr,"withdraw %s M.%d N.%d %s %s %.8f processed\n",refcoin,M,N,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); - gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid); - } + { + gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex")); + fprintf(stderr,"withdraw %.8f %s M.%d N.%d to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,M,N,withdrawaddr); } else if ( jint(clijson,"partialtx") != 0 ) { txid=gatewayspartialsign(refcoin,acname,origtxid,jstr(clijson,"hex")); - fprintf(stderr,"%d of %d partialtx %s sent\n",K+1,N,bits256_str(str,txid)); + fprintf(stderr,"%d sign(s) %dof%d partialtx %s sent\n",K+1,M,N,bits256_str(str,txid)); } free_json(clijson); } @@ -949,6 +1024,33 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t } free_json(retjson); } + if ( (retjson= get_gatewaysprocessed("KMD",acname,bindtxidstr)) != 0 ) + { + if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 ) + { + if ( (pending=jarray(&n,retjson,"processed")) != 0 ) + { + for (i=0; i +#include +#include +#include +#include "cJSON.c" + +/* +z_migrate: the purpose of z_migrate is to make converting of all sprout outputs into sapling. the usage would be for the user to specify a sapling address and call z_migrate zsaddr, until it returns that there is nothing left to be done. + +its main functionality is quite similar to a z_mergetoaddress ANY_ZADDR -> onetime_taddr followed by a z_sendmany onetime_taddr -> zsaddr + +since the z_mergetoaddress will take time, it would just queue up an async operation. When it starts, it should see if there are any onetime_taddr with 10000.0001 funds in it, that is a signal for it to do the sapling tx and it can just do that without async as it is fast enough, especially with a taddr input. Maybe it limits itself to one, or it does all possible taddr -> sapling as fast as it can. either is fine as it will be called over and over anyway. + +It might be that there is nothing to do, but some operations are pending. in that case it would return such a status. as soon as the operation finishes, there would be more work to do. + +the amount sent to the taddr, should be 10000.0001 + +The GUI or user would be expected to generate a sapling address and then call z_migrate saplingaddr in a loop, until it returns that it is all done. this loop should pause for 10 seconds or so, if z_migrate is just waiting for opid to complete. +*/ + +bits256 zeroid; + +char hexbyte(int32_t c) +{ + c &= 0xf; + if ( c < 10 ) + return('0'+c); + else if ( c < 16 ) + return('a'+c-10); + else return(0); +} + +int32_t _unhex(char c) +{ + if ( c >= '0' && c <= '9' ) + return(c - '0'); + else if ( c >= 'a' && c <= 'f' ) + return(c - 'a' + 10); + else if ( c >= 'A' && c <= 'F' ) + return(c - 'A' + 10); + return(-1); +} + +int32_t is_hexstr(char *str,int32_t n) +{ + int32_t i; + if ( str == 0 || str[0] == 0 ) + return(0); + for (i=0; str[i]!=0; i++) + { + if ( n > 0 && i >= n ) + break; + if ( _unhex(str[i]) < 0 ) + break; + } + if ( n == 0 ) + return(i); + return(i == n); +} + +int32_t unhex(char c) +{ + int32_t hex; + if ( (hex= _unhex(c)) < 0 ) + { + //printf("unhex: illegal hexchar.(%c)\n",c); + } + return(hex); +} + +unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])); } + +int32_t decode_hex(unsigned char *bytes,int32_t n,char *hex) +{ + int32_t adjust,i = 0; + //printf("decode.(%s)\n",hex); + if ( is_hexstr(hex,n) <= 0 ) + { + memset(bytes,0,n); + return(n); + } + if ( hex[n-1] == '\n' || hex[n-1] == '\r' ) + hex[--n] = 0; + if ( hex[n-1] == '\n' || hex[n-1] == '\r' ) + hex[--n] = 0; + if ( n == 0 || (hex[n*2+1] == 0 && hex[n*2] != 0) ) + { + if ( n > 0 ) + { + bytes[0] = unhex(hex[0]); + printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex)); + } + bytes++; + hex++; + adjust = 1; + } else adjust = 0; + if ( n > 0 ) + { + for (i=0; i>4) & 0xf); + hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf); + //printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]); + } + hexbytes[len*2] = 0; + //printf("len.%ld\n",len*2+1); + return((int32_t)len*2+1); +} + +long _stripwhite(char *buf,int accept) +{ + int32_t i,j,c; + if ( buf == 0 || buf[0] == 0 ) + return(0); + for (i=j=0; buf[i]!=0; i++) + { + buf[j] = c = buf[i]; + if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') ) + j++; + } + buf[j] = 0; + return(j); +} + +char *clonestr(char *str) +{ + char *clone; + if ( str == 0 || str[0]==0) + { + printf("warning cloning nullstr.%p\n",str); + //#ifdef __APPLE__ + // while ( 1 ) sleep(1); + //#endif + str = (char *)""; + } + clone = (char *)malloc(strlen(str)+16); + strcpy(clone,str); + return(clone); +} + +int32_t safecopy(char *dest,char *src,long len) +{ + int32_t i = -1; + if ( src != 0 && dest != 0 && src != dest ) + { + if ( dest != 0 ) + memset(dest,0,len); + for (i=0; i0; i--) + str[i] = str[i-1]; + str[0] = '/'; + str[n+1] = 0; + }*/ +#endif + return(str); +#endif +} + +void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep) +{ + FILE *fp; + long filesize,buflen = *allocsizep; + uint8_t *buf = *bufp; + *lenp = 0; + if ( (fp= fopen(portable_path(fname),"rb")) != 0 ) + { + fseek(fp,0,SEEK_END); + filesize = ftell(fp); + if ( filesize == 0 ) + { + fclose(fp); + *lenp = 0; + printf("loadfile null size.(%s)\n",fname); + return(0); + } + if ( filesize > buflen ) + { + *allocsizep = filesize; + *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); + } + rewind(fp); + if ( buf == 0 ) + printf("Null buf ???\n"); + else + { + if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) + printf("error reading filesize.%ld\n",(long)filesize); + buf[filesize] = 0; + } + fclose(fp); + *lenp = filesize; + //printf("loaded.(%s)\n",buf); + } //else printf("OS_loadfile couldnt load.(%s)\n",fname); + return(buf); +} + +void *filestr(long *allocsizep,char *_fname) +{ + long filesize = 0; char *fname,*buf = 0; void *retptr; + *allocsizep = 0; + fname = malloc(strlen(_fname)+1); + strcpy(fname,_fname); + retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep); + free(fname); + return(retptr); +} + +char *send_curl(char *url,char *fname) +{ + long fsize; char curlstr[1024]; + sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); + system(curlstr); + return(filestr(&fsize,fname)); +} + +cJSON *get_urljson(char *url,char *fname) +{ + char *jsonstr; cJSON *json = 0; + if ( (jsonstr= send_curl(url,fname)) != 0 ) + { + //printf("(%s) -> (%s)\n",url,jsonstr); + json = cJSON_Parse(jsonstr); + free(jsonstr); + } + return(json); +} + +////////////////////////////////////////////// +// start of dapp +////////////////////////////////////////////// + +char *REFCOIN_CLI; + +cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3) +{ + long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[256]; + sprintf(fname,"/tmp/zmigrate.%s",method); + if ( acname[0] != 0 ) + { + if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 ) + printf("unexpected: refcoin.(%s) acname.(%s)\n",refcoin,acname); + sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,arg3,fname); + } + else if ( strcmp(refcoin,"KMD") == 0 ) + sprintf(cmdstr,"./komodo-cli %s %s %s %s %s > %s\n",method,arg0,arg1,arg2,arg3,fname); + else if ( REFCOIN_CLI != 0 && REFCOIN_CLI[0] != 0 ) + { + sprintf(cmdstr,"%s %s %s %s %s %s > %s\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,fname); + //printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr); + } + system(cmdstr); + *retstrp = 0; + if ( (jsonstr= filestr(&fsize,fname)) != 0 ) + { + jsonstr[strlen(jsonstr)-1]='\0'; + //fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr); + if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 ) + *retstrp = jsonstr; + else free(jsonstr); + } + return(retjson); +} + +bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson) +{ + char *hexstr,*retstr,str[65]; cJSON *retjson; bits256 txid; + memset(txid.bytes,0,sizeof(txid)); + if ( (hexstr= jstr(hexjson,"hex")) != 0 ) + { + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","")) != 0 ) + { + //fprintf(stderr,"broadcast.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + if ( strlen(retstr) >= 64 ) + { + retstr[64] = 0; + decode_hex(txid.bytes,32,retstr); + } + fprintf(stderr,"broadcast %s txid.(%s)\n",strlen(acname)>0?acname:refcoin,bits256_str(str,txid)); + free(retstr); + } + } + return(txid); +} + +bits256 sendtoaddress(char *refcoin,char *acname,char *destaddr,int64_t satoshis) +{ + char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid; + memset(txid.bytes,0,sizeof(txid)); + sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendtoaddress",destaddr,numstr,"","")) != 0 ) + { + fprintf(stderr,"unexpected sendrawtransaction json.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + if ( strlen(retstr) >= 64 ) + { + retstr[64] = 0; + decode_hex(txid.bytes,32,retstr); + } + fprintf(stderr,"sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid)); + free(retstr); + } + return(txid); +} + +int32_t get_coinheight(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr; int32_t height=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockchaininfo","","","","")) != 0 ) + { + height = jint(retjson,"blocks"); + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"%s get_coinheight.(%s) error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(height); +} + +bits256 get_coinblockhash(char *refcoin,char *acname,int32_t height) +{ + cJSON *retjson; char *retstr,heightstr[32]; bits256 hash; + memset(hash.bytes,0,sizeof(hash)); + sprintf(heightstr,"%d",height); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","")) != 0 ) + { + fprintf(stderr,"unexpected blockhash json.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + if ( strlen(retstr) >= 64 ) + { + retstr[64] = 0; + decode_hex(hash.bytes,32,retstr); + } + free(retstr); + } + return(hash); +} + +bits256 get_coinmerkleroot(char *refcoin,char *acname,bits256 blockhash) +{ + cJSON *retjson; char *retstr,str[65]; bits256 merkleroot; + memset(merkleroot.bytes,0,sizeof(merkleroot)); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","")) != 0 ) + { + merkleroot = jbits256(retjson,"merkleroot"); + //fprintf(stderr,"got merkleroot.(%s)\n",bits256_str(str,merkleroot)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"%s %s get_coinmerkleroot error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(merkleroot); +} + +int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *merklerootp,int32_t prevheight) +{ + int32_t height = 0; char str[65]; + if ( prevheight == 0 ) + height = get_coinheight(refcoin,acname) - 20; + else height = prevheight + 1; + if ( height > 0 ) + { + *blockhashp = get_coinblockhash(refcoin,acname,height); + if ( bits256_nonz(*blockhashp) != 0 ) + { + *merklerootp = get_coinmerkleroot(refcoin,acname,*blockhashp); + if ( bits256_nonz(*merklerootp) != 0 ) + return(height); + } + } + memset(blockhashp,0,sizeof(*blockhashp)); + memset(merklerootp,0,sizeof(*merklerootp)); + return(0); +} + +cJSON *get_rawmempool(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawmempool","","","","")) != 0 ) + { + //printf("mempool.(%s)\n",jprint(retjson,0)); + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_rawmempool.(%s) error.(%s)\n",acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr) +{ + cJSON *retjson; char *retstr,jsonbuf[256]; + if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 ) + printf("warning: assumes %s has addressindex enabled\n",refcoin); + sprintf(jsonbuf,"{\\\"addresses\\\":[\\\"%s\\\"]}",coinaddr); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","")) != 0 ) + { + //printf("addressutxos.(%s)\n",jprint(retjson,0)); + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_rawtransaction.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_listunspent(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_listunspent.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *z_listunspent(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_listunspent","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_listunspent.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *z_listoperationids(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_listoperationids","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_listoperationids.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *z_getoperationstatus(char *refcoin,char *acname,char *opid) +{ + cJSON *retjson; char *retstr,str[65],params[512]; + sprintf(params,"'[\"%s\"]'",opid); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getoperationstatus",params,"","","")) != 0 ) + { + //printf("got status (%s)\n",jprint(retjson,0)); + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_getoperationstatus.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *z_getoperationresult(char *refcoin,char *acname,char *opid) +{ + cJSON *retjson; char *retstr,str[65],params[512]; + sprintf(params,"'[\"%s\"]'",opid); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getoperationresult",params,"","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_getoperationresult.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +int32_t validateaddress(char *refcoin,char *acname,char *depositaddr, char* compare) +{ + cJSON *retjson; char *retstr; int32_t res=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","")) != 0 ) + { + if (is_cJSON_True(jobj(retjson,compare)) != 0 ) res=1; + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"validateaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return (res); +} + +int32_t z_validateaddress(char *refcoin,char *acname,char *depositaddr, char *compare) +{ + cJSON *retjson; char *retstr; int32_t res=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_validateaddress",depositaddr,"","","")) != 0 ) + { + if (is_cJSON_True(jobj(retjson,compare)) != 0 ) + res=1; + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_validateaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return (res); +} + +int64_t z_getbalance(char *refcoin,char *acname,char *coinaddr) +{ + cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getbalance",coinaddr,"","","")) != 0 ) + { + fprintf(stderr,"z_getbalance.(%s) %s returned json!\n",refcoin,acname); + free_json(retjson); + } + else if ( retstr != 0 ) + { + amount = atof(retstr) * SATOSHIDEN; + sprintf(cmpstr,"%.8f",dstr(amount)); + if ( strcmp(retstr,cmpstr) != 0 ) + amount++; + //printf("retstr %s -> %.8f\n",retstr,dstr(amount)); + free(retstr); + } + return (amount); +} + +int32_t getnewaddress(char *coinaddr,char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr; int64_t amount=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getnewaddress","","","","")) != 0 ) + { + fprintf(stderr,"getnewaddress.(%s) %s returned json!\n",refcoin,acname); + free_json(retjson); + return(-1); + } + else if ( retstr != 0 ) + { + strcpy(coinaddr,retstr); + free(retstr); + return(0); + } +} + +int64_t find_onetime_amount(char *coinstr,char *coinaddr) +{ + cJSON *array,*item; int32_t i,n; char *addr; int64_t amount = 0; + coinaddr[0] = 0; + if ( (array= get_listunspent(coinstr,"")) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i 0 ) + { + for (i=0; i opid.(%s)\n",coinstr,retstr); + strcpy(opidstr,retstr); + free(retstr); + return(0); + } +} + +int32_t empty_mempool(char *coinstr,char *acname) +{ + cJSON *array; int32_t n; + if ( (array= get_rawmempool(coinstr,acname)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + return(0); + free_json(array); + return(1); + } + return(-1); +} + +cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required) +{ + cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid; + *totalp = 0; + if ( (n= cJSON_GetArraySize(unspents)) > 0 ) + { + for (i=0; i= required ) + break; + } + } + } + return(vins); +} + +int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinaddr) +{ + cJSON *txobj,*vouts,*vout,*vins,*vin,*sobj,*addresses; char *addr,str[65]; int32_t i,j,n,numarray,retval = 0, hasvout=0; + if ( (txobj= get_rawtransaction(refcoin,acname,txid)) != 0 ) + { + if ( (vouts= jarray(&numarray,txobj,"vout")) != 0 ) + { + for (i=0; i 0 ) + { + for (i=0; i 0 ) + { + for (j=0; j txfee ) + { + // find taddr with funds and send all to zsaddr + z_sendmany(opidstr,coinstr,"",coinaddr,zsaddr,amount-txfee); + lastopid = (uint32_t)time(NULL); + sleep(1); + continue; + } + if ( (amount= find_sprout_amount(coinstr,zcaddr)) > txfee ) + { + // generate taddr, send max of 10000.0001 + if ( amount > stdamount+txfee ) + amount = stdamount + txfee; + if ( getnewaddress(coinaddr,coinstr,"") == 0 ) + { + z_sendmany(opidstr,coinstr,"",zcaddr,coinaddr,amount-txfee); + lastopid = (uint32_t)time(NULL); + } else printf("couldnt getnewaddress!\n"); + sleep(30); + continue; + } + if ( time(NULL) > lastopid+600 ) + break; + } + sleep(3); + printf("%s %s ALLDONE! taddr %.8f sprout %.8f mempool empty.%d\n",coinstr,zsaddr,dstr(find_onetime_amount(coinstr,coinaddr)),dstr(find_sprout_amount(coinstr,zcaddr)),empty_mempool(coinstr,"")); + sleep(3); + if ( find_onetime_amount(coinstr,coinaddr) == 0 && find_sprout_amount(coinstr,zcaddr) == 0 ) + { + printf("about to purge all opid results!. ctrl-C to abort, to proceed\n"); + getchar(); + have_pending_opid(coinstr,1); + } else goto again; + return(0); +} diff --git a/src/cc/dice.cpp b/src/cc/dice.cpp index addef4e06..de07a394b 100644 --- a/src/cc/dice.cpp +++ b/src/cc/dice.cpp @@ -245,9 +245,12 @@ bool mySenddicetransaction(std::string res,uint256 entropyused,int32_t entropyvo { RelayTransaction(tx); fprintf(stderr,"rebroadcast.%c and clear [%d] and broadcast entropyused.%s bettxid.%s -> %s\n",funcid,i,entropyused.GetHex().c_str(),bettxid.GetHex().c_str(),tx.GetHash().GetHex().c_str()); - if ( ptr->rawtx.empty() == 0 ) - ptr->rawtx.clear(); - ptr->txid = zeroid; + if ( ptr != 0 ) + { + if ( ptr->rawtx.empty() == 0 ) + ptr->rawtx.clear(); + ptr->txid = zeroid; + } //fprintf(stderr,"error adding funcid.%c E.%s bet.%s -> %s to mempool, probably Disable replacement feature size.%d\n",funcid,entropyused.GetHex().c_str(),bettxid.GetHex().c_str(),tx.GetHash().GetHex().c_str(),(int32_t)ptr->rawtx.size()); } } else fprintf(stderr,"error duplicate entropyused different bettxid\n"); @@ -540,10 +543,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); } @@ -831,7 +833,7 @@ bool DiceVerifyTimeout(CTransaction &betTx,int32_t timeoutblocks) return(numblocks >= timeoutblocks); } -bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) +bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn) { uint256 txid,fundingtxid,vinfundingtxid,vinhentropy,vinproof,hashBlock,hash,proof,entropy; int64_t minbet,maxbet,maxodds,timeoutblocks,odds,winnings; uint64_t vinsbits,refsbits=0,sbits,amount,inputs,outputs,txfee=10000; int32_t numvins,entropyvout,numvouts,preventCCvins,preventCCvouts,i,iswin; uint8_t funcid; CScript fundingPubKey; CTransaction fundingTx,vinTx,vinofvinTx; char CCaddr[64]; numvins = tx.vin.size(); @@ -917,8 +919,8 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) fprintf(stderr,"%s != %s betTx.%s\n",addr0,addr1,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(); + ptr0 = (uint8_t *)&vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey[0]; + ptr1 = (uint8_t *)&fundingPubKey[0]; for (i=0; iInvalid("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; @@ -996,7 +998,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'); @@ -1162,8 +1164,8 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit Getscriptaddress(addr1,fundingPubKey); if ( strcmp(addr0,addr1) != 0 ) { - ptr0 = (uint8_t *)vinTx.vout[1].scriptPubKey.data(); - ptr1 = (uint8_t *)fundingPubKey.data(); + ptr0 = (uint8_t *)&vinTx.vout[1].scriptPubKey[0]; + ptr1 = (uint8_t *)&fundingPubKey[0]; for (i=0; i 9999 || timeoutblocks < 0 || timeoutblocks > 1440 ) { CCerror = "invalid parameter error"; @@ -1368,7 +1370,8 @@ std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount) { - CMutableTransaction mtx; CScript fundingPubKey,scriptPubKey; uint256 entropy,hentropy; CPubKey mypk,dicepk; uint64_t sbits; struct CCcontract_info *cp,C; int64_t minbet,maxbet,maxodds,timeoutblocks; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CScript fundingPubKey,scriptPubKey; uint256 entropy,hentropy; CPubKey mypk,dicepk; uint64_t sbits; struct CCcontract_info *cp,C; int64_t minbet,maxbet,maxodds,timeoutblocks; if ( amount < 0 ) { CCerror = "amount must be positive"; @@ -1383,13 +1386,11 @@ std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int6 if ( 0 ) { uint8_t *ptr0,*ptr1; int32_t i; - ptr0 = (uint8_t *)scriptPubKey.data(); - ptr1 = (uint8_t *)fundingPubKey.data(); for (i=0; i<35; i++) - fprintf(stderr,"%02x",ptr0[i]); + fprintf(stderr,"%02x",scriptPubKey[i]); fprintf(stderr," script vs "); for (i=0; i<35; i++) - fprintf(stderr,"%02x",ptr1[i]); + fprintf(stderr,"%02x",fundingPubKey[i]); fprintf(stderr," funding\n"); } if ( scriptPubKey == fundingPubKey ) @@ -1413,7 +1414,8 @@ std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int6 std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds) { - CMutableTransaction mtx; CScript fundingPubKey; CPubKey mypk,dicepk; uint64_t sbits,entropyval,entropyval2; int64_t funding,minbet,maxbet,maxodds,timeoutblocks; uint256 entropytxid,entropytxid2,entropy,hentropy; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CScript fundingPubKey; CPubKey mypk,dicepk; uint64_t sbits,entropyval,entropyval2; int64_t funding,minbet,maxbet,maxodds,timeoutblocks; uint256 entropytxid,entropytxid2,entropy,hentropy; struct CCcontract_info *cp,C; if ( bet < 0 ) { CCerror = "bet must be positive"; @@ -1472,7 +1474,8 @@ std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet std::string DiceBetFinish(uint8_t &funcid,uint256 &entropyused,int32_t &entropyvout,int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout,uint256 vin0txid,int32_t vin0vout) { - CMutableTransaction mtx; CScript scriptPubKey,fundingPubKey; CTransaction oldbetTx,betTx,entropyTx; uint256 hentropyproof,entropytxid,hashBlock,bettorentropy,entropy,hentropy,oldbettxid; CPubKey mypk,dicepk,fundingpk; struct CCcontract_info *cp,C; int64_t inputs=0,CCchange=0,odds,fundsneeded,minbet,maxbet,maxodds,timeoutblocks; int32_t oldentropyvout,retval=0,iswin=0; uint64_t entropyval,sbits; + CMutableTransaction savemtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CScript scriptPubKey,fundingPubKey; CTransaction oldbetTx,betTx,entropyTx; uint256 hentropyproof,entropytxid,hashBlock,bettorentropy,entropy,hentropy,oldbettxid; CPubKey mypk,dicepk,fundingpk; struct CCcontract_info *cp,C; int64_t inputs=0,CCchange=0,odds,fundsneeded,minbet,maxbet,maxodds,timeoutblocks; int32_t oldentropyvout,retval=0,iswin=0; uint64_t entropyval,sbits; entropyused = zeroid; *resultp = 0; funcid = 0; @@ -1483,9 +1486,9 @@ std::string DiceBetFinish(uint8_t &funcid,uint256 &entropyused,int32_t &entropyv return(""); } fundingpk = DiceFundingPk(fundingPubKey); + scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG; if ( winlosetimeout != 0 ) // must be dealernode { - scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG; if ( scriptPubKey != fundingPubKey ) { //fprintf(stderr,"only dice fund creator can submit winner or loser\n"); @@ -1506,7 +1509,7 @@ std::string DiceBetFinish(uint8_t &funcid,uint256 &entropyused,int32_t &entropyv { if ( vin0txid == zeroid || vin0vout < 0 ) { - if ( AddNormalinputs(mtx,mypk,2*txfee,1) == 0 ) // must be a single vin!! + if ( AddNormalinputs(mtx,mypk,2*txfee,3) == 0 ) // must be a single vin!! { CCerror = "no txfee inputs for win/lose"; fprintf(stderr,"%s\n", CCerror.c_str() ); @@ -1587,6 +1590,7 @@ std::string DiceBetFinish(uint8_t &funcid,uint256 &entropyused,int32_t &entropyv } CCchange = betTx.vout[0].nValue + betTx.vout[1].nValue; fundsneeded = txfee + (odds+1)*betTx.vout[1].nValue; + savemtx = mtx; if ( CCchange >= fundsneeded ) CCchange -= fundsneeded; else if ( (inputs= AddDiceInputs(cp,mtx,dicepk,fundsneeded,1,sbits,fundingtxid)) >= fundsneeded ) @@ -1596,6 +1600,7 @@ std::string DiceBetFinish(uint8_t &funcid,uint256 &entropyused,int32_t &entropyv } else { + mtx = savemtx; if ( (inputs= AddDiceInputs(cp,mtx,dicepk,fundsneeded,60,sbits,fundingtxid)) > 0 ) { if ( inputs > fundsneeded ) @@ -1621,6 +1626,15 @@ std::string DiceBetFinish(uint8_t &funcid,uint256 &entropyused,int32_t &entropyv //fprintf(stderr,"make tx.%c\n",funcid); if ( funcid == 'L' || funcid == 'W' ) // dealernode only hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1); + else + { + if ( scriptPubKey != betTx.vout[2].scriptPubKey ) + { + CCerror = strprintf("can only finish your own bettxid\n"); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + } *resultp = 1; //char str[65],str2[65]; //fprintf(stderr,"iswin.%d house entropy %s vs bettor %s\n",iswin,uint256_str(str,hentropyproof),uint256_str(str2,bettorentropy)); @@ -1715,6 +1729,12 @@ double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettx GetCCaddress(cp,coinaddr,dicepk); if ( bettxid == zeroid ) // scan { + if ( fundingpk != mypk ) + { + CCerror = "Diceinit error in status, non-dealer must provide bettxid"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(0.); + } std::vector > unspentOutputs; SetCCunspents(unspentOutputs,coinaddr); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) diff --git a/src/cc/disputepayout.cpp b/src/cc/disputepayout.cpp index 610342274..1271b0da5 100644 --- a/src/cc/disputepayout.cpp +++ b/src/cc/disputepayout.cpp @@ -46,7 +46,7 @@ bool Eval::DisputePayout(AppVM &vm, std::vector params, const CTransact if (!GetTxConfirmed(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlock)) return Error("couldnt-get-parent"); - if (GetCurrentHeight() < sessionBlock.nHeight + waitBlocks) + if (GetCurrentHeight() < sessionBlock.GetHeight() + waitBlocks) return Invalid("dispute-too-soon"); // Not yet } diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 4fc855b46..03a0cd142 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -74,11 +74,11 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) switch ( ecode ) { case EVAL_IMPORTPAYOUT: - return ImportPayout(vparams, txTo, nIn); + //return ImportPayout(vparams, txTo, nIn); break; case EVAL_IMPORTCOIN: - return ImportCoin(vparams, txTo, nIn); + //return ImportCoin(vparams, txTo, nIn); break; default: @@ -98,9 +98,10 @@ bool Eval::GetSpendsConfirmed(uint256 hash, std::vector &spends) c bool Eval::GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const { - if (!myGetTransaction(hash, txOut,hashBlock)) { + return(myGetTransaction(hash, txOut,hashBlock)); + /*if (!myGetTransaction(hash, txOut,hashBlock)) { return(GetTransaction(hash, txOut,hashBlock)); - } else return(true); + } else return(true);*/ } @@ -157,7 +158,7 @@ bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data) CTransaction notarisationTx; CBlockIndex block; if (!GetTxConfirmed(notaryHash, notarisationTx, block)) return false; - if (!CheckNotaryInputs(notarisationTx, block.nHeight, block.nTime)) return false; + if (!CheckNotaryInputs(notarisationTx, block.GetHeight(), block.nTime)) return false; if (!ParseNotarisationOpReturn(notarisationTx, data)) return false; return true; } diff --git a/src/cc/eval.h b/src/cc/eval.h index 51752f0bc..006fca950 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -36,6 +36,7 @@ * there should be a code identifying it. For example, * a possible code is EVAL_BITCOIN_SCRIPT, where the entire binary * after the code is interpreted as a bitcoin script. + * Verus EVAL_STAKEGUARD is 0x01 */ #define FOREACH_EVAL(EVAL) \ EVAL(EVAL_IMPORTPAYOUT, 0xe1) \ @@ -173,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); @@ -269,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/cc/faucet.cpp b/src/cc/faucet.cpp index 3bf8a3476..afd97c1aa 100644 --- a/src/cc/faucet.cpp +++ b/src/cc/faucet.cpp @@ -77,7 +77,7 @@ bool FaucetExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction else return(true); } -bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; std::vector > txids; @@ -146,7 +146,7 @@ int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); - threshold = total/maxinputs; + threshold = total/(maxinputs+1); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; @@ -174,7 +174,8 @@ int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub std::string FaucetGet(uint64_t txfee) { - CMutableTransaction mtx,tmpmtx; CPubKey mypk,faucetpk; int64_t inputs,CCchange=0,nValue=FAUCETSIZE; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; + CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,faucetpk; int64_t inputs,CCchange=0,nValue=FAUCETSIZE; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; cp = CCinit(&C,EVAL_FAUCET); if ( txfee == 0 ) txfee = 10000; @@ -214,7 +215,8 @@ std::string FaucetGet(uint64_t txfee) std::string FaucetFund(uint64_t txfee,int64_t funds) { - CMutableTransaction mtx; CPubKey mypk,faucetpk; CScript opret; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,faucetpk; CScript opret; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_FAUCET); if ( txfee == 0 ) txfee = 10000; @@ -231,7 +233,8 @@ std::string FaucetFund(uint64_t txfee,int64_t funds) UniValue FaucetInfo() { UniValue result(UniValue::VOBJ); char numstr[64]; - CMutableTransaction mtx; CPubKey faucetpk; struct CCcontract_info *cp,C; int64_t funding; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey faucetpk; struct CCcontract_info *cp,C; int64_t funding; result.push_back(Pair("result","success")); result.push_back(Pair("name","Faucet")); cp = CCinit(&C,EVAL_FAUCET); diff --git a/src/cc/fsm.cpp b/src/cc/fsm.cpp index 9f9accbb5..e75c53bcc 100644 --- a/src/cc/fsm.cpp +++ b/src/cc/fsm.cpp @@ -72,7 +72,7 @@ bool FSMExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &t else return(true); } -bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval; return(false); // reject any FSM CC for now @@ -157,7 +157,8 @@ std::string FSMList() std::string FSMCreate(uint64_t txfee,std::string name,std::string states) { - CMutableTransaction mtx; CPubKey mypk,fsmpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,fsmpk; CScript opret; int64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_FSM); if ( txfee == 0 ) txfee = 10000; @@ -177,7 +178,8 @@ std::string FSMCreate(uint64_t txfee,std::string name,std::string states) std::string FSMInfo(uint256 fsmtxid) { - CMutableTransaction mtx; CPubKey mypk,fsmpk; int64_t funds = 0; CScript opret; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,fsmpk; int64_t funds = 0; CScript opret; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_FSM); mypk = pubkey2pk(Mypubkey()); fsmpk = GetUnspendable(cp,0); diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index a9fc6a4cd..da9b57766 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -159,60 +159,6 @@ CScript EncodeGatewaysBindOpRet(uint8_t funcid,std::string coin,uint256 tokenid, return(opret); } -CScript EncodeGatewaysOpRet(uint8_t funcid,std::string coin,uint256 bindtxid,std::vector publishers,std::vectortxids,int32_t height,uint256 cointxid,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) -{ - CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << bindtxid << publishers << txids << height << cointxid << deposithex << proof << destpub << amount); - return(opret); -} - -uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey,std::string &coin,uint256 &bindtxid,std::vector&publishers,std::vector&txids,int32_t &height,uint256 &cointxid,std::string &deposithex,std::vector &proof,CPubKey &destpub,int64_t &amount) -{ - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> cointxid; ss >> deposithex; ss >> proof; ss >> destpub; ss >> amount) != 0 ) - { - return(f); - } - return(0); -} - -uint8_t DecodeGatewaysPartialOpRet(const CScript &scriptPubKey,int32_t &K, CPubKey &signerpk, std::string &coin,std::string &hex) -{ - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> K; ss >> signerpk; ss >> coin; ss >> hex) != 0 ) - { - return(f); - } - return(0); -} - -uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &assetid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) -{ - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) - { - return(f); - } - return(0); -} -uint8_t DecodeGatewaysMarkdoneOpRet(const CScript &scriptPubKey, std::string &refcoin, uint256 &cointxid) -{ - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> cointxid) != 0 ) - { - return(f); - } - return(0); -} - uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,std::string &coin,uint256 &tokenid,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &pubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2) { std::vector vopret; uint8_t *script,e,f; @@ -239,6 +185,133 @@ uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,st return(0); } +CScript EncodeGatewaysDepositOpRet(uint8_t funcid,std::string coin,uint256 bindtxid,std::vector publishers,std::vectortxids,int32_t height,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) +{ + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << bindtxid << publishers << txids << height << cointxid << claimvout << deposithex << proof << destpub << amount); + return(opret); +} + +uint8_t DecodeGatewaysDepositOpRet(const CScript &scriptPubKey,std::string &coin,uint256 &bindtxid,std::vector&publishers,std::vector&txids,int32_t &height,uint256 &cointxid, int32_t &claimvout,std::string &deposithex,std::vector &proof,CPubKey &destpub,int64_t &amount) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> cointxid; ss >> claimvout; ss >> deposithex; ss >> proof; ss >> destpub; ss >> amount) != 0 ) + { + return(f); + } + return(0); +} + +CScript EncodeGatewaysClaimOpRet(uint8_t funcid,uint256 assetid,std::string refcoin,uint256 bindtxid,uint256 deposittxid,CPubKey destpub,int64_t amount) +{ + CScript opret; uint8_t evalcode = EVAL_ASSETS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << refcoin << bindtxid << deposittxid << destpub << amount); + return(opret); +} + +uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &assetid,std::string &refcoin,uint256 &bindtxid,uint256 &deposittxid,CPubKey &destpub,int64_t &amount) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> refcoin; ss >> bindtxid; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 ) + { + return(f); + } + return(0); +} + +CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid,uint256 assetid, std::string refcoin, CPubKey withdrawpub, int64_t amount) +{ + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << refcoin << withdrawpub << amount); + return(opret); +} + +uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &assetid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) + { + return(f); + } + return(0); +} + +CScript EncodeGatewaysPartialOpRet(uint8_t funcid,int32_t K, CPubKey signerpk, std::string refcoin,std::string hex) +{ + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << K << signerpk << refcoin << hex); + return(opret); +} + +uint8_t DecodeGatewaysPartialOpRet(const CScript &scriptPubKey,int32_t &K, CPubKey &signerpk, std::string &refcoin,std::string &hex) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> K; ss >> signerpk; ss >> refcoin; ss >> hex) != 0 ) + { + return(f); + } + return(0); +} + +CScript EncodeGatewaysCompleteSigningOpRet(uint8_t funcid,std::string refcoin,uint256 withdrawtxid,std::string hex) +{ + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << withdrawtxid << hex); + return(opret); +} + +uint8_t DecodeGatewaysCompleteSigningOpRet(const CScript &scriptPubKey, std::string &refcoin, uint256 &withdrawtxid,std::string &hex) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> withdrawtxid; ss >> hex) != 0 ) + { + return(f); + } + return(0); +} + +CScript EncodeGatewaysMarkDoneOpRet(uint8_t funcid,std::string refcoin,uint256 withdrawtxid) +{ + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << withdrawtxid); + return(opret); +} + +uint8_t DecodeGatewaysMarkDoneOpRet(const CScript &scriptPubKey, std::string &refcoin, uint256 &withdrawtxid) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> withdrawtxid;) != 0 ) + { + return(f); + } + return(0); +} + +uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && (script[0] == EVAL_GATEWAYS || script[0] == EVAL_ASSETS) && E_UNMARSHAL(vopret,ss >> e; ss >> f) != 0 ) + { + if (f == 'B' && f == 'D' && f == 't' && f == 'W' && f == 'P' && f == 'M') + return(f); + } + return(0); +} + int64_t IsGatewaysvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) { char destaddr[64]; @@ -288,10 +361,160 @@ bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti else return(true); } -bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) +static int32_t myIs_coinaddr_inmempoolvout(char *coinaddr) { - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; - std::vector > txids; + int32_t i,n; char destaddr[64]; + BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) + { + const CTransaction &tx = e.GetTx(); + if ( (n= tx.vout.size()) > 0 ) + { + const uint256 &txid = tx.GetHash(); + for (i=0; idata; + txid = zeroid; + char str[65]; + //fprintf(stderr,"start reverse scan %s\n",uint256_str(str,batontxid)); + while ( myGetTransaction(batontxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 ) + { + //fprintf(stderr,"check %s\n",uint256_str(str,batontxid)); + if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid ) + { + //fprintf(stderr,"decoded %s\n",uint256_str(str,batontxid)); + if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height ) + { + len = oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()); + len2 = oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size()); + char str2[65]; fprintf(stderr,"found merkleht.%d len.%d len2.%d %s %s\n",(int32_t)merkleht,len,len2,uint256_str(str,hash),uint256_str(str2,mhash)); + if ( len == sizeof(hash)+sizeof(int32_t) && len2 == 2*sizeof(mhash)+sizeof(int32_t) && mhash != zeroid ) + { + txid = batontxid; + //fprintf(stderr,"set txid\n"); + return(mhash); + } + else + { + //fprintf(stderr,"missing hash\n"); + return(zeroid); + } + } //else fprintf(stderr,"height.%d vs search ht.%d\n",(int32_t)merkleht,(int32_t)height); + batontxid = bhash; + //fprintf(stderr,"new hash %s\n",uint256_str(str,batontxid)); + } else break; + } + fprintf(stderr,"end of loop\n"); + return(zeroid); +} + +int32_t GatewaysCointxidExists(struct CCcontract_info *cp,uint256 cointxid) // dont forget to check mempool! +{ + char txidaddr[64]; std::string coin; int32_t numvouts; uint256 hashBlock; + std::vector > addressIndex; + CCtxidaddr(txidaddr,cointxid); + SetCCtxids(addressIndex,txidaddr); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + { + return(-1); + } + return(myIs_coinaddr_inmempoolvout(txidaddr)); +} + +/* Get the block merkle root for a proof + * IN: proofData + * OUT: merkle root + * OUT: transaction IDS + */ +uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::vector &txids) +{ + CMerkleBlock merkleBlock; + if (!E_UNMARSHAL(proofData, ss >> merkleBlock)) + return uint256(); + return merkleBlock.txn.ExtractMatches(txids); +} + +int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub) +{ + std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; char destaddr[64],destpubaddr[64],claimaddr[64],str[65],str2[65]; int32_t i,numvouts; int64_t nValue = 0; + if ( myGetTransaction(oracletxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + fprintf(stderr,"GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid)); + return(0); + } + if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin ) + { + fprintf(stderr,"GatewaysVerify mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str()); + return(0); + } + proofroot = BitcoinGetProofMerkleRoot(proof,txids); + if ( proofroot != merkleroot ) + { + fprintf(stderr,"GatewaysVerify mismatched merkleroot %s != %s\n",uint256_str(str,proofroot),uint256_str(str2,merkleroot)); + return(0); + } + if ( DecodeHexTx(tx,deposithex) != 0 ) + { + Getscriptaddress(claimaddr,tx.vout[claimvout].scriptPubKey); + Getscriptaddress(destpubaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG); + if ( strcmp(claimaddr,destpubaddr) == 0 ) + { + for (i=0; i publishers; std::vectortxids; uint256 bindtxid,cointxid; std::vector proof; CPubKey claimpubkey; + if ( (numvouts= tx.vout.size()) > 0 ) + { + if ( DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,claimvout,deposithex,proof,claimpubkey,amount) == 'D' && claimpubkey == mypk ) + { + // coin, bindtxid, publishers + fprintf(stderr,"need to validate deposittxid more\n"); + return(amount); + } + } + return(0); +} + +bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn) +{ + int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks,height,claimvout; bool retval; uint8_t funcid,hash[32],M,N,taddr,prefix,prefix2; + char str[65],destaddr[64],depositaddr[65],validationError[512]; + std::vector txids; std::vector pubkeys,publishers,tmppublishers; std::vector proof; int64_t totalsupply,amount,tmpamount; + uint256 hashblock,txid,bindtxid,deposittxid,assetid,oracletxid,tokenid,cointxid,tmptxid,tmpxtxid2,merkleroot,mhash; CTransaction bindtx,deposittx,oracletx; + std::string refcoin,tmprefcoin,deposithex; CPubKey destpub,tmpdestpub; + fprintf(stderr,"return true without gateways validation\n"); return(true); numvins = tx.vin.size(); @@ -301,29 +524,151 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("no vouts"); else { - for (i=0; iInvalid("illegal normal vini"); - } - } + // for (i=0; iInvalid("illegal normal vini"); + // } + // } //fprintf(stderr,"check amounts\n"); - if ( GatewaysExactAmounts(cp,eval,tx,1,10000) == false ) - { - fprintf(stderr,"Gatewaysget invalid amount\n"); - return false; - } - else - { + // if ( GatewaysExactAmounts(cp,eval,tx,1,10000) == false ) + // { + // fprintf(stderr,"Gatewaysget invalid amount\n"); + // return false; + // } + // else + // { txid = tx.GetHash(); memcpy(hash,&txid,sizeof(hash)); + + if ( (funcid = DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey)) != 0) + { + switch ( funcid ) + { + case 'B': + //vin.0: normal input + //vout.0: CC vout txfee marker + //vout.n-1: opreturn - 'B' coin tokenid totalsupply oracletxid M N pubkeys taddr prefix prefix2 + return eval->Invalid("unexpected GatewaysValidate for gatewaysbind!"); + break; + case 'D': + //vin.0: normal input + //vout.0: CC vout txfee marker to destination pubkey + //vout.1: normal output txfee marker to txidaddr + //vout.n-1: opreturn - 'D' coin bindtxid publishers txids height cointxid deposithex proof destpub amount + return eval->Invalid("unexpected GatewaysValidate for gatewaysdeposit!"); + break; + case 't': + //vin.0: normal input + //vin.1: CC input of converted token to gateways eval code + //vin.2: CC input of marker from gatewaysdeposit tx + //vout.0: CC vout of total tokens from deposit amount to asset eval code + //(vout.1): CC vout if there is change of unused tokens back to owner of tokens (deposit amount less than available tokens) + //vout.n-1: opreturn - 't' assetid zeroid 0 mypubkey (NOTE: opreturn is with asset eval code) + if ((numvouts=tx.vout.size()) > 0 && DecodeGatewaysClaimOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,refcoin,bindtxid,deposittxid,destpub,amount)==0) + return eval->Invalid("invalid gatewaysclaim OP_RETURN data!"); + else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + return eval->Invalid("vin.0 is normal for gatewaysClaim!"); + else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) + return eval->Invalid("vin.1 is CC for gatewaysClaim!"); + else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) + return eval->Invalid("vin.2 is CC for gatewaysClaim!"); + else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.0 is CC for gatewaysClaim!"); + else if ( numvouts > 2 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.1 is CC for gatewaysClaim!"); + else if (myGetTransaction(bindtxid,bindtx,hashblock) == 0) + return eval->Invalid("invalid gatewaysbind txid!"); + else if ((numvouts=bindtx.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B') + return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); + else if (tmprefcoin!=refcoin) + return eval->Invalid("refcoin different in bind tx"); + else if (tokenid!=assetid) + return eval->Invalid("assetid does not match tokenid from gatewaysbind"); + else if (komodo_txnotarizedconfirmed(bindtxid) == false) + return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); + else if (myGetTransaction(deposittxid,deposittx,hashblock) == 0) + return eval->Invalid("invalid gatewaysdeposittxid!"); + else if ((numvouts=deposittx.vout.size()) > 0 && DecodeGatewaysDepositOpRet(deposittx.vout[numvouts-1].scriptPubKey,tmprefcoin,tmptxid,tmppublishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D') + return eval->Invalid("invalid gatewaysdeposit OP_RETURN data!"); + else if (tmprefcoin!=refcoin) + return eval->Invalid("refcoin different in deposit tx"); + else if (bindtxid!=tmptxid) + return eval->Invalid("bindtxid does not match to bindtxid from gatewaysdeposit"); + else if (tmpamount>totalsupply) + return eval->Invalid("deposit amount greater then bind total supply"); + else if (komodo_txnotarizedconfirmed(deposittxid) == false) + return eval->Invalid("gatewaysdeposit tx is not yet confirmed(notarised)!"); + else if (amount>tmpamount) + return eval->Invalid("claimed amount greater then deposit amount"); + else if (destpub!=tmpdestpub) + return eval->Invalid("destination pubkey different than in deposit tx"); + else + { + int32_t m; + merkleroot = zeroid; + for (i=m=0; iInvalid(validationError); + } + if ( GatewaysCointxidExists(cp,cointxid) != 0 ) + { + sprintf(validationError,"cointxid.%s already exists\n",uint256_str(str,cointxid)); + return eval->Invalid(validationError); + } + if (GatewaysVerify(depositaddr,oracletxid,claimvout,tmprefcoin,cointxid,deposithex,proof,merkleroot,destpub)!=amount) + return eval->Invalid("deposittxid didnt validate\n"); + } + break; + case 'W': + //vin.0: normal input + //vin.1: CC input of converted token back to gateways eval code + //vout.0: CC vout of tokens back to gateways CC address + //vout.1: normal vout txfee marker to withdraw destination pubkey + //vout.2: CC vout txfee marker to gateways CC address + //vout.n-2: CC vout if there is change of unused tokens back to owner of tokens (withdraw amount less than owner available tokens) + //vout.n-1: opreturn - 'W' assetid refcoin withdrawpub amount + break; + case 'P': + //vin.0: normal input + //(vin.1): CC input form previous marker of gatewayspartialsign tx (if exists) + //vout.0: CC vout 5k sat marker to senders pubKey + //vout.n-1: opreturn - 'P' number_of_signs mypk refcoin hex + break; + case 'C': + //vin.0: CC input from gatewayswithdraw tx marker to gateways CC address + //vout.0: CC vout txfee marker to gateways CC address + //vout.n-1: opreturn - 'C' refcoin cointxid external_tx_hex + break; + case 'M': + //vin.0: CC input from gatewayscompletesigning tx marker to gateways CC address + //vout.0: opreturn - 'M' refcoin cointxid + break; + } + } + + retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); if ( retval != 0 ) fprintf(stderr,"Gatewaysget validated\n"); else fprintf(stderr,"Gatewaysget invalid\n"); return(retval); - } + // } } } // end of consensus code @@ -336,8 +681,8 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); - threshold = total/maxinputs; - fprintf(stderr,"check %s for gateway inputs\n",coinaddr); + threshold = total/(maxinputs+1); + //fprintf(stderr,"check %s for gateway inputs\n",coinaddr); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; @@ -352,7 +697,7 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { Getscriptaddress(destaddr,vintx.vout[vout].scriptPubKey); - fprintf(stderr,"check %s vout.%d %.8f %.8f\n",destaddr,vout,(double)vintx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN); + //fprintf(stderr,"check %s vout.%d %.8f %.8f\n",destaddr,vout,(double)vintx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN); if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 ) continue; GetOpReturnData(vintx.vout[vintx.vout.size()-1].scriptPubKey, vopret); @@ -362,6 +707,7 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for refassetid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,refassetid),uint256_str(str2,assetid),(double)vintx.vout[vout].nValue/COIN); if ( assetid == refassetid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) { + // call IsAssetsVout? //fprintf(stderr,"total %llu maxinputs.%d %.8f\n",(long long)total,maxinputs,(double)it->second.satoshis/COIN); if ( total != 0 && maxinputs != 0 ) mtx.vin.push_back(CTxIn(txid,vout,CScript())); @@ -401,104 +747,10 @@ int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 return(0); } -static int32_t myIs_coinaddr_inmempoolvout(char *coinaddr) -{ - int32_t i,n; char destaddr[64]; - BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) - { - const CTransaction &tx = e.GetTx(); - if ( (n= tx.vout.size()) > 0 ) - { - const uint256 &txid = tx.GetHash(); - for (i=0; i > addressIndex; - CCtxidaddr(txidaddr,cointxid); - SetCCtxids(addressIndex,txidaddr); - for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) - { - return(-1); - } - return(myIs_coinaddr_inmempoolvout(txidaddr)); -} - -UniValue GatewaysInfo(uint256 bindtxid) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; char str[67],numstr[65],depositaddr[64],gatewaysassets[64]; uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CMutableTransaction mtx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int32_t i; int64_t totalsupply,remaining; - result.push_back(Pair("result","success")); - result.push_back(Pair("name","Gateways")); - cp = CCinit(&C,EVAL_GATEWAYS); - Gatewayspk = GetUnspendable(cp,0); - _GetCCaddress(gatewaysassets,EVAL_GATEWAYS,Gatewayspk); - if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) - { - depositaddr[0] = 0; - if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 0 ) - { - if ( N > 1 ) - { - result.push_back(Pair("M",M)); - result.push_back(Pair("N",N)); - for (i=0; i > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid,tokenid; CTransaction vintx; std::string coin; int64_t totalsupply; char str[65],depositaddr[64]; uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; - cp = CCinit(&C,EVAL_GATEWAYS); - SetCCtxids(addressIndex,cp->unspendableCCaddr); - for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) - { - txid = it->first.txhash; - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) - { - if ( vintx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 ) - { - result.push_back(uint256_str(str,txid)); - } - } - } - return(result); -} - std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector pubkeys) { - CMutableTransaction mtx; CTransaction oracletx; uint8_t taddr,prefix,prefix2; CPubKey mypk,gatewayspk; CScript opret; uint256 hashBlock; struct CCcontract_info *cp,C; std::string name,description,format; int32_t i,numvouts; int64_t fullsupply; char destaddr[64],coinaddr[64],str[65],*fstr; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction oracletx; uint8_t taddr,prefix,prefix2; CPubKey mypk,gatewayspk; CScript opret; uint256 hashBlock; struct CCcontract_info *cp,C; std::string name,description,format; int32_t i,numvouts; int64_t fullsupply; char destaddr[64],coinaddr[64],str[65],*fstr; cp = CCinit(&C,EVAL_GATEWAYS); if ( strcmp((char *)"KMD",coin.c_str()) == 0 ) { @@ -571,128 +823,23 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t fprintf(stderr,"Gateway bind.%s (%s) already exists\n",coin.c_str(),uint256_str(str,tokenid)); return(""); } - if ( AddNormalinputs(mtx,mypk,2*txfee,60) > 0 ) + if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gatewayspk)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysBindOpRet('B',coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2))); } - fprintf(stderr,"cant find enough inputs\n"); + CCerror = strprintf("cant find enough inputs"); + fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } -uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid) -{ - CTransaction tx; uint256 hash,mhash,bhash,hashBlock,oracletxid; int32_t len,len2,numvouts; int64_t val,merkleht; CPubKey pk; std::vectordata; - txid = zeroid; - char str[65]; - //fprintf(stderr,"start reverse scan %s\n",uint256_str(str,batontxid)); - while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) - { - //fprintf(stderr,"check %s\n",uint256_str(str,batontxid)); - if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid ) - { - //fprintf(stderr,"decoded %s\n",uint256_str(str,batontxid)); - if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height ) - { - len = oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()); - len2 = oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size()); - char str2[65]; fprintf(stderr,"found merkleht.%d len.%d len2.%d %s %s\n",(int32_t)merkleht,len,len2,uint256_str(str,hash),uint256_str(str2,mhash)); - if ( len == sizeof(hash)+sizeof(int32_t) && len2 == 2*sizeof(mhash)+sizeof(int32_t) && mhash != zeroid ) - { - txid = batontxid; - //fprintf(stderr,"set txid\n"); - return(mhash); - } - else - { - //fprintf(stderr,"missing hash\n"); - return(zeroid); - } - } //else fprintf(stderr,"height.%d vs search ht.%d\n",(int32_t)merkleht,(int32_t)height); - batontxid = bhash; - //fprintf(stderr,"new hash %s\n",uint256_str(str,batontxid)); - } else break; - } - fprintf(stderr,"end of loop\n"); - return(zeroid); -} - -/* Get the block merkle root for a proof - * IN: proofData - * OUT: merkle root - * OUT: transaction IDS - */ -uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::vector &txids) -{ - CMerkleBlock merkleBlock; - if (!E_UNMARSHAL(proofData, ss >> merkleBlock)) - return uint256(); - return merkleBlock.txn.ExtractMatches(txids); -} - -int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub) -{ - std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; char destaddr[64],destpubaddr[64],claimaddr[64],str[65],str2[65]; int32_t i,numvouts; int64_t nValue = 0; - if ( GetTransaction(oracletxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - fprintf(stderr,"GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid)); - return(0); - } - if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin ) - { - fprintf(stderr,"GatewaysVerify mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str()); - return(0); - } - proofroot = BitcoinGetProofMerkleRoot(proof,txids); - if ( proofroot != merkleroot ) - { - fprintf(stderr,"GatewaysVerify mismatched merkleroot %s != %s\n",uint256_str(str,proofroot),uint256_str(str2,merkleroot)); - return(0); - } - if ( DecodeHexTx(tx,deposithex) != 0 ) - { - Getscriptaddress(claimaddr,tx.vout[claimvout].scriptPubKey); - Getscriptaddress(destpubaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG); - if ( strcmp(claimaddr,destpubaddr) == 0 ) - { - for (i=0; i publishers; std::vectortxids; uint256 bindtxid,cointxid; std::vector proof; CPubKey claimpubkey; - if ( (numvouts= tx.vout.size()) > 0 ) - { - if ( DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,claimpubkey,amount) == 'D' && claimpubkey == mypk ) - { - // coin, bindtxid, publishers - fprintf(stderr,"need to validate deposittxid more\n"); - return(amount); - } - } - return(0); -} - std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) { - CMutableTransaction mtx; CTransaction bindtx; CPubKey mypk,gatewayspk; uint256 oracletxid,merkleroot,mhash,hashBlock,tokenid,txid; int64_t totalsupply; int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2; std::string coin; struct CCcontract_info *cp,C; std::vector pubkeys,publishers; std::vectortxids; char str[67],depositaddr[64],txidaddr[64]; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction bindtx; CPubKey mypk,gatewayspk; uint256 oracletxid,merkleroot,mhash,hashBlock,tokenid,txid; + int64_t totalsupply; int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2; std::string coin; struct CCcontract_info *cp,C; + std::vector pubkeys,publishers; std::vectortxids; char str[67],depositaddr[64],txidaddr[64]; + cp = CCinit(&C,EVAL_GATEWAYS); if ( txfee == 0 ) txfee = 10000; @@ -706,7 +853,7 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: } if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin ) { - fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); + fprintf(stderr,"invalid coin - bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); } n = (int32_t)pubkeys.size(); @@ -743,11 +890,11 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: fprintf(stderr,"deposittxid didnt validate\n"); return(""); } - if ( AddNormalinputs(mtx,mypk,3*txfee,60) > 0 ) + if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 ) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,destpub)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr,cointxid))) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,destpub,amount))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysDepositOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,claimvout,deposithex,proof,destpub,amount))); } fprintf(stderr,"cant find enough inputs\n"); return(""); @@ -755,7 +902,12 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount) { - CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector msigpubkeys; int64_t totalsupply,depositamount,inputs,CCchange=0; int32_t numvouts; uint256 hashBlock,assetid,oracletxid; char str[65],depositaddr[64],coinaddr[64],destaddr[64]; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction tx; CPubKey mypk,gatewayspk,tmpdestpub; struct CCcontract_info *cp,C; uint8_t M,N,taddr,prefix,prefix2; + std::string coin, deposithex; std::vector msigpubkeys,publishers; int64_t totalsupply,depositamount,tmpamount,inputs,CCchange=0; + int32_t numvouts,claimvout,height; std::vector proof; + uint256 hashBlock,assetid,oracletxid,tmptxid,cointxid; char str[65],depositaddr[64],coinaddr[64],destaddr[64]; std::vector txids; + cp = CCinit(&C,EVAL_GATEWAYS); if ( txfee == 0 ) txfee = 10000; @@ -768,44 +920,56 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui } if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) { - fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); + fprintf(stderr,"invalid coin - bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); } - if ( GetTransaction(deposittxid,tx,hashBlock,false) == 0 ) + if ( GetTransaction(deposittxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { fprintf(stderr,"cant find deposittxid %s\n",uint256_str(str,bindtxid)); return(""); } + if (DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,coin,tmptxid,publishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D' || coin != refcoin) + { + fprintf(stderr,"invalid coin - deposittxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); + return(""); + } + if (tmpdestpub!=destpub) + { + fprintf(stderr,"different destination pubkey from desdeposittxid\n"); + return(""); + } if ( (depositamount= GatewaysDepositval(tx,mypk)) != amount ) { fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN); return(""); } //fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,assetid,amount,60)) > 0 ) { if ( inputs > amount ) CCchange = (inputs - amount); _GetCCaddress(destaddr,EVAL_GATEWAYS,mypk); - printf("expecting deposittxid/v0 to be to %s\n",destaddr); + //printf("expecting deposittxid/v0 to be to %s\n",destaddr); mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); // triggers EVAL_GATEWAYS validation mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk)); // transfer back to normal token if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey()))); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysClaimOpRet('t',assetid,refcoin,bindtxid,deposittxid,destpub,amount))); } } - fprintf(stderr,"cant find enough inputs or mismatched total\n"); + CCerror = strprintf("cant find enough inputs or mismatched total"); + fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) { - CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; - std::vector msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; CScript opret; + std::vector msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; cp = CCinit(&C,EVAL_GATEWAYS); if ( txfee == 0 ) txfee = 10000; @@ -821,7 +985,7 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); } - if ( AddNormalinputs(mtx,mypk,3*txfee,3) > 0 ) + if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 ) { if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,assetid,amount,60)) > 0 ) { @@ -831,35 +995,88 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG)); mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk)); if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,mypk)); - opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'W' << assetid << refcoin << withdrawpub << amount); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,mypk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysWithdrawOpRet('W',assetid,refcoin,withdrawpub,amount))); } } - fprintf(stderr,"cant find enough inputs or mismatched total\n"); + CCerror = strprintf("cant find enough inputs or mismatched total"); + fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } -std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,uint256 cointxid) +std::string GatewaysPartialSign(uint64_t txfee,uint256 txid,std::string refcoin, std::string hex) { - CMutableTransaction mtx; CScript opret; CPubKey mypk; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,txidaddrpk,signerpk; struct CCcontract_info *cp,C; CTransaction tx; + std::vector > unspentOutputs; char txidaddr[65]; + int32_t maxK,K=0; uint256 tmptxid,parttxid,hashBlock; cp = CCinit(&C,EVAL_GATEWAYS); if ( txfee == 0 ) txfee = 5000; mypk = pubkey2pk(Mypubkey()); + txidaddrpk=CCtxidaddr(txidaddr,txid); + SetCCunspents(unspentOutputs,txidaddr); + maxK=0; + if (unspentOutputs.size()==0) + { + if (AddNormalinputs(mtx,mypk,2*txfee,3)==0) fprintf(stderr,"error adding funds for partialsign\n"); + } + else + { + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + tmptxid = it->first.txhash; + if (GetTransaction(tmptxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && DecodeGatewaysPartialOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK ) + { + maxK=K; + parttxid=tmptxid; + } + } + if (maxK>0) + { + if (AddNormalinputs(mtx,mypk,txfee,3)==0) fprintf(stderr,"error adding funds for partialsign\n"); + mtx.vin.push_back(CTxIn(parttxid,0,CScript())); + } + else fprintf(stderr,"Error finding previous partial tx\n"); + } + + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,5000,txidaddrpk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysPartialOpRet('P',maxK+1,mypk,refcoin,hex))); +} + +std::string GatewaysCompleteSigning(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,std::string hex) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; char txidaddr[65]; + cp = CCinit(&C,EVAL_GATEWAYS); + mypk = pubkey2pk(Mypubkey()); + gatewayspk = GetUnspendable(cp,0); + if ( txfee == 0 ) + txfee = 10000; mtx.vin.push_back(CTxIn(withdrawtxid,2,CScript())); - mtx.vout.push_back(CTxOut(5000,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'M' << cointxid << refcoin); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysCompleteSigningOpRet('C',refcoin,withdrawtxid,hex))); +} + +std::string GatewaysMarkDone(uint64_t txfee,uint256 completetxid,std::string refcoin) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; char txidaddr[65]; + cp = CCinit(&C,EVAL_GATEWAYS); + mypk = pubkey2pk(Mypubkey()); + if ( txfee == 0 ) + txfee = 10000; + mtx.vin.push_back(CTxIn(completetxid,0,CScript())); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysMarkDoneOpRet('M',refcoin,completetxid))); } UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) { - UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string coin,tmprefcoin; CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; - uint256 cointxid,hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; - char depositaddr[64],withmarker[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],signeraddr[64]; - int32_t i,n,numvouts,vout,numqueued,queueflag; int64_t totalsupply,amount,nValue; struct CCcontract_info *cp,C; + UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string tmprefcoin; CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; + uint256 hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; + char depositaddr[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],cctxidaddr[64],signeraddr[64]; + int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,amount,nValue; struct CCcontract_info *cp,C; std::vector > unspentOutputs; cp = CCinit(&C,EVAL_GATEWAYS); @@ -871,9 +1088,9 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(result); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) { - fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); + fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str()); return(result); } n = msigpubkeys.size(); @@ -884,15 +1101,14 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) queueflag = 1; break; } - SetCCunspents(unspentOutputs,coinaddr); - numqueued = 0; + SetCCunspents(unspentOutputs,coinaddr); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; vout = (int32_t)it->first.index; nValue = (int64_t)it->second.satoshis; fprintf(stderr,"%s %d %ld\n",txid.ToString().c_str(),vout,(long)nValue); - if ( vout == 2 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) && + if ( vout == 2 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0) { Getscriptaddress(destaddr,tx.vout[0].scriptPubKey); @@ -901,11 +1117,12 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid",uint256_str(str,txid))); - CCtxidaddr(txidaddr,txid); - obj.push_back(Pair("txidaddr",txidaddr)); + _GetCCaddress(cctxidaddr,EVAL_GATEWAYS,CCtxidaddr(txidaddr,txid)); + obj.push_back(Pair("txidaddr",cctxidaddr)); obj.push_back(Pair("withdrawaddr",withaddr)); sprintf(numstr,"%.8f",(double)tx.vout[0].nValue/COIN); obj.push_back(Pair("amount",numstr)); + obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(txid))); if ( queueflag != 0 ) { obj.push_back(Pair("depositaddr",depositaddr)); @@ -922,12 +1139,73 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) return(result); } -UniValue GatewaysMultisig(char *txidaddr) +UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) +{ + UniValue result(UniValue::VOBJ),processed(UniValue::VARR); CTransaction tx; std::string tmprefcoin,hex; CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; + uint256 withdrawtxid,hashBlock,txid,assetid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; + char depositaddr[64],coinaddr[64],str[65],numstr[32],txidaddr[64],cctxidaddr[64],withaddr[64]; + int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,nValue,amount; struct CCcontract_info *cp,C; + std::vector > unspentOutputs; + + cp = CCinit(&C,EVAL_GATEWAYS); + mypk = pubkey2pk(Mypubkey()); + gatewayspk = GetUnspendable(cp,0); + _GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); + return(result); + } + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) + { + fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str()); + return(result); + } + n = msigpubkeys.size(); + queueflag = 0; + for (i=0; i >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + nValue = (int64_t)it->second.satoshis; + //fprintf(stderr,"%s %d %ld\n",txid.ToString().c_str(),vout,(long)nValue); + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && + DecodeGatewaysCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,tmprefcoin,withdrawtxid,hex) == 'C' && myIsutxo_spentinmempool(txid,vout) == 0) + { + if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,tmprefcoin,withdrawpub,amount) == 'W') + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("txid",uint256_str(str,txid))); + obj.push_back(Pair("withdrawtxid",uint256_str(str,withdrawtxid))); + _GetCCaddress(cctxidaddr,EVAL_GATEWAYS,CCtxidaddr(txidaddr,withdrawtxid)); + obj.push_back(Pair("withdrawtxidaddr",cctxidaddr)); + Getscriptaddress(withaddr,tx.vout[1].scriptPubKey); + obj.push_back(Pair("withdrawaddr",withaddr)); + obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(txid))); + obj.push_back(Pair("hex",hex)); + processed.push_back(obj); + } + } + } + result.push_back(Pair("coin",refcoin)); + result.push_back(Pair("processed",processed)); + result.push_back(Pair("queueflag",queueflag)); + return(result); +} + +UniValue GatewaysMultisig(char *cctxidaddr) { std::string parthex,hex,refcoin; uint256 txid,hashBlock; CTransaction tx; int32_t i,maxK,K,numvouts; CPubKey signerpk; std::vector > unspentOutputs; UniValue result(UniValue::VOBJ); - - SetCCunspents(unspentOutputs,txidaddr); + + SetCCunspents(unspentOutputs,cctxidaddr); maxK=0; for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { @@ -956,38 +1234,62 @@ UniValue GatewaysMultisig(char *txidaddr) return (result); } -std::string GatewaysPartialSign(uint64_t txfee,uint256 txid,std::string refcoin, std::string hex) +UniValue GatewaysList() { - CMutableTransaction mtx; CScript opret; CPubKey mypk,txidaddrpk,signerpk; struct CCcontract_info *cp,C; CTransaction tx; - std::vector > unspentOutputs; char txidaddr[65]; - int32_t maxK,K=0; uint256 tmptxid,parttxid,hashBlock; + UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid,tokenid; CTransaction vintx; std::string coin; int64_t totalsupply; char str[65],depositaddr[64]; uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; cp = CCinit(&C,EVAL_GATEWAYS); - if ( txfee == 0 ) - txfee = 5000; - mypk = pubkey2pk(Mypubkey()); - txidaddrpk=CCtxidaddr(txidaddr,txid); - SetCCunspents(unspentOutputs,txidaddr); - maxK=0; - if (unspentOutputs.size()==0) + SetCCtxids(addressIndex,cp->unspendableCCaddr); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { - if (AddNormalinputs(mtx,mypk,2*txfee,2)==0) fprintf(stderr,"error adding funds for partialsign\n"); - } - else - { - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + txid = it->first.txhash; + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - tmptxid = it->first.txhash; - if (GetTransaction(tmptxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && DecodeGatewaysPartialOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK ) + if ( vintx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 ) { - maxK=K; - parttxid=tmptxid; + result.push_back(uint256_str(str,txid)); } } - if (maxK>0) mtx.vin.push_back(CTxIn(parttxid,0,CScript())); - else fprintf(stderr,"Error finding previous partial tx\n"); } - - mtx.vout.push_back(CTxOut(5000,CScript() << ParseHex(HexStr(txidaddrpk)) << OP_CHECKSIG)); - opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'P' << maxK+1 << mypk << refcoin << hex); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); + return(result); +} + +UniValue GatewaysInfo(uint256 bindtxid) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; char str[67],numstr[65],depositaddr[64],gatewaysassets[64]; uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int32_t i; int64_t totalsupply,remaining; + result.push_back(Pair("result","success")); + result.push_back(Pair("name","Gateways")); + cp = CCinit(&C,EVAL_GATEWAYS); + Gatewayspk = GetUnspendable(cp,0); + _GetCCaddress(gatewaysassets,EVAL_GATEWAYS,Gatewayspk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) + { + depositaddr[0] = 0; + if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 0 ) + { + if ( N > 1 ) + { + result.push_back(Pair("M",M)); + result.push_back(Pair("N",N)); + for (i=0; i vopret,data; CScript scriptPubKey; CPubKey publisher; numvins = tx.vin.size(); @@ -724,7 +728,8 @@ int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubK std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format) { - CMutableTransaction mtx; CPubKey mypk,Oraclespk; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,Oraclespk; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_ORACLES); if ( name.size() > 32 || description.size() > 4096 || format.size() > 4096 ) { @@ -735,7 +740,7 @@ std::string OracleCreate(int64_t txfee,std::string name,std::string description, txfee = 10000; mypk = pubkey2pk(Mypubkey()); Oraclespk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) { mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(Oraclespk)) << OP_CHECKSIG)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesCreateOpRet('C',name,description,format))); @@ -745,7 +750,8 @@ std::string OracleCreate(int64_t txfee,std::string name,std::string description, std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee) { - CMutableTransaction mtx; CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64]; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64]; cp = CCinit(&C,EVAL_ORACLES); if ( txfee == 0 ) txfee = 10000; @@ -768,13 +774,14 @@ std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee) std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount) { - CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; char markeraddr[64]; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; char markeraddr[64]; cp = CCinit(&C,EVAL_ORACLES); if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); markerpubkey = CCtxidaddr(markeraddr,oracletxid); - if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,64) > 0 ) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,publisher)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); @@ -785,17 +792,20 @@ std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,i std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector data) { - CMutableTransaction mtx; CScript pubKey; CPubKey mypk,batonpk; int64_t datafee,inputs,CCchange = 0; struct CCcontract_info *cp,C; uint256 batontxid; char coinaddr[64],batonaddr[64]; std::vector prevdata; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CScript pubKey; CPubKey mypk,batonpk; int64_t datafee,inputs,CCchange = 0; struct CCcontract_info *cp,C; uint256 batontxid; char coinaddr[64],batonaddr[64]; std::vector prevdata; cp = CCinit(&C,EVAL_ORACLES); mypk = pubkey2pk(Mypubkey()); if ( data.size() > 8192 ) { - fprintf(stderr,"datasize %d is too big\n",(int32_t)data.size()); + CCerror = strprintf("datasize %d is too big",(int32_t)data.size()); + fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } if ( (datafee= OracleDatafee(pubKey,oracletxid,mypk)) <= 0 ) { - fprintf(stderr,"datafee %.8f is illegal\n",(double)datafee/COIN); + CCerror = strprintf("datafee %.8f is illegal",(double)datafee/COIN); + fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } if ( txfee == 0 ) @@ -816,8 +826,14 @@ std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector da mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk)); mtx.vout.push_back(CTxOut(datafee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesData('D',oracletxid,batontxid,mypk,data))); - } else fprintf(stderr,"couldnt find enough oracle inputs %s, limit 1 per utxo\n",coinaddr); - } else fprintf(stderr,"couldnt add normal inputs\n"); + } else { + CCerror = strprintf("couldnt find enough oracle inputs %s, limit 1 per utxo\n",coinaddr); + fprintf(stderr,"%s\n", CCerror.c_str() ); + } + } else { + CCerror = strprintf("couldnt add normal inputs\n"); + fprintf(stderr,"%s\n", CCerror.c_str() ); + } return(""); } @@ -867,7 +883,8 @@ UniValue OracleInfo(uint256 origtxid) { UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::vector > unspentOutputs; - CMutableTransaction mtx; CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector data; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector data; cp = CCinit(&C,EVAL_ORACLES); CCtxidaddr(markeraddr,origtxid); if ( GetTransaction(origtxid,tx,hashBlock,false) == 0 ) diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index f3cd40ba2..70f1ab914 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -72,7 +72,7 @@ bool PaymentsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti else return(true); } -bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; return(false); @@ -144,7 +144,8 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP std::string PaymentsGet(uint64_t txfee,int64_t nValue) { - CMutableTransaction mtx,tmpmtx; CPubKey mypk,Paymentspk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; + CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,Paymentspk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; cp = CCinit(&C,EVAL_PAYMENTS); if ( txfee == 0 ) txfee = 10000; @@ -184,7 +185,8 @@ std::string PaymentsGet(uint64_t txfee,int64_t nValue) std::string PaymentsFund(uint64_t txfee,int64_t funds) { - CMutableTransaction mtx; CPubKey mypk,Paymentspk; CScript opret; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,Paymentspk; CScript opret; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_PAYMENTS); if ( txfee == 0 ) txfee = 10000; @@ -201,7 +203,8 @@ std::string PaymentsFund(uint64_t txfee,int64_t funds) UniValue PaymentsInfo() { UniValue result(UniValue::VOBJ); char numstr[64]; - CMutableTransaction mtx; CPubKey Paymentspk; struct CCcontract_info *cp,C; int64_t funding; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey Paymentspk; struct CCcontract_info *cp,C; int64_t funding; result.push_back(Pair("result","success")); result.push_back(Pair("name","Payments")); cp = CCinit(&C,EVAL_PAYMENTS); diff --git a/src/cc/pegs.cpp b/src/cc/pegs.cpp index 21e371b4a..403dfb87a 100644 --- a/src/cc/pegs.cpp +++ b/src/cc/pegs.cpp @@ -79,7 +79,7 @@ bool PegsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction & else return(true); } -bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; return(false); @@ -151,7 +151,8 @@ int64_t AddPegsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe std::string PegsGet(uint64_t txfee,int64_t nValue) { - CMutableTransaction mtx,tmpmtx; CPubKey mypk,Pegspk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; + CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,Pegspk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; cp = CCinit(&C,EVAL_PEGS); if ( txfee == 0 ) txfee = 10000; @@ -191,7 +192,8 @@ std::string PegsGet(uint64_t txfee,int64_t nValue) std::string PegsFund(uint64_t txfee,int64_t funds) { - CMutableTransaction mtx; CPubKey mypk,Pegspk; CScript opret; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,Pegspk; CScript opret; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_PEGS); if ( txfee == 0 ) txfee = 10000; @@ -208,7 +210,8 @@ std::string PegsFund(uint64_t txfee,int64_t funds) UniValue PegsInfo() { UniValue result(UniValue::VOBJ); char numstr[64]; - CMutableTransaction mtx; CPubKey Pegspk; struct CCcontract_info *cp,C; int64_t funding; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey Pegspk; struct CCcontract_info *cp,C; int64_t funding; result.push_back(Pair("result","success")); result.push_back(Pair("name","Pegs")); cp = CCinit(&C,EVAL_PEGS); diff --git a/src/cc/prices.cpp b/src/cc/prices.cpp index 3d69ceec1..50787fd34 100644 --- a/src/cc/prices.cpp +++ b/src/cc/prices.cpp @@ -86,7 +86,7 @@ uint8_t DecodePricesFundingOpRet(CScript scriptPubKey,CPubKey &planpk,uint256 &o return(0); } -bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; return(false); @@ -182,7 +182,8 @@ UniValue PricesList() // bettoken std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector pubkeys) { - CMutableTransaction mtx; CTransaction oracletx; int64_t fullsupply,inputs,CCchange=0; uint256 hashBlock; char str[65],coinaddr[64],houseaddr[64]; CPubKey mypk,pricespk; int32_t i,N,numvouts; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction oracletx; int64_t fullsupply,inputs,CCchange=0; uint256 hashBlock; char str[65],coinaddr[64],houseaddr[64]; CPubKey mypk,pricespk; int32_t i,N,numvouts; struct CCcontract_info *cp,C; if ( funding < 100*COIN || maxleverage <= 0 || maxleverage > 10000 ) { CCerror = "invalid parameter error"; @@ -229,7 +230,7 @@ std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletx return(""); } fprintf(stderr,"error check bettoken\n"); - if ( AddNormalinputs(mtx,mypk,3*txfee,3) > 0 ) + if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 ) { mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(pricespk)) << OP_CHECKSIG)); @@ -293,7 +294,8 @@ UniValue PricesInfo(uint256 fundingtxid) std::string PricesAddFunding(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount) { - CMutableTransaction mtx; struct CCcontract_info *cp,C; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,CCchange = 0; uint64_t funding,mode; int32_t margin,maxleverage; char houseaddr[64],myaddr[64]; std::vectorpubkeys; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + struct CCcontract_info *cp,C; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,CCchange = 0; uint64_t funding,mode; int32_t margin,maxleverage; char houseaddr[64],myaddr[64]; std::vectorpubkeys; if ( amount < 10000 ) { CCerror = "amount must be positive"; @@ -343,7 +345,8 @@ std::string PricesAddFunding(uint64_t txfee,uint256 refbettoken,uint256 fundingt std::string PricesBet(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount,int32_t leverage) { - CMutableTransaction mtx; struct CCcontract_info *cp,C; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,tokenid,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,inputs2,longexposure,netexposure,shortexposure,CCchange = 0,CCchange2 = 0; uint64_t funding,mode; int32_t dir,margin,maxleverage; char houseaddr[64],myaddr[64],exposureaddr[64]; std::vectorpubkeys; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + struct CCcontract_info *cp,C; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,tokenid,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,inputs2,longexposure,netexposure,shortexposure,CCchange = 0,CCchange2 = 0; uint64_t funding,mode; int32_t dir,margin,maxleverage; char houseaddr[64],myaddr[64],exposureaddr[64]; std::vectorpubkeys; if ( amount < 0 ) { amount = -amount; diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index 649a9a9e6..7e4626b19 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -192,7 +192,7 @@ bool RewardsExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransactio else return(true); } -bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { uint256 txid,fundingtxid,hashBlock,vinfundingtxid; uint64_t vinsbits,sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx; numvins = tx.vin.size(); @@ -333,7 +333,7 @@ int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcont std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); - threshold = total/maxinputs; + threshold = total/(maxinputs+1); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; @@ -500,7 +500,8 @@ UniValue RewardsList() std::string RewardsCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t APR,int64_t minseconds,int64_t maxseconds,int64_t mindeposit) { - CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C; if ( funds < COIN || mindeposit < 0 || minseconds < 0 || maxseconds < 0 ) { fprintf(stderr,"negative parameter error\n"); @@ -534,7 +535,8 @@ std::string RewardsCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int6 std::string RewardsAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount) { - CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C; if ( amount < 0 ) { fprintf(stderr,"negative parameter error\n"); @@ -568,7 +570,8 @@ std::string RewardsAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,i std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t deposit) { - CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t lockedfunds,sbits,funding,APR,minseconds,maxseconds,mindeposit; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,rewardspk; CScript opret; uint64_t lockedfunds,sbits,funding,APR,minseconds,maxseconds,mindeposit; struct CCcontract_info *cp,C; if ( deposit < txfee ) { CCerror = "deposit amount less than txfee"; @@ -611,7 +614,8 @@ std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid) { - CMutableTransaction mtx,firstmtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,rewardspk; CScript scriptPubKey,ignore; uint256 hashBlock; uint64_t sbits,APR,minseconds,maxseconds,mindeposit; int64_t funding,reward=0,amount=0,inputs,CCchange=0; struct CCcontract_info *cp,C; + CMutableTransaction firstmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction tx; char coinaddr[64]; CPubKey mypk,rewardspk; CScript scriptPubKey,ignore; uint256 hashBlock; uint64_t sbits,APR,minseconds,maxseconds,mindeposit; int64_t funding,reward=0,amount=0,inputs,CCchange=0; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_REWARDS); if ( txfee == 0 ) txfee = 10000; diff --git a/src/cc/triggers.cpp b/src/cc/triggers.cpp index 5283bada7..ce6f10f58 100644 --- a/src/cc/triggers.cpp +++ b/src/cc/triggers.cpp @@ -71,7 +71,7 @@ bool TriggersExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti else return(true); } -bool TriggersValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool TriggersValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; return(false); @@ -143,7 +143,8 @@ int64_t AddTriggersInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP std::string TriggersGet(uint64_t txfee,int64_t nValue) { - CMutableTransaction mtx,tmpmtx; CPubKey mypk,Triggerspk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; + CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,Triggerspk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; cp = CCinit(&C,EVAL_TRIGGERS); if ( txfee == 0 ) txfee = 10000; @@ -183,7 +184,8 @@ std::string TriggersGet(uint64_t txfee,int64_t nValue) std::string TriggersFund(uint64_t txfee,int64_t funds) { - CMutableTransaction mtx; CPubKey mypk,Triggerspk; CScript opret; struct CCcontract_info *cp,C; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk,Triggerspk; CScript opret; struct CCcontract_info *cp,C; cp = CCinit(&C,EVAL_TRIGGERS); if ( txfee == 0 ) txfee = 10000; @@ -200,7 +202,8 @@ std::string TriggersFund(uint64_t txfee,int64_t funds) UniValue TriggersInfo() { UniValue result(UniValue::VOBJ); char numstr[64]; - CMutableTransaction mtx; CPubKey Triggerspk; struct CCcontract_info *cp,C; int64_t funding; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey Triggerspk; struct CCcontract_info *cp,C; int64_t funding; result.push_back(Pair("result","success")); result.push_back(Pair("name","Triggers")); cp = CCinit(&C,EVAL_TRIGGERS); diff --git a/src/chain.cpp b/src/chain.cpp index d79a66f9a..0d4ac7f2a 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -16,9 +16,9 @@ void CChain::SetTip(CBlockIndex *pindex) { vChain.clear(); return; } - vChain.resize(pindex->nHeight + 1); - while (pindex && vChain[pindex->nHeight] != pindex) { - vChain[pindex->nHeight] = pindex; + vChain.resize(pindex->GetHeight() + 1); + while (pindex && vChain[pindex->GetHeight()] != pindex) { + vChain[pindex->GetHeight()] = pindex; pindex = pindex->pprev; } } @@ -33,10 +33,10 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const { while (pindex) { vHave.push_back(pindex->GetBlockHash()); // Stop when we have added the genesis block. - if (pindex->nHeight == 0) + if (pindex->GetHeight() == 0) break; // Exponentially larger steps back, plus the genesis block. - int nHeight = std::max(pindex->nHeight - nStep, 0); + int nHeight = std::max(pindex->GetHeight() - nStep, 0); if (Contains(pindex)) { // Use O(1) CChain index if possible. pindex = (*this)[nHeight]; @@ -54,13 +54,63 @@ CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const { const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const { if ( pindex == 0 ) return(0); - if (pindex->nHeight > Height()) + if (pindex->GetHeight() > Height()) pindex = pindex->GetAncestor(Height()); while (pindex && !Contains(pindex)) pindex = pindex->pprev; return pindex; } +CChainPower::CChainPower(CBlockIndex *pblockIndex) +{ + nHeight = pblockIndex->GetHeight(); + chainStake = arith_uint256(0); + chainWork = arith_uint256(0); +} + +CChainPower::CChainPower(CBlockIndex *pblockIndex, const arith_uint256 &stake, const arith_uint256 &work) +{ + nHeight = pblockIndex->GetHeight(); + chainStake = stake; + chainWork = work; +} + +bool operator==(const CChainPower &p1, const CChainPower &p2) +{ + arith_uint256 bigZero = arith_uint256(0); + arith_uint256 workDivisor = p1.chainWork > p2.chainWork ? p1.chainWork : (p2.chainWork != bigZero ? p2.chainWork : 1); + arith_uint256 stakeDivisor = p1.chainStake > p2.chainStake ? p1.chainStake : (p2.chainStake != bigZero ? p2.chainStake : 1); + + // use up 16 bits for precision + return ((p1.chainWork << 16) / workDivisor + (p1.chainStake << 16) / stakeDivisor) == + ((p2.chainWork << 16) / workDivisor + (p2.chainStake << 16) / stakeDivisor); +} + +bool operator<(const CChainPower &p1, const CChainPower &p2) +{ + arith_uint256 bigZero = arith_uint256(0); + arith_uint256 workDivisor = p1.chainWork > p2.chainWork ? p1.chainWork : (p2.chainWork != bigZero ? p2.chainWork : 1); + arith_uint256 stakeDivisor = p1.chainStake > p2.chainStake ? p1.chainStake : (p2.chainStake != bigZero ? p2.chainStake : 1); + + // use up 16 bits for precision + return ((p1.chainWork << 16) / workDivisor + (p1.chainStake << 16) / stakeDivisor) < + ((p2.chainWork << 16) / workDivisor + (p2.chainStake << 16) / stakeDivisor); +} + +bool operator<=(const CChainPower &p1, const CChainPower &p2) +{ + arith_uint256 bigZero = arith_uint256(0); + arith_uint256 workDivisor = p1.chainWork > p2.chainWork ? p1.chainWork : (p2.chainWork != bigZero ? p2.chainWork : 1); + arith_uint256 stakeDivisor = p1.chainStake > p2.chainStake ? p1.chainStake : (p2.chainStake != bigZero ? p2.chainStake : 1); + + // use up 16 bits for precision + return ((p1.chainWork << 16) / workDivisor + (p1.chainStake << 16) / stakeDivisor) <= + ((p2.chainWork << 16) / workDivisor + (p2.chainStake << 16) / stakeDivisor); +} + + + + /** Turn the lowest '1' bit in the binary representation of a number into a '0'. */ int static inline InvertLowestOne(int n) { return n & (n - 1); } @@ -77,11 +127,11 @@ int static inline GetSkipHeight(int height) { CBlockIndex* CBlockIndex::GetAncestor(int height) { - if (height > nHeight || height < 0) + if (height > GetHeight() || height < 0) return NULL; CBlockIndex* pindexWalk = this; - int heightWalk = nHeight; + int heightWalk = GetHeight(); while ( heightWalk > height && pindexWalk != 0 ) { int heightSkip = GetSkipHeight(heightWalk); @@ -94,6 +144,7 @@ CBlockIndex* CBlockIndex::GetAncestor(int height) pindexWalk = pindexWalk->pskip; heightWalk = heightSkip; } else { + assert(pindexWalk->pprev); pindexWalk = pindexWalk->pprev; heightWalk--; } @@ -109,5 +160,5 @@ const CBlockIndex* CBlockIndex::GetAncestor(int height) const void CBlockIndex::BuildSkip() { if (pprev) - pskip = pprev->GetAncestor(GetSkipHeight(nHeight)); + pskip = pprev->GetAncestor(GetSkipHeight(GetHeight())); } diff --git a/src/chain.h b/src/chain.h index 394b4a6bd..95553c23c 100644 --- a/src/chain.h +++ b/src/chain.h @@ -6,6 +6,8 @@ #ifndef BITCOIN_CHAIN_H #define BITCOIN_CHAIN_H +class CChainPower; + #include "arith_uint256.h" #include "primitives/block.h" #include "pow.h" @@ -17,6 +19,8 @@ #include static const int SPROUT_VALUE_VERSION = 1001400; +static const int SAPLING_VALUE_VERSION = 1010100; +extern int32_t ASSETCHAINS_LWMAPOS; struct CDiskBlockPos { @@ -26,7 +30,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)); } @@ -102,6 +106,101 @@ enum BlockStatus: uint32_t { //! Blocks with this validity are assumed to satisfy all consensus rules. static const BlockStatus BLOCK_VALID_CONSENSUS = BLOCK_VALID_SCRIPTS; +class CBlockIndex; + +// This class provides an accumulator for both the chainwork and the chainPOS value +// CChainPower's can be compared, and the comparison ensures that work and proof of stake power +// are both used equally to determine which chain has the most work. This makes an attack +// that involves mining in secret completely ineffective, even before dPOW, unless a large part +// of the staking supply is also controlled. It also enables a faster deterministic convergence, +// aided by both POS and POW. +class CChainPower +{ + public: + arith_uint256 chainWork; + arith_uint256 chainStake; + int32_t nHeight; + + CChainPower() : nHeight(0), chainStake(0), chainWork(0) {} + CChainPower(CBlockIndex *pblockIndex); + CChainPower(CBlockIndex *pblockIndex, const arith_uint256 &stake, const arith_uint256 &work); + CChainPower(int32_t height) : nHeight(height), chainStake(0), chainWork(0) {} + CChainPower(int32_t height, const arith_uint256 &stake, const arith_uint256 &work) : + nHeight(height), chainStake(stake), chainWork(work) {} + + CChainPower &operator=(const CChainPower &chainPower) + { + chainWork = chainPower.chainWork; + chainStake = chainPower.chainStake; + nHeight = chainPower.nHeight; + return *this; + } + + CChainPower &operator+=(const CChainPower &chainPower) + { + this->chainWork += chainPower.chainWork; + this->chainStake += chainPower.chainStake; + return *this; + } + + friend CChainPower operator+(const CChainPower &chainPowerA, const CChainPower &chainPowerB) + { + CChainPower result = CChainPower(chainPowerA); + result.chainWork += chainPowerB.chainWork; + result.chainStake += chainPowerB.chainStake; + return result; + } + + friend CChainPower operator-(const CChainPower &chainPowerA, const CChainPower &chainPowerB) + { + CChainPower result = CChainPower(chainPowerA); + result.chainWork -= chainPowerB.chainWork; + result.chainStake -= chainPowerB.chainStake; + return result; + } + + friend CChainPower operator*(const CChainPower &chainPower, int32_t x) + { + CChainPower result = CChainPower(chainPower); + result.chainWork *= x; + result.chainStake *= x; + return result; + } + + CChainPower &addStake(const arith_uint256 &nChainStake) + { + chainStake += nChainStake; + return *this; + } + + CChainPower &addWork(const arith_uint256 &nChainWork) + { + chainWork += nChainWork; + return *this; + } + + friend bool operator==(const CChainPower &p1, const CChainPower &p2); + + friend bool operator!=(const CChainPower &p1, const CChainPower &p2) + { + return !(p1 == p2); + } + + friend bool operator<(const CChainPower &p1, const CChainPower &p2); + + friend bool operator<=(const CChainPower &p1, const CChainPower &p2); + + friend bool operator>(const CChainPower &p1, const CChainPower &p2) + { + return !(p1 <= p2); + } + + friend bool operator>=(const CChainPower &p1, const CChainPower &p2) + { + return !(p1 < p2); + } +}; + /** The block chain is a tree shaped structure starting with the * genesis block at the root, with each block potentially having multiple * candidates to be the next block. A blockindex may have multiple pprev pointing @@ -120,7 +219,6 @@ public: CBlockIndex* pskip; //! height of the entry in the chain. The genesis block has height 0 - int nHeight; int64_t newcoins,zfunds; int8_t segid; // jl777 fields //! Which # file this block is stored in (blk?????.dat) int nFile; @@ -132,7 +230,7 @@ public: unsigned int nUndoPos; //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block - arith_uint256 nChainWork; + CChainPower chainPower; //! Number of transactions in this block. //! Note: in a potential headers-first mode, this number cannot be relied upon @@ -152,10 +250,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 +264,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; @@ -185,24 +292,25 @@ public: segid = -2; pprev = NULL; pskip = NULL; - nHeight = 0; nFile = 0; nDataPos = 0; nUndoPos = 0; - nChainWork = arith_uint256(); + chainPower = CChainPower(); nTx = 0; 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,13 +328,23 @@ public: nVersion = block.nVersion; hashMerkleRoot = block.hashMerkleRoot; - hashReserved = block.hashReserved; + hashFinalSaplingRoot = block.hashFinalSaplingRoot; nTime = block.nTime; nBits = block.nBits; nNonce = block.nNonce; nSolution = block.nSolution; } + int32_t SetHeight(int32_t height) + { + this->chainPower.nHeight = height; + } + + inline int32_t GetHeight() const + { + return this->chainPower.nHeight; + } + CDiskBlockPos GetBlockPos() const { CDiskBlockPos ret; if (nStatus & BLOCK_HAVE_DATA) { @@ -252,7 +370,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; @@ -289,7 +407,7 @@ public: std::string ToString() const { return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)", - pprev, nHeight, + pprev, this->chainPower.nHeight, hashMerkleRoot.ToString(), GetBlockHash().ToString()); } @@ -324,6 +442,17 @@ public: CBlockIndex* GetAncestor(int height); const CBlockIndex* GetAncestor(int height) const; + int32_t GetVerusPOSTarget() const + { + return GetBlockHeader().GetVerusPOSTarget(); + } + + bool IsVerusPOSBlock() const + { + if ( ASSETCHAINS_LWMAPOS != 0 ) + return GetBlockHeader().IsVerusPOSBlock(); + else return(0); + } }; /** Used to marshal pointers into hashes for db storage. */ @@ -332,7 +461,7 @@ class CDiskBlockIndex : public CBlockIndex public: uint256 hashPrev; - CDiskBlockIndex() { + CDiskBlockIndex() : CBlockIndex() { hashPrev = uint256(); } @@ -343,11 +472,15 @@ 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)); + if (ser_action.ForRead()) { + chainPower = CChainPower(); + } + READWRITE(VARINT(chainPower.nHeight)); READWRITE(VARINT(nStatus)); READWRITE(VARINT(nTx)); if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) @@ -368,13 +501,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); @@ -382,9 +515,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 @@ -393,7 +532,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; @@ -450,18 +589,18 @@ public: /** Efficiently check whether a block is present in this chain. */ bool Contains(const CBlockIndex *pindex) const { - return (*this)[pindex->nHeight] == pindex; + return (*this)[pindex->GetHeight()] == pindex; } /** Find the successor of a block in this chain, or NULL if the given index is not found or is the tip. */ CBlockIndex *Next(const CBlockIndex *pindex) const { if (Contains(pindex)) - return (*this)[pindex->nHeight + 1]; + return (*this)[pindex->GetHeight() + 1]; else return NULL; } - /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */ + /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->GetHeight() : -1. */ int Height() const { return vChain.size() - 1; } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 6903fe54e..a04e4131a 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 = @@ -80,9 +79,9 @@ void *chainparams_commandline(void *ptr); extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; -extern uint32_t ASSETCHAIN_INIT; -extern uint32_t ASSETCHAINS_MAGIC; -extern uint64_t ASSETCHAINS_SUPPLY; +extern uint32_t ASSETCHAIN_INIT, ASSETCHAINS_MAGIC; +extern int32_t VERUS_BLOCK_POSUNITS, ASSETCHAINS_LWMAPOS, ASSETCHAINS_SAPLING, ASSETCHAINS_OVERWINTER; +extern uint64_t ASSETCHAINS_SUPPLY, ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH; const arith_uint256 maxUint = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); @@ -90,30 +89,39 @@ class CMainParams : public CChainParams { public: CMainParams() { + strNetworkID = "main"; strCurrencyUnits = "KMD"; - consensus.fCoinbaseMustBeProtected = false;//true; + 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; consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 4000; consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); + consensus.powAlternate = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); consensus.nPowAveragingWindow = 17; + consensus.nMaxFutureBlockTime = 7 * 60; // 7 mins + assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); consensus.nPowMaxAdjustDown = 32; // 32% adjustment down consensus.nPowMaxAdjustUp = 16; // 16% adjustment up consensus.nPowTargetSpacing = 1 * 60; - consensus.fPowAllowMinDifficultyBlocks = true; //false; + consensus.nPowAllowMinDifficultyBlocksAfterHeight = boost::none; consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002; consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = Consensus::NetworkUpgrade::ALWAYS_ACTIVE; 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 = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nProtocolVersion = 170007; + consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + + // 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. @@ -125,6 +133,7 @@ public: pchMessageStart[2] = 0xe4; pchMessageStart[3] = 0x8d; vAlertPubKey = ParseHex("020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9"); + // (Zcash) vAlertPubKey = ParseHex("04b7ecf0baa90495ceb4e4090f6b2fd37eec1e9c85fac68a487f3ce11589692e4a317479316ee814e066638e1db54e37a10689b70286e6315b1087b6615d179264"); nDefaultPort = 7770; nMinerThreads = 0; nMaxTipAge = 24 * 60 * 60; @@ -162,6 +171,7 @@ public: assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); vFixedSeeds.clear(); vSeeds.clear(); + vSeeds.push_back(CDNSSeedData("veruscoin.io", "seeds.veruscoin.io")); // @kolo - old static dns seeds vSeeds.push_back(CDNSSeedData("komodoplatform.com", "seeds.komodoplatform.com")); // @kolo - old static dns seeds vSeeds.push_back(CDNSSeedData("kolo.supernet.org", "static.kolo.supernet.org")); // @kolo - new static dns seeds ToDo vSeeds.push_back(CDNSSeedData("kolo.supernet.org", "dynamic.kolo.supernet.org")); // @kolo - crawler seeds ToDo @@ -178,6 +188,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; @@ -186,21 +201,13 @@ public: fMineBlocksOnDemand = false; fTestnetToBeDeprecatedFieldRPC = false; -// LogPrintf(">>>>>>>> ac_name = %u\n",GetArg("-ac_name","").c_str()); - -// if ( GetArg("-ac_name","").c_str()[0] != 0 ) -// { -// } -// else -// { -// } - if ( pthread_create((pthread_t *)malloc(sizeof(pthread_t)),NULL,chainparams_commandline,(void *)&consensus) != 0 ) { } } }; + static CMainParams mainParams; void CChainParams::SetCheckpointData(CChainParams::CCheckpointData checkpointData) @@ -208,6 +215,22 @@ void CChainParams::SetCheckpointData(CChainParams::CCheckpointData checkpointDat CChainParams::checkpointData = checkpointData; } +int32_t MAX_BLOCK_SIZE(int32_t height) +{ + //fprintf(stderr,"MAX_BLOCK_SIZE %d vs. %d\n",height,mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight); + if ( height <= 0 || (mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight > 0 && height >= mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight) ) + return(4096 * 1024); + else return(2000000); +} + +void komodo_setactivation(int32_t height) +{ + mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = height; + mainParams.consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = height; + ASSETCHAINS_SAPLING = height; + fprintf(stderr,"SET SAPLING ACTIVATION height.%d\n",height); +} + void *chainparams_commandline(void *ptr) { CChainParams::CCheckpointData checkpointData; @@ -231,20 +254,69 @@ void *chainparams_commandline(void *ptr) mainParams.pchMessageStart[3] = (ASSETCHAINS_MAGIC >> 24) & 0xff; fprintf(stderr,">>>>>>>>>> %s: p2p.%u rpc.%u magic.%08x %u %u coins\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_MAGIC,ASSETCHAINS_MAGIC,(uint32_t)ASSETCHAINS_SUPPLY); - checkpointData = //(Checkpoints::CCheckpointData) - { - boost::assign::map_list_of - (0, mainParams.consensus.hashGenesisBlock), - //(2500, uint256S("0x0e6a3d5a46eba97c4e7618d66a39f115729e1176433c98481124c2bf733aa54e")) - //(15000, uint256S("0x00f0bd236790e903321a2d22f85bd6bf8a505f6ef4eddb20458a65d37e14d142")), - //(100000, uint256S("0x0f02eb1f3a4b89df9909fec81a4bd7d023e32e24e1f5262d9fc2cc36a715be6f")), - (int64_t)1481120910, // * UNIX timestamp of last checkpoint block - (int64_t)110415, // * total number of transactions between genesis and last checkpoint - // (the tx=... number in the SetBestChain debug.log lines) - (double)2777 // * estimated number of transactions per day after checkpoint - // total number of tx / (checkpoint block height / (24 * 24)) - }; + if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH) + { + // this is only good for 60 second blocks with an averaging window of 45. for other parameters, use: + // nLwmaAjustedWeight = (N+1)/2 * (0.9989^(500/nPowAveragingWindow)) * nPowTargetSpacing + mainParams.consensus.nLwmaAjustedWeight = 1350; + mainParams.consensus.nPowAveragingWindow = 45; + mainParams.consensus.powAlternate = uint256S("00000f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); + } + if (ASSETCHAINS_LWMAPOS != 0) + { + mainParams.consensus.posLimit = uint256S("000000000f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); + mainParams.consensus.nPOSAveragingWindow = 45; + // spacing is 1000 units per block to get better resolution, POS is 50% hard coded for now, we can vary it later + // when we get reliable integer math on nLwmaPOSAjustedWeight + mainParams.consensus.nPOSTargetSpacing = VERUS_BLOCK_POSUNITS * 2; + // nLwmaPOSAjustedWeight = (N+1)/2 * (0.9989^(500/nPOSAveragingWindow)) * nPOSTargetSpacing + // this needs to be recalculated if VERUS_BLOCK_POSUNITS is changed + mainParams.consensus.nLwmaPOSAjustedWeight = 46531; + } + + // only require coinbase protection on Verus from the Komodo family of coins + if (strcmp(ASSETCHAINS_SYMBOL,"VRSC") == 0) + { + mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 227520; + mainParams.consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 227520; + mainParams.consensus.fCoinbaseMustBeProtected = true; + checkpointData = //(Checkpoints::CCheckpointData) + { + boost::assign::map_list_of + (0, mainParams.consensus.hashGenesisBlock) + (10000, uint256S("0xac2cd7d37177140ea4991cf630c0b9c7f94d707b84fb0351bf3a44856d2ae5dc")) + (20000, uint256S("0xb0e8cb9f77aaa7ff5bd90d6c08d06f4c4bf03e00c2b8a35a042e760845590c8a")) + (30000, uint256S("0xf2112ca577338ad7104bf905fa6a63d36b17a86f914c97b73cd31d43fcd7557c")) + (40000, uint256S("0x00000000008f83378dab727864b763ce91a4ea5f75d55939c0c1390cfb8c38f1")) + (49170, uint256S("0x2add646c0089871ec2379f02f7cd60b3af6efd9c152a6f16fc10925458c270cc")), + (int64_t)1529910234, // * UNIX timestamp of last checkpoint block + (int64_t)63661, // * total number of transactions between genesis and last checkpoint + // (the tx=... number in the SetBestChain debug.log lines) + (double)2777 // * estimated number of transactions per day after checkpoint + // total number of tx / (checkpoint block height / (24 * 24)) + }; + + mainParams.consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000001a8f4f23f8b2d1f7e"); + } + else + { + if (strcmp(ASSETCHAINS_SYMBOL,"VRSCTEST") == 0 || strcmp(ASSETCHAINS_SYMBOL,"VERUSTEST") == 0) + { + mainParams.consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000000000000000001f7e"); + } + mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = ASSETCHAINS_SAPLING; + mainParams.consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = ASSETCHAINS_OVERWINTER; + checkpointData = //(Checkpoints::CCheckpointData) + { + boost::assign::map_list_of + (0, mainParams.consensus.hashGenesisBlock), + (int64_t)1231006505, + (int64_t)1, + (double)2777 // * estimated number of transactions per day after checkpoint + // total number of tx / (checkpoint block height / (24 * 24)) + }; + } } else { @@ -412,6 +484,7 @@ public: CTestNetParams() { strNetworkID = "test"; strCurrencyUnits = "TAZ"; + bip44CoinType = 1; consensus.fCoinbaseMustBeProtected = true; consensus.nSubsidySlowStartInterval = 20000; consensus.nSubsidyHalvingInterval = 840000; @@ -419,8 +492,10 @@ public: consensus.nMajorityRejectBlockOutdated = 75; consensus.nMajorityWindow = 400; consensus.powLimit = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.powAlternate = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowAveragingWindow = 17; assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); + consensus.nMaxFutureBlockTime = 7 * 60; vAlertPubKey = ParseHex("00"); nDefaultPort = 17770; @@ -428,6 +503,7 @@ public: consensus.nPowMaxAdjustDown = 32; // 32% adjustment down consensus.nPowMaxAdjustUp = 16; // 16% adjustment up consensus.nPowTargetSpacing = 2.5 * 60; + consensus.nPowAllowMinDifficultyBlocksAfterHeight = 299187; consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002; consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = Consensus::NetworkUpgrade::ALWAYS_ACTIVE; @@ -436,8 +512,12 @@ 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; pchMessageStart[1] = 0x1F; pchMessageStart[2] = 0x7E; @@ -473,6 +553,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; @@ -482,6 +567,7 @@ public: fMineBlocksOnDemand = false; fTestnetToBeDeprecatedFieldRPC = true; + checkpointData = (CCheckpointData) { boost::assign::map_list_of (0, consensus.hashGenesisBlock) @@ -503,6 +589,7 @@ public: CRegTestParams() { strNetworkID = "regtest"; strCurrencyUnits = "REG"; + bip44CoinType = 1; consensus.fCoinbaseMustBeProtected = false; consensus.nSubsidySlowStartInterval = 0; consensus.nSubsidyHalvingInterval = 150; @@ -510,11 +597,14 @@ public: consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); + consensus.powAlternate = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); consensus.nPowAveragingWindow = 17; + consensus.nMaxFutureBlockTime = 7 * 60; // 7 mins assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up consensus.nPowTargetSpacing = 2.5 * 60; + consensus.nPowAllowMinDifficultyBlocksAfterHeight = 0; consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002; consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = Consensus::NetworkUpgrade::ALWAYS_ACTIVE; @@ -524,6 +614,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; @@ -581,6 +677,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()); @@ -632,6 +733,7 @@ bool SelectParamsFromCommandLine() return false; SelectParams(network); + return true; } @@ -652,10 +754,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/chainparamsseeds.h b/src/chainparamsseeds.h index 1139441fd..4b091457b 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -8,6 +8,12 @@ * IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly. */ static SeedSpec6 pnSeed6_main[] = { + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0xec}, 27485}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0xec}, 27487}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x40,0x69,0x6f}, 27485}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x40,0x69,0x6f}, 27487}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0x48}, 27485}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0x48}, 27487} }; static SeedSpec6 pnSeed6_test[] = { diff --git a/src/clientversion.h b/src/clientversion.h index 1203760bb..d8117a6ba 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -15,10 +15,10 @@ */ //! 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 +#define CLIENT_VERSION_BUILD 26 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true @@ -27,7 +27,7 @@ * Copyright year (2009-this) * Todo: update this when changing our copyright comments in the source */ -#define COPYRIGHT_YEAR 2017 +#define COPYRIGHT_YEAR 2018 #endif //HAVE_CONFIG_H @@ -39,7 +39,7 @@ #define DO_STRINGIZE(X) #X //! Copyright string used in Windows .rc files -#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin Core Developers and The Zcash developers" +#define COPYRIGHT_STR "2009-" STRINGIZE(COPYRIGHT_YEAR) " The Bitcoin Core Developers, The Zcash developers, Komodo developers, and Verus developers" /** * bitcoind-res.rc includes this file, but it cannot cope with real c++ code. diff --git a/src/coins.cpp b/src/coins.cpp index 38b105e9d..306e2278f 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 { @@ -254,26 +382,104 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) const { uint256 CCoinsViewCache::GetBestBlock() const { if (hashBlock.IsNull()) - hashBlock = base->GetBestBlock(); + { + if (base) + { + hashBlock = base->GetBestBlock(); + } + else + { + hashBlock = uint256(); + } + } return hashBlock; } -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). @@ -310,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; } @@ -380,17 +550,34 @@ const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const return coins->vout[input.prevout.n]; } -const CScript &CCoinsViewCache::GetSpendFor(const CTxIn& input) const -{ - const CCoins* coins = AccessCoins(input.prevout.hash); - assert(coins); - return coins->vout[input.prevout.n].scriptPubKey; -} - //uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime); uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight); extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; +const CScript &CCoinsViewCache::GetSpendFor(const CCoins *coins, const CTxIn& input) +{ + assert(coins); + if (coins->nHeight < 6400 && !strcmp(ASSETCHAINS_SYMBOL, "VRSC")) + { + std::string hc = input.prevout.hash.ToString(); + if (LaunchMap().lmap.count(hc)) + { + CTransactionExceptionData &txData = LaunchMap().lmap[hc]; + if ((txData.voutMask & (((uint64_t)1) << (uint64_t)input.prevout.n)) != 0) + { + return txData.scriptPubKey; + } + } + } + return coins->vout[input.prevout.n].scriptPubKey; +} + +const CScript &CCoinsViewCache::GetSpendFor(const CTxIn& input) const +{ + const CCoins* coins = AccessCoins(input.prevout.hash); + return GetSpendFor(coins, input); +} + CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTransaction& tx,uint32_t tiptime) const { CAmount value,nResult = 0; @@ -419,7 +606,7 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr } #endif } - nResult += tx.GetJoinSplitValueIn(); + nResult += tx.GetShieldedValueIn(); return nResult; } @@ -427,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; } @@ -456,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; } @@ -478,19 +675,17 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const { if (tx.IsCoinBase()) return 0.0; - // Joinsplits do not reveal any information about the value or age of a note, so we + + // Shielded transfers do not reveal any information about the value or age of a note, so we // cannot apply the priority algorithm used for transparent utxos. Instead, we just - // use the maximum priority whenever a transaction contains any JoinSplits. - // (Note that coinbase transactions cannot contain JoinSplits.) - // FIXME: this logic is partially duplicated between here and CreateNewBlock in miner.cpp. - - if (tx.vjoinsplit.size() > 0) { - return MAX_PRIORITY; - } - if (tx.IsCoinImport()) { + // use the maximum priority for all (partially or fully) shielded transactions. + // (Note that coinbase transactions cannot contain JoinSplits, or Sapling shielded Spends or Outputs.) + + if (tx.vjoinsplit.size() > 0 || tx.vShieldedSpend.size() > 0 || tx.vShieldedOutput.size() > 0 || tx.IsCoinImport()) { return MAX_PRIORITY; } + // FIXME: this logic is partially duplicated between here and CreateNewBlock in miner.cpp. double dResult = 0.0; BOOST_FOREACH(const CTxIn& txin, tx.vin) { diff --git a/src/coins.h b/src/coins.h index fcc32caae..f35af02f0 100644 --- a/src/coins.h +++ b/src/coins.h @@ -13,13 +13,18 @@ #include "memusage.h" #include "serialize.h" #include "uint256.h" +#include "base58.h" +#include "pubkey.h" #include #include +#include +#include #include #include #include "zcash/IncrementalMerkleTree.hpp" +#include "veruslaunch.h" /** * Pruned version of CTransaction: only retains metadata and unspent transaction outputs @@ -157,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(); @@ -189,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; @@ -224,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); @@ -236,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(); } @@ -267,6 +249,14 @@ public: } return ret; } + + int64_t TotalTxValue() const { + int64_t total = 0; + BOOST_FOREACH(const CTxOut &out, vout) { + total += out.nValue; + } + return total; + } }; class CCoinsKeyHasher @@ -300,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 @@ -325,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 @@ -347,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; @@ -364,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; @@ -390,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; }; @@ -428,6 +448,37 @@ public: friend class CCoinsViewCache; }; +class CTransactionExceptionData +{ + public: + CScript scriptPubKey; + uint64_t voutMask; + CTransactionExceptionData() : scriptPubKey(), voutMask() {} +}; + +class CLaunchMap +{ + public: + std::unordered_map lmap; + CLaunchMap() : lmap() + { + //printf("txid: %s -> addr: %s\n", whitelist_ids[i], whitelist_addrs[i]); + CBitcoinAddress bcaddr(whitelist_address); + CKeyID key; + if (bcaddr.GetKeyID_NoCheck(key)) + { + std::vector address = std::vector(key.begin(), key.end()); + for (int i = 0; i < WHITELIST_COUNT; i++) + { + std::string hash = uint256S(whitelist_ids[i]).ToString(); + lmap[hash].scriptPubKey << OP_DUP << OP_HASH160 << address << OP_EQUALVERIFY << OP_CHECKSIG; + lmap[hash].voutMask = whitelist_masks[i]; + } + } + } +}; +static CLaunchMap launchMap = CLaunchMap(); + /** CCoinsView that adds a memory cache for transactions to another CCoinsView */ class CCoinsViewCache : public CCoinsViewBacked { @@ -435,16 +486,18 @@ protected: /* Whether this cache has an active modifier. */ bool hasModifier; - /** * Make mutable so that we can "fill the cache" even from Get-methods * declared as "const". */ 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; @@ -454,30 +507,35 @@ public: ~CCoinsViewCache(); // Standard CCoinsView methods - bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const; - bool GetNullifier(const uint256 &nullifier) const; + static CLaunchMap &LaunchMap() { return launchMap; } + 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 @@ -512,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; @@ -527,6 +585,7 @@ public: const CTxOut &GetOutputFor(const CTxIn& input) const; const CScript &GetSpendFor(const CTxIn& input) const; + static const CScript &GetSpendFor(const CCoins *coins, const CTxIn& input); friend class CCoinsModifier; @@ -538,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..3f44bcafd 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; +//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 = (2 * MAX_TX_SIZE_BEFORE_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 855729ff0..b7dc8b475 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -8,6 +8,10 @@ #include "uint256.h" +#include + +int32_t MAX_BLOCK_SIZE(int32_t height); + namespace Consensus { /** @@ -23,6 +27,7 @@ enum UpgradeIndex { BASE_SPROUT, UPGRADE_TESTDUMMY, UPGRADE_OVERWINTER, + UPGRADE_SAPLING, // NOTE: Also add new upgrades to NetworkUpgradeInfo in upgrades.cpp MAX_NETWORK_UPGRADES }; @@ -37,7 +42,6 @@ struct NetworkUpgrade { * Height of the first block for which the new consensus rules will be active */ int nActivationHeight; - /** * Special value for nActivationHeight indicating that the upgrade is always active. * This is useful for testing, as it means tests don't need to deal with the activation @@ -87,17 +91,33 @@ struct Params { int nMajorityEnforceBlockUpgrade; int nMajorityRejectBlockOutdated; int nMajorityWindow; - int fPowAllowMinDifficultyBlocks; NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES]; + /** Proof of work parameters */ uint256 powLimit; + uint256 powAlternate; + boost::optional nPowAllowMinDifficultyBlocksAfterHeight; int64_t nPowAveragingWindow; int64_t nPowMaxAdjustDown; int64_t nPowMaxAdjustUp; int64_t nPowTargetSpacing; + int64_t nLwmaAjustedWeight; + + /* Proof of stake parameters */ + uint256 posLimit; + int64_t nPOSAveragingWindow; // can be completely different than POW and initially trying a relatively large number, like 100 + int64_t nPOSTargetSpacing; // spacing is 1000 units per block to get better resolution, (100 % = 1000, 50% = 2000, 10% = 10000) + int64_t nLwmaPOSAjustedWeight; + + /* applied to all block times */ + int64_t nMaxFutureBlockTime; + 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; } + int32_t SetSaplingHeight(int32_t height) { vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = height; } + int32_t SetOverwinterHeight(int32_t height) { vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = height; } + uint256 nMinimumChainWork; }; } // namespace Consensus diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp index 1dd3fe706..5f484e949 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.", } }; @@ -33,6 +38,10 @@ UpgradeState NetworkUpgradeState( const Consensus::Params& params, Consensus::UpgradeIndex idx) { + if (nHeight < 0) + { + printf("height: %d", nHeight); + } assert(nHeight >= 0); assert(idx >= Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES); auto nActivationHeight = params.vUpgrades[idx].nActivationHeight; @@ -69,13 +78,23 @@ int CurrentEpoch(int nHeight, const Consensus::Params& params) { return idxInt; } } - return(0); // jl777 seems the right value to return + // Base case + return Consensus::BASE_SPROUT; } uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params) { return NetworkUpgradeInfo[CurrentEpoch(nHeight, params)].nBranchId; } +bool IsConsensusBranchId(int branchId) { + for (int idx = Consensus::BASE_SPROUT; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) { + if (branchId == NetworkUpgradeInfo[idx].nBranchId) { + return true; + } + } + return false; +} + bool IsActivationHeight( int nHeight, const Consensus::Params& params, @@ -108,20 +127,28 @@ bool IsActivationHeightForAnyUpgrade( return false; } -boost::optional NextActivationHeight( - int nHeight, - const Consensus::Params& params) -{ +boost::optional NextEpoch(int nHeight, const Consensus::Params& params) { if (nHeight < 0) { return boost::none; } - // Don't count Sprout as an activation height + // Sprout is never pending for (auto idx = Consensus::BASE_SPROUT + 1; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) { if (NetworkUpgradeState(nHeight, params, Consensus::UpgradeIndex(idx)) == UPGRADE_PENDING) { - return params.vUpgrades[idx].nActivationHeight; + return idx; } } return boost::none; } + +boost::optional NextActivationHeight( + int nHeight, + const Consensus::Params& params) +{ + auto idx = NextEpoch(nHeight, params); + if (idx) { + return params.vUpgrades[idx.get()].nActivationHeight; + } + return boost::none; +} diff --git a/src/consensus/upgrades.h b/src/consensus/upgrades.h index 620dc94c4..920ec1ea8 100644 --- a/src/consensus/upgrades.h +++ b/src/consensus/upgrades.h @@ -63,6 +63,12 @@ int CurrentEpoch(int nHeight, const Consensus::Params& params); */ uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params); +/** + * Returns true if a given branch id is a valid nBranchId for one of the network + * upgrades contained in NetworkUpgradeInfo. + */ +bool IsConsensusBranchId(int branchId); + /** * Returns true if the given block height is the activation height for the given * upgrade. @@ -79,6 +85,12 @@ bool IsActivationHeightForAnyUpgrade( int nHeight, const Consensus::Params& params); +/** + * Returns the index of the next upgrade after the given block height, or + * boost::none if there are no more known upgrades. + */ +boost::optional NextEpoch(int nHeight, const Consensus::Params& params); + /** * Returns the activation height for the next upgrade after the given block height, * or boost::none if there are no more known upgrades. 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/crosschain.cpp b/src/crosschain.cpp index d27bd735c..ff143da2c 100644 --- a/src/crosschain.cpp +++ b/src/crosschain.cpp @@ -25,6 +25,7 @@ int NOTARISATION_SCAN_LIMIT_BLOCKS = 1440; +CBlockIndex *komodo_getblockindex(uint256 hash); /* On KMD */ @@ -142,7 +143,7 @@ TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_ CBlockIndex blockIdx; if (!eval->GetTxConfirmed(assetChainProof.first, sourceNotarisation, blockIdx)) throw std::runtime_error("Notarisation not found"); - kmdHeight = blockIdx.nHeight; + kmdHeight = blockIdx.GetHeight(); } // We now have a kmdHeight of the notarisation from chain A. So we know that a MoM exists @@ -252,7 +253,7 @@ bool GetNextBacknotarisation(uint256 kmdNotarisationTxid, Notarisation &out) return false; } - return (bool) ScanNotarisationsFromHeight(block.nHeight+1, &IsSameAssetChain, out); + return (bool) ScanNotarisationsFromHeight(block.GetHeight()+1, &IsSameAssetChain, out); } @@ -309,20 +310,20 @@ TxProof GetAssetchainProof(uint256 hash) if (blockHash.IsNull()) throw std::runtime_error("tx still in mempool"); - blockIndex = mapBlockIndex[blockHash]; - int h = blockIndex->nHeight; + blockIndex = komodo_getblockindex(blockHash); + int h = blockIndex->GetHeight(); // The assumption here is that the first notarisation for a height GTE than // the transaction block height will contain the corresponding MoM. If there // are sequence issues with the notarisations this may fail. auto isTarget = [&](Notarisation ¬a) { if (!IsSameAssetChain(nota)) return false; - return nota.second.height >= blockIndex->nHeight; + return nota.second.height >= blockIndex->GetHeight(); }; - if (!ScanNotarisationsFromHeight(blockIndex->nHeight, isTarget, nota)) + if (!ScanNotarisationsFromHeight(blockIndex->GetHeight(), isTarget, nota)) throw std::runtime_error("backnotarisation not yet confirmed"); // index of block in MoM leaves - nIndex = nota.second.height - blockIndex->nHeight; + nIndex = nota.second.height - blockIndex->GetHeight(); } // build merkle chain from blocks to MoM 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/crypto/haraka.c b/src/crypto/haraka.c new file mode 100644 index 000000000..d611b9af5 --- /dev/null +++ b/src/crypto/haraka.c @@ -0,0 +1,606 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 kste + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Optimized Implementations for Haraka256 and Haraka512 +*/ + +#include +#include "crypto/haraka.h" + +u128 rc[40]; +u128 rc0[40] = {0}; + +void load_constants() { + rc[0] = _mm_set_epi32(0x0684704c,0xe620c00a,0xb2c5fef0,0x75817b9d); + rc[1] = _mm_set_epi32(0x8b66b4e1,0x88f3a06b,0x640f6ba4,0x2f08f717); + rc[2] = _mm_set_epi32(0x3402de2d,0x53f28498,0xcf029d60,0x9f029114); + rc[3] = _mm_set_epi32(0x0ed6eae6,0x2e7b4f08,0xbbf3bcaf,0xfd5b4f79); + rc[4] = _mm_set_epi32(0xcbcfb0cb,0x4872448b,0x79eecd1c,0xbe397044); + rc[5] = _mm_set_epi32(0x7eeacdee,0x6e9032b7,0x8d5335ed,0x2b8a057b); + rc[6] = _mm_set_epi32(0x67c28f43,0x5e2e7cd0,0xe2412761,0xda4fef1b); + rc[7] = _mm_set_epi32(0x2924d9b0,0xafcacc07,0x675ffde2,0x1fc70b3b); + rc[8] = _mm_set_epi32(0xab4d63f1,0xe6867fe9,0xecdb8fca,0xb9d465ee); + rc[9] = _mm_set_epi32(0x1c30bf84,0xd4b7cd64,0x5b2a404f,0xad037e33); + rc[10] = _mm_set_epi32(0xb2cc0bb9,0x941723bf,0x69028b2e,0x8df69800); + rc[11] = _mm_set_epi32(0xfa0478a6,0xde6f5572,0x4aaa9ec8,0x5c9d2d8a); + rc[12] = _mm_set_epi32(0xdfb49f2b,0x6b772a12,0x0efa4f2e,0x29129fd4); + rc[13] = _mm_set_epi32(0x1ea10344,0xf449a236,0x32d611ae,0xbb6a12ee); + rc[14] = _mm_set_epi32(0xaf044988,0x4b050084,0x5f9600c9,0x9ca8eca6); + rc[15] = _mm_set_epi32(0x21025ed8,0x9d199c4f,0x78a2c7e3,0x27e593ec); + rc[16] = _mm_set_epi32(0xbf3aaaf8,0xa759c9b7,0xb9282ecd,0x82d40173); + rc[17] = _mm_set_epi32(0x6260700d,0x6186b017,0x37f2efd9,0x10307d6b); + rc[18] = _mm_set_epi32(0x5aca45c2,0x21300443,0x81c29153,0xf6fc9ac6); + rc[19] = _mm_set_epi32(0x9223973c,0x226b68bb,0x2caf92e8,0x36d1943a); + rc[20] = _mm_set_epi32(0xd3bf9238,0x225886eb,0x6cbab958,0xe51071b4); + rc[21] = _mm_set_epi32(0xdb863ce5,0xaef0c677,0x933dfddd,0x24e1128d); + rc[22] = _mm_set_epi32(0xbb606268,0xffeba09c,0x83e48de3,0xcb2212b1); + rc[23] = _mm_set_epi32(0x734bd3dc,0xe2e4d19c,0x2db91a4e,0xc72bf77d); + rc[24] = _mm_set_epi32(0x43bb47c3,0x61301b43,0x4b1415c4,0x2cb3924e); + rc[25] = _mm_set_epi32(0xdba775a8,0xe707eff6,0x03b231dd,0x16eb6899); + rc[26] = _mm_set_epi32(0x6df3614b,0x3c755977,0x8e5e2302,0x7eca472c); + rc[27] = _mm_set_epi32(0xcda75a17,0xd6de7d77,0x6d1be5b9,0xb88617f9); + rc[28] = _mm_set_epi32(0xec6b43f0,0x6ba8e9aa,0x9d6c069d,0xa946ee5d); + rc[29] = _mm_set_epi32(0xcb1e6950,0xf957332b,0xa2531159,0x3bf327c1); + rc[30] = _mm_set_epi32(0x2cee0c75,0x00da619c,0xe4ed0353,0x600ed0d9); + rc[31] = _mm_set_epi32(0xf0b1a5a1,0x96e90cab,0x80bbbabc,0x63a4a350); + rc[32] = _mm_set_epi32(0xae3db102,0x5e962988,0xab0dde30,0x938dca39); + rc[33] = _mm_set_epi32(0x17bb8f38,0xd554a40b,0x8814f3a8,0x2e75b442); + rc[34] = _mm_set_epi32(0x34bb8a5b,0x5f427fd7,0xaeb6b779,0x360a16f6); + rc[35] = _mm_set_epi32(0x26f65241,0xcbe55438,0x43ce5918,0xffbaafde); + rc[36] = _mm_set_epi32(0x4ce99a54,0xb9f3026a,0xa2ca9cf7,0x839ec978); + rc[37] = _mm_set_epi32(0xae51a51a,0x1bdff7be,0x40c06e28,0x22901235); + rc[38] = _mm_set_epi32(0xa0c1613c,0xba7ed22b,0xc173bc0f,0x48a659cf); + rc[39] = _mm_set_epi32(0x756acc03,0x02288288,0x4ad6bdfd,0xe9c59da1); +} + +void test_implementations() { + unsigned char *in = (unsigned char *)calloc(64*8, sizeof(unsigned char)); + unsigned char *out256 = (unsigned char *)calloc(32*8, sizeof(unsigned char)); + unsigned char *out512 = (unsigned char *)calloc(32*8, sizeof(unsigned char)); + unsigned char testvector256[32] = {0x80, 0x27, 0xcc, 0xb8, 0x79, 0x49, 0x77, 0x4b, + 0x78, 0xd0, 0x54, 0x5f, 0xb7, 0x2b, 0xf7, 0x0c, + 0x69, 0x5c, 0x2a, 0x09, 0x23, 0xcb, 0xd4, 0x7b, + 0xba, 0x11, 0x59, 0xef, 0xbf, 0x2b, 0x2c, 0x1c}; + + unsigned char testvector512[32] = {0xbe, 0x7f, 0x72, 0x3b, 0x4e, 0x80, 0xa9, 0x98, + 0x13, 0xb2, 0x92, 0x28, 0x7f, 0x30, 0x6f, 0x62, + 0x5a, 0x6d, 0x57, 0x33, 0x1c, 0xae, 0x5f, 0x34, + 0xdd, 0x92, 0x77, 0xb0, 0x94, 0x5b, 0xe2, 0xaa}; + + + + int i; + + // Input for testvector + for(i = 0; i < 512; i++) { + in[i] = i % 64; + } + + load_constants(); + haraka512_8x(out512, in); + + // Verify output + for(i = 0; i < 32; i++) { + if (out512[i % 32] != testvector512[i]) { + printf("Error: testvector incorrect.\n"); + return; + } + } + + free(in); + free(out256); + free(out512); +} + +void haraka256(unsigned char *out, const unsigned char *in) { + __m128i s[2], tmp; + + s[0] = LOAD(in); + s[1] = LOAD(in + 16); + + AES2(s[0], s[1], 0); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 4); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 8); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 12); + MIX2(s[0], s[1]); + + AES2(s[0], s[1], 16); + MIX2(s[0], s[1]); + + s[0] = _mm_xor_si128(s[0], LOAD(in)); + s[1] = _mm_xor_si128(s[1], LOAD(in + 16)); + + STORE(out, s[0]); + STORE(out + 16, s[1]); +} + +void haraka256_4x(unsigned char *out, const unsigned char *in) { + __m128i s[4][2], tmp; + + s[0][0] = LOAD(in); + s[0][1] = LOAD(in + 16); + s[1][0] = LOAD(in + 32); + s[1][1] = LOAD(in + 48); + s[2][0] = LOAD(in + 64); + s[2][1] = LOAD(in + 80); + s[3][0] = LOAD(in + 96); + s[3][1] = LOAD(in + 112); + + // Round 1 + AES2_4x(s[0], s[1], s[2], s[3], 0); + + MIX2(s[0][0], s[0][1]); + MIX2(s[1][0], s[1][1]); + MIX2(s[2][0], s[2][1]); + MIX2(s[3][0], s[3][1]); + + // Round 2 + AES2_4x(s[0], s[1], s[2], s[3], 4); + + MIX2(s[0][0], s[0][1]); + MIX2(s[1][0], s[1][1]); + MIX2(s[2][0], s[2][1]); + MIX2(s[3][0], s[3][1]); + + // Round 3 + AES2_4x(s[0], s[1], s[2], s[3], 8); + + MIX2(s[0][0], s[0][1]); + MIX2(s[1][0], s[1][1]); + MIX2(s[2][0], s[2][1]); + MIX2(s[3][0], s[3][1]); + + // Round 4 + AES2_4x(s[0], s[1], s[2], s[3], 12); + + MIX2(s[0][0], s[0][1]); + MIX2(s[1][0], s[1][1]); + MIX2(s[2][0], s[2][1]); + MIX2(s[3][0], s[3][1]); + + // Round 5 + AES2_4x(s[0], s[1], s[2], s[3], 16); + + MIX2(s[0][0], s[0][1]); + MIX2(s[1][0], s[1][1]); + MIX2(s[2][0], s[2][1]); + MIX2(s[3][0], s[3][1]); + + // Feed Forward + s[0][0] = _mm_xor_si128(s[0][0], LOAD(in)); + s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16)); + s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 32)); + s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 48)); + s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 64)); + s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 80)); + s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 96)); + s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 112)); + + STORE(out, s[0][0]); + STORE(out + 16, s[0][1]); + STORE(out + 32, s[1][0]); + STORE(out + 48, s[1][1]); + STORE(out + 64, s[2][0]); + STORE(out + 80, s[2][1]); + STORE(out + 96, s[3][0]); + STORE(out + 112, s[3][1]); +} + +void haraka256_8x(unsigned char *out, const unsigned char *in) { + // This is faster on Skylake, the code below is faster on Haswell. + haraka256_4x(out, in); + haraka256_4x(out + 128, in + 128); + return; + // __m128i s[8][2], tmp; + // + // int i; + // + // s[0][0] = LOAD(in); + // s[0][1] = LOAD(in + 16); + // s[1][0] = LOAD(in + 32); + // s[1][1] = LOAD(in + 48); + // s[2][0] = LOAD(in + 64); + // s[2][1] = LOAD(in + 80); + // s[3][0] = LOAD(in + 96); + // s[3][1] = LOAD(in + 112); + // s[4][0] = LOAD(in + 128); + // s[4][1] = LOAD(in + 144); + // s[5][0] = LOAD(in + 160); + // s[5][1] = LOAD(in + 176); + // s[6][0] = LOAD(in + 192); + // s[6][1] = LOAD(in + 208); + // s[7][0] = LOAD(in + 224); + // s[7][1] = LOAD(in + 240); + // + // // Round 1 + // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0); + // + // MIX2(s[0][0], s[0][1]); + // MIX2(s[1][0], s[1][1]); + // MIX2(s[2][0], s[2][1]); + // MIX2(s[3][0], s[3][1]); + // MIX2(s[4][0], s[4][1]); + // MIX2(s[5][0], s[5][1]); + // MIX2(s[6][0], s[6][1]); + // MIX2(s[7][0], s[7][1]); + // + // + // // Round 2 + // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 4); + // + // MIX2(s[0][0], s[0][1]); + // MIX2(s[1][0], s[1][1]); + // MIX2(s[2][0], s[2][1]); + // MIX2(s[3][0], s[3][1]); + // MIX2(s[4][0], s[4][1]); + // MIX2(s[5][0], s[5][1]); + // MIX2(s[6][0], s[6][1]); + // MIX2(s[7][0], s[7][1]); + // + // // Round 3 + // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 8); + // + // MIX2(s[0][0], s[0][1]); + // MIX2(s[1][0], s[1][1]); + // MIX2(s[2][0], s[2][1]); + // MIX2(s[3][0], s[3][1]); + // MIX2(s[4][0], s[4][1]); + // MIX2(s[5][0], s[5][1]); + // MIX2(s[6][0], s[6][1]); + // MIX2(s[7][0], s[7][1]); + // + // // Round 4 + // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 12); + // + // MIX2(s[0][0], s[0][1]); + // MIX2(s[1][0], s[1][1]); + // MIX2(s[2][0], s[2][1]); + // MIX2(s[3][0], s[3][1]); + // MIX2(s[4][0], s[4][1]); + // MIX2(s[5][0], s[5][1]); + // MIX2(s[6][0], s[6][1]); + // MIX2(s[7][0], s[7][1]); + // + // // Round 5 + // AES2_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 16); + // + // MIX2(s[0][0], s[0][1]); + // MIX2(s[1][0], s[1][1]); + // MIX2(s[2][0], s[2][1]); + // MIX2(s[3][0], s[3][1]); + // MIX2(s[4][0], s[4][1]); + // MIX2(s[5][0], s[5][1]); + // MIX2(s[6][0], s[6][1]); + // MIX2(s[7][0], s[7][1]); + // + // // Feed Forward + // s[0][0] = _mm_xor_si128(s[0][0], LOAD(in)); + // s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16)); + // s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 32)); + // s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 48)); + // s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 64)); + // s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 80)); + // s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 96)); + // s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 112)); + // s[4][0] = _mm_xor_si128(s[4][0], LOAD(in + 128)); + // s[4][1] = _mm_xor_si128(s[4][1], LOAD(in + 144)); + // s[5][0] = _mm_xor_si128(s[5][0], LOAD(in + 160)); + // s[5][1] = _mm_xor_si128(s[5][1], LOAD(in + 176)); + // s[6][0] = _mm_xor_si128(s[6][0], LOAD(in + 192)); + // s[6][1] = _mm_xor_si128(s[6][1], LOAD(in + 208)); + // s[7][0] = _mm_xor_si128(s[7][0], LOAD(in + 224)); + // s[7][1] = _mm_xor_si128(s[7][1], LOAD(in + 240)); + // + // STORE(out, s[0][0]); + // STORE(out + 16, s[0][1]); + // STORE(out + 32, s[1][0]); + // STORE(out + 48, s[1][1]); + // STORE(out + 64, s[2][0]); + // STORE(out + 80, s[2][1]); + // STORE(out + 96, s[3][0]); + // STORE(out + 112, s[3][1]); + // STORE(out + 128, s[4][0]); + // STORE(out + 144, s[4][1]); + // STORE(out + 160, s[5][0]); + // STORE(out + 176, s[5][1]); + // STORE(out + 192, s[6][0]); + // STORE(out + 208, s[6][1]); + // STORE(out + 224, s[7][0]); + // STORE(out + 240, s[7][1]); +} + +void haraka512(unsigned char *out, const unsigned char *in) { + u128 s[4], tmp; + + s[0] = LOAD(in); + s[1] = LOAD(in + 16); + s[2] = LOAD(in + 32); + s[3] = LOAD(in + 48); + + AES4(s[0], s[1], s[2], s[3], 0); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 8); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 16); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 24); + MIX4(s[0], s[1], s[2], s[3]); + + AES4(s[0], s[1], s[2], s[3], 32); + MIX4(s[0], s[1], s[2], s[3]); + + s[0] = _mm_xor_si128(s[0], LOAD(in)); + s[1] = _mm_xor_si128(s[1], LOAD(in + 16)); + s[2] = _mm_xor_si128(s[2], LOAD(in + 32)); + s[3] = _mm_xor_si128(s[3], LOAD(in + 48)); + + TRUNCSTORE(out, s[0], s[1], s[2], s[3]); +} + +void haraka512_zero(unsigned char *out, const unsigned char *in) { + u128 s[4], tmp; + + s[0] = LOAD(in); + s[1] = LOAD(in + 16); + s[2] = LOAD(in + 32); + s[3] = LOAD(in + 48); + + AES4_zero(s[0], s[1], s[2], s[3], 0); + MIX4(s[0], s[1], s[2], s[3]); + + AES4_zero(s[0], s[1], s[2], s[3], 8); + MIX4(s[0], s[1], s[2], s[3]); + + AES4_zero(s[0], s[1], s[2], s[3], 16); + MIX4(s[0], s[1], s[2], s[3]); + + AES4_zero(s[0], s[1], s[2], s[3], 24); + MIX4(s[0], s[1], s[2], s[3]); + + AES4_zero(s[0], s[1], s[2], s[3], 32); + MIX4(s[0], s[1], s[2], s[3]); + + s[0] = _mm_xor_si128(s[0], LOAD(in)); + s[1] = _mm_xor_si128(s[1], LOAD(in + 16)); + s[2] = _mm_xor_si128(s[2], LOAD(in + 32)); + s[3] = _mm_xor_si128(s[3], LOAD(in + 48)); + + TRUNCSTORE(out, s[0], s[1], s[2], s[3]); +} + +void haraka512_4x(unsigned char *out, const unsigned char *in) { + u128 s[4][4], tmp; + + s[0][0] = LOAD(in); + s[0][1] = LOAD(in + 16); + s[0][2] = LOAD(in + 32); + s[0][3] = LOAD(in + 48); + s[1][0] = LOAD(in + 64); + s[1][1] = LOAD(in + 80); + s[1][2] = LOAD(in + 96); + s[1][3] = LOAD(in + 112); + s[2][0] = LOAD(in + 128); + s[2][1] = LOAD(in + 144); + s[2][2] = LOAD(in + 160); + s[2][3] = LOAD(in + 176); + s[3][0] = LOAD(in + 192); + s[3][1] = LOAD(in + 208); + s[3][2] = LOAD(in + 224); + s[3][3] = LOAD(in + 240); + + AES4_4x(s[0], s[1], s[2], s[3], 0); + MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + + AES4_4x(s[0], s[1], s[2], s[3], 8); + MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + + AES4_4x(s[0], s[1], s[2], s[3], 16); + MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + + AES4_4x(s[0], s[1], s[2], s[3], 24); + MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + + AES4_4x(s[0], s[1], s[2], s[3], 32); + MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + + + s[0][0] = _mm_xor_si128(s[0][0], LOAD(in)); + s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16)); + s[0][2] = _mm_xor_si128(s[0][2], LOAD(in + 32)); + s[0][3] = _mm_xor_si128(s[0][3], LOAD(in + 48)); + s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 64)); + s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 80)); + s[1][2] = _mm_xor_si128(s[1][2], LOAD(in + 96)); + s[1][3] = _mm_xor_si128(s[1][3], LOAD(in + 112)); + s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 128)); + s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 144)); + s[2][2] = _mm_xor_si128(s[2][2], LOAD(in + 160)); + s[2][3] = _mm_xor_si128(s[2][3], LOAD(in + 176)); + s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 192)); + s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 208)); + s[3][2] = _mm_xor_si128(s[3][2], LOAD(in + 224)); + s[3][3] = _mm_xor_si128(s[3][3], LOAD(in + 240)); + + TRUNCSTORE(out, s[0][0], s[0][1], s[0][2], s[0][3]); + TRUNCSTORE(out + 32, s[1][0], s[1][1], s[1][2], s[1][3]); + TRUNCSTORE(out + 64, s[2][0], s[2][1], s[2][2], s[2][3]); + TRUNCSTORE(out + 96, s[3][0], s[3][1], s[3][2], s[3][3]); +} + +void haraka512_8x(unsigned char *out, const unsigned char *in) { + // This is faster on Skylake, the code below is faster on Haswell. + haraka512_4x(out, in); + haraka512_4x(out + 128, in + 256); + + // u128 s[8][4], tmp; + // + // s[0][0] = LOAD(in); + // s[0][1] = LOAD(in + 16); + // s[0][2] = LOAD(in + 32); + // s[0][3] = LOAD(in + 48); + // s[1][0] = LOAD(in + 64); + // s[1][1] = LOAD(in + 80); + // s[1][2] = LOAD(in + 96); + // s[1][3] = LOAD(in + 112); + // s[2][0] = LOAD(in + 128); + // s[2][1] = LOAD(in + 144); + // s[2][2] = LOAD(in + 160); + // s[2][3] = LOAD(in + 176); + // s[3][0] = LOAD(in + 192); + // s[3][1] = LOAD(in + 208); + // s[3][2] = LOAD(in + 224); + // s[3][3] = LOAD(in + 240); + // s[4][0] = LOAD(in + 256); + // s[4][1] = LOAD(in + 272); + // s[4][2] = LOAD(in + 288); + // s[4][3] = LOAD(in + 304); + // s[5][0] = LOAD(in + 320); + // s[5][1] = LOAD(in + 336); + // s[5][2] = LOAD(in + 352); + // s[5][3] = LOAD(in + 368); + // s[6][0] = LOAD(in + 384); + // s[6][1] = LOAD(in + 400); + // s[6][2] = LOAD(in + 416); + // s[6][3] = LOAD(in + 432); + // s[7][0] = LOAD(in + 448); + // s[7][1] = LOAD(in + 464); + // s[7][2] = LOAD(in + 480); + // s[7][3] = LOAD(in + 496); + // + // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 0); + // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]); + // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]); + // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]); + // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]); + // + // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 8); + // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]); + // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]); + // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]); + // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]); + // + // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 16); + // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]); + // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]); + // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]); + // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]); + // + // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 24); + // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]); + // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]); + // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]); + // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]); + // + // AES4_8x(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], 32); + // MIX4(s[0][0], s[0][1], s[0][2], s[0][3]); + // MIX4(s[1][0], s[1][1], s[1][2], s[1][3]); + // MIX4(s[2][0], s[2][1], s[2][2], s[2][3]); + // MIX4(s[3][0], s[3][1], s[3][2], s[3][3]); + // MIX4(s[4][0], s[4][1], s[4][2], s[4][3]); + // MIX4(s[5][0], s[5][1], s[5][2], s[5][3]); + // MIX4(s[6][0], s[6][1], s[6][2], s[6][3]); + // MIX4(s[7][0], s[7][1], s[7][2], s[7][3]); + // + // + // s[0][0] = _mm_xor_si128(s[0][0], LOAD(in)); + // s[0][1] = _mm_xor_si128(s[0][1], LOAD(in + 16)); + // s[0][2] = _mm_xor_si128(s[0][2], LOAD(in + 32)); + // s[0][3] = _mm_xor_si128(s[0][3], LOAD(in + 48)); + // s[1][0] = _mm_xor_si128(s[1][0], LOAD(in + 64)); + // s[1][1] = _mm_xor_si128(s[1][1], LOAD(in + 80)); + // s[1][2] = _mm_xor_si128(s[1][2], LOAD(in + 96)); + // s[1][3] = _mm_xor_si128(s[1][3], LOAD(in + 112)); + // s[2][0] = _mm_xor_si128(s[2][0], LOAD(in + 128)); + // s[2][1] = _mm_xor_si128(s[2][1], LOAD(in + 144)); + // s[2][2] = _mm_xor_si128(s[2][2], LOAD(in + 160)); + // s[2][3] = _mm_xor_si128(s[2][3], LOAD(in + 176)); + // s[3][0] = _mm_xor_si128(s[3][0], LOAD(in + 192)); + // s[3][1] = _mm_xor_si128(s[3][1], LOAD(in + 208)); + // s[3][2] = _mm_xor_si128(s[3][2], LOAD(in + 224)); + // s[3][3] = _mm_xor_si128(s[3][3], LOAD(in + 240)); + // s[4][0] = _mm_xor_si128(s[4][0], LOAD(in + 256)); + // s[4][1] = _mm_xor_si128(s[4][1], LOAD(in + 272)); + // s[4][2] = _mm_xor_si128(s[4][2], LOAD(in + 288)); + // s[4][3] = _mm_xor_si128(s[4][3], LOAD(in + 304)); + // s[5][0] = _mm_xor_si128(s[5][0], LOAD(in + 320)); + // s[5][1] = _mm_xor_si128(s[5][1], LOAD(in + 336)); + // s[5][2] = _mm_xor_si128(s[5][2], LOAD(in + 352)); + // s[5][3] = _mm_xor_si128(s[5][3], LOAD(in + 368)); + // s[6][0] = _mm_xor_si128(s[6][0], LOAD(in + 384)); + // s[6][1] = _mm_xor_si128(s[6][1], LOAD(in + 400)); + // s[6][2] = _mm_xor_si128(s[6][2], LOAD(in + 416)); + // s[6][3] = _mm_xor_si128(s[6][3], LOAD(in + 432)); + // s[7][0] = _mm_xor_si128(s[7][0], LOAD(in + 448)); + // s[7][1] = _mm_xor_si128(s[7][1], LOAD(in + 464)); + // s[7][2] = _mm_xor_si128(s[7][2], LOAD(in + 480)); + // s[7][3] = _mm_xor_si128(s[7][3], LOAD(in + 496)); + // + // TRUNCSTORE(out, s[0][0], s[0][1], s[0][2], s[0][3]); + // TRUNCSTORE(out + 32, s[1][0], s[1][1], s[1][2], s[1][3]); + // TRUNCSTORE(out + 64, s[2][0], s[2][1], s[2][2], s[2][3]); + // TRUNCSTORE(out + 96, s[3][0], s[3][1], s[3][2], s[3][3]); + // TRUNCSTORE(out + 128, s[4][0], s[4][1], s[4][2], s[4][3]); + // TRUNCSTORE(out + 160, s[5][0], s[5][1], s[5][2], s[5][3]); + // TRUNCSTORE(out + 192, s[6][0], s[6][1], s[6][2], s[6][3]); + // TRUNCSTORE(out + 224, s[7][0], s[7][1], s[7][2], s[7][3]); +} diff --git a/src/crypto/haraka.h b/src/crypto/haraka.h new file mode 100644 index 000000000..daf657184 --- /dev/null +++ b/src/crypto/haraka.h @@ -0,0 +1,126 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 kste + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Optimized Implementations for Haraka256 and Haraka512 +*/ +#ifndef HARAKA_H_ +#define HARAKA_H_ + +#include "immintrin.h" + +#define NUMROUNDS 5 + +#ifdef _WIN32 +typedef unsigned long long u64; +#else +typedef unsigned long u64; +#endif +typedef __m128i u128; + +extern u128 rc[40]; + +#define LOAD(src) _mm_load_si128((u128 *)(src)) +#define STORE(dest,src) _mm_storeu_si128((u128 *)(dest),src) + +#define AES2(s0, s1, rci) \ + s0 = _mm_aesenc_si128(s0, rc[rci]); \ + s1 = _mm_aesenc_si128(s1, rc[rci + 1]); \ + s0 = _mm_aesenc_si128(s0, rc[rci + 2]); \ + s1 = _mm_aesenc_si128(s1, rc[rci + 3]); + +#define AES2_4x(s0, s1, s2, s3, rci) \ + AES2(s0[0], s0[1], rci); \ + AES2(s1[0], s1[1], rci); \ + AES2(s2[0], s2[1], rci); \ + AES2(s3[0], s3[1], rci); + +#define AES2_8x(s0, s1, s2, s3, s4, s5, s6, s7, rci) \ + AES2_4x(s0, s1, s2, s3, rci); \ + AES2_4x(s4, s5, s6, s7, rci); + +#define AES4(s0, s1, s2, s3, rci) \ + s0 = _mm_aesenc_si128(s0, rc[rci]); \ + s1 = _mm_aesenc_si128(s1, rc[rci + 1]); \ + s2 = _mm_aesenc_si128(s2, rc[rci + 2]); \ + s3 = _mm_aesenc_si128(s3, rc[rci + 3]); \ + s0 = _mm_aesenc_si128(s0, rc[rci + 4]); \ + s1 = _mm_aesenc_si128(s1, rc[rci + 5]); \ + s2 = _mm_aesenc_si128(s2, rc[rci + 6]); \ + s3 = _mm_aesenc_si128(s3, rc[rci + 7]); \ + +#define AES4_zero(s0, s1, s2, s3, rci) \ + s0 = _mm_aesenc_si128(s0, rc0[rci]); \ + s1 = _mm_aesenc_si128(s1, rc0[rci + 1]); \ + s2 = _mm_aesenc_si128(s2, rc0[rci + 2]); \ + s3 = _mm_aesenc_si128(s3, rc0[rci + 3]); \ + s0 = _mm_aesenc_si128(s0, rc0[rci + 4]); \ + s1 = _mm_aesenc_si128(s1, rc0[rci + 5]); \ + s2 = _mm_aesenc_si128(s2, rc0[rci + 6]); \ + s3 = _mm_aesenc_si128(s3, rc0[rci + 7]); \ + +#define AES4_4x(s0, s1, s2, s3, rci) \ + AES4(s0[0], s0[1], s0[2], s0[3], rci); \ + AES4(s1[0], s1[1], s1[2], s1[3], rci); \ + AES4(s2[0], s2[1], s2[2], s2[3], rci); \ + AES4(s3[0], s3[1], s3[2], s3[3], rci); + +#define AES4_8x(s0, s1, s2, s3, s4, s5, s6, s7, rci) \ + AES4_4x(s0, s1, s2, s3, rci); \ + AES4_4x(s4, s5, s6, s7, rci); + +#define MIX2(s0, s1) \ + tmp = _mm_unpacklo_epi32(s0, s1); \ + s1 = _mm_unpackhi_epi32(s0, s1); \ + s0 = tmp; + +#define MIX4(s0, s1, s2, s3) \ + tmp = _mm_unpacklo_epi32(s0, s1); \ + s0 = _mm_unpackhi_epi32(s0, s1); \ + s1 = _mm_unpacklo_epi32(s2, s3); \ + s2 = _mm_unpackhi_epi32(s2, s3); \ + s3 = _mm_unpacklo_epi32(s0, s2); \ + s0 = _mm_unpackhi_epi32(s0, s2); \ + s2 = _mm_unpackhi_epi32(s1, tmp); \ + s1 = _mm_unpacklo_epi32(s1, tmp); + +#define TRUNCSTORE(out, s0, s1, s2, s3) \ + *(u64*)(out) = (u64*)(s0)[1]; \ + *(u64*)(out + 8) = (u64*)(s1)[1]; \ + *(u64*)(out + 16) = (u64*)(s2)[0]; \ + *(u64*)(out + 24) = (u64*)(s3)[0]; + +void load_constants(); +void test_implementations(); + +void load_constants(); + +void haraka256(unsigned char *out, const unsigned char *in); +void haraka256_4x(unsigned char *out, const unsigned char *in); +void haraka256_8x(unsigned char *out, const unsigned char *in); + +void haraka512(unsigned char *out, const unsigned char *in); +void haraka512_zero(unsigned char *out, const unsigned char *in); +void haraka512_4x(unsigned char *out, const unsigned char *in); +void haraka512_8x(unsigned char *out, const unsigned char *in); + +#endif diff --git a/src/crypto/haraka_portable.c b/src/crypto/haraka_portable.c new file mode 100644 index 000000000..0792f8b2f --- /dev/null +++ b/src/crypto/haraka_portable.c @@ -0,0 +1,375 @@ +/* +Plain C implementation of the Haraka256 and Haraka512 permutations. +*/ +#include +#include +#include + +#include "haraka_portable.h" + +#define HARAKAS_RATE 32 + +static const unsigned char haraka_rc[40][16] = { + {0x9d, 0x7b, 0x81, 0x75, 0xf0, 0xfe, 0xc5, 0xb2, 0x0a, 0xc0, 0x20, 0xe6, 0x4c, 0x70, 0x84, 0x06}, + {0x17, 0xf7, 0x08, 0x2f, 0xa4, 0x6b, 0x0f, 0x64, 0x6b, 0xa0, 0xf3, 0x88, 0xe1, 0xb4, 0x66, 0x8b}, + {0x14, 0x91, 0x02, 0x9f, 0x60, 0x9d, 0x02, 0xcf, 0x98, 0x84, 0xf2, 0x53, 0x2d, 0xde, 0x02, 0x34}, + {0x79, 0x4f, 0x5b, 0xfd, 0xaf, 0xbc, 0xf3, 0xbb, 0x08, 0x4f, 0x7b, 0x2e, 0xe6, 0xea, 0xd6, 0x0e}, + {0x44, 0x70, 0x39, 0xbe, 0x1c, 0xcd, 0xee, 0x79, 0x8b, 0x44, 0x72, 0x48, 0xcb, 0xb0, 0xcf, 0xcb}, + {0x7b, 0x05, 0x8a, 0x2b, 0xed, 0x35, 0x53, 0x8d, 0xb7, 0x32, 0x90, 0x6e, 0xee, 0xcd, 0xea, 0x7e}, + {0x1b, 0xef, 0x4f, 0xda, 0x61, 0x27, 0x41, 0xe2, 0xd0, 0x7c, 0x2e, 0x5e, 0x43, 0x8f, 0xc2, 0x67}, + {0x3b, 0x0b, 0xc7, 0x1f, 0xe2, 0xfd, 0x5f, 0x67, 0x07, 0xcc, 0xca, 0xaf, 0xb0, 0xd9, 0x24, 0x29}, + {0xee, 0x65, 0xd4, 0xb9, 0xca, 0x8f, 0xdb, 0xec, 0xe9, 0x7f, 0x86, 0xe6, 0xf1, 0x63, 0x4d, 0xab}, + {0x33, 0x7e, 0x03, 0xad, 0x4f, 0x40, 0x2a, 0x5b, 0x64, 0xcd, 0xb7, 0xd4, 0x84, 0xbf, 0x30, 0x1c}, + {0x00, 0x98, 0xf6, 0x8d, 0x2e, 0x8b, 0x02, 0x69, 0xbf, 0x23, 0x17, 0x94, 0xb9, 0x0b, 0xcc, 0xb2}, + {0x8a, 0x2d, 0x9d, 0x5c, 0xc8, 0x9e, 0xaa, 0x4a, 0x72, 0x55, 0x6f, 0xde, 0xa6, 0x78, 0x04, 0xfa}, + {0xd4, 0x9f, 0x12, 0x29, 0x2e, 0x4f, 0xfa, 0x0e, 0x12, 0x2a, 0x77, 0x6b, 0x2b, 0x9f, 0xb4, 0xdf}, + {0xee, 0x12, 0x6a, 0xbb, 0xae, 0x11, 0xd6, 0x32, 0x36, 0xa2, 0x49, 0xf4, 0x44, 0x03, 0xa1, 0x1e}, + {0xa6, 0xec, 0xa8, 0x9c, 0xc9, 0x00, 0x96, 0x5f, 0x84, 0x00, 0x05, 0x4b, 0x88, 0x49, 0x04, 0xaf}, + {0xec, 0x93, 0xe5, 0x27, 0xe3, 0xc7, 0xa2, 0x78, 0x4f, 0x9c, 0x19, 0x9d, 0xd8, 0x5e, 0x02, 0x21}, + {0x73, 0x01, 0xd4, 0x82, 0xcd, 0x2e, 0x28, 0xb9, 0xb7, 0xc9, 0x59, 0xa7, 0xf8, 0xaa, 0x3a, 0xbf}, + {0x6b, 0x7d, 0x30, 0x10, 0xd9, 0xef, 0xf2, 0x37, 0x17, 0xb0, 0x86, 0x61, 0x0d, 0x70, 0x60, 0x62}, + {0xc6, 0x9a, 0xfc, 0xf6, 0x53, 0x91, 0xc2, 0x81, 0x43, 0x04, 0x30, 0x21, 0xc2, 0x45, 0xca, 0x5a}, + {0x3a, 0x94, 0xd1, 0x36, 0xe8, 0x92, 0xaf, 0x2c, 0xbb, 0x68, 0x6b, 0x22, 0x3c, 0x97, 0x23, 0x92}, + {0xb4, 0x71, 0x10, 0xe5, 0x58, 0xb9, 0xba, 0x6c, 0xeb, 0x86, 0x58, 0x22, 0x38, 0x92, 0xbf, 0xd3}, + {0x8d, 0x12, 0xe1, 0x24, 0xdd, 0xfd, 0x3d, 0x93, 0x77, 0xc6, 0xf0, 0xae, 0xe5, 0x3c, 0x86, 0xdb}, + {0xb1, 0x12, 0x22, 0xcb, 0xe3, 0x8d, 0xe4, 0x83, 0x9c, 0xa0, 0xeb, 0xff, 0x68, 0x62, 0x60, 0xbb}, + {0x7d, 0xf7, 0x2b, 0xc7, 0x4e, 0x1a, 0xb9, 0x2d, 0x9c, 0xd1, 0xe4, 0xe2, 0xdc, 0xd3, 0x4b, 0x73}, + {0x4e, 0x92, 0xb3, 0x2c, 0xc4, 0x15, 0x14, 0x4b, 0x43, 0x1b, 0x30, 0x61, 0xc3, 0x47, 0xbb, 0x43}, + {0x99, 0x68, 0xeb, 0x16, 0xdd, 0x31, 0xb2, 0x03, 0xf6, 0xef, 0x07, 0xe7, 0xa8, 0x75, 0xa7, 0xdb}, + {0x2c, 0x47, 0xca, 0x7e, 0x02, 0x23, 0x5e, 0x8e, 0x77, 0x59, 0x75, 0x3c, 0x4b, 0x61, 0xf3, 0x6d}, + {0xf9, 0x17, 0x86, 0xb8, 0xb9, 0xe5, 0x1b, 0x6d, 0x77, 0x7d, 0xde, 0xd6, 0x17, 0x5a, 0xa7, 0xcd}, + {0x5d, 0xee, 0x46, 0xa9, 0x9d, 0x06, 0x6c, 0x9d, 0xaa, 0xe9, 0xa8, 0x6b, 0xf0, 0x43, 0x6b, 0xec}, + {0xc1, 0x27, 0xf3, 0x3b, 0x59, 0x11, 0x53, 0xa2, 0x2b, 0x33, 0x57, 0xf9, 0x50, 0x69, 0x1e, 0xcb}, + {0xd9, 0xd0, 0x0e, 0x60, 0x53, 0x03, 0xed, 0xe4, 0x9c, 0x61, 0xda, 0x00, 0x75, 0x0c, 0xee, 0x2c}, + {0x50, 0xa3, 0xa4, 0x63, 0xbc, 0xba, 0xbb, 0x80, 0xab, 0x0c, 0xe9, 0x96, 0xa1, 0xa5, 0xb1, 0xf0}, + {0x39, 0xca, 0x8d, 0x93, 0x30, 0xde, 0x0d, 0xab, 0x88, 0x29, 0x96, 0x5e, 0x02, 0xb1, 0x3d, 0xae}, + {0x42, 0xb4, 0x75, 0x2e, 0xa8, 0xf3, 0x14, 0x88, 0x0b, 0xa4, 0x54, 0xd5, 0x38, 0x8f, 0xbb, 0x17}, + {0xf6, 0x16, 0x0a, 0x36, 0x79, 0xb7, 0xb6, 0xae, 0xd7, 0x7f, 0x42, 0x5f, 0x5b, 0x8a, 0xbb, 0x34}, + {0xde, 0xaf, 0xba, 0xff, 0x18, 0x59, 0xce, 0x43, 0x38, 0x54, 0xe5, 0xcb, 0x41, 0x52, 0xf6, 0x26}, + {0x78, 0xc9, 0x9e, 0x83, 0xf7, 0x9c, 0xca, 0xa2, 0x6a, 0x02, 0xf3, 0xb9, 0x54, 0x9a, 0xe9, 0x4c}, + {0x35, 0x12, 0x90, 0x22, 0x28, 0x6e, 0xc0, 0x40, 0xbe, 0xf7, 0xdf, 0x1b, 0x1a, 0xa5, 0x51, 0xae}, + {0xcf, 0x59, 0xa6, 0x48, 0x0f, 0xbc, 0x73, 0xc1, 0x2b, 0xd2, 0x7e, 0xba, 0x3c, 0x61, 0xc1, 0xa0}, + {0xa1, 0x9d, 0xc5, 0xe9, 0xfd, 0xbd, 0xd6, 0x4a, 0x88, 0x82, 0x28, 0x02, 0x03, 0xcc, 0x6a, 0x75} +}; + +static unsigned char rc[40][16]; +static unsigned char rc0[40][16]; +static unsigned char rc_sseed[40][16]; + +static const unsigned char sbox[256] = +{ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, + 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, + 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, + 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, + 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, + 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, + 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, + 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, + 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, + 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, + 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, + 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, + 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, + 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, + 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, + 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, + 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + +#define XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) + +// Simulate _mm_aesenc_si128 instructions from AESNI +void aesenc(unsigned char *s, const unsigned char *rk) +{ + unsigned char i, t, u, v[4][4]; + for (i = 0; i < 16; ++i) { + v[((i / 4) + 4 - (i%4) ) % 4][i % 4] = sbox[s[i]]; + } + for (i = 0; i < 4; ++i) { + t = v[i][0]; + u = v[i][0] ^ v[i][1] ^ v[i][2] ^ v[i][3]; + v[i][0] ^= u ^ XT(v[i][0] ^ v[i][1]); + v[i][1] ^= u ^ XT(v[i][1] ^ v[i][2]); + v[i][2] ^= u ^ XT(v[i][2] ^ v[i][3]); + v[i][3] ^= u ^ XT(v[i][3] ^ t); + } + for (i = 0; i < 16; ++i) { + s[i] = v[i / 4][i % 4] ^ rk[i]; + } +} + +// Simulate _mm_unpacklo_epi32 +void unpacklo32(unsigned char *t, unsigned char *a, unsigned char *b) +{ + unsigned char tmp[16]; + memcpy(tmp, a, 4); + memcpy(tmp + 4, b, 4); + memcpy(tmp + 8, a + 4, 4); + memcpy(tmp + 12, b + 4, 4); + memcpy(t, tmp, 16); +} + +// Simulate _mm_unpackhi_epi32 +void unpackhi32(unsigned char *t, unsigned char *a, unsigned char *b) +{ + unsigned char tmp[16]; + memcpy(tmp, a + 8, 4); + memcpy(tmp + 4, b + 8, 4); + memcpy(tmp + 8, a + 12, 4); + memcpy(tmp + 12, b + 12, 4); + memcpy(t, tmp, 16); +} + +void load_constants_port() +{ + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40*16); +} + +void tweak_constants(const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length) +{ + unsigned char buf[40*16]; + + /* Use the standard constants to generate tweaked ones. */ + memcpy(rc, haraka_rc, 40*16); + + /* Constants for sk.seed */ + if (sk_seed != NULL) { + haraka_S(buf, 40*16, sk_seed, seed_length); + memcpy(rc_sseed, buf, 40*16); + } + + /* Constants for pk.seed */ + haraka_S(buf, 40*16, pk_seed, seed_length); + memcpy(rc, buf, 40*16); +} + +static void haraka_S_absorb(unsigned char *s, unsigned int r, + const unsigned char *m, unsigned long long mlen, + unsigned char p) +{ + unsigned long long i; + unsigned char t[r]; + + while (mlen >= r) { + // XOR block to state + for (i = 0; i < r; ++i) { + s[i] ^= m[i]; + } + haraka512_perm(s, s); + mlen -= r; + m += r; + } + + for (i = 0; i < r; ++i) { + t[i] = 0; + } + for (i = 0; i < mlen; ++i) { + t[i] = m[i]; + } + t[i] = p; + t[r - 1] |= 128; + for (i = 0; i < r; ++i) { + s[i] ^= t[i]; + } +} + +static void haraka_S_squeezeblocks(unsigned char *h, unsigned long long nblocks, + unsigned char *s, unsigned int r) +{ + while (nblocks > 0) { + haraka512_perm(s, s); + memcpy(h, s, HARAKAS_RATE); + h += r; + nblocks--; + } +} + + +void haraka_S(unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen) +{ + unsigned long long i; + unsigned char s[64]; + unsigned char d[32]; + + for (i = 0; i < 64; i++) { + s[i] = 0; + } + haraka_S_absorb(s, 32, in, inlen, 0x1F); + + haraka_S_squeezeblocks(out, outlen / 32, s, 32); + out += (outlen / 32) * 32; + + if (outlen % 32) { + haraka_S_squeezeblocks(d, 1, s, 32); + for (i = 0; i < outlen % 32; i++) { + out[i] = d[i]; + } + } +} + +void haraka512_perm(unsigned char *out, const unsigned char *in) +{ + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[4*2*i + 4*j]); + aesenc(s + 16, rc[4*2*i + 4*j + 1]); + aesenc(s + 32, rc[4*2*i + 4*j + 2]); + aesenc(s + 48, rc[4*2*i + 4*j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void haraka512_port(unsigned char *out, const unsigned char *in) +{ + int i; + + unsigned char buf[64]; + + haraka512_perm(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + +void haraka512_perm_zero(unsigned char *out, const unsigned char *in) +{ + int i, j; + + unsigned char s[64], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + memcpy(s + 32, in + 32, 16); + memcpy(s + 48, in + 48, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc0[4*2*i + 4*j]); + aesenc(s + 16, rc0[4*2*i + 4*j + 1]); + aesenc(s + 32, rc0[4*2*i + 4*j + 2]); + aesenc(s + 48, rc0[4*2*i + 4*j + 3]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s, s, s + 16); + unpacklo32(s + 16, s + 32, s + 48); + unpackhi32(s + 32, s + 32, s + 48); + unpacklo32(s + 48, s, s + 32); + unpackhi32(s, s, s + 32); + unpackhi32(s + 32, s + 16, tmp); + unpacklo32(s + 16, s + 16, tmp); + } + + memcpy(out, s, 64); +} + +void haraka512_port_zero(unsigned char *out, const unsigned char *in) +{ + int i; + + unsigned char buf[64]; + + haraka512_perm_zero(buf, in); + /* Feed-forward */ + for (i = 0; i < 64; i++) { + buf[i] = buf[i] ^ in[i]; + } + + /* Truncated */ + memcpy(out, buf + 8, 8); + memcpy(out + 8, buf + 24, 8); + memcpy(out + 16, buf + 32, 8); + memcpy(out + 24, buf + 48, 8); +} + +void haraka256_port(unsigned char *out, const unsigned char *in) +{ + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc[2*2*i + 2*j]); + aesenc(s + 16, rc[2*2*i + 2*j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} + +void haraka256_sk(unsigned char *out, const unsigned char *in) +{ + int i, j; + + unsigned char s[32], tmp[16]; + + memcpy(s, in, 16); + memcpy(s + 16, in + 16, 16); + + for (i = 0; i < 5; ++i) { + // aes round(s) + for (j = 0; j < 2; ++j) { + aesenc(s, rc_sseed[2*2*i + 2*j]); + aesenc(s + 16, rc_sseed[2*2*i + 2*j + 1]); + } + + // mixing + unpacklo32(tmp, s, s + 16); + unpackhi32(s + 16, s, s + 16); + memcpy(s, tmp, 16); + } + + /* Feed-forward */ + for (i = 0; i < 32; i++) { + out[i] = in[i] ^ s[i]; + } +} diff --git a/src/crypto/haraka_portable.h b/src/crypto/haraka_portable.h new file mode 100644 index 000000000..dcc4f65ae --- /dev/null +++ b/src/crypto/haraka_portable.h @@ -0,0 +1,33 @@ +#ifndef SPX_HARAKA_H +#define SPX_HARAKA_H + +/* load constants */ +void load_constants_port(); + +/* Tweak constants with seed */ +void tweak_constants(const unsigned char *pk_seed, const unsigned char *sk_seed, + unsigned long long seed_length); + +/* Haraka Sponge */ +void haraka_S(unsigned char *out, unsigned long long outlen, + const unsigned char *in, unsigned long long inlen); + +/* Applies the 512-bit Haraka permutation to in. */ +void haraka512_perm(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512 */ +void haraka512_port(unsigned char *out, const unsigned char *in); + +/* Applies the 512-bit Haraka permutation to in, using zero key. */ +void haraka512_perm_zero(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-512, using zero key */ +void haraka512_port_zero(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 */ +void haraka256_port(unsigned char *out, const unsigned char *in); + +/* Implementation of Haraka-256 using sk.seed constants */ +void haraka256_sk(unsigned char *out, const unsigned char *in); + +#endif diff --git a/src/crypto/verus_hash.cpp b/src/crypto/verus_hash.cpp new file mode 100644 index 000000000..f5cb1c9f3 --- /dev/null +++ b/src/crypto/verus_hash.cpp @@ -0,0 +1,180 @@ +// (C) 2018 The Verus Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/* +This provides the PoW hash function for Verus, a CPU-optimized hash +function with a Haraka V2 core. Unlike Haraka, which is made for short +inputs only, Verus Hash takes any length of input and produces a 256 +bit output. +*/ +#include +#include "crypto/common.h" +#include "crypto/verus_hash.h" + +void (*CVerusHash::haraka512Function)(unsigned char *out, const unsigned char *in); + +void CVerusHash::Hash(void *result, const void *data, size_t _len) +{ + unsigned char buf[128]; + unsigned char *bufPtr = buf; + int nextOffset = 64; + uint32_t pos = 0, len = _len; + unsigned char *bufPtr2 = bufPtr + nextOffset; + unsigned char *ptr = (unsigned char *)data; + + // put our last result or zero at beginning of buffer each time + memset(bufPtr, 0, 32); + + // digest up to 32 bytes at a time + for ( ; pos < len; pos += 32) + { + if (len - pos >= 32) + { + memcpy(bufPtr + 32, ptr + pos, 32); + } + else + { + int i = (int)(len - pos); + memcpy(bufPtr + 32, ptr + pos, i); + memset(bufPtr + 32 + i, 0, 32 - i); + } + (*haraka512Function)(bufPtr2, bufPtr); + bufPtr2 = bufPtr; + bufPtr += nextOffset; + nextOffset *= -1; + } + memcpy(result, bufPtr, 32); +}; + +void CVerusHash::init() +{ + if (IsCPUVerusOptimized()) + { + haraka512Function = &haraka512_zero; + } + else + { + haraka512Function = &haraka512_port_zero; + } +} + +CVerusHash &CVerusHash::Write(const unsigned char *data, size_t _len) +{ + unsigned char *tmp; + uint32_t pos, len = _len; + + // digest up to 32 bytes at a time + for ( pos = 0; pos < len; ) + { + uint32_t room = 32 - curPos; + + if (len - pos >= room) + { + memcpy(curBuf + 32 + curPos, data + pos, room); + (*haraka512Function)(result, curBuf); + tmp = curBuf; + curBuf = result; + result = tmp; + pos += room; + curPos = 0; + } + else + { + memcpy(curBuf + 32 + curPos, data + pos, len - pos); + curPos += len - pos; + pos = len; + } + } + return *this; +} + +// to be declared and accessed from C +void verus_hash(void *result, const void *data, size_t len) +{ + return CVerusHash::Hash(result, data, len); +} + +void (*CVerusHashV2::haraka512Function)(unsigned char *out, const unsigned char *in); + +void CVerusHashV2::init() +{ + if (IsCPUVerusOptimized()) + { + load_constants(); + haraka512Function = &haraka512; + } + else + { + // load and tweak the haraka constants + load_constants_port(); + haraka512Function = &haraka512_port; + } +} + +void CVerusHashV2::Hash(void *result, const void *data, size_t len) +{ + unsigned char buf[128]; + unsigned char *bufPtr = buf; + int pos = 0, nextOffset = 64; + unsigned char *bufPtr2 = bufPtr + nextOffset; + unsigned char *ptr = (unsigned char *)data; + + // put our last result or zero at beginning of buffer each time + memset(bufPtr, 0, 32); + + // digest up to 32 bytes at a time + for ( ; pos < len; pos += 32) + { + if (len - pos >= 32) + { + memcpy(bufPtr + 32, ptr + pos, 32); + } + else + { + int i = (int)(len - pos); + memcpy(bufPtr + 32, ptr + pos, i); + memset(bufPtr + 32 + i, 0, 32 - i); + } + (*haraka512Function)(bufPtr2, bufPtr); + bufPtr2 = bufPtr; + bufPtr += nextOffset; + nextOffset *= -1; + } + memcpy(result, bufPtr, 32); +}; + +CVerusHashV2 &CVerusHashV2::Write(const unsigned char *data, size_t len) +{ + unsigned char *tmp; + + // digest up to 32 bytes at a time + for ( int pos = 0; pos < len; ) + { + int room = 32 - curPos; + + if (len - pos >= room) + { + memcpy(curBuf + 32 + curPos, data + pos, room); + (*haraka512Function)(result, curBuf); + tmp = curBuf; + curBuf = result; + result = tmp; + pos += room; + curPos = 0; + } + else + { + memcpy(curBuf + 32 + curPos, data + pos, len - pos); + curPos += len - pos; + pos = len; + } + } + return *this; +} + +// to be declared and accessed from C +void verus_hash_v2(void *result, const void *data, size_t len) +{ + return CVerusHashV2::Hash(result, data, len); +} diff --git a/src/crypto/verus_hash.h b/src/crypto/verus_hash.h new file mode 100644 index 000000000..5ac49c209 --- /dev/null +++ b/src/crypto/verus_hash.h @@ -0,0 +1,133 @@ +// (C) 2018 Michael Toutonghi +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/* +This provides the PoW hash function for Verus, enabling CPU mining. +*/ +#ifndef VERUS_HASH_H_ +#define VERUS_HASH_H_ + +#include +#include + +#include + +extern "C" +{ +#include "crypto/haraka.h" +#include "crypto/haraka_portable.h" +} + +class CVerusHash +{ + public: + static void Hash(void *result, const void *data, size_t len); + static void (*haraka512Function)(unsigned char *out, const unsigned char *in); + + static void init(); + + CVerusHash() { } + + CVerusHash &Write(const unsigned char *data, size_t len); + + CVerusHash &Reset() + { + curBuf = buf1; + result = buf2; + curPos = 0; + std::fill(buf1, buf1 + sizeof(buf1), 0); + return *this; + } + + int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } + void ClearExtra() + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + } + } + void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); } + + void Finalize(unsigned char hash[32]) + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + (*haraka512Function)(hash, curBuf); + } + else + std::memcpy(hash, curBuf, 32); + } + + private: + // only buf1, the first source, needs to be zero initialized + unsigned char buf1[64] = {0}, buf2[64]; + unsigned char *curBuf = buf1, *result = buf2; + size_t curPos = 0; +}; + +class CVerusHashV2 +{ + public: + static void Hash(void *result, const void *data, size_t len); + static void (*haraka512Function)(unsigned char *out, const unsigned char *in); + + static void init(); + + CVerusHashV2() {} + + CVerusHashV2 &Write(const unsigned char *data, size_t len); + + CVerusHashV2 &Reset() + { + curBuf = buf1; + result = buf2; + curPos = 0; + std::fill(buf1, buf1 + sizeof(buf1), 0); + } + + int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } + void ClearExtra() + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + } + } + void ExtraHash(unsigned char hash[32]) { (*haraka512Function)(hash, curBuf); } + + void Finalize(unsigned char hash[32]) + { + if (curPos) + { + std::fill(curBuf + 32 + curPos, curBuf + 64, 0); + (*haraka512Function)(hash, curBuf); + } + else + std::memcpy(hash, curBuf, 32); + } + + private: + // only buf1, the first source, needs to be zero initialized + unsigned char buf1[64] = {0}, buf2[64]; + unsigned char *curBuf = buf1, *result = buf2; + size_t curPos = 0; +}; + +extern void verus_hash(void *result, const void *data, size_t len); +extern void verus_hash_v2(void *result, const void *data, size_t len); + +inline bool IsCPUVerusOptimized() +{ + unsigned int eax,ebx,ecx,edx; + + if (!__get_cpuid(1,&eax,&ebx,&ecx,&edx)) + { + return false; + } + return ((ecx & (bit_AVX | bit_AES)) == (bit_AVX | bit_AES)); +}; + +#endif diff --git a/src/cryptoconditions/Makefile.am b/src/cryptoconditions/Makefile.am index 52f12eee0..787b11ac6 100644 --- a/src/cryptoconditions/Makefile.am +++ b/src/cryptoconditions/Makefile.am @@ -15,7 +15,7 @@ AM_CFLAGS = -I$(top_srcdir)/src/asn -I$(top_srcdir)/include -I$(top_srcdir)/src/ LIBSECP256K1=src/include/secp256k1/libsecp256k1.la $(LIBSECP256K1): $(wildcard src/secp256k1/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) -march:x86-64 -g CRYPTOCONDITIONS_CORE=libcryptoconditions_core.la diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h index 08f00a2ca..71f9cb460 100644 --- a/src/cryptoconditions/include/cryptoconditions.h +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -56,8 +56,6 @@ typedef struct CC { }; } CC; - - /* * Crypto Condition Visitor */ @@ -87,6 +85,7 @@ struct CC* cc_conditionFromJSON(cJSON *params, char *err); struct CC* cc_conditionFromJSONString(const char *json, char *err); struct CC* cc_readConditionBinary(const uint8_t *cond_bin, size_t cond_bin_len); struct CC* cc_readFulfillmentBinary(const uint8_t *ffill_bin, size_t ffill_bin_len); +int cc_readFulfillmentBinaryExt(const unsigned char *ffill_bin, size_t ffill_bin_len, CC **ppcc); struct CC* cc_new(int typeId); struct cJSON* cc_conditionToJSON(const CC *cond); char* cc_conditionToJSONString(const CC *cond); diff --git a/src/cryptoconditions/src/anon.c b/src/cryptoconditions/src/anon.c index 8c2b9cea6..f3214995b 100644 --- a/src/cryptoconditions/src/anon.c +++ b/src/cryptoconditions/src/anon.c @@ -55,7 +55,7 @@ static void anonToJSON(const CC *cond, cJSON *params) { static unsigned char *anonFingerprint(const CC *cond) { unsigned char *out = calloc(1, 32); - fprintf(stderr,"anon fingerprint %p %p\n",out,cond->fingerprint); + //fprintf(stderr,"anon fingerprint %p %p\n",out,cond->fingerprint); memcpy(out, cond->fingerprint, 32); return out; } diff --git a/src/cryptoconditions/src/asn/CompoundSha256Condition.h b/src/cryptoconditions/src/asn/CompoundSha256Condition.h index 5d791be4f..9dea601c4 100644 --- a/src/cryptoconditions/src/asn/CompoundSha256Condition.h +++ b/src/cryptoconditions/src/asn/CompoundSha256Condition.h @@ -8,7 +8,7 @@ #define _CompoundSha256Condition_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/Condition.h b/src/cryptoconditions/src/asn/Condition.h index ad32b18aa..9994d8b88 100644 --- a/src/cryptoconditions/src/asn/Condition.h +++ b/src/cryptoconditions/src/asn/Condition.h @@ -8,7 +8,7 @@ #define _Condition_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include "SimpleSha256Condition.h" diff --git a/src/cryptoconditions/src/asn/ConditionTypes.h b/src/cryptoconditions/src/asn/ConditionTypes.h index 3d391eb36..760d5bfff 100644 --- a/src/cryptoconditions/src/asn/ConditionTypes.h +++ b/src/cryptoconditions/src/asn/ConditionTypes.h @@ -8,7 +8,7 @@ #define _ConditionTypes_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/Ed25519FingerprintContents.h b/src/cryptoconditions/src/asn/Ed25519FingerprintContents.h index 7ef9e188e..c936f8718 100644 --- a/src/cryptoconditions/src/asn/Ed25519FingerprintContents.h +++ b/src/cryptoconditions/src/asn/Ed25519FingerprintContents.h @@ -8,7 +8,7 @@ #define _Ed25519FingerprintContents_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.h b/src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.h index 603839803..01c1fb104 100644 --- a/src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.h +++ b/src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.h @@ -8,7 +8,7 @@ #define _Ed25519Sha512Fulfillment_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/EvalFulfillment.h b/src/cryptoconditions/src/asn/EvalFulfillment.h index 378baa367..a484a4103 100644 --- a/src/cryptoconditions/src/asn/EvalFulfillment.h +++ b/src/cryptoconditions/src/asn/EvalFulfillment.h @@ -8,7 +8,7 @@ #define _EvalFulfillment_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/Fulfillment.h b/src/cryptoconditions/src/asn/Fulfillment.h index 01799e949..169faf0b1 100644 --- a/src/cryptoconditions/src/asn/Fulfillment.h +++ b/src/cryptoconditions/src/asn/Fulfillment.h @@ -8,7 +8,7 @@ #define _Fulfillment_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include "PreimageFulfillment.h" diff --git a/src/cryptoconditions/src/asn/INTEGER.h b/src/cryptoconditions/src/asn/INTEGER.h index 9a8809707..b68bd250b 100644 --- a/src/cryptoconditions/src/asn/INTEGER.h +++ b/src/cryptoconditions/src/asn/INTEGER.h @@ -5,7 +5,7 @@ #ifndef _INTEGER_H_ #define _INTEGER_H_ -#include +#include "asn_application.h" #include #ifdef __cplusplus diff --git a/src/cryptoconditions/src/asn/NativeInteger.h b/src/cryptoconditions/src/asn/NativeInteger.h index 4e63a8355..9369111b4 100644 --- a/src/cryptoconditions/src/asn/NativeInteger.h +++ b/src/cryptoconditions/src/asn/NativeInteger.h @@ -12,7 +12,7 @@ #ifndef _NativeInteger_H_ #define _NativeInteger_H_ -#include +#include "asn_application.h" #include #ifdef __cplusplus diff --git a/src/cryptoconditions/src/asn/OCTET_STRING.h b/src/cryptoconditions/src/asn/OCTET_STRING.h index 013c7b13f..75c995de9 100644 --- a/src/cryptoconditions/src/asn/OCTET_STRING.h +++ b/src/cryptoconditions/src/asn/OCTET_STRING.h @@ -5,7 +5,7 @@ #ifndef _OCTET_STRING_H_ #define _OCTET_STRING_H_ -#include +#include "asn_application.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/PrefixFingerprintContents.h b/src/cryptoconditions/src/asn/PrefixFingerprintContents.h index 5d1254cd4..48b8ffaa5 100644 --- a/src/cryptoconditions/src/asn/PrefixFingerprintContents.h +++ b/src/cryptoconditions/src/asn/PrefixFingerprintContents.h @@ -8,7 +8,7 @@ #define _PrefixFingerprintContents_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/PrefixFulfillment.h b/src/cryptoconditions/src/asn/PrefixFulfillment.h index 1c06cbc8d..974b7ecd8 100644 --- a/src/cryptoconditions/src/asn/PrefixFulfillment.h +++ b/src/cryptoconditions/src/asn/PrefixFulfillment.h @@ -8,7 +8,7 @@ #define _PrefixFulfillment_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/PreimageFulfillment.h b/src/cryptoconditions/src/asn/PreimageFulfillment.h index 04df5bd3b..ebfe35f22 100644 --- a/src/cryptoconditions/src/asn/PreimageFulfillment.h +++ b/src/cryptoconditions/src/asn/PreimageFulfillment.h @@ -8,7 +8,7 @@ #define _PreimageFulfillment_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/RsaFingerprintContents.h b/src/cryptoconditions/src/asn/RsaFingerprintContents.h index 8637cd911..ca9ac6993 100644 --- a/src/cryptoconditions/src/asn/RsaFingerprintContents.h +++ b/src/cryptoconditions/src/asn/RsaFingerprintContents.h @@ -8,7 +8,7 @@ #define _RsaFingerprintContents_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/RsaSha256Fulfillment.h b/src/cryptoconditions/src/asn/RsaSha256Fulfillment.h index fda524276..801e745a0 100644 --- a/src/cryptoconditions/src/asn/RsaSha256Fulfillment.h +++ b/src/cryptoconditions/src/asn/RsaSha256Fulfillment.h @@ -8,7 +8,7 @@ #define _RsaSha256Fulfillment_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/Secp256k1FingerprintContents.h b/src/cryptoconditions/src/asn/Secp256k1FingerprintContents.h index d0a3b0b39..1f6e8fa61 100644 --- a/src/cryptoconditions/src/asn/Secp256k1FingerprintContents.h +++ b/src/cryptoconditions/src/asn/Secp256k1FingerprintContents.h @@ -8,7 +8,7 @@ #define _Secp256k1FingerprintContents_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/Secp256k1Fulfillment.h b/src/cryptoconditions/src/asn/Secp256k1Fulfillment.h index 79221317f..894826cb8 100644 --- a/src/cryptoconditions/src/asn/Secp256k1Fulfillment.h +++ b/src/cryptoconditions/src/asn/Secp256k1Fulfillment.h @@ -8,7 +8,7 @@ #define _Secp256k1Fulfillment_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/SimpleSha256Condition.h b/src/cryptoconditions/src/asn/SimpleSha256Condition.h index 4ca08877b..cd859b4b3 100644 --- a/src/cryptoconditions/src/asn/SimpleSha256Condition.h +++ b/src/cryptoconditions/src/asn/SimpleSha256Condition.h @@ -8,7 +8,7 @@ #define _SimpleSha256Condition_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/ThresholdFingerprintContents.h b/src/cryptoconditions/src/asn/ThresholdFingerprintContents.h index 4d1c4f491..4162a7070 100644 --- a/src/cryptoconditions/src/asn/ThresholdFingerprintContents.h +++ b/src/cryptoconditions/src/asn/ThresholdFingerprintContents.h @@ -8,7 +8,7 @@ #define _ThresholdFingerprintContents_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/ThresholdFulfillment.h b/src/cryptoconditions/src/asn/ThresholdFulfillment.h index e00ae5f2b..29bf19236 100644 --- a/src/cryptoconditions/src/asn/ThresholdFulfillment.h +++ b/src/cryptoconditions/src/asn/ThresholdFulfillment.h @@ -8,7 +8,7 @@ #define _ThresholdFulfillment_H_ -#include +#include "asn_application.h" /* Including external dependencies */ #include diff --git a/src/cryptoconditions/src/asn/asn_codecs_prim.h b/src/cryptoconditions/src/asn/asn_codecs_prim.h index 0f683fdd0..be673ba19 100644 --- a/src/cryptoconditions/src/asn/asn_codecs_prim.h +++ b/src/cryptoconditions/src/asn/asn_codecs_prim.h @@ -5,7 +5,7 @@ #ifndef ASN_CODECS_PRIM_H #define ASN_CODECS_PRIM_H -#include +#include "asn_application.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/ber_decoder.h b/src/cryptoconditions/src/asn/ber_decoder.h index 9fe2e895d..a3e5c5a3d 100644 --- a/src/cryptoconditions/src/asn/ber_decoder.h +++ b/src/cryptoconditions/src/asn/ber_decoder.h @@ -5,7 +5,7 @@ #ifndef _BER_DECODER_H_ #define _BER_DECODER_H_ -#include +#include "asn_application.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/constr_CHOICE.h b/src/cryptoconditions/src/asn/constr_CHOICE.h index e824a2206..60d8105e0 100644 --- a/src/cryptoconditions/src/asn/constr_CHOICE.h +++ b/src/cryptoconditions/src/asn/constr_CHOICE.h @@ -6,7 +6,7 @@ #ifndef _CONSTR_CHOICE_H_ #define _CONSTR_CHOICE_H_ -#include +#include "asn_application.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/constr_SEQUENCE.h b/src/cryptoconditions/src/asn/constr_SEQUENCE.h index c2aeb6676..6a7c6e5ed 100644 --- a/src/cryptoconditions/src/asn/constr_SEQUENCE.h +++ b/src/cryptoconditions/src/asn/constr_SEQUENCE.h @@ -5,7 +5,7 @@ #ifndef _CONSTR_SEQUENCE_H_ #define _CONSTR_SEQUENCE_H_ -#include +#include "asn_application.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/constr_SET_OF.h b/src/cryptoconditions/src/asn/constr_SET_OF.h index 75e18cfa0..c0f1db8d9 100644 --- a/src/cryptoconditions/src/asn/constr_SET_OF.h +++ b/src/cryptoconditions/src/asn/constr_SET_OF.h @@ -5,7 +5,7 @@ #ifndef _CONSTR_SET_OF_H_ #define _CONSTR_SET_OF_H_ -#include +#include "asn_application.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/constr_TYPE.h b/src/cryptoconditions/src/asn/constr_TYPE.h index a9cd86dc3..596e5f298 100644 --- a/src/cryptoconditions/src/asn/constr_TYPE.h +++ b/src/cryptoconditions/src/asn/constr_TYPE.h @@ -12,8 +12,8 @@ #ifndef _CONSTR_TYPE_H_ #define _CONSTR_TYPE_H_ -#include -#include +#include "ber_tlv_length.h" +#include "ber_tlv_tag.h" #ifdef __cplusplus extern "C" { @@ -35,13 +35,13 @@ typedef struct asn_struct_ctx_s { ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ } asn_struct_ctx_t; -#include /* Basic Encoding Rules decoder */ -#include /* Distinguished Encoding Rules encoder */ -#include /* Decoder of XER (XML, text) */ -#include /* Encoder into XER (XML, text) */ -#include /* Packet Encoding Rules decoder */ -#include /* Packet Encoding Rules encoder */ -#include /* Subtype constraints support */ +#include "ber_decoder.h" /* Basic Encoding Rules decoder */ +#include "der_encoder.h" /* Distinguished Encoding Rules encoder */ +#include "xer_decoder.h" /* Decoder of XER (XML, text) */ +#include "xer_encoder.h" /* Encoder into XER (XML, text) */ +#include "per_decoder.h" /* Packet Encoding Rules decoder */ +#include "per_encoder.h" /* Packet Encoding Rules encoder */ +#include "constraints.h" /* Subtype constraints support */ /* * Free the structure according to its specification. diff --git a/src/cryptoconditions/src/asn/constraints.h b/src/cryptoconditions/src/asn/constraints.h index 48d49e246..a38e586c8 100644 --- a/src/cryptoconditions/src/asn/constraints.h +++ b/src/cryptoconditions/src/asn/constraints.h @@ -5,7 +5,7 @@ #ifndef ASN1_CONSTRAINTS_VALIDATOR_H #define ASN1_CONSTRAINTS_VALIDATOR_H -#include /* Platform-dependent types */ +#include "asn_system.h" /* Platform-dependent types */ #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/der_encoder.h b/src/cryptoconditions/src/asn/der_encoder.h index 61431c6db..b7debab3f 100644 --- a/src/cryptoconditions/src/asn/der_encoder.h +++ b/src/cryptoconditions/src/asn/der_encoder.h @@ -5,7 +5,7 @@ #ifndef _DER_ENCODER_H_ #define _DER_ENCODER_H_ -#include +#include "asn_application.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/per_decoder.c b/src/cryptoconditions/src/asn/per_decoder.c index 461b7262f..4f2e73e9b 100644 --- a/src/cryptoconditions/src/asn/per_decoder.c +++ b/src/cryptoconditions/src/asn/per_decoder.c @@ -1,4 +1,4 @@ -#include +#include "asn_application.h" #include #include diff --git a/src/cryptoconditions/src/asn/per_decoder.h b/src/cryptoconditions/src/asn/per_decoder.h index 8397a545f..9fe08887a 100644 --- a/src/cryptoconditions/src/asn/per_decoder.h +++ b/src/cryptoconditions/src/asn/per_decoder.h @@ -5,8 +5,8 @@ #ifndef _PER_DECODER_H_ #define _PER_DECODER_H_ -#include -#include +#include "asn_application.h" +#include "per_support.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/per_encoder.c b/src/cryptoconditions/src/asn/per_encoder.c index 47f3c916d..b54170b82 100644 --- a/src/cryptoconditions/src/asn/per_encoder.c +++ b/src/cryptoconditions/src/asn/per_encoder.c @@ -1,4 +1,4 @@ -#include +#include "asn_application.h" #include #include diff --git a/src/cryptoconditions/src/asn/per_encoder.h b/src/cryptoconditions/src/asn/per_encoder.h index 95a6506e4..0c4501791 100644 --- a/src/cryptoconditions/src/asn/per_encoder.h +++ b/src/cryptoconditions/src/asn/per_encoder.h @@ -5,8 +5,8 @@ #ifndef _PER_ENCODER_H_ #define _PER_ENCODER_H_ -#include -#include +#include "asn_application.h" +#include "per_support.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/per_opentype.c b/src/cryptoconditions/src/asn/per_opentype.c index 404aa7264..0c221aba2 100644 --- a/src/cryptoconditions/src/asn/per_opentype.c +++ b/src/cryptoconditions/src/asn/per_opentype.c @@ -3,7 +3,7 @@ * Redistribution and modifications are permitted subject to BSD license. */ #include -#include +#include "per_support.h" #include #include diff --git a/src/cryptoconditions/src/asn/per_support.c b/src/cryptoconditions/src/asn/per_support.c index 14b4c4c76..6ee0c55f1 100644 --- a/src/cryptoconditions/src/asn/per_support.c +++ b/src/cryptoconditions/src/asn/per_support.c @@ -5,7 +5,7 @@ */ #include #include -#include +#include "per_support.h" char * per_data_string(asn_per_data_t *pd) { diff --git a/src/cryptoconditions/src/asn/per_support.h b/src/cryptoconditions/src/asn/per_support.h index a75ac94fc..cc470ce2f 100644 --- a/src/cryptoconditions/src/asn/per_support.h +++ b/src/cryptoconditions/src/asn/per_support.h @@ -6,7 +6,7 @@ #ifndef _PER_SUPPORT_H_ #define _PER_SUPPORT_H_ -#include /* Platform-specific types */ +#include "asn_system.h" /* Platform-specific types */ #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/xer_decoder.c b/src/cryptoconditions/src/asn/xer_decoder.c index 299a7c1ee..b410c620f 100644 --- a/src/cryptoconditions/src/asn/xer_decoder.c +++ b/src/cryptoconditions/src/asn/xer_decoder.c @@ -2,7 +2,7 @@ * Copyright (c) 2004, 2005 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#include +#include "asn_application.h" #include #include /* XER/XML parsing support */ diff --git a/src/cryptoconditions/src/asn/xer_decoder.h b/src/cryptoconditions/src/asn/xer_decoder.h index 301b613cf..06a434989 100644 --- a/src/cryptoconditions/src/asn/xer_decoder.h +++ b/src/cryptoconditions/src/asn/xer_decoder.h @@ -5,7 +5,7 @@ #ifndef _XER_DECODER_H_ #define _XER_DECODER_H_ -#include +#include "asn_application.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/xer_encoder.h b/src/cryptoconditions/src/asn/xer_encoder.h index 055e73c0c..f86dc543e 100644 --- a/src/cryptoconditions/src/asn/xer_encoder.h +++ b/src/cryptoconditions/src/asn/xer_encoder.h @@ -5,7 +5,7 @@ #ifndef _XER_ENCODER_H_ #define _XER_ENCODER_H_ -#include +#include "asn_application.h" #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c index b9b08af20..11410a3ec 100644 --- a/src/cryptoconditions/src/cryptoconditions.c +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -216,6 +216,35 @@ end: return cond; } +int cc_readFulfillmentBinaryExt(const unsigned char *ffill_bin, size_t ffill_bin_len, CC **ppcc) { + + int error = 0; + unsigned char *buf = calloc(1,ffill_bin_len); + Fulfillment_t *ffill = 0; + asn_dec_rval_t rval = ber_decode(0, &asn_DEF_Fulfillment, (void **)&ffill, ffill_bin, ffill_bin_len); + if (rval.code != RC_OK) { + error = rval.code; + goto end; + } + // Do malleability check + asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Fulfillment, ffill, buf, ffill_bin_len); + if (rc.encoded == -1) { + fprintf(stderr, "FULFILLMENT NOT ENCODED\n"); + error = -1; + goto end; + } + if (rc.encoded != ffill_bin_len || 0 != memcmp(ffill_bin, buf, rc.encoded)) { + error = (rc.encoded == ffill_bin_len) ? -3 : -2; + goto end; + } + + *ppcc = fulfillmentToCC(ffill); +end: + free(buf); + if (ffill) ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill); + return error; +} + int cc_visit(CC *cond, CCVisitor visitor) { int out = visitor.visit(cond, visitor); @@ -225,7 +254,6 @@ int cc_visit(CC *cond, CCVisitor visitor) { return out; } - int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength, int doHashMsg, const unsigned char *condBin, size_t condBinLength, VerifyEval verifyEval, void *evalContext) { diff --git a/src/cryptoconditions/src/include/secp256k1/Makefile.am b/src/cryptoconditions/src/include/secp256k1/Makefile.am index c071fbe27..52303e4e4 100644 --- a/src/cryptoconditions/src/include/secp256k1/Makefile.am +++ b/src/cryptoconditions/src/include/secp256k1/Makefile.am @@ -71,7 +71,7 @@ endif endif libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) +libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) -march=x86-64 -g libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB) libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c 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..21f57d094 --- /dev/null +++ b/src/dbwrapper.h @@ -0,0 +1,277 @@ +// 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; + } + + bool GetKeyDataStream(CDataStream &ssKey) { + leveldb::Slice slKey = piter->key(); + try { + ssKey = CDataStream(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); + } 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..9b34b1d0f 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); + CAlert::Notify(msg, fThread); uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_WARNING); } } diff --git a/src/deprecation.h b/src/deprecation.h index 11eb69ef4..16484ed5a 100644 --- a/src/deprecation.h +++ b/src/deprecation.h @@ -9,7 +9,7 @@ // * Shut down WEEKS_UNTIL_DEPRECATION weeks' worth of blocks after the estimated release block height. // * A warning is shown during the DEPRECATION_WARN_LIMIT worth of blocks prior to shut down. static const int WEEKS_UNTIL_DEPRECATION = 52; -static const int DEPRECATION_HEIGHT = 1400000; +static const int DEPRECATION_HEIGHT = 1600000; static const int APPROX_RELEASE_HEIGHT = DEPRECATION_HEIGHT - (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 60); // Number of blocks before deprecation to warn users @@ -20,6 +20,6 @@ static const int DEPRECATION_WARN_LIMIT = 60 * 24 * 60; // 2 months * shuts down the node with an error if so (and deprecation is not disabled for * the current client version). */ -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/fiat/verus b/src/fiat/verus new file mode 100755 index 000000000..956ac71c4 --- /dev/null +++ b/src/fiat/verus @@ -0,0 +1,7 @@ +#!/bin/bash + +#set working directory to the location of this script +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd $DIR + +../komodo-cli -ac_name=VRSC "$@" diff --git a/src/fiat/verus.bat b/src/fiat/verus.bat new file mode 100644 index 000000000..0bf87d33b --- /dev/null +++ b/src/fiat/verus.bat @@ -0,0 +1,14 @@ +@call :GET_CURRENT_DIR +@cd %THIS_DIR% +komodo-cli.exe -ac_name=VRSC %1 %2 %3 %4 %5 %6 %7 %8 %9 +@goto :EOF + +:GET_CURRENT_DIR +@pushd %~dp0 +@set THIS_DIR=%CD% +@popd +@goto :EOF + + + + 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..5f32b5fef 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,42 @@ 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"; + + static_assert( + sizeof(boost::filesystem::path::value_type) == sizeof(codeunit), + "librustzcash not configured correctly"); + auto sapling_spend_str = sapling_spend.native(); + auto sapling_output_str = sapling_output.native(); + auto sprout_groth16_str = sprout_groth16.native(); + + librustzcash_init_zksnark_params( + reinterpret_cast(sapling_spend_str.c_str()), + sapling_spend_str.length(), + "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c", + reinterpret_cast(sapling_output_str.c_str()), + sapling_output_str.length(), + "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028", + reinterpret_cast(sprout_groth16_str.c_str()), + sprout_groth16_str.length(), + "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..01f098004 100644 --- a/src/gtest/test_checkblock.cpp +++ b/src/gtest/test_checkblock.cpp @@ -68,32 +68,104 @@ 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; CBlockIndex indexPrev {prev}; - indexPrev.nHeight = 0; + indexPrev.SetHeight(0); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-cb-height", false)).Times(1); EXPECT_FALSE(ContextualCheckBlock(block, state, &indexPrev)); @@ -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..c6f66cc64 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,8 +506,11 @@ TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) { CTransaction tx(mtx); MockCValidationState state; + // during initial block download, DoS ban score should be zero, else 100 + EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); + ContextualCheckTransaction(tx, state, 0, 100, []() { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - ContextualCheckTransaction(tx, state, 0, 100); + ContextualCheckTransaction(tx, state, 0, 100, []() { return false; }); } TEST(checktransaction_tests, non_canonical_ed25519_signature) { @@ -394,14 +542,17 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) { CTransaction tx(mtx); MockCValidationState state; + // during initial block download, DoS ban score should be zero, else 100 + EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); + ContextualCheckTransaction(tx, state, 0, 100, []() { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - ContextualCheckTransaction(tx, state, 0, 100); + ContextualCheckTransaction(tx, state, 0, 100, []() { return false; }); } 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 +583,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 +647,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 +659,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 +718,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 +813,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,14 +829,17 @@ 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; + // during initial block download, DoS ban score should be zero, else 100 + EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1); + ContextualCheckTransaction(tx, state, 1, 100, []() { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "tx-overwinter-not-active", false)).Times(1); - ContextualCheckTransaction(tx, state, 1, 100); + ContextualCheckTransaction(tx, state, 1, 100, []() { return false; }); } // This tests a transaction without the fOverwintered flag set, against the Overwinter consensus rule set. @@ -643,7 +849,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 +890,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 +912,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 +1033,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..bd9599421 --- /dev/null +++ b/src/gtest/test_keys.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include "consensus/upgrades.h" + +#include + +TEST(Keys, 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, SAPLING_BRANCH_ID)); + + 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..ccf9cb9ba 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,43 @@ 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)); + + // 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 +236,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 +334,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_pow.cpp b/src/gtest/test_pow.cpp index ac3ce59e1..3f7b3f0ce 100644 --- a/src/gtest/test_pow.cpp +++ b/src/gtest/test_pow.cpp @@ -15,10 +15,10 @@ TEST(PoW, DifficultyAveraging) { std::vector blocks(lastBlk+1); for (int i = 0; i <= lastBlk; i++) { blocks[i].pprev = i ? &blocks[i - 1] : nullptr; - blocks[i].nHeight = i; + blocks[i].SetHeight(i); blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing; blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */ - blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); + blocks[i].chainPower = i ? (CChainPower(&blocks[i]) + blocks[i - 1].chainPower) + GetBlockProof(blocks[i - 1]) : CChainPower(&blocks[i]); } // Result should be the same as if last difficulty was used @@ -68,3 +68,44 @@ TEST(PoW, DifficultyAveraging) { params), GetNextWorkRequired(&blocks[lastBlk], nullptr, params)); } + +TEST(PoW, MinDifficultyRules) { + SelectParams(CBaseChainParams::TESTNET); + const Consensus::Params& params = Params().GetConsensus(); + size_t lastBlk = 2*params.nPowAveragingWindow; + size_t firstBlk = lastBlk - params.nPowAveragingWindow; + + // Start with blocks evenly-spaced and equal difficulty + std::vector blocks(lastBlk+1); + for (int i = 0; i <= lastBlk; i++) { + blocks[i].pprev = i ? &blocks[i - 1] : nullptr; + blocks[i].nHeight = params.nPowAllowMinDifficultyBlocksAfterHeight.get() + i; + blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing; + blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */ + blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); + } + + // Create a new block at the target spacing + CBlockHeader next; + next.nTime = blocks[lastBlk].nTime + params.nPowTargetSpacing; + + // Result should be unchanged, modulo integer division precision loss + arith_uint256 bnRes; + bnRes.SetCompact(0x1e7fffff); + bnRes /= params.AveragingWindowTimespan(); + bnRes *= params.AveragingWindowTimespan(); + EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), bnRes.GetCompact()); + + // Delay last block up to the edge of the min-difficulty limit + next.nTime += params.nPowTargetSpacing * 5; + + // Result should be unchanged, modulo integer division precision loss + EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), bnRes.GetCompact()); + + // Delay last block over the min-difficulty limit + next.nTime += 1; + + // Result should be the minimum difficulty + EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), + UintToArith256(params.powLimit).GetCompact()); +} 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..202b2e3ab 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" @@ -21,7 +21,7 @@ TEST(rpc, check_blockToJSON_returns_minified_solution) { ss >> block; CBlockIndex index {block}; - index.nHeight = 1391; + index.SetHeight(1391); UniValue obj = blockToJSON(block, &index); EXPECT_EQ("009f44ff7505d789b964d6817734b8ce1377d456255994370d06e59ac99bd5791b6ad174a66fd71c70e60cfc7fd88243ffe06f80b1ad181625f210779c745524629448e25348a5fce4f346a1735e60fdf53e144c0157dbc47c700a21a236f1efb7ee75f65b8d9d9e29026cfd09048233175202b211b9a49de4ab46f1cac71b6ea57a686377bd612378746e70c61a659c9cd683269e9c2a5cbc1d19f1149345302bbd0a1e62bf4bab01e9caeea789a1519441a61b146de35a4cc75dbdf01029127e311ad5073e7e96397f47226a7df9df66b2086b70756db013bbaeb068260157014b2602fc7dc71336e1439c887d2742d9730b4e79b08ec7839c3e2a037ae1565d04e05e351bb3531e5ef42cf7b71ca1482a9205245dd41f4db0f71644f8bdb88e845558537c03834c06ac83f336651e54e2edfc12e15ea9b7ea2c074e6155654d44c4d3bd90d9511050e9ad87d170db01448e5be6f45419cd86008978db5e3ceab79890234f992648d69bf1053855387db646ccdee5575c65f81dd0f670b016d9f9a84707d91f77b862f697b8bb08365ba71fbe6bfa47af39155a75ebdcb1e5d69f59c40c9e3a64988c1ec26f7f5159eef5c244d504a9e46125948ecc389c2ec3028ac4ff39ffd66e7743970819272b21e0c2df75b308bc62896873952147e57ed79446db4cdb5a563e76ec4c25899d41128afb9a5f8fc8063621efb7a58b9dd666d30c73e318cdcf3393bfec200e160f500e645f7baac263db99fa4a7c1cb4fea219fc512193102034d379f244c21a81821301b8d47c90247713a3e902c762d7bafa6cdb744eeb6d3b50dd175599d02b6e9f5bbda59366e04862aa765135968426e7ac0116de7351940dc57c0ae451d63f667e39891bc81e09e6c76f6f8a7582f7447c6f5945f717b0e52a7e3dd0c6db4061362123cc53fd8ede4abed4865201dc4d8eb4e5d48baa565183b69a5304a44c0600bb24dcaeee9d95ceebd27c1b0a33e0b46f23797d7d7907300b2bb7d62ef2fc5aa139250c73930c621bb5f41fc235534ee8014dfaddd5245aeb01198420ba7b5c076545329c94d54fa725a8e807579f5f0cc9d98170598023268f5930893620190275e6b3c6f5181e36310a9a475208316911d78f917d724c5946c553b7ec042c563c540114b6b78bd4c6e808ee391a4a9d93e127032983c5b3708037b14aa604cfb034e7c8b0ffdd6936446fe80216178506a87402653a373926eeff66e704daf992a0a9a5c3ad80566c0339be9e5b8e35b3b3226b2f7767e20d992ea6c3d6e322eca37b0c7f7e60060802f5abcc1975841365cadbdc3867063addfc803766ae525375ecddee61f9df9ffcd20343c83ab82b0e91de039c59cb435c8d3159cc338b4901f40c9b5c27043bcf2bd5fa9b685b65c9ba5a1e11a51dd3f773051560341f9ec81d05bf259e2d4b7161f896fbb6812cfc924a32120b7367d5e40439e267adda6a1315bb0d6200ce6a503174c8d2a638ea6fd6b1f486d68db11bdca63c4f4a725d1ab6231ea875484e70b27d293c05803386924f283d4c12bb953474d92b7dd43d2d97193bd96281ebb63fa075d2f9ecd310c70ee1d97b5330bd8fb5791c5943ecf084e5f2c83915acac57519c46b166136068d6f9ec0dd598616e32c591128ce13705a283ca39d5b211409600e07b3713113374d9700207a45394eac5b3b7afc9b1b2bad7d89fd3f35f6b2413ce615ee7869b3569009403b96fdacdb32ef0a7e5229e2b666d51e95bdfb009b892e88bde70621a9b6509f068781392df4bdbc5723bb15071993f0d9a11575af5ff6ef85eaea39bc86805b35d8beee91b779354147f2d85304b8b49d053e7444fdd3deb9d16de331f2552af5b3be7766bb8f3f6a78c62148efb231f2268", find_value(obj, "solution").get_str()); 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..05a8cb601 --- /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.ovk, 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.ovk, 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.ovk, 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.ovk); + 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.ovk, 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.ovk, 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_upgrades.cpp b/src/gtest/test_upgrades.cpp index 1066a28d0..54fa48832 100644 --- a/src/gtest/test_upgrades.cpp +++ b/src/gtest/test_upgrades.cpp @@ -143,6 +143,35 @@ TEST_F(UpgradesTest, IsActivationHeightForAnyUpgrade) { EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params)); } +TEST_F(UpgradesTest, NextEpoch) { + SelectParams(CBaseChainParams::REGTEST); + const Consensus::Params& params = Params().GetConsensus(); + + // Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT + EXPECT_EQ(NextEpoch(-1, params), boost::none); + EXPECT_EQ(NextEpoch(0, params), boost::none); + EXPECT_EQ(NextEpoch(1, params), boost::none); + EXPECT_EQ(NextEpoch(1000000, params), boost::none); + + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + + EXPECT_EQ(NextEpoch(-1, params), boost::none); + EXPECT_EQ(NextEpoch(0, params), boost::none); + EXPECT_EQ(NextEpoch(1, params), boost::none); + EXPECT_EQ(NextEpoch(1000000, params), boost::none); + + int nActivationHeight = 100; + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); + + EXPECT_EQ(NextEpoch(-1, params), boost::none); + EXPECT_EQ(NextEpoch(0, params), static_cast(Consensus::UPGRADE_TESTDUMMY)); + EXPECT_EQ(NextEpoch(1, params), static_cast(Consensus::UPGRADE_TESTDUMMY)); + EXPECT_EQ(NextEpoch(nActivationHeight - 1, params), static_cast(Consensus::UPGRADE_TESTDUMMY)); + EXPECT_EQ(NextEpoch(nActivationHeight, params), boost::none); + EXPECT_EQ(NextEpoch(nActivationHeight + 1, params), boost::none); + EXPECT_EQ(NextEpoch(1000000, params), boost::none); +} + TEST_F(UpgradesTest, NextActivationHeight) { SelectParams(CBaseChainParams::REGTEST); const Consensus::Params& params = Params().GetConsensus(); 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 06fcced0a..09f71b432 100644 --- a/src/hash.h +++ b/src/hash.h @@ -8,6 +8,8 @@ #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" @@ -120,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 @@ -147,7 +158,7 @@ public: template CHashWriter& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } }; @@ -172,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); @@ -187,11 +201,82 @@ public: template CBLAKE2bWriter& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } }; +/** A writer stream (for serialization) that computes a 256-bit Verus hash. */ +class CVerusHashWriter +{ +private: + CVerusHash state; + +public: + int nType; + int nVersion; + + CVerusHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() { } + void Reset() { state.Reset(); } + + CVerusHashWriter& write(const char *pch, size_t size) { + state.Write((const unsigned char*)pch, size); + return (*this); + } + + // invalidates the object for further writing + uint256 GetHash() { + uint256 result; + state.Finalize((unsigned char*)&result); + return result; + } + + int64_t *xI64p() { return state.ExtraI64Ptr(); } + CVerusHash &GetState() { return state; } + + template + CVerusHashWriter& operator<<(const T& obj) { + // Serialize to this stream + ::Serialize(*this, obj); + return (*this); + } +}; + +/** A writer stream (for serialization) that computes a 256-bit Verus hash with key initialized to Haraka standard. */ +class CVerusHashV2Writer +{ +private: + CVerusHashV2 state; + +public: + int nType; + int nVersion; + + CVerusHashV2Writer(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn), state() {} + void Reset() { state.Reset(); } + + CVerusHashV2Writer& write(const char *pch, size_t size) { + state.Write((const unsigned char*)pch, size); + return (*this); + } + + // invalidates the object for further writing + uint256 GetHash() { + uint256 result; + state.Finalize((unsigned char*)&result); + return result; + } + + int64_t *xI64p() { return state.ExtraI64Ptr(); } + CVerusHashV2 &GetState() { return state; } + + template + CVerusHashV2Writer& operator<<(const T& obj) { + // Serialize to this stream + ::Serialize(*this, obj); + return (*this); + } +}; /** Compute the 256-bit hash of an object's serialization. */ template @@ -202,6 +287,24 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL return ss.GetHash(); } +/** Compute the 256-bit Verus hash of an object's serialization. */ +template +uint256 SerializeVerusHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) +{ + CVerusHashWriter ss(nType, nVersion); + ss << obj; + return ss.GetHash(); +} + +/** Compute the 256-bit Verus hash of an object's serialization. */ +template +uint256 SerializeVerusHashV2(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) +{ + CVerusHashV2Writer ss(nType, nVersion); + ss << obj; + return ss.GetHash(); +} + unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector& vDataToHash); void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]); 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/httpserver.h b/src/httpserver.h index 93fb5d8d6..f04a332ec 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -7,6 +7,9 @@ #include #include +#ifdef _WIN32 +#undef __cpuid +#endif #include #include #include diff --git a/src/init.cpp b/src/init.cpp index 1105cda31..f3d728933 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -9,11 +9,9 @@ #include "init.h" #include "crypto/common.h" +#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" @@ -22,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" @@ -67,10 +69,13 @@ #include "amqp/amqpnotificationinterface.h" #endif +#include "librustzcash.h" + using namespace std; extern void ThreadSendAlert(); extern int32_t KOMODO_LOADINGBLOCKS; +extern bool VERUS_MINTBLOCKS; ZCJoinSplit* pzcashParams = NULL; @@ -190,7 +195,7 @@ void Shutdown() /// for example if the data directory was found to be locked. /// Be sure that anything that writes files or flushes caches only does this if the respective /// module was initialized. - RenameThread("zcash-shutoff"); + RenameThread("verus-shutoff"); mempool.AddTransactionsUpdated(1); StopHTTPRPC(); @@ -351,13 +356,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 @@ -393,6 +396,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)); @@ -471,6 +477,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()))); @@ -498,8 +505,9 @@ std::string HelpMessage(HelpMessageMode mode) #ifdef ENABLE_MINING strUsage += HelpMessageGroup(_("Mining options:")); - strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0)); - strUsage += HelpMessageOpt("-genproclimit=", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 0)); + strUsage += HelpMessageOpt("-mint", strprintf(_("Mint/stake coins automatically (default: %u)"), 0)); + strUsage += HelpMessageOpt("-gen", strprintf(_("Mine/generate coins (default: %u)"), 0)); + strUsage += HelpMessageOpt("-genproclimit=", strprintf(_("Set the number of threads for coin mining if enabled (-1 = all cores, default: %d)"), 0)); strUsage += HelpMessageOpt("-equihashsolver=", _("Specify the Equihash solver to be used if enabled (default: \"default\")")); strUsage += HelpMessageOpt("-mineraddress=", _("Send mined coins to a specific single address")); strUsage += HelpMessageOpt("-minetolocalwallet", strprintf( @@ -682,15 +690,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" @@ -709,6 +728,34 @@ 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); + + static_assert( + sizeof(boost::filesystem::path::value_type) == sizeof(codeunit), + "librustzcash not configured correctly"); + auto sapling_spend_str = sapling_spend.native(); + auto sapling_output_str = sapling_output.native(); + auto sprout_groth16_str = sprout_groth16.native(); + + LogPrintf("Loading Sapling (Spend) parameters from %s\n", sapling_spend.string().c_str()); + LogPrintf("Loading Sapling (Output) parameters from %s\n", sapling_output.string().c_str()); + LogPrintf("Loading Sapling (Sprout Groth16) parameters from %s\n", sprout_groth16.string().c_str()); + gettimeofday(&tv_start, 0); + + librustzcash_init_zksnark_params( + reinterpret_cast(sapling_spend_str.c_str()), + sapling_spend_str.length(), + "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c", + reinterpret_cast(sapling_output_str.c_str()), + sapling_output_str.length(), + "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028", + reinterpret_cast(sprout_groth16_str.c_str()), + sprout_groth16_str.length(), + "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) @@ -791,6 +838,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(); @@ -959,8 +1008,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); @@ -1035,10 +1087,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"])); @@ -1100,6 +1157,16 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) ECC_Start(); globalVerifyHandle.reset(new ECCVerifyHandle()); + // set the hash algorithm to use for this chain + extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH; + CVerusHash::init(); + CVerusHashV2::init(); + if (ASSETCHAINS_ALGO == ASSETCHAINS_VERUSHASH) + { + // initialize VerusHash + CBlockHeader::SetVerusHash(); + } + // Sanity check if (!InitSanityCheck()) return InitError(_("Initialization sanity check failed. Komodo is shutting down.")); @@ -1172,7 +1239,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 @@ -1211,6 +1278,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"]) { @@ -1405,22 +1486,24 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex, dbCompression, dbMaxOpenFiles); fAddressIndex = GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX); pblocktree->ReadFlag("addressindex", checkval); - if ( checkval != fAddressIndex ) + if ( checkval != fAddressIndex && fAddressIndex != 0 ) { pblocktree->WriteFlag("addressindex", fAddressIndex); - fprintf(stderr,"set addressindex, will reindex. sorry will take a while.\n"); + fprintf(stderr,"set addressindex, will reindex. could take a while.\n"); fReindex = true; } fSpentIndex = GetBoolArg("-spentindex", DEFAULT_SPENTINDEX); pblocktree->ReadFlag("spentindex", checkval); - if ( checkval != fSpentIndex ) + if ( checkval != fSpentIndex && fSpentIndex != 0 ) { pblocktree->WriteFlag("spentindex", fSpentIndex); - fprintf(stderr,"set spentindex, will reindex. sorry will take a while.\n"); + fprintf(stderr,"set spentindex, will reindex. could take a while.\n"); fReindex = true; } } + bool clearWitnessCaches = false; + bool fLoaded = false; while (!fLoaded) { bool fReset = fReindex; @@ -1483,7 +1566,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; } @@ -1617,6 +1700,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 @@ -1636,7 +1725,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(); @@ -1653,7 +1742,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (chainActive.Tip() && chainActive.Tip() != pindexRescan) { uiInterface.InitMessage(_("Rescanning...")); - LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight); + LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->GetHeight(), pindexRescan->GetHeight()); nStart = GetTimeMillis(); pwalletMain->ScanForWalletTransactions(pindexRescan, true); LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); @@ -1706,9 +1795,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) { @@ -1768,6 +1856,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("nBestHeight = %d\n", chainActive.Height()); #ifdef ENABLE_WALLET + RescanWallets(); + LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0); LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0); LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0); @@ -1778,10 +1868,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) StartNode(threadGroup, scheduler); - #ifdef ENABLE_MINING // Generate coins in the background #ifdef ENABLE_WALLET + VERUS_MINTBLOCKS = GetBoolArg("-mint", false); + if (pwalletMain || !GetArg("-mineraddress", "").empty()) GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 0)); #else 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..f04c4da04 --- /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