diff --git a/.python-version b/.python-version new file mode 100644 index 0000000000000..c49282585a030 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.5.6 diff --git a/.travis.yml b/.travis.yml index fd30dd38918d5..b4e588069f3e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,39 @@ -sudo: required -dist: trusty +# The test build matrix (stage: test) is constructed to test a wide range of +# configurations, rather than a single pass/fail. This helps to catch build +# failures and logic errors that present on platforms other than the ones the +# author has tested. +# +# Some builders use the dependency-generator in `./depends`, rather than using +# apt-get to install build dependencies. This guarantees that the tester is +# using the same versions as Gitian, so the build results are nearly identical +# to what would be found in a final release. +# +# In order to avoid rebuilding all dependencies for each build, the binaries +# are cached and re-used when possible. Changes in the dependency-generator +# will trigger cache-invalidation and rebuilds as necessary. +# +# These caches can be manually removed if necessary. This is one of the very +# few manual operations that is possible with Travis, and it can be done by a +# ION GitHub member via the Travis web interface [0]. +# +# Travis CI uploads the cache after the script phase of the build [1]. +# However, the build is terminated without saving the chache if it takes over +# 50 minutes [2]. Thus, if we spent too much time in early build stages, fail +# with an error and save the cache. +# +# [0] https://travis-ci.org/ion-project/ion/caches +# [1] https://docs.travis-ci.com/user/caching/#build-phases +# [2] https://docs.travis-ci.com/user/customizing-the-build#build-timeouts + +dist: xenial os: linux language: minimal cache: ccache: true directories: - - depends/built - - depends/sdk-sources - - $HOME/.ccache + - $TRAVIS_BUILD_DIR/depends/built + - $TRAVIS_BUILD_DIR/depends/sdk-sources + - $HOME/.ccache stages: - lint - test @@ -27,7 +53,7 @@ env: - SDK_URL=https://github.com/gitianuser/MacOSX-SDKs/releases/download/MacOSX10.11.sdk - WINEDEBUG=fixme-all - DOCKER_PACKAGES="build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache" - + - CACHE_ERR_MSG="Error! Initial build successful, but not enough time remains to run later build stages and tests. Please manually re-run this job by using the travis restart button or asking a bitcoin maintainer to restart. The next run should not time out because the build cache has been saved." before_install: - set -o errexit; source .travis/test_03_before_install.sh install: @@ -35,122 +61,156 @@ install: before_script: - set -o errexit; source .travis/test_05_before_script.sh script: - - set -o errexit; source .travis/test_06_script.sh + - export CONTINUE=1 + - if [ $SECONDS -gt 1200 ]; then export CONTINUE=0; fi # Likely the depends build took very long + - if [ $CONTINUE = "1" ]; then set -o errexit; source .travis/test_06_script_a.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi + - if [ $SECONDS -gt 1500 ]; then export CONTINUE=0; fi # Likely the build took very long; The tests take about 1000s, so we should abort if we have less than 50*60-1000=2000s left + - if [ $CONTINUE = "1" ]; then set -o errexit; source .travis/test_06_script_b.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi after_script: - - echo $TRAVIS_COMMIT_RANGE - - echo $TRAVIS_COMMIT_LOG - + - echo $TRAVIS_COMMIT_RANGE + - echo $TRAVIS_COMMIT_LOG jobs: include: -# lint stage + - stage: lint + name: 'lint' env: - sudo: false cache: false language: python - python: '3.6' + python: '3.5' # Oldest supported version according to doc/dependencies.md install: - set -o errexit; source .travis/lint_04_install.sh before_script: - set -o errexit; source .travis/lint_05_before_script.sh script: - set -o errexit; source .travis/lint_06_script.sh -# ARM + - stage: test + name: 'ARM 32-bit [GOAL: install] [no unit or functional tests]' env: >- HOST=arm-linux-gnueabihf PACKAGES="python3 g++-arm-linux-gnueabihf" - DEP_OPTS="NO_QT=1" RUN_FUNCTIONAL_TESTS=false GOAL="install" # -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1" # This could be removed once the ABI change warning does not show up by default ION_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi" -# AArch64 + - stage: test + name: 'ARM 64-bit [GOAL:install] [no unit or functional tests]' env: >- HOST=aarch64-linux-gnu PACKAGES="python3 g++-aarch64-linux-gnu" - DEP_OPTS="NO_QT=1" RUN_FUNCTIONAL_TESTS=false GOAL="install" ION_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" -# RISC-V + - stage: test + name: 'RISC-V [GOAL:install] [no unit or functional tests]' env: >- HOST=riscv64-linux-gnu PACKAGES="python3 g++-riscv64-linux-gnu" - DEP_OPTS="NO_QT=1" RUN_FUNCTIONAL_TESTS=false GOAL="install" ION_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" -# Win32 + - stage: test + name: 'Win32 [GOAL: deploy] [no functional tests]' env: >- HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" - DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-i686 wine-binfmt wine32" - GOAL="install" + RUN_FUNCTIONAL_TESTS=false + GOAL="deploy" ION_CONFIG="--enable-reduce-exports" -# Win64 + - stage: test + name: 'Win64 [GOAL: deploy] [no functional tests]' env: >- HOST=x86_64-w64-mingw32 - DEP_OPTS="NO_QT=1" PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64" - GOAL="install" + RUN_FUNCTIONAL_TESTS=false + GOAL="deploy" ION_CONFIG="--enable-reduce-exports" -# 32-bit + dash + - stage: test + name: '32-bit + dash [GOAL: install] [no gui]' env: >- HOST=i686-pc-linux-gnu PACKAGES="g++-multilib python3-zmq" - DEP_OPTS="NO_QT=1" GOAL="install" - ION_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" + ION_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" CONFIG_SHELL="/bin/dash" -# x86_64 Linux (uses qt5 dev package instead of depends Qt to speed up build and avoid timeout) + - stage: test + name: 'x86_64 Linux [GOAL: install] [bionic] [uses qt5 dev package instead of depends Qt to speed up build and avoid timeout]' env: >- HOST=x86_64-unknown-linux-gnu PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1" + RUN_FUNCTIONAL_TESTS=true + #TEST_RUNNER_EXTRA="--coverage --extended" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash + GOAL="install" + ION_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports" + + - stage: test + name: 'x86_64 Linux [GOAL: install] [trusty] [no functional tests, no depends, only system libs]' + env: >- + HOST=x86_64-unknown-linux-gnu + DOCKER_NAME_TAG=ubuntu:14.04 + PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libicu-dev libpng-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.1++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" + NO_DEPENDS=1 + RUN_FUNCTIONAL_TESTS=false + GOAL="install" + ION_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no" + + - stage: test + name: 'x86_64 Linux [GOAL: install] [xenial] [no depends, only system libs]' + env: >- + HOST=x86_64-unknown-linux-gnu + DOCKER_NAME_TAG=ubuntu:16.04 + PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" + NO_DEPENDS=1 GOAL="install" - ION_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER" -# x86_64 Linux (no depends, only system libs) + ION_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --disable-hardening --disable-asm" + - stage: test + name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs]' env: >- HOST=x86_64-unknown-linux-gnu PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" NO_DEPENDS=1 GOAL="install" - ION_CONFIG="--enable-zmq --with-incompatible-bdb --enable-glibc-back-compat --enable-reduce-exports --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER" -# x86_64 Linux (sanitizers) + ION_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER" + # - stage: test +# name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: fuzzer,address]' # env: >- # HOST=x86_64-unknown-linux-gnu # PACKAGES="clang python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" # NO_DEPENDS=1 +# RUN_UNIT_TESTS=false +# RUN_FUNCTIONAL_TESTS=false # RUN_BENCH=true -# RUN_FUNCTIONAL_TESTS=false # Disabled for now, can be combined with the other x86_64 linux NO_DEPENDS job when functional tests pass the sanitizers # GOAL="install" # ION_CONFIG="--enable-zmq --with-incompatible-bdb --enable-glibc-back-compat --enable-reduce-exports --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=undefined CC=clang CXX=clang++" -# x86_64 Linux, No wallet + # - stage: test +# name: 'x86_64 Linux [GOAL: install] [bionic] [no wallet]' # env: >- # HOST=x86_64-unknown-linux-gnu -# PACKAGES="python3" +# PACKAGES="python3-zmq" # DEP_OPTS="NO_WALLET=1" # GOAL="install" # ION_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" -# Cross-Mac + - stage: test + name: 'macOS 10.10 [GOAL: deploy] [no functional tests]' env: >- HOST=x86_64-apple-darwin14 - PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git" + PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python3-dev python3-setuptools" OSX_SDK=10.11 RUN_UNIT_TESTS=false RUN_FUNCTIONAL_TESTS=false - GOAL="all deploy" + GOAL="deploy" ION_CONFIG="--enable-gui --enable-reduce-exports --enable-werror" diff --git a/.travis/lint_04_install.sh b/.travis/lint_04_install.sh index 34118a57c345f..9a22773e57655 100755 --- a/.travis/lint_04_install.sh +++ b/.travis/lint_04_install.sh @@ -6,4 +6,10 @@ export LC_ALL=C -travis_retry pip install flake8 +travis_retry pip install codespell==1.13.0 +travis_retry pip install flake8==3.5.0 +travis_retry pip install vulture==0.29 + +SHELLCHECK_VERSION=v0.6.0 +curl -s "https://storage.googleapis.com/shellcheck/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar --xz -xf - --directory /tmp/ +export PATH="/tmp/shellcheck-${SHELLCHECK_VERSION}:${PATH}" diff --git a/.travis/test_03_before_install.sh b/.travis/test_03_before_install.sh index d091a67ca93d0..3c9fcf3f983ae 100755 --- a/.travis/test_03_before_install.sh +++ b/.travis/test_03_before_install.sh @@ -7,6 +7,8 @@ export LC_ALL=C.UTF-8 PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g") +# Add llvm-symbolizer directory to PATH. Needed to get symbolized stack traces from the sanitizers. +PATH=$PATH:/usr/lib/llvm-6.0/bin/ export PATH BEGIN_FOLD () { diff --git a/.travis/test_04_install.sh b/.travis/test_04_install.sh index ef595287b7150..f9bd903f7630d 100755 --- a/.travis/test_04_install.sh +++ b/.travis/test_04_install.sh @@ -7,9 +7,11 @@ export LC_ALL=C.UTF-8 travis_retry docker pull "$DOCKER_NAME_TAG" -env | grep -E '^(CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL)' | tee /tmp/env +env | grep -E '^(ION_CONFIG|CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL)' | tee /tmp/env if [[ $HOST = *-mingw32 ]]; then DOCKER_ADMIN="--cap-add SYS_ADMIN" +elif [[ $ION_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764) + DOCKER_ADMIN="--cap-add SYS_PTRACE" fi DOCKER_ID=$(docker run $DOCKER_ADMIN -idt --mount type=bind,src=$TRAVIS_BUILD_DIR,dst=$TRAVIS_BUILD_DIR --mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR -w $TRAVIS_BUILD_DIR --env-file /tmp/env $DOCKER_NAME_TAG) diff --git a/.travis/test_06_script.sh b/.travis/test_06_script_a.sh similarity index 67% rename from .travis/test_06_script.sh rename to .travis/test_06_script_a.sh index d762d0f9f8e6f..ffe1932c682fe 100755 --- a/.travis/test_06_script.sh +++ b/.travis/test_06_script_a.sh @@ -40,28 +40,11 @@ BEGIN_FOLD configure DOCKER_EXEC ./configure --cache-file=../config.cache $ION_CONFIG_ALL $ION_CONFIG || ( cat config.log && false) END_FOLD +set -o errtrace +trap 'DOCKER_EXEC "cat ${TRAVIS_BUILD_DIR}/sanitizer-output/* 2> /dev/null"' ERR + BEGIN_FOLD build DOCKER_EXEC make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && DOCKER_EXEC make $GOAL V=1 ; false ) END_FOLD -if [ "$RUN_UNIT_TESTS" = "true" ]; then - BEGIN_FOLD unit-tests - DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1 - END_FOLD -fi - -if [ "$RUN_BENCH" = "true" ]; then - BEGIN_FOLD bench - DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib $OUTDIR/bin/bench_ion -scaling=0.001 - END_FOLD -fi - -if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then - extended="--extended --exclude feature_pruning,feature_dbcrash" -fi - -if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then - BEGIN_FOLD functional-tests - DOCKER_EXEC test/functional/test_runner.py --combinedlogslen=4000 --coverage --quiet --failfast ${extended} - END_FOLD -fi +cd ${TRAVIS_BUILD_DIR} || (echo "could not enter travis build dir $TRAVIS_BUILD_DIR"; exit 1) diff --git a/.travis/test_06_script_b.sh b/.travis/test_06_script_b.sh new file mode 100755 index 0000000000000..c2e9d6e2aa46e --- /dev/null +++ b/.travis/test_06_script_b.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +cd "build/ion-$HOST" || (echo "could not enter distdir build/ion-$HOST"; exit 1) + +if [ "$RUN_UNIT_TESTS" = "true" ]; then + BEGIN_FOLD unit-tests + DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1 + END_FOLD +fi + +if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then + BEGIN_FOLD functional-tests + DOCKER_EXEC test/functional/test_runner.py --combinedlogslen=4000 ${TEST_RUNNER_EXTRA} + END_FOLD +fi + +cd ${TRAVIS_BUILD_DIR} || (echo "could not enter travis build dir $TRAVIS_BUILD_DIR"; exit 1) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000..ad1328d2e0a74 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,544 @@ +cmake_minimum_required(VERSION 3.10) +project(ION) + +set(BDB_VER "4.8.30") +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/contrib/cmake") +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ") +include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) + +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + message(STATUS "Compiling on macOS") + list(APPEND CMAKE_PREFIX_PATH /usr/local/opt/qt5) + list(APPEND CMAKE_PREFIX_PATH /usr/local/opt/openssl) + list(APPEND CMAKE_PREFIX_PATH /usr/local/Cellar/berkeley-db@4) + set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl/") + set(ENV{CPPFLAGS} "-I${OPENSSL_ROOT_DIR}/include") + set(ENV{LDFLAGS} "-L${OPENSSL_ROOT_DIR}/lib") + set(BerkeleyDB_ROOT_DIR "/usr/local/Cellar/berkeley-db@4/${BDB_VER}/") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + file(READ "/proc/version" _SYS_VERSION) + string(REGEX MATCH "Microsoft" _SYSTEM_VERSION_PARSED "${_SYS_VERSION}") + if(${_SYSTEM_VERSION_PARSED} MATCHES "Microsoft") + message(STATUS "Compiling on WSL") + set(ENV{triple} x86_64-w64-mingw32) + set(ENV{target} Windows) + execute_process( + COMMAND make HOST=x86_64-w64-mingw32 -j16 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/depends + ) + file(REMOVE ${CMAKE_BINARY_DIR}/CMakeFiles/${CMAKE_VERSION}/CMakeCXXCompiler.cmake) + file(REMOVE ${CMAKE_BINARY_DIR}/CMakeFiles/${CMAKE_VERSION}/CMakeCCompiler.cmake) + set(CMAKE_C_COMPILER /usr/bin/$ENV{triple}-gcc) + set(CMAKE_CXX_COMPILER /usr/bin/$ENV{triple}-g++) + set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}) + set(BOOST_INCLUDEDIR ${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/include/) + set(BOOST_LIBRARYDIR ${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/lib) + set(Boost_USE_STATIC_RUNTIME ON) + set(Boost_THREADAPI "win32") + else() + message(STATUS "Compiling on Linux") + list(APPEND CMAKE_PREFIX_PATH /usr/lib/x86_64-linux-gnu/cmake/Qt5) + set(Qt5core_DIR "/usr/lib/x86_64-linux-gnu/cmake/Qt5/QtCore") + include_directories("/usr/include") + include_directories("/usr/include/x86_64-linux-gnu") + add_definitions("-D__BYTE_ORDER -D__LITTLE_ENDIAN") + endif() +endif() + +# Find Dependencies +find_package(BerkeleyDB ${BDB_VER} REQUIRED) +if (BerkeleyDB_FOUND) + if(NOT ${BerkeleyDB_VERSION} MATCHES "${BDB_VER}") + message(WARNING "BerkeleyDB version other than ${BDB_VER} found!") + set(BDB_CONFIGURE_FLAGS "--with-incompatible-bdb") + endif() + include_directories( ${BerkeleyDB_INCLUDE_DIRS} ) + link_directories( ${BerkeleyDB_ROOT_DIR}/lib ) +endif () + +find_package(OpenSSL REQUIRED) +if (OPENSSL_FOUND) + message(STATUS "Found OpenSSL (${OPENSSL_VERSION}): ${OPENSSL_LIBRARIES}") + include_directories( ${OPENSSL_INCLUDE_DIR} ) +endif() + +find_package(LibEvent REQUIRED) +if (LibEvent_FOUND) + include_directories ( ${LibEvent_INCLUDE_DIR} ) + link_directories ( ${LibEvent_LIBRARY_DIRS} ) +endif() + +find_package(GMP) +if (GMP_FOUND) + include_directories ( ${GMP_INCLUDE_DIR} ) + link_directories ( ${GMP_LIBRARY_DIRS} ) +else() + message(WARNING "GMP not found, falling back to OpenSSL for bignum!") + set(BIGNUM_CONFIGURE_FLAGS "--with-zerocoin-bignum=openssl") +endif() + +find_package(ZMQ) +if (ZMQ_Found) + include_directories ( ${ZMQ_INCLUDE_DIR} ) + link_directories ( ${ZMQ_LIB_DIRS} ) +endif() + +find_package(Boost COMPONENTS system filesystem thread program_options REQUIRED) +include_directories( ${Boost_INCLUDE_DIRS} ) +link_directories ( ${Boost_LIBRARY_DIRS} ) + +# run autogen.sh if missing header files from configure on Linux/Mac +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/configure") +else() + execute_process( + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/autogen.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +endif() + +# run configure if ion_config.h doesn't exist +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/config/ion-config.h") +else() + execute_process( + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/configure ${BDB_CONFIGURE_FLAGS} ${BIGNUM_CONFIGURE_FLAGS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +endif() +add_definitions(-DHAVE_CONFIG_H) + +ExternalProject_Add ( + libunivalue + SOURCE_DIR ${CMAKE_SOURCE_DIR}/src/univalue + CONFIGURE_COMMAND "" + BUILD_COMMAND make + BUILD_IN_SOURCE 1 + INSTALL_COMMAND "" + ) + +ExternalProject_Add ( + libsecp256k1 + SOURCE_DIR ${CMAKE_SOURCE_DIR}/src/secp256k1 + CONFIGURE_COMMAND "" + BUILD_COMMAND make + BUILD_IN_SOURCE 1 + INSTALL_COMMAND "" +) + +link_directories( + ${CMAKE_SOURCE_DIR}/src/univalue/.libs + ${CMAKE_SOURCE_DIR}/src/secp256k1/.libs +) + +include_directories( + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/src/compat + ${CMAKE_SOURCE_DIR}/src/config + ${CMAKE_SOURCE_DIR}/src/obj + ${CMAKE_SOURCE_DIR}/src/leveldb + ${CMAKE_SOURCE_DIR}/src/leveldb/include + ${CMAKE_SOURCE_DIR}/src/leveldb/helpers/memenv + ${CMAKE_SOURCE_DIR}/src/secp256k1 + ${CMAKE_SOURCE_DIR}/src/secp256k1/include + ${CMAKE_SOURCE_DIR}/src/univalue/include +) + +set(libleveldb_a_headers + ${CMAKE_CURRENT_SOURCE_DIR}/src/config/ion-config.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/atomic_pointer.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_example.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_posix.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/win/stdint.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_win.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/thread_annotations.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/db.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/options.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/comparator.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/filter_policy.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/slice.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/table_builder.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/env.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/c.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/iterator.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/cache.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/dumpfile.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/table.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/write_batch.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/include/leveldb/status.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/log_format.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/memtable.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/version_set.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/write_batch_internal.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/filename.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/version_edit.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/dbformat.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/builder.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/log_writer.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/db_iter.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/skiplist.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/db_impl.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/table_cache.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/snapshot.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/log_reader.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/filter_block.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/block_builder.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/block.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/two_level_iterator.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/merger.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/format.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/iterator_wrapper.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/crc32c.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/env_posix_test_helper.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/arena.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/random.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/posix_logger.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/hash.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/histogram.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/coding.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/testutil.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/mutexlock.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/logging.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/testharness.h + ) + +set(libleveldb_a_sources + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/builder.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/c.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/dbformat.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/db_impl.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/db_iter.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/dumpfile.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/filename.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/log_reader.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/log_writer.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/memtable.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/repair.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/table_cache.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/version_edit.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/version_set.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/db/write_batch.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/block_builder.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/block.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/filter_block.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/format.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/iterator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/merger.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/table_builder.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/table.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/table/two_level_iterator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/arena.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/bloom.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/cache.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/coding.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/comparator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/crc32c.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/env.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/env_posix.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/filter_policy.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/hash.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/histogram.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/logging.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/options.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/status.cc + ) + +set(libleveldb_cpp_flags) +if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(libleveldb_cpp_flags -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1) + list(APPEND libleveldb_a_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/util/env_win.cc) + list(APPEND libleveldb_a_srouces ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_win.cc) +else() + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(libleveldb_cpp_flags -DOS_MACOSX -DLEVELDB_PLATFORM_POSIX) + else() + set(libleveldb_cpp_flags -DOS_LINUX -DLEVELDB_PLATFORM_POSIX) + endif() + list(APPEND libleveldb_a_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_posix.cc) +endif() + +add_library(leveldb STATIC ${libleveldb_a_headers} ${libleveldb_a_sources}) +target_compile_definitions(leveldb PUBLIC ${libleveldb_cpp_flags} -DLEVELDB_ATOMIC_PRESENT -D__STDC_LIMIT_MACROS) +target_compile_options(leveldb PUBLIC -I${CMAKE_CURRENT_SOURCE_DIR}/src/compat) + +set(libmemenv_a_sources + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/helpers/memenv/memenv.cc + ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/helpers/memenv/memenv.h + ) +add_library(memenv STATIC ${libmemenv_a_sources}) +target_compile_definitions(memenv PUBLIC ${libleveldb_cpp_flags}) + +set(libleveldb_sse42_a_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb/port/port_posix_sse.cc) +add_library(leveldb_sse42 ${libleveldb_sse42_a_sources}) + +link_directories ( ${CMAKE_CURRENT_SOURCE_DIR}/src/leveldb ) + +file(GLOB HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h) +file(GLOB CRYPTO_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/crypto/*.h) +file(GLOB PRIMITIVE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/primitives/*.h) +file(GLOB ZMQ_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/zmq/*.h) +file(GLOB SCRIPT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/script/*.h) +file(GLOB RPC_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/rpc/*.h) +file(GLOB COMPAT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/compat/*.h) + +source_group("BitcoinHeaders" FILES + ${HEADERS} + ${CRYPTO_HEADERS} + ${PRIMITIVE_HEADERS} + ${ZMQ_HEADERS} + ${SCRIPT_HEADERS} + ${RPC_HEADERS} + ${COMPAT_HEADERS} + ./src/support/cleanse.h + ) + +set(SERVER_SOURCES + ./src/addrman.cpp + ./src/alert.cpp + ./src/bloom.cpp + ./src/blocksignature.cpp + ./src/chain.cpp + ./src/checkpoints.cpp + ./src/httprpc.cpp + ./src/httpserver.cpp + ./src/init.cpp + ./src/leveldbwrapper.cpp + ./src/main.cpp + ./src/merkleblock.cpp + ./src/miner.cpp + ./src/net.cpp + ./src/noui.cpp + ./src/pow.cpp + ./src/rest.cpp + ./src/rpc/blockchain.cpp + ./src/rpc/masternode.cpp + ./src/rpc/budget.cpp + ./src/rpc/mining.cpp + ./src/rpc/misc.cpp + ./src/rpc/net.cpp + ./src/rpc/rawtransaction.cpp + ./src/rpc/server.cpp + ./src/script/sigcache.cpp + ./src/sporkdb.cpp + ./src/timedata.cpp + ./src/torcontrol.cpp + ./src/txdb.cpp + ./src/txmempool.cpp + ./src/validationinterface.cpp + ./src/xionchain.cpp + ) +add_library(SERVER_A STATIC ${BitcoinHeaders} ${SERVER_SOURCES}) + +if (ZMQ_FOUND) + set(ZMQ_SOURCES + ./src/zmq/zmqabstractnotifier.cpp + ./src/zmq/zmqnotificationinterface.cpp + ./src/zmq/zmqpublishnotifier.cpp + ) + add_library(ZMQ_A STATIC ${BitcoinHeaders} ${ZMQ_SOURCES}) +endif() + +set(WALLET_SOURCES + ./src/activemasternode.cpp + ./src/bip38.cpp + ./src/denomination_functions.cpp + ./src/obfuscation.cpp + ./src/obfuscation-relay.cpp + ./src/wallet/db.cpp + ./src/crypter.cpp + ./src/swifttx.cpp + ./src/masternode.cpp + ./src/masternode-budget.cpp + ./src/masternode-payments.cpp + ./src/masternode-sync.cpp + ./src/masternodeconfig.cpp + ./src/masternodeman.cpp + ./src/xion/mintpool.cpp + ./src/wallet/rpcdump.cpp + ./src/xion/deterministicmint.cpp + ./src/xion/zerocoin.cpp + ./src/wallet/rpcwallet.cpp + ./src/kernel.cpp + ./src/wallet/wallet.cpp + ./src/wallet/wallet_ismine.cpp + ./src/wallet/walletdb.cpp + ./src/xion/xionwallet.cpp + ./src/xion/xiontracker.cpp + ./src/xion/xionmodule.cpp + ./src/stakeinput.cpp + ./src/genwit.cpp + ./src/lightxionthread.cpp + ) +add_library(WALLET_A STATIC ${BitcoinHeaders} ${WALLET_SOURCES}) + +set(BITCOIN_CRYPTO_SOURCES + ./src/crypto/sha1.cpp + ./src/crypto/sha256.cpp + ./src/crypto/sha512.cpp + ./src/crypto/hmac_sha256.cpp + ./src/crypto/rfc6979_hmac_sha256.cpp + ./src/crypto/hmac_sha512.cpp + ./src/crypto/scrypt.cpp + ./src/crypto/ripemd160.cpp + ./src/crypto/aes_helper.c + ./src/crypto/blake.c + ./src/crypto/bmw.c + ./src/crypto/groestl.c + ./src/crypto/jh.c + ./src/crypto/keccak.c + ./src/crypto/skein.c + ./src/crypto/common.h + ./src/crypto/sha256.h + ./src/crypto/sha512.h + ./src/crypto/hmac_sha256.h + ./src/crypto/rfc6979_hmac_sha256.h + ./src/crypto/hmac_sha512.h + ./src/crypto/scrypt.h + ./src/crypto/sha1.h + ./src/crypto/ripemd160.h + ./src/crypto/sph_blake.h + ./src/crypto/sph_bmw.h + ./src/crypto/sph_groestl.h + ./src/crypto/sph_jh.h + ./src/crypto/sph_keccak.h + ./src/crypto/sph_skein.h + ./src/crypto/sph_types.h + ) +add_library(BITCOIN_CRYPTO_A STATIC ${BITCOIN_CRYPTO_SOURCES}) + +set(ZEROCOIN_SOURCES + ./src/libzerocoin/Accumulator.h + ./src/libzerocoin/AccumulatorProofOfKnowledge.h + ./src/libzerocoin/bignum.h + ./src/libzerocoin/bignum.cpp + ./src/libzerocoin/Coin.h + ./src/libzerocoin/CoinSpend.h + ./src/libzerocoin/Commitment.h + ./src/libzerocoin/Denominations.h + ./src/libzerocoin/ParamGeneration.h + ./src/libzerocoin/Params.h + ./src/libzerocoin/SerialNumberSignatureOfKnowledge.h + ./src/libzerocoin/SpendType.h + ./src/libzerocoin/ZerocoinDefines.h + ./src/libzerocoin/Accumulator.cpp + ./src/libzerocoin/AccumulatorProofOfKnowledge.cpp + ./src/libzerocoin/Coin.cpp + ./src/libzerocoin/Denominations.cpp + ./src/libzerocoin/CoinSpend.cpp + ./src/libzerocoin/Commitment.cpp + ./src/libzerocoin/ParamGeneration.cpp + ./src/libzerocoin/Params.cpp + ./src/libzerocoin/SerialNumberSignatureOfKnowledge.cpp + ) +if(GMP_FOUND) + list(APPEND ZEROCOIN_SOURCES ./src/libzerocoin/bignum_gmp.cpp) +else() + list(APPEND ZEROCOIN_SOURCES ./src/libzerocoin/bignum_openssl.cpp) +endif() +add_library(ZEROCOIN_A STATIC ${ZEROCOIN_SOURCES}) + +set(COMMON_SOURCES + ./src/xion/accumulators.cpp + ./src/xion/accumulatorcheckpoints.cpp + ./src/xion/accumulatormap.cpp + ./src/xion/witness.cpp + ./src/allocators.cpp + ./src/amount.cpp + ./src/base58.cpp + ./src/bip38.cpp + ./src/chainparams.cpp + ./src/coins.cpp + ./src/compressor.cpp + ./src/primitives/block.cpp + ./src/xion/deterministicmint.cpp + ./src/primitives/transaction.cpp + ./src/xion/zerocoin.cpp + ./src/core_read.cpp + ./src/core_write.cpp + ./src/hash.cpp + ./src/invalid.cpp + ./src/key.cpp + ./src/keystore.cpp + ./src/netbase.cpp + ./src/protocol.cpp + ./src/pubkey.cpp + ./src/scheduler.cpp + ./src/script/interpreter.cpp + ./src/script/script.cpp + ./src/script/sign.cpp + ./src/script/standard.cpp + ./src/script/script_error.cpp + ./src/spork.cpp + ./src/sporkdb.cpp + ) +add_library(COMMON_A STATIC ${BitcoinHeaders} ${COMMON_SOURCES}) + +set(UTIL_SOURCES + ./src/allocators.cpp + ./src/compat/strnlen.cpp + ./src/compat/glibc_sanity.cpp + ./src/compat/glibcxx_sanity.cpp + ./src/chainparamsbase.cpp + ./src/clientversion.cpp + ./src/random.cpp + ./src/rpc/protocol.cpp + ./src/sync.cpp + ./src/uint256.cpp + ./src/util.cpp + ./src/utilstrencodings.cpp + ./src/utilmoneystr.cpp + ./src/utiltime.cpp + ./src/support/cleanse.cpp + ) +add_library(UTIL_A STATIC ${BitcoinHeaders} ${UTIL_SOURCES}) + +set(CLI_SOURCES ./src/rpc/client.cpp) +add_library(CLI_A STATIC ${BitcoinHeaders} ${CLI_SOURCES}) + +add_executable(ion-cli ${CMAKE_CURRENT_SOURCE_DIR}/src/ion-cli.cpp) +add_dependencies(ion-cli libunivalue) +target_link_libraries(ion-cli + CLI_A + univalue + UTIL_A + BITCOIN_CRYPTO_A + ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${LIBEVENT_LIB} + ) + +add_executable(ion-tx ${CMAKE_CURRENT_SOURCE_DIR}/src/ion-tx.cpp) +add_dependencies(ion-tx libunivalue libsecp256k1) +target_link_libraries(ion-tx + univalue + COMMON_A + ZEROCOIN_A + UTIL_A + BITCOIN_CRYPTO_A + secp256k1 + ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${LIBEVENT_LIB} + ) +if(GMP_FOUND) + target_link_libraries(ion-tx ${GMP_LIBRARY}) +endif() + +add_executable(iond ${CMAKE_CURRENT_SOURCE_DIR}/src/iond.cpp) +add_dependencies(iond libunivalue libsecp256k1 leveldb leveldb_sse42 memenv) +target_link_libraries(iond + SERVER_A + COMMON_A + univalue + ZEROCOIN_A + UTIL_A + WALLET_A + BITCOIN_CRYPTO_A + leveldb leveldb_sse42 memenv secp256k1 + ${BerkeleyDB_LIBRARIES} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${LIBEVENT_LIB} miniupnpc pthread + ) +if(GMP_FOUND) + target_link_libraries(iond ${GMP_LIBRARY}) +endif() +if(ZMQ_FOUND) + target_link_libraries(iond ZMQ_A ${ZMQ_LIB}) +endif () + + +add_subdirectory(src/qt) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7766aec866b24..197b829432e38 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,12 +54,14 @@ Commit messages should be verbose by default consisting of a short subject line paragraph(s), unless the title alone is self-explanatory (like "Corrected typo in init.cpp") in which case a single title line is sufficient. Commit messages should be helpful to people reading your code in the future, so explain the reasoning for -your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/). +your decisions. Further explanation [here](https://chris.beams.io/posts/git-commit/). -If a particular commit references another issue, please add the reference, for -example `refs #1234`, or `fixes #4321`. Using the `fixes` or `closes` keywords +If a particular commit references another issue, please add the reference. For +example: `refs #1234` or `fixes #4321`. Using the `fixes` or `closes` keywords will cause the corresponding issue to be closed when the pull request is merged. +Commit messages should never contain any `@` mentions. + Please refer to the [Git manual](https://git-scm.com/doc) for more information about Git. @@ -95,7 +97,11 @@ the pull request affects. Valid areas as: Qt: Add feed bump button Trivial: Fix typo in init.cpp -If a pull request is specifically not to be considered for merging (yet) please +Note that translations should not be submitted as pull requests, please see +[Translation Process](https://github.com/ion-project/ion/blob/master/doc/translation_process.md) +for more information on helping with translations. + +If a pull request is not to be considered for merging (yet), please prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists) in the body of the pull request to indicate tasks are pending. @@ -108,6 +114,8 @@ At this stage one should expect comments and review from other contributors. You can add more commits to your pull request by committing them locally and pushing to your fork until you have satisfied all feedback. +Note: Code review is a burdensome but important part of the development process, and as such, certain types of pull requests are rejected. In general, if the **improvements** do not warrant the **review effort** required, the PR has a high chance of being rejected. It is up to the PR author to convince the reviewers that the changes warrant the review effort, and if reviewers are "Concept NAK'ing" the PR, the author may need to present arguments and/or do research backing their suggested changes. + ## Squashing Commits If your pull request is accepted for merging, you may be asked by a maintainer @@ -116,12 +124,16 @@ before it will be merged. The basic squashing workflow is shown below. git checkout your_branch_name git rebase -i HEAD~n - # n is normally the number of commits in the pull - # set commits from 'pick' to 'squash', save and quit - # on the next screen, edit/refine commit messages - # save and quit + # n is normally the number of commits in the pull request. + # Set commits (except the one in the first line) from 'pick' to 'squash', save and quit. + # On the next screen, edit/refine commit messages. + # Save and quit. git push -f # (force push to GitHub) +Please update the resulting commit message if needed, it should read as a +coherent message. In most cases this means that you should not just list the +interim commits. + If you have problems with squashing (or other workflows with `git`), you can alternatively enable "Allow edits from maintainers" in the right GitHub sidebar and ask for help in the pull request. @@ -134,10 +146,36 @@ the respective change set. The length of time required for peer review is unpredictable and will vary from pull request to pull request. +Rebasing Pull Requests +------------------------- +It may become necessary for a pull request to be rebased after other pull requests have been +merged. This is typically due to mutually exclusive changes (conflicts) between your pull +request and the current `master` branch. + +When a rebase is needed, a comment will be added to the pull request indicating this need. +Rather than simply merge the `master` branch into your pull request (which results in an +ugly and confusing merge commit), it is better to use git's rebase feature. The basic +workflow is as follows: + + # replace 'origin' with the remote name for the main project repo in the example + git checkout your_branch_name + git fetch origin + git pull --rebase origin master + +This will "rewind" your branch commits, pull any new commits from `master`, then attempt to +re-apply your commits on top of the new HEAD. If any conflicts are found, the process will +pause and allow you to resolve any conflicts. Once conflicts have been resolved: + + git rebase --continue + +Repeat as necessary until there are no more conflicts and your git tree is in a clean state. +The final step is to push your rebased branch back up to github: + + git push -f # force pushes the branch to github ## Pull Request Philosophy -Patch sets should always be focused. For example, a pull request could add a +Patchsets should always be focused. For example, a pull request could add a feature, fix a bug, or refactor code; but not a mixture. Please also avoid super pull requests which attempt to do too much, are overly large, or overly complex as this makes review difficult. @@ -161,10 +199,18 @@ There are three categories of refactoring, code only moves, code style fixes, code refactoring. In general refactoring pull requests should not mix these three kinds of activity in order to make refactoring pull requests easy to review and uncontroversial. In all cases, refactoring PRs must not change the -behavior of code within the pull request (bugs must be preserved as is). +behaviour of code within the pull request (bugs must be preserved as is). Project maintainers aim for a quick turnaround on refactoring pull requests, so -where possible keep them short, un-complex and easy to verify. +where possible keep them short, uncomplex and easy to verify. + +Pull requests that refactor the code should not be made by new contributors. It +requires a certain level of experience to know where the code belongs and to +understand the full ramification (including rebase effort of open pull requests). + +Trivial pull requests or pull requests that refactor the code with no clear +benefits may be immediately closed by the maintainers to reduce unnecessary +workload on reviewing. ## "Decision Making" Process @@ -181,12 +227,12 @@ judge the general consensus of contributors. In general, all pull requests must: -- have a clear use case, fix a demonstrable bug or serve the greater good of +- Have a clear use case, fix a demonstrable bug or serve the greater good of the project (for example refactoring for modularisation); -- be well peer reviewed; +- Be well peer reviewed; - follow code style guidelines; -Patches that change Ion consensus rules are considerably more involved than +Patches that change ION consensus rules are considerably more involved than normal because they affect the entire ecosystem and so must be preceded by extensive discussions and clear detailing. While each case will be different, one should be prepared to expend more time and effort than for other kinds of @@ -197,13 +243,16 @@ patches because of increased peer review and consensus building requirements. Anyone may participate in peer review which is expressed by comments in the pull request. Typically reviewers will review the code for obvious errors, as well as -test out the patch set and opine on the technical merits of the patch. Project +test out the patchset and opine on the technical merits of the patch. Project maintainers take into account the peer review when determining if there is consensus to merge a pull request (remember that discussions may have been -spread out over GitHub, forums, email, and Slack discussions). The following +spread out over GitHub, forums, email, and Discord discussions). The following language is used within pull-request comments: -- ACK means "I have tested the code and I agree it should be merged"; +- (t)ACK means "I have tested the code and I agree it should be merged", involving + change-specific manual testing in addition to running the unit and functional + tests, and in case it is not obvious how the manual testing was done, it should + be described; - NACK means "I disagree this should be merged", and must be accompanied by sound technical justification (or in certain cases of copyright/patent/licensing issues, legal justification). NACKs without accompanying reasoning may be @@ -221,13 +270,13 @@ that have demonstrated a deeper commitment and understanding towards the project (over time) or have clear domain expertise may naturally have more weight, as one would expect in all walks of life. -Where a patch set affects consensus critical code, the bar will be set much +Where a patchset affects consensus critical code, the bar will be set much higher in terms of discussion and peer review requirements, keeping in mind that mistakes could be very costly to the wider community. This includes refactoring of consensus critical code. -Where a patch set proposes to change the Ion consensus, it must have been -discussed extensively on the forums and Slack, be accompanied by a widely +Where a patchset proposes to change the ION consensus, it must have been +discussed extensively on the forums and Discord, be accompanied by a widely discussed Proposal and have a generally widely perceived technical consensus of being a worthwhile change based on the judgement of the maintainers. @@ -249,7 +298,7 @@ about: that personally, though! Instead, take another critical look at what you are suggesting and see if it: changes too much, is too broad, doesn't adhere to the [developer notes](doc/developer-notes.md), is dangerous or insecure, is messily written, etc. - Identify and address any of the issues you find. Then ask e.g. on Slack if someone could give + Identify and address any of the issues you find. Then ask e.g. on Discord if someone could give their opinion on the concept itself. - It may be because your code is too complex for all but a few people. And those people may not have realized your pull request even exists. A great way to find people who @@ -257,7 +306,7 @@ about: [Git Blame feature](https://help.github.com/articles/tracing-changes-in-a-file/). Simply find the person touching the code you are touching before you and see if you can find them and give them a nudge. Don't be incessant about the nudging though. -- Finally, if all else fails, ask on Slack or elsewhere for someone to give your pull request +- Finally, if all else fails, ask on Discord or elsewhere for someone to give your pull request a look. If you think you've been waiting an unreasonably long amount of time (month+) for no particular reason (few lines changed, etc), this is totally fine. Try to return the favor when someone else is asking for feedback on their code, and universe balances out. diff --git a/configure.ac b/configure.ac index bc7458d585ab2..0a703e5a4d879 100644 --- a/configure.ac +++ b/configure.ac @@ -81,8 +81,8 @@ AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) AC_PATH_TOOL(GCOV, gcov) AC_PATH_PROG(LCOV, lcov) -dnl Python 3.x is supported from 3.4 on (see https://github.com/bitcoin/bitcoin/issues/7893) -AC_PATH_PROGS([PYTHON], [python3.7 python3.6 python3.5 python3.4 python3 python]) +dnl Python 3.5 is specified in .python-version and should be used if available, see doc/dependencies.md +AC_PATH_PROGS([PYTHON], [python3.5 python3.6 python3.7 python3.8 python3 python]) AC_PATH_PROG(GENHTML, genhtml) AC_PATH_PROG([GIT], [git]) AC_PATH_PROG(CCACHE,ccache) @@ -1310,6 +1310,9 @@ openssl) ;; esac +AM_CONDITIONAL([USE_NUM_GMP], [test "x$set_bignum" = "xgmp"]) +AM_CONDITIONAL([USE_NUM_OPENSSL], [test "x$set_bignum" = "xopenssl"]) + AC_MSG_CHECKING([whether to build test_ion]) if test x$use_tests = xyes; then AC_MSG_RESULT([yes]) diff --git a/contrib/cmake/FindBerkeleyDB.cmake b/contrib/cmake/FindBerkeleyDB.cmake new file mode 100644 index 0000000000000..1b5188cf25e87 --- /dev/null +++ b/contrib/cmake/FindBerkeleyDB.cmake @@ -0,0 +1,146 @@ +# Author: sum01 +# Git: https://github.com/sum01/FindBerkeleyDB +# Read the README.md for the full info. + +# Allow user to pass a path instead of guessing +if(BerkeleyDB_ROOT_DIR) + set(_BERKELEYDB_PATHS "${BerkeleyDB_ROOT_DIR}") +elseif(CMAKE_SYSTEM_NAME MATCHES ".*[wW]indows.*") + # MATCHES is used to work on any devies with windows in the name + # Shameless copy-paste from FindOpenSSL.cmake v3.8 + file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) + list(APPEND _BERKELEYDB_HINTS "${_programfiles}") + + # There's actually production release and version numbers in the file path. + # For example, if they're on v6.2.32: C:/Program Files/Oracle/Berkeley DB 12cR1 6.2.32/ + # But this still works to find it, so I'm guessing it can accept partial path matches. + + foreach(_TARGET_BERKELEYDB_PATH "Oracle/Berkeley DB" "Berkeley DB") + list(APPEND _BERKELEYDB_PATHS + "${_programfiles}/${_TARGET_BERKELEYDB_PATH}" + "C:/Program Files (x86)/${_TARGET_BERKELEYDB_PATH}" + "C:/Program Files/${_TARGET_BERKELEYDB_PATH}" + "C:/${_TARGET_BERKELEYDB_PATH}" + ) + endforeach() +else() + # Paths for anything other than Windows + # Cellar/berkeley-db is for macOS from homebrew installation + list(APPEND _BERKELEYDB_PATHS + "/usr/local/Cellar/berkeley-db@4" + "/usr/local/Cellar/berkeley-db" + "/opt" + "/opt/local" + "/usr/local" + ) +endif() + +# Find includes path +find_path(BerkeleyDB_INCLUDE_DIRS + db_cxx.h + PATHS "${_BERKELEYDB_PATHS}" + PATH_SUFFIXES "include" "includes" + ) + +# Checks if the version file exists, save the version file to a var, and fail if there's no version file +if(BerkeleyDB_INCLUDE_DIRS) + # Read the version file db.h into a variable + file(READ "${BerkeleyDB_INCLUDE_DIRS}/db.h" _BERKELEYDB_DB_HEADER) + # Parse the DB version into variables to be used in the lib names + string(REGEX REPLACE ".*DB_VERSION_MAJOR ([0-9]+).*" "\\1" BerkeleyDB_VERSION_MAJOR "${_BERKELEYDB_DB_HEADER}") + string(REGEX REPLACE ".*DB_VERSION_MINOR ([0-9]+).*" "\\1" BerkeleyDB_VERSION_MINOR "${_BERKELEYDB_DB_HEADER}") + # Patch version example on non-crypto installs: x.x.xNC + string(REGEX REPLACE ".*DB_VERSION_PATCH ([0-9]+(NC)?).*" "\\1" BerkeleyDB_VERSION_PATCH "${_BERKELEYDB_DB_HEADER}") +else() + if(BerkeleyDB_FIND_REQUIRED) + # If the find_package(BerkeleyDB REQUIRED) was used, fail since we couldn't find the header + message(FATAL_ERROR "Failed to find Berkeley DB's header file \"db.h\"! Try setting \"BerkeleyDB_ROOT_DIR\" when initiating Cmake.") + elseif(NOT BerkeleyDB_FIND_QUIETLY) + message(WARNING "Failed to find Berkeley DB's header file \"db.h\"! Try setting \"BerkeleyDB_ROOT_DIR\" when initiating Cmake.") + endif() + # Set some garbage values to the versions since we didn't find a file to read + set(BerkeleyDB_VERSION_MAJOR "0") + set(BerkeleyDB_VERSION_MINOR "0") + set(BerkeleyDB_VERSION_PATCH "0") +endif() + +# The actual returned/output version variable (the others can be used if needed) +set(BerkeleyDB_VERSION "${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}.${BerkeleyDB_VERSION_PATCH}") + +# Finds the target library for berkeley db, since they all follow the same naming conventions +macro(findpackage_berkeleydb_get_lib _BERKELEYDB_OUTPUT_VARNAME _TARGET_BERKELEYDB_LIB) + # Different systems sometimes have a version in the lib name... + # and some have a dash or underscore before the versions. + # CMake recommends to put unversioned names before versioned names + find_library(${_BERKELEYDB_OUTPUT_VARNAME} + NAMES + "${_TARGET_BERKELEYDB_LIB}" + "lib${_TARGET_BERKELEYDB_LIB}" + "lib${_TARGET_BERKELEYDB_LIB}${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}-${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}_${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}${BerkeleyDB_VERSION_MAJOR}${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}-${BerkeleyDB_VERSION_MAJOR}${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}_${BerkeleyDB_VERSION_MAJOR}${BerkeleyDB_VERSION_MINOR}" + "lib${_TARGET_BERKELEYDB_LIB}${BerkeleyDB_VERSION_MAJOR}" + "lib${_TARGET_BERKELEYDB_LIB}-${BerkeleyDB_VERSION_MAJOR}" + "lib${_TARGET_BERKELEYDB_LIB}_${BerkeleyDB_VERSION_MAJOR}" + HINTS ${_BERKELEYDB_HINTS} + PATH_SUFFIXES "lib" "lib64" "libs" "libs64" + PATHS ${_BERKELEYDB_PATHS} + ) + # If the library was found, add it to our list of libraries + if(${_BERKELEYDB_OUTPUT_VARNAME}) + # If found, append to our libraries variable + # The ${{}} is because the first expands to target the real variable, the second expands the variable's contents... + # and the real variable's contents is the path to the lib. Thus, it appends the path of the lib to BerkeleyDB_LIBRARIES. + list(APPEND BerkeleyDB_LIBRARIES "${${_BERKELEYDB_OUTPUT_VARNAME}}") + endif() +endmacro() + +# Find and set the paths of the specific library to the variable +findpackage_berkeleydb_get_lib(BerkeleyDB_LIBRARY "db") +# NOTE: Windows doesn't have a db_cxx lib, but instead compiles the cxx code into the "db" lib +findpackage_berkeleydb_get_lib(BerkeleyDB_Cxx_LIBRARY "db_cxx") +# NOTE: I don't think Linux/Unix gets an SQL lib +findpackage_berkeleydb_get_lib(BerkeleyDB_Sql_LIBRARY "db_sql") +findpackage_berkeleydb_get_lib(BerkeleyDB_Stl_LIBRARY "db_stl") + +# Needed for find_package_handle_standard_args() +include(FindPackageHandleStandardArgs) +# Fails if required vars aren't found, or if the version doesn't meet specifications. +find_package_handle_standard_args(BerkeleyDB + FOUND_VAR BerkeleyDB_FOUND + REQUIRED_VARS + BerkeleyDB_INCLUDE_DIRS + BerkeleyDB_LIBRARY + VERSION_VAR BerkeleyDB_VERSION + ) + +# Create an imported lib for easy linking by external projects +if(BerkeleyDB_FOUND AND BerkeleyDB_LIBRARIES AND NOT TARGET Oracle::BerkeleyDB) + add_library(Oracle::BerkeleyDB UNKNOWN IMPORTED) + set_target_properties(Oracle::BerkeleyDB PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${BerkeleyDB_INCLUDE_DIRS}" + IMPORTED_LOCATION "${BerkeleyDB_LIBRARY}" + INTERFACE_LINK_LIBRARIES "${BerkeleyDB_LIBRARIES}" + ) +endif() + +# Only show the includes path and libraries in the GUI if they click "advanced". +# Does nothing when using the CLI +mark_as_advanced(FORCE + BerkeleyDB_INCLUDE_DIRS + BerkeleyDB_LIBRARIES + BerkeleyDB_LIBRARY + BerkeleyDB_Cxx_LIBRARY + BerkeleyDB_Sql_LIBRARY + BerkeleyDB_Stl_LIBRARY + ) + +include(FindPackageMessage) +# A message that tells the user what includes/libs were found, and obeys the QUIET command. +find_package_message(BerkeleyDB + "Found BerkeleyDB libraries: ${BerkeleyDB_LIBRARIES}" + "[${BerkeleyDB_LIBRARIES}[${BerkeleyDB_INCLUDE_DIRS}]]" + ) diff --git a/contrib/cmake/FindGMP.cmake b/contrib/cmake/FindGMP.cmake new file mode 100644 index 0000000000000..ee39ba114385c --- /dev/null +++ b/contrib/cmake/FindGMP.cmake @@ -0,0 +1,33 @@ +# - Find GMP +# This module defines +# GMP_INCLUDE_DIR, where to find GMP headers +# GMP_LIBRARY, LibEvent libraries +# GMP_FOUND, If false, do not try to use GMP + +set(GMP_PREFIX "" CACHE PATH "path ") + +find_path(GMP_INCLUDE_DIR gmp.h gmpxx.h + PATHS ${GMP_PREFIX}/include /usr/include /usr/local/include ) + +find_library(GMP_LIBRARY NAMES gmp libgmp + PATHS ${GMP_PREFIX}/lib /usr/lib /usr/local/lib) + +if(GMP_INCLUDE_DIR AND GMP_LIBRARY) + get_filename_component(GMP_LIBRARY_DIR ${GMP_LIBRARY} PATH) + set(GMP_FOUND TRUE) +endif() + +if(GMP_FOUND) + if(NOT GMP_FIND_QUIETLY) + MESSAGE(STATUS "Found GMP: ${GMP_LIBRARY}") + endif() +elseif(GMP_FOUND) + if(GMP_FIND_REQUIRED) + message(FATAL_ERROR "Could not find GMP") + endif() +endif() + +mark_as_advanced( + GMP_LIB + GMP_INCLUDE_DIR +) diff --git a/contrib/cmake/FindLibEvent.cmake b/contrib/cmake/FindLibEvent.cmake new file mode 100644 index 0000000000000..d0ffdf0ad4720 --- /dev/null +++ b/contrib/cmake/FindLibEvent.cmake @@ -0,0 +1,44 @@ +# - Find LibEvent (a cross event library) +# This module defines +# LIBEVENT_INCLUDE_DIR, where to find LibEvent headers +# LIBEVENT_LIB, LibEvent libraries +# LibEvent_FOUND, If false, do not try to use libevent + +if(($ENV{triple}) AND (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}")) + set(LIBEVENT_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/include") + set(LIBEVENT_LIB "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/lib/libevent.a") + set(LIBEVENT_PTHREAD_LIB "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/lib/libevent.a") +else() + set(LibEvent_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}") + foreach(prefix ${LibEvent_EXTRA_PREFIXES}) + list(APPEND LibEvent_INCLUDE_PATHS "${prefix}/include") + list(APPEND LibEvent_LIB_PATHS "${prefix}/lib") + endforeach() + + find_path(LIBEVENT_INCLUDE_DIR event.h PATHS ${LibEvent_INCLUDE_PATHS}) + find_library(LIBEVENT_LIB NAMES event PATHS ${LibEvent_LIB_PATHS}) + find_library(LIBEVENT_PTHREAD_LIB NAMES event_pthreads PATHS ${LibEvent_LIB_PATHS}) +endif() + +if (LIBEVENT_LIB AND LIBEVENT_INCLUDE_DIR AND LIBEVENT_PTHREAD_LIB) + set(LibEvent_FOUND TRUE) + set(LIBEVENT_LIB ${LIBEVENT_LIB} ${LIBEVENT_PTHREAD_LIB}) +else () + set(LibEvent_FOUND FALSE) +endif () + +if (LibEvent_FOUND) + if (NOT LibEvent_FIND_QUIETLY) + message(STATUS "Found libevent: ${LIBEVENT_LIB}") + endif () +else () + if (LibEvent_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find libevent and libevent_pthread.") + endif () + message(STATUS "libevent and libevent_pthread NOT found.") +endif () + +mark_as_advanced( + LIBEVENT_LIB + LIBEVENT_INCLUDE_DIR +) diff --git a/contrib/cmake/FindQrcode.cmake b/contrib/cmake/FindQrcode.cmake new file mode 100644 index 0000000000000..702d0d10f7d16 --- /dev/null +++ b/contrib/cmake/FindQrcode.cmake @@ -0,0 +1,37 @@ +# - Find Qrcode +# This module defines +# QRCODE_INCLUDE_DIR, where to find libqrencode headers +# QRCODE_LIB, libqrencode libraries +# QRCODE_FOUND, If false, do not try to use libqrencode + +set(QRCODE_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}") +foreach(prefix ${ZMQ_EXTRA_PREFIXES}) + list(APPEND QRCODE_INCLUDE_PATHS "${prefix}/include") + list(APPEND QRCODE_LIB_PATHS "${prefix}/lib") +endforeach() + +find_path(QRCODE_INCLUDE_DIR qrencode.h PATHS ${QRCODE_INCLUDE_PATHS}) +find_library(QRCODE_LIB NAMES qrencode PATHS ${QRCODE_LIB_PATHS}) + +if (QRCODE_LIB AND QRCODE_INCLUDE_DIR) + set(QRCODE_FOUND TRUE) +else () + set(QRCODE_FOUND FALSE) +endif () + +if (QRCODE_FOUND) + if (NOT QRCODE_FIND_QUIETLY) + message(STATUS "Found libqrencode: ${QRCODE_LIB}") + include_directories(${QRCODE_INCLUDE_DIR}) + endif () +else () + if (QRCODE_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find libqrencode.") + endif () + message(STATUS "libqrencode NOT found.") +endif () + +mark_as_advanced( + QRCODE_LIB + QRCODE_INCLUDE_DIR +) diff --git a/contrib/cmake/FindZMQ.cmake b/contrib/cmake/FindZMQ.cmake new file mode 100644 index 0000000000000..84b02736da299 --- /dev/null +++ b/contrib/cmake/FindZMQ.cmake @@ -0,0 +1,37 @@ +# - Find ZeroMQ +# This module defines +# ZMQ_INCLUDE_DIR, where to find ZMQ headers +# ZMQ_LIB, ZMQ libraries +# ZMQ_FOUND, If false, do not try to use ZeroMQ + +set(ZMQ_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}") +foreach(prefix ${ZMQ_EXTRA_PREFIXES}) + list(APPEND ZMQ_INCLUDE_PATHS "${prefix}/include") + list(APPEND ZMQ_LIB_PATHS "${prefix}/lib") +endforeach() + +find_path(ZMQ_INCLUDE_DIR zmq.h PATHS ${ZMQ_INCLUDE_PATHS}) +find_library(ZMQ_LIB NAMES zmq PATHS ${ZMQ_LIB_PATHS}) + +if (ZMQ_LIB AND ZMQ_INCLUDE_DIR) + set(ZMQ_FOUND TRUE) +else () + set(ZMQ_FOUND FALSE) +endif () + +if (ZMQ_FOUND) + if (NOT ZMQ_FIND_QUIETLY) + message(STATUS "Found ZeroMQ: ${ZMQ_LIB}") + include_directories(${ZMQ_INCLUDE_DIR}) + endif () +else () + if (ZMQ_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find ZeroMQ.") + endif () + message(STATUS "ZeroMQ NOT found.") +endif () + +mark_as_advanced( + ZMQ_LIB + ZMQ_INCLUDE_DIR +) diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md index cdad6ab2ca569..ce1931c82b70a 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -1,5 +1,5 @@ Contents -=========== +======== This directory contains tools for developers working on this repository. check-doc.py @@ -8,6 +8,79 @@ check-doc.py Check if all command line args are documented. The return value indicates the number of undocumented args. +clang-format-diff.py +=================== + +A script to format unified git diffs according to [.clang-format](../../src/.clang-format). + +Requires `clang-format`, installed e.g. via `brew install clang-format` on macOS. + +For instance, to format the last commit with 0 lines of context, +the script should be called from the git root folder as follows. + +``` +git diff -U0 HEAD~1.. | ./contrib/devtools/clang-format-diff.py -p1 -i -v +``` + +copyright\_header.py +==================== + +Provides utilities for managing copyright headers of `The ION +developers` in repository source files. It has three subcommands: + +``` +$ ./copyright_header.py report [verbose] +$ ./copyright_header.py update +$ ./copyright_header.py insert +``` +Running these subcommands without arguments displays a usage string. + +copyright\_header.py report \ [verbose] +--------------------------------------------------------- + +Produces a report of all copyright header notices found inside the source files +of a repository. Useful to quickly visualize the state of the headers. +Specifying `verbose` will list the full filenames of files of each category. + +copyright\_header.py update \ [verbose] +--------------------------------------------------------- +Updates all the copyright headers of `The ION developers` which were +changed in a year more recent than is listed. For example: +``` +// Copyright (c) - The ION developers +``` +will be updated to: +``` +// Copyright (c) - The ION developers +``` +where `` is obtained from the `git log` history. + +This subcommand also handles copyright headers that have only a single year. In +those cases: +``` +// Copyright (c) The ION developers +``` +will be updated to: +``` +// Copyright (c) - The ION developers +``` +where the update is appropriate. + +copyright\_header.py insert \ +------------------------------------ +Inserts a copyright header for `The ION developers` at the top of the +file in either Python or C++ style as determined by the file extension. If the +file is a Python file and it has `#!` starting the first line, the header is +inserted in the line below it. + +The copyright dates will be set to be `-` where +`` is according to the `git log` history. If +`` is equal to ``, it will be set as a single +year rather than two hyphenated years. + +If the file already has a copyright for `The ION developers`, the +script will exit. + gen-manpages.sh =============== @@ -54,43 +127,44 @@ Configuring the github-merge tool for the ion repository is done in the followin git config githubmerge.repository cevap/ion git config githubmerge.testcmd "make -j4 check" (adapt to whatever you want to use for testing) - git config --global user.signingkey mykeyid (if you want to GPG sign) - -optimize-pngs.py -================ - -A script to optimize png files in the ION -repository (requires pngcrush). + git config --global user.signingkey mykeyid -fix-copyright-headers.py -=========================== +Authentication (optional) +-------------------------- -Every year newly updated files need to have its copyright headers updated to reflect the current year. -If you run this script from src/ it will automatically update the year on the copyright header for all -.cpp and .h files if these have a git commit from the current year. +The API request limit for unauthenticated requests is quite low, but the +limit for authenticated requests is much higher. If you start running +into rate limiting errors it can be useful to set an authentication token +so that the script can authenticate requests. -For example a file changed in 2014 (with 2014 being the current year): -```// Copyright (c) 2009-2013 The Bitcoin developers``` +- First, go to [Personal access tokens](https://github.com/settings/tokens). +- Click 'Generate new token'. +- Fill in an arbitrary token description. No further privileges are needed. +- Click the `Generate token` button at the bottom of the form. +- Copy the generated token (should be a hexadecimal string) -would be changed to: -```// Copyright (c) 2009-2014 The Bitcoin developers``` +Then do: -logprint-scanner.py -=================== -LogPrint and LogPrintf are known to throw exceptions when the number of arguments supplied to the -LogPrint(f) function is not the same as the number of format specifiers. + git config --global user.ghtoken "pasted token" -Ideally, the presentation of this mismatch would be at compile-time, but instead it is at run-time. +Create and verify timestamps of merge commits +--------------------------------------------- +To create or verify timestamps on the merge commits, install the OpenTimestamps +client via `pip3 install opentimestamps-client`. Then, dowload the gpg wrapper +`ots-git-gpg-wrapper.sh` and set it as git's `gpg.program`. See +[the ots git integration documentation](https://github.com/opentimestamps/opentimestamps-client/blob/master/doc/git-integration.md#usage) +for further details. -This script scans the src/ directory recursively and looks in each .cpp/.h file and identifies all -errorneous LogPrint(f) calls where the number of arguments do not match. +optimize-pngs.py +================ -The filename and line number of the errorneous occurence is given. +A script to optimize png files in the ION +repository (requires pngcrush). -The script returns with the number of erroneous occurences as an error code to help facilitate -integration with a continuous integration system. +security-check.py and test-security-check.py +============================================ -The script can be ran from any working directory inside the git repository. +Perform basic ELF security checks on a series of executables. symbol-check.py =============== @@ -101,7 +175,7 @@ still compatible with the minimum supported Linux distribution versions. Example usage after a gitian build: - find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py + find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py If only supported symbols are used the return value will be 0 and the output will be empty. @@ -160,4 +234,15 @@ Reading icns family from ion.icns... Saved 'ic08' element to ion_256x256x32.png. Saved 'ic09' element to ion_512x512x32.png. Extracted 6 images from ion.icns. -``` \ No newline at end of file +``` + +circular-dependencies.py +======================== + +Run this script from the root of the source tree (`src/`) to find circular dependencies in the source code. +This looks only at which files include other files, treating the `.cpp` and `.h` file as one unit. + +Example usage: + + cd .../src + ../contrib/devtools/circular-dependencies.py {*,*/*,*/*/*}.{h,cpp} diff --git a/contrib/devtools/circular-dependencies.py b/contrib/devtools/circular-dependencies.py new file mode 100755 index 0000000000000..73d82eb2509f0 --- /dev/null +++ b/contrib/devtools/circular-dependencies.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 + +import sys +import re + +MAPPING = { + 'core_read.cpp': 'core_io.cpp', + 'core_write.cpp': 'core_io.cpp', +} + +# Directories with header-based modules, where the assumption that .cpp files +# define functions and variables declared in corresponding .h files is +# incorrect. +HEADER_MODULE_PATHS = [ + 'interfaces/' +] + +def module_name(path): + if path in MAPPING: + path = MAPPING[path] + if any(path.startswith(dirpath) for dirpath in HEADER_MODULE_PATHS): + return path + if path.endswith(".h"): + return path[:-2] + if path.endswith(".c"): + return path[:-2] + if path.endswith(".cpp"): + return path[:-4] + return None + +files = dict() +deps = dict() + +RE = re.compile("^#include \"(.*)\"") + +# Iterate over files, and create list of modules +for arg in sys.argv[1:]: + module = module_name(arg) + if module is None: + print("Ignoring file %s (does not constitute module)\n" % arg) + else: + files[arg] = module + deps[module] = set() + +# Iterate again, and build list of direct dependencies for each module +# TODO: implement support for multiple include directories +for arg in sorted(files.keys()): + module = files[arg] + with open(arg, 'r', encoding="utf8") as f: + for line in f: + match = RE.match(line) + if match: + include = match.group(1) + included_module = module_name(include) + if included_module is not None and included_module in deps and included_module != module: + deps[module].add(included_module) + +# Loop to find the shortest (remaining) circular dependency +have_cycle = False +while True: + shortest_cycle = None + for module in sorted(deps.keys()): + # Build the transitive closure of dependencies of module + closure = dict() + for dep in deps[module]: + closure[dep] = [] + while True: + old_size = len(closure) + old_closure_keys = sorted(closure.keys()) + for src in old_closure_keys: + for dep in deps[src]: + if dep not in closure: + closure[dep] = closure[src] + [src] + if len(closure) == old_size: + break + # If module is in its own transitive closure, it's a circular dependency; check if it is the shortest + if module in closure and (shortest_cycle is None or len(closure[module]) + 1 < len(shortest_cycle)): + shortest_cycle = [module] + closure[module] + if shortest_cycle is None: + break + # We have the shortest circular dependency; report it + module = shortest_cycle[0] + print("Circular dependency: %s" % (" -> ".join(shortest_cycle + [module]))) + # And then break the dependency to avoid repeating in other cycles + deps[shortest_cycle[-1]] = deps[shortest_cycle[-1]] - set([module]) + have_cycle = True + +sys.exit(1 if have_cycle else 0) diff --git a/contrib/devtools/commit-script-check.sh b/contrib/devtools/commit-script-check.sh new file mode 100644 index 0000000000000..1c9dbc7f68ff5 --- /dev/null +++ b/contrib/devtools/commit-script-check.sh @@ -0,0 +1,46 @@ +#!/bin/sh +# Copyright (c) 2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# This simple script checks for commits beginning with: scripted-diff: +# If found, looks for a script between the lines -BEGIN VERIFY SCRIPT- and +# -END VERIFY SCRIPT-. If no ending is found, it reads until the end of the +# commit message. + +# The resulting script should exactly transform the previous commit into the current +# one. Any remaining diff signals an error. + +if test "x$1" = "x"; then + echo "Usage: $0 ..." + exit 1 +fi + +RET=0 +PREV_BRANCH=`git name-rev --name-only HEAD` +PREV_HEAD=`git rev-parse HEAD` +for i in `git rev-list --reverse $1`; do + if git rev-list -n 1 --pretty="%s" $i | grep -q "^scripted-diff:"; then + git checkout --quiet $i^ || exit + SCRIPT="`git rev-list --format=%b -n1 $i | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d'`" + if test "x$SCRIPT" = "x"; then + echo "Error: missing script for: $i" + echo "Failed" + RET=1 + else + echo "Running script for: $i" + echo "$SCRIPT" + eval "$SCRIPT" + git --no-pager diff --exit-code $i && echo "OK" || (echo "Failed"; false) || RET=1 + fi + git reset --quiet --hard HEAD + else + if git rev-list "--format=%b" -n1 $i | grep -q '^-\(BEGIN\|END\)[ a-zA-Z]*-$'; then + echo "Error: script block marker but no scripted-diff in title" + echo "Failed" + RET=1 + fi + fi +done +git checkout --quiet $PREV_BRANCH 2>/dev/null || git checkout --quiet $PREV_HEAD +exit $RET diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py index ae2997c5441e1..495979672221b 100755 --- a/contrib/devtools/github-merge.py +++ b/contrib/devtools/github-merge.py @@ -14,17 +14,16 @@ # In case of a clean merge that is accepted by the user, the local branch with # name $BRANCH is overwritten with the merged result, and optionally pushed. -from __future__ import division,print_function,unicode_literals import os from sys import stdin,stdout,stderr import argparse import hashlib import subprocess -import json,codecs -try: - from urllib.request import Request,urlopen -except: - from urllib2 import Request,urlopen +import sys +import json +import codecs +from urllib.request import Request, urlopen +from urllib.error import HTTPError # External tools (can be overridden using environment) GIT = os.getenv('GIT','git') @@ -45,24 +44,61 @@ def git_config_get(option, default=None): ''' try: return subprocess.check_output([GIT,'config','--get',option]).rstrip().decode('utf-8') - except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError: return default -def retrieve_pr_info(repo,pull): +def get_response(req_url, ghtoken): + req = Request(req_url) + if ghtoken is not None: + req.add_header('Authorization', 'token ' + ghtoken) + return urlopen(req) + +def retrieve_json(req_url, ghtoken, use_pagination=False): ''' - Retrieve pull request information from github. - Return None if no title can be found, or an error happens. + Retrieve json from github. + Return None if an error happens. ''' try: - req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull) - result = urlopen(req) reader = codecs.getreader('utf-8') - obj = json.load(reader(result)) + if not use_pagination: + return json.load(reader(get_response(req_url, ghtoken))) + + obj = [] + page_num = 1 + while True: + req_url_page = '{}?page={}'.format(req_url, page_num) + result = get_response(req_url_page, ghtoken) + obj.extend(json.load(reader(result))) + + link = result.headers.get('link', None) + if link is not None: + link_next = [l for l in link.split(',') if 'rel="next"' in l] + if len(link_next) > 0: + page_num = int(link_next[0][link_next[0].find("page=")+5:link_next[0].find(">")]) + continue + break return obj + except HTTPError as e: + error_message = e.read() + print('Warning: unable to retrieve pull information from github: %s' % e) + print('Detailed error: %s' % error_message) + return None except Exception as e: print('Warning: unable to retrieve pull information from github: %s' % e) return None +def retrieve_pr_info(repo,pull,ghtoken): + req_url = "https://api.github.com/repos/"+repo+"/pulls/"+pull + return retrieve_json(req_url,ghtoken) + +def retrieve_pr_comments(repo,pull,ghtoken): + req_url = "https://api.github.com/repos/"+repo+"/issues/"+pull+"/comments" + return retrieve_json(req_url,ghtoken,use_pagination=True) + +def retrieve_pr_reviews(repo,pull,ghtoken): + req_url = "https://api.github.com/repos/"+repo+"/pulls/"+pull+"/reviews" + return retrieve_json(req_url,ghtoken,use_pagination=True) + def ask_prompt(text): print(text,end=" ",file=stderr) stderr.flush() @@ -127,12 +163,26 @@ def tree_sha512sum(commit='HEAD'): raise IOError('Non-zero return value executing git cat-file') return overall.hexdigest() +def get_acks_from_comments(head_commit, comments): + assert len(head_commit) == 6 + ack_str ='\n\nACKs for commit {}:\n'.format(head_commit) + for c in comments: + review = [l for l in c['body'].split('\r\n') if 'ACK' in l and head_commit in l] + if review: + ack_str += ' {}:\n'.format(c['user']['login']) + ack_str += ' {}\n'.format(review[0]) + return ack_str + +def print_merge_details(pull, title, branch, base_branch, head_branch): + print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET)) + subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch]) def parse_arguments(): epilog = ''' In addition, you can set the following git configuration variables: githubmerge.repository (mandatory), user.signingkey (mandatory), + user.ghtoken (default: none). githubmerge.host (default: git@github.com), githubmerge.branch (no default), githubmerge.testcmd (default: none). @@ -151,27 +201,35 @@ def main(): host = git_config_get('githubmerge.host','git@github.com') opt_branch = git_config_get('githubmerge.branch',None) testcmd = git_config_get('githubmerge.testcmd') + ghtoken = git_config_get('user.ghtoken') signingkey = git_config_get('user.signingkey') if repo is None: print("ERROR: No repository configured. Use this command to set:", file=stderr) print("git config githubmerge.repository /", file=stderr) - exit(1) + sys.exit(1) if signingkey is None: print("ERROR: No GPG signing key set. Set one using:",file=stderr) print("git config --global user.signingkey ",file=stderr) - exit(1) + sys.exit(1) - host_repo = host+":"+repo # shortcut for push/pull target + if host.startswith(('https:','http:')): + host_repo = host+"/"+repo+".git" + else: + host_repo = host+":"+repo # Extract settings from command line args = parse_arguments() pull = str(args.pull[0]) # Receive pull information from github - info = retrieve_pr_info(repo,pull) + info = retrieve_pr_info(repo,pull,ghtoken) if info is None: - exit(1) - title = info['title'] + sys.exit(1) + comments = retrieve_pr_comments(repo,pull,ghtoken) + retrieve_pr_reviews(repo,pull,ghtoken) + if comments is None: + sys.exit(1) + title = info['title'].strip() + body = info['body'].strip() # precedence order for destination branch argument: # - command line argument # - githubmerge.branch setting @@ -185,32 +243,28 @@ def main(): merge_branch = 'pull/'+pull+'/merge' local_merge_branch = 'pull/'+pull+'/local-merge' - devnull = open(os.devnull,'w') + devnull = open(os.devnull, 'w', encoding="utf8") try: subprocess.check_call([GIT,'checkout','-q',branch]) - except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError: print("ERROR: Cannot check out branch %s." % (branch), file=stderr) - exit(3) + sys.exit(3) try: - subprocess.check_call([GIT,'fetch','-q',host_repo,'+refs/pull/'+pull+'/*:refs/heads/pull/'+pull+'/*']) - except subprocess.CalledProcessError as e: - print("ERROR: Cannot find pull request #%s on %s." % (pull,host_repo), file=stderr) - exit(3) + subprocess.check_call([GIT,'fetch','-q',host_repo,'+refs/pull/'+pull+'/*:refs/heads/pull/'+pull+'/*', + '+refs/heads/'+branch+':refs/heads/'+base_branch]) + except subprocess.CalledProcessError: + print("ERROR: Cannot find pull request #%s or branch %s on %s." % (pull,branch,host_repo), file=stderr) + sys.exit(3) try: subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+head_branch], stdout=devnull, stderr=stdout) - except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError: print("ERROR: Cannot find head of pull request #%s on %s." % (pull,host_repo), file=stderr) - exit(3) + sys.exit(3) try: subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+merge_branch], stdout=devnull, stderr=stdout) - except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError: print("ERROR: Cannot find merge of pull request #%s on %s." % (pull,host_repo), file=stderr) - exit(3) - try: - subprocess.check_call([GIT,'fetch','-q',host_repo,'+refs/heads/'+branch+':refs/heads/'+base_branch]) - except subprocess.CalledProcessError as e: - print("ERROR: Cannot find branch %s on %s." % (branch,host_repo), file=stderr) - exit(3) + sys.exit(3) subprocess.check_call([GIT,'checkout','-q',base_branch]) subprocess.call([GIT,'branch','-q','-D',local_merge_branch], stderr=devnull) subprocess.check_call([GIT,'checkout','-q','-b',local_merge_branch]) @@ -226,45 +280,46 @@ def main(): firstline = 'Merge #%s' % (pull,) message = firstline + '\n\n' message += subprocess.check_output([GIT,'log','--no-merges','--topo-order','--pretty=format:%h %s (%an)',base_branch+'..'+head_branch]).decode('utf-8') + message += '\n\nPull request description:\n\n ' + body.replace('\n', '\n ') + '\n' + message += get_acks_from_comments(head_commit=subprocess.check_output([GIT,'log','-1','--pretty=format:%H',head_branch]).decode('utf-8')[:6], comments=comments) try: - subprocess.check_call([GIT,'merge','-q','--commit','--no-edit','--no-ff','-m',message.encode('utf-8'),head_branch]) - except subprocess.CalledProcessError as e: + subprocess.check_call([GIT,'merge','-q','--commit','--no-edit','--no-ff','--no-gpg-sign','-m',message.encode('utf-8'),head_branch]) + except subprocess.CalledProcessError: print("ERROR: Cannot be merged cleanly.",file=stderr) subprocess.check_call([GIT,'merge','--abort']) - exit(4) + sys.exit(4) logmsg = subprocess.check_output([GIT,'log','--pretty=format:%s','-n','1']).decode('utf-8') if logmsg.rstrip() != firstline.rstrip(): print("ERROR: Creating merge failed (already merged?).",file=stderr) - exit(4) + sys.exit(4) symlink_files = get_symlink_files() for f in symlink_files: print("ERROR: File %s was a symlink" % f) if len(symlink_files) > 0: - exit(4) + sys.exit(4) # Put tree SHA512 into the message try: first_sha512 = tree_sha512sum() message += '\n\nTree-SHA512: ' + first_sha512 - except subprocess.CalledProcessError as e: - printf("ERROR: Unable to compute tree hash") - exit(4) + except subprocess.CalledProcessError: + print("ERROR: Unable to compute tree hash") + sys.exit(4) try: - subprocess.check_call([GIT,'commit','--amend','-m',message.encode('utf-8')]) - except subprocess.CalledProcessError as e: - printf("ERROR: Cannot update message.",file=stderr) - exit(4) + subprocess.check_call([GIT,'commit','--amend','--no-gpg-sign','-m',message.encode('utf-8')]) + except subprocess.CalledProcessError: + print("ERROR: Cannot update message.", file=stderr) + sys.exit(4) - print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET)) - subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch]) + print_merge_details(pull, title, branch, base_branch, head_branch) print() # Run test command if configured. if testcmd: if subprocess.call(testcmd,shell=True): print("ERROR: Running %s failed." % testcmd,file=stderr) - exit(5) + sys.exit(5) # Show the created merge. diff = subprocess.check_output([GIT,'diff',merge_branch+'..'+local_merge_branch]) @@ -275,13 +330,7 @@ def main(): if reply.lower() == 'ignore': print("Difference with github ignored.",file=stderr) else: - exit(6) - reply = ask_prompt("Press 'd' to accept the diff.") - if reply.lower() == 'd': - print("Diff accepted.",file=stderr) - else: - print("ERROR: Diff rejected.",file=stderr) - exit(6) + sys.exit(6) else: # Verify the result manually. print("Dropping you on a shell so you can try building/testing the merged source.",file=stderr) @@ -290,29 +339,25 @@ def main(): if os.path.isfile('/etc/debian_version'): # Show pull number on Debian default prompt os.putenv('debian_chroot',pull) subprocess.call([BASH,'-i']) - reply = ask_prompt("Type 'm' to accept the merge.") - if reply.lower() == 'm': - print("Merge accepted.",file=stderr) - else: - print("ERROR: Merge rejected.",file=stderr) - exit(7) second_sha512 = tree_sha512sum() if first_sha512 != second_sha512: print("ERROR: Tree hash changed unexpectedly",file=stderr) - exit(8) + sys.exit(8) # Sign the merge commit. - reply = ask_prompt("Type 's' to sign off on the merge.") - if reply == 's': - try: - subprocess.check_call([GIT,'commit','-q','--gpg-sign','--amend','--no-edit']) - except subprocess.CalledProcessError as e: - print("Error signing, exiting.",file=stderr) - exit(1) - else: - print("Not signing off on merge, exiting.",file=stderr) - exit(1) + print_merge_details(pull, title, branch, base_branch, head_branch) + while True: + reply = ask_prompt("Type 's' to sign off on the above merge, or 'x' to reject and exit.").lower() + if reply == 's': + try: + subprocess.check_call([GIT,'commit','-q','--gpg-sign','--amend','--no-edit']) + break + except subprocess.CalledProcessError: + print("Error while signing, asking again.",file=stderr) + elif reply == 'x': + print("Not signing off on merge, exiting.",file=stderr) + sys.exit(1) # Put the result in branch. subprocess.check_call([GIT,'checkout','-q',branch]) @@ -326,9 +371,14 @@ def main(): subprocess.call([GIT,'branch','-q','-D',local_merge_branch],stderr=devnull) # Push the result. - reply = ask_prompt("Type 'push' to push the result to %s, branch %s." % (host_repo,branch)) - if reply.lower() == 'push': - subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch]) + while True: + reply = ask_prompt("Type 'push' to push the result to %s, branch %s, or 'x' to exit without pushing." % (host_repo,branch)).lower() + if reply == 'push': + subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch]) + break + elif reply == 'x': + sys.exit(1) if __name__ == '__main__': main() + diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py index 21749a2e1dbd6..5812ce58d2d31 100755 --- a/contrib/devtools/security-check.py +++ b/contrib/devtools/security-check.py @@ -86,7 +86,7 @@ def check_ELF_RELRO(executable): # This does not affect security: the permission flags of the GNU_RELRO program header are ignored, the PT_LOAD header determines the effective permissions. # However, the dynamic linker need to write to this area so these are RW. # Glibc itself takes care of mprotecting this area R after relocations are finished. - # See also http://permalink.gmane.org/gmane.comp.gnu.binutils/71347 + # See also https://marc.info/?l=binutils&m=1498883354122353 if typ == 'GNU_RELRO': have_gnu_relro = True diff --git a/contrib/devtools/split-debug.sh.in b/contrib/devtools/split-debug.sh.in index deda49cc54104..92b72b1446cf6 100644 --- a/contrib/devtools/split-debug.sh.in +++ b/contrib/devtools/split-debug.sh.in @@ -1,5 +1,5 @@ #!/bin/sh - +set -e if [ $# -ne 3 ]; then echo "usage: $0 " fi diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index c6158c94225ad..7729dd7257dda 100755 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -9,7 +9,7 @@ Example usage: - find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py + find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py ''' import subprocess import re diff --git a/contrib/devtools/update-translations.py b/contrib/devtools/update-translations.py index 58d62ddee4dc2..5a174995f0e94 100755 --- a/contrib/devtools/update-translations.py +++ b/contrib/devtools/update-translations.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # 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. @@ -15,7 +15,6 @@ TODO: - auto-add new translations to the build system according to the translation process ''' -from __future__ import division, print_function import subprocess import re import sys @@ -36,12 +35,12 @@ def check_at_repository_root(): if not os.path.exists('.git'): print('No .git directory found') print('Execute this script at the root of the repository', file=sys.stderr) - exit(1) + sys.exit(1) def fetch_all_translations(): if subprocess.call([TX, 'pull', '-f', '-a']): print('Error while fetching translations', file=sys.stderr) - exit(1) + sys.exit(1) def find_format_specifiers(s): '''Find all format specifiers in a string.''' @@ -208,3 +207,4 @@ def postprocess_translations(reduce_diff_hacks=False): check_at_repository_root() fetch_all_translations() postprocess_translations() + diff --git a/contrib/gitian-build.py b/contrib/gitian-build.py index 161a308d685a6..6088862089a67 100755 --- a/contrib/gitian-build.py +++ b/contrib/gitian-build.py @@ -11,20 +11,20 @@ def setup(): global args, workdir - programs = ['ruby', 'git', 'apt-cacher-ng', 'make', 'wget'] + programs = ['ruby', 'git', 'make', 'wget', 'curl'] if args.kvm: - programs += ['python-vm-builder', 'qemu-kvm', 'qemu-utils'] - elif args.docker: + programs += ['apt-cacher-ng', 'python-vm-builder', 'qemu-kvm', 'qemu-utils'] + elif args.docker and not os.path.isfile('/lib/systemd/system/docker.service'): dockers = ['docker.io', 'docker-ce'] for i in dockers: return_code = subprocess.call(['sudo', 'apt-get', 'install', '-qq', i]) if return_code == 0: break if return_code != 0: - print('Cannot find any way to install docker', file=sys.stderr) - exit(1) + print('Cannot find any way to install Docker.', file=sys.stderr) + sys.exit(1) else: - programs += ['lxc', 'debootstrap'] + programs += ['apt-cacher-ng', 'lxc', 'debootstrap'] subprocess.check_call(['sudo', 'apt-get', 'install', '-qq'] + programs) if not os.path.isdir('gitian.sigs'): subprocess.check_call(['git', 'clone', 'https://github.com/gitianuser/gitian.sigs-ion.git', 'gitian.sigs']) @@ -45,7 +45,7 @@ def setup(): if args.is_bionic and not args.kvm and not args.docker: subprocess.check_call(['sudo', 'sed', '-i', 's/lxcbr0/br0/', '/etc/default/lxc-net']) print('Reboot is required') - exit(0) + sys.exit(0) def build(): global args, workdir @@ -57,6 +57,8 @@ def build(): subprocess.check_call(['wget', '-O', 'inputs/osslsigncode-1.7.1.tar.xz', '-N', '-P', 'inputs', 'https://github.com/cevap/osslsigncode/releases/download/v1.7.1/osslsigncode-1.7.1.tar.xz']) subprocess.check_call(['wget', '-O', 'inputs/osslsigncode-Backports-to-1.7.1.patch', '-N', '-P', 'inputs', 'https://github.com/cevap/osslsigncode/releases/download/v1.7.1/osslsigncode-Backports-to-1.7.1.patch']) + subprocess.check_call(["echo 'a8c4e9cafba922f89de0df1f2152e7be286aba73f78505169bc351a7938dd911 inputs/osslsigncode-Backports-to-1.7.1.patch' | sha256sum -c"], shell=True) + subprocess.check_call(["echo 'f9a8cdb38b9c309326764ebc937cba1523a3a751a7ab05df3ecc99d18ae466c9 inputs/osslsigncode-1.7.1.tar.gz' | sha256sum -c"], shell=True) subprocess.check_call(['make', '-C', '../ion/depends', 'download', 'SOURCES_PATH=' + os.getcwd() + '/cache/common']) if args.linux: @@ -84,13 +86,9 @@ def build(): if args.commit_files: print('\nCommitting '+args.version+' Unsigned Sigs\n') os.chdir('gitian.sigs') - subprocess.check_call(['git', 'config', 'user.signingkey', args.signer]) - if args.linux: - subprocess.check_call(['git', 'add', args.version+'-linux/'+args.signer]) - if args.windows: - subprocess.check_call(['git', 'add', args.version+'-win-unsigned/'+args.signer]) - if args.macos: - subprocess.check_call(['git', 'add', args.version+'-osx-unsigned/'+args.signer]) + subprocess.check_call(['git', 'add', args.version+'-linux/'+args.signer]) + subprocess.check_call(['git', 'add', args.version+'-win-unsigned/'+args.signer]) + subprocess.check_call(['git', 'add', args.version+'-osx-unsigned/'+args.signer]) subprocess.check_call(['git', 'commit', '-m', 'Add '+args.version+' unsigned sigs for '+args.signer]) os.chdir(workdir) @@ -139,45 +137,48 @@ def sign(): if args.commit_files: print('\nCommitting '+args.version+' Signed Sigs\n') os.chdir('gitian.sigs') - - if args.windows: - subprocess.check_call(['git', 'add', args.version+'-win-signed/'+args.signer]) - if args.macos: - subprocess.check_call(['git', 'add', args.version+'-osx-signed/'+args.signer]) - - subprocess.check_call(['git', 'commit', '-S', '-m', 'Add '+args.version+' signed binary sigs for '+args.signer]) + subprocess.check_call(['git', 'add', args.version+'-win-signed/'+args.signer]) + subprocess.check_call(['git', 'add', args.version+'-osx-signed/'+args.signer]) + subprocess.check_call(['git', 'commit', '-a', '-m', 'Add '+args.version+' signed binary sigs for '+args.signer]) os.chdir(workdir) def verify(): global args, workdir + rc = 0 os.chdir('gitian-builder') - if args.linux: - print('\nVerifying v'+args.version+' Linux\n') - subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-linux', '../ion/contrib/gitian-descriptors/gitian-linux.yml']) - print('\nVerifying v'+args.version+' Linux\n') - subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-linux', '../ion/contrib/gitian-descriptors/gitian-linux.yml']) + print('\nVerifying v'+args.version+' Linux\n') + if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-linux', '../ion/contrib/gitian-descriptors/gitian-linux.yml']): + print('Verifying v'+args.version+' Linux FAILED\n') + rc = 1 - if args.windows: - print('\nVerifying v'+args.version+' Windows\n') - subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-unsigned', '../ion/contrib/gitian-descriptors/gitian-win.yml']) - if args.sign: - print('\nVerifying v'+args.version+' Signed Windows\n') - subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-signed', '../ion/contrib/gitian-descriptors/gitian-win-signer.yml']) + print('\nVerifying v'+args.version+' Windows\n') + if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-unsigned', '../ion/contrib/gitian-descriptors/gitian-win.yml']): + print('Verifying v'+args.version+' Windows FAILED\n') + rc = 1 - if args.macos: - print('\nVerifying v'+args.version+' MacOS\n') - subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-unsigned', '../ion/contrib/gitian-descriptors/gitian-osx.yml']) - if args.sign: - print('\nVerifying v'+args.version+' Signed MacOS\n') - subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-signed', '../ion/contrib/gitian-descriptors/gitian-osx-signer.yml']) + print('\nVerifying v'+args.version+' MacOS\n') + if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-unsigned', '../ion/contrib/gitian-descriptors/gitian-osx.yml']): + print('Verifying v'+args.version+' MacOS FAILED\n') + rc = 1 + + print('\nVerifying v'+args.version+' Signed Windows\n') + if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-signed', '../ion/contrib/gitian-descriptors/gitian-win-signer.yml']): + print('Verifying v'+args.version+' Signed Windows FAILED\n') + rc = 1 + + print('\nVerifying v'+args.version+' Signed MacOS\n') + if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-signed', '../ion/contrib/gitian-descriptors/gitian-osx-signer.yml']): + print('Verifying v'+args.version+' Signed MacOS FAILED\n') + rc = 1 os.chdir(workdir) + return rc def main(): global args, workdir - parser = argparse.ArgumentParser(usage='%(prog)s [options] signer version') + parser = argparse.ArgumentParser(description='Script for running full Gitian builds.') parser.add_argument('-c', '--commit', action='store_true', dest='commit', help='Indicate that the version argument is for a commit or branch') parser.add_argument('-p', '--pull', action='store_true', dest='pull', help='Indicate that the version argument is the number of a github repository pull request') parser.add_argument('-u', '--url', dest='url', default='https://github.com/cevap/ion', help='Specify the URL of the repository. Default is %(default)s') @@ -190,11 +191,11 @@ def main(): parser.add_argument('-m', '--memory', dest='memory', default='2000', help='Memory to allocate in MiB. Default %(default)s') parser.add_argument('-k', '--kvm', action='store_true', dest='kvm', help='Use KVM instead of LXC') parser.add_argument('-d', '--docker', action='store_true', dest='docker', help='Use Docker instead of LXC') - parser.add_argument('-S', '--setup', action='store_true', dest='setup', help='Set up the Gitian building environment. Uses LXC. If you want to use KVM, use the --kvm option. Only works on Debian-based systems (Ubuntu, Debian)') + parser.add_argument('-S', '--setup', action='store_true', dest='setup', help='Set up the Gitian building environment. Only works on Debian-based systems (Ubuntu, Debian)') parser.add_argument('-D', '--detach-sign', action='store_true', dest='detach_sign', help='Create the assert file for detached signing. Will not commit anything.') parser.add_argument('-n', '--no-commit', action='store_false', dest='commit_files', help='Do not commit anything to git') - parser.add_argument('signer', help='GPG signer to sign each build assert file') - parser.add_argument('version', help='Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified') + parser.add_argument('signer', nargs='?', help='GPG signer to sign each build assert file') + parser.add_argument('version', nargs='?', help='Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified') parser.add_argument('upload', help='Use scp to upload file to the server, defines in .ssh as uploadserver, pass serverIp and path to ssh private key') parser.add_argument('uploadlogs', help='Upload logs and scripts (var folder)') parser.add_argument('uploadfolder', help='Upload folder on uploadserver') @@ -202,34 +203,42 @@ def main(): args = parser.parse_args() workdir = os.getcwd() - args.linux = 'l' in args.os - args.windows = 'w' in args.os - args.macos = 'm' in args.os - args.is_bionic = b'bionic' in subprocess.check_output(['lsb_release', '-cs']) - if args.buildsign: - args.build=True - args.sign=True - if args.kvm and args.docker: raise Exception('Error: cannot have both kvm and docker') - args.sign_prog = 'true' if args.detach_sign else 'gpg --detach-sign' - - # Set environment variable USE_LXC or USE_DOCKER, let gitian-builder know that we use lxc or docker + # Ensure no more than one environment variable for gitian-builder (USE_LXC, USE_VBOX, USE_DOCKER) is set as they + # can interfere (e.g., USE_LXC being set shadows USE_DOCKER; for details see gitian-builder/libexec/make-clean-vm). + os.environ['USE_LXC'] = '' + os.environ['USE_VBOX'] = '' + os.environ['USE_DOCKER'] = '' if args.docker: os.environ['USE_DOCKER'] = '1' elif not args.kvm: os.environ['USE_LXC'] = '1' - if not 'GITIAN_HOST_IP' in os.environ.keys(): + if 'GITIAN_HOST_IP' not in os.environ.keys(): os.environ['GITIAN_HOST_IP'] = '10.0.3.1' - if not 'LXC_GUEST_IP' in os.environ.keys(): + if 'LXC_GUEST_IP' not in os.environ.keys(): os.environ['LXC_GUEST_IP'] = '10.0.3.5' # Script will fail to automaticly download all resources if inputs folder does not exist subprocess.check_call(['mkdir', '-p', 'gitian-builder/inputs']) + if args.setup: + setup() + + if args.buildsign: + args.build = True + args.sign = True + + if not args.build and not args.sign and not args.verify: + sys.exit(0) + + args.linux = 'l' in args.os + args.windows = 'w' in args.os + args.macos = 'm' in args.os + # Disable for MacOS if no SDK found if args.macos and not os.path.isfile('gitian-builder/inputs/MacOSX10.11.sdk.tar.xz'): subprocess.check_call(['wget', '-O', 'gitian-builder/inputs/MacOSX10.11.sdk.tar.xz', '-N', '-P', 'inputs', 'https://github.com/gitianuser/MacOSX-SDKs/releases/download/MacOSX10.11.sdk/MacOSX10.11.sdk.tar.xz']) @@ -238,23 +247,19 @@ def main(): args.macos = False script_name = os.path.basename(sys.argv[0]) - # Signer and version shouldn't be empty - if args.signer == '': - print(script_name+': Missing signer.') + if not args.signer: + print(script_name+': Missing signer') print('Try '+script_name+' --help for more information') - exit(1) - if args.version == '': - print(script_name+': Missing version.') + sys.exit(1) + if not args.version: + print(script_name+': Missing version') print('Try '+script_name+' --help for more information') - exit(1) + sys.exit(1) # Add leading 'v' for tags if args.commit and args.pull: raise Exception('Cannot have both commit and pull') args.commit = ('' if args.commit else 'v') + args.version - if args.setup: - setup() - os.chdir('ion') if args.pull: subprocess.check_call(['git', 'fetch', args.url, 'refs/pull/'+args.version+'/merge']) @@ -267,6 +272,10 @@ def main(): subprocess.check_call(['git', 'checkout', args.commit]) os.chdir(workdir) + os.chdir('gitian-builder') + subprocess.check_call(['git', 'pull']) + os.chdir(workdir) + if args.build: build() @@ -274,7 +283,10 @@ def main(): sign() if args.verify: - verify() + os.chdir('gitian.sigs') + subprocess.check_call(['git', 'pull']) + os.chdir(workdir) + sys.exit(verify()) if __name__ == '__main__': main() diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 01c6948aed2ba..93d33743944d1 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,6 +1,7 @@ --- -name: "ion-linux-3.2" +name: "ion-linux-3.3" enable_cache: true +distro: "ubuntu" suites: - "bionic" architectures: @@ -53,12 +54,13 @@ packages: - "faketime" - "bsdmainutils" - "ca-certificates" -- "python" +- "python3" remotes: - "url": "https://github.com/cevap/ion.git" "dir": "ion" files: [] script: | + set -e -o pipefail WRAP_DIR=$HOME/wrapped HOSTS="i686-pc-linux-gnu x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu riscv32-linux-gnu powerpc64le-linux-gnu s390x mips-linux-gnu mipsel-linux-gnu arm-linux-gnueabi" @@ -202,8 +204,9 @@ script: | find . -name "lib*.la" -delete find . -name "lib*.a" -delete rm -rf ${DISTNAME}/lib/pkgconfig - find ${DISTNAME}/bin -type f -executable -exec ../contrib/devtools/split-debug.sh {} {} {}.dbg \; - # find ${DISTNAME}/lib -type f -exec ../contrib/devtools/split-debug.sh {} {} {}.dbg \; + find ${DISTNAME}/bin -type f -executable -print0 | xargs -0 -n1 -I{} ../contrib/devtools/split-debug.sh {} {} {}.dbg + #find ${DISTNAME}/lib -type f -print0 | xargs -0 -n1 -I{} ../contrib/devtools/split-debug.sh {} {} {}.dbg + cp ../doc/README.md ${DISTNAME}/ find ${DISTNAME} -not -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | xz -9 > ${OUTDIR}/${DISTNAME}-${i}.tar.xz find ${DISTNAME} -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | xz -9 > ${OUTDIR}/${DISTNAME}-${i}-debug.tar.xz cd ../../ diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml index 4522b18002d09..c0a691762b2d4 100644 --- a/contrib/gitian-descriptors/gitian-osx-signer.yml +++ b/contrib/gitian-descriptors/gitian-osx-signer.yml @@ -1,5 +1,6 @@ --- name: "ion-dmg-signer" +distro: "ubuntu" suites: - "bionic" architectures: @@ -12,6 +13,8 @@ remotes: files: - "ion-osx-unsigned.tar.xz" script: | + set -e -o pipefail + WRAP_DIR=$HOME/wrapped mkdir -p ${WRAP_DIR} export PATH=`pwd`:$PATH diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 18d0006d1e532..815587593a9ca 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,6 +1,7 @@ --- -name: "ion-osx-3.2" +name: "ion-osx-3.3" enable_cache: true +distro: "ubuntu" suites: - "bionic" architectures: @@ -23,9 +24,9 @@ packages: - "libcap-dev" - "libz-dev" - "libbz2-dev" -- "python" -- "python-dev" -- "python-setuptools" +- "python3" +- "python3-dev" +- "python3-setuptools" - "fonts-tuffy" remotes: - "url": "https://github.com/cevap/ion.git" @@ -33,6 +34,8 @@ remotes: files: - "MacOSX10.11.sdk.tar.xz" script: | + set -e -o pipefail + WRAP_DIR=$HOME/wrapped HOSTS="x86_64-apple-darwin14" CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests GENISOIMAGE=$WRAP_DIR/genisoimage" diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml index 621a9d9c268e2..5e97ced5299e3 100644 --- a/contrib/gitian-descriptors/gitian-win-signer.yml +++ b/contrib/gitian-descriptors/gitian-win-signer.yml @@ -1,5 +1,6 @@ --- name: "ion-win-signer" +distro: "ubuntu" suites: - "bionic" architectures: @@ -16,6 +17,8 @@ files: - "osslsigncode-Backports-to-1.7.1.patch" - "ion-win-unsigned.tar.xz" script: | + set -e -o pipefail + BUILD_DIR=`pwd` SIGDIR=${BUILD_DIR}/signature/win UNSIGNED_DIR=${BUILD_DIR}/unsigned diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index b5801c18309ef..87fae8a1e620a 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -1,6 +1,7 @@ --- -name: "ion-win-3.2" +name: "ion-win-3.3" enable_cache: true +distro: "ubuntu" suites: - "bionic" architectures: @@ -20,13 +21,15 @@ packages: - "nsis" - "zip" - "ca-certificates" -- "python" +- "python3" - "rename" remotes: - "url": "https://github.com/cevap/ion.git" "dir": "ion" files: [] script: | + set -e -o pipefail + WRAP_DIR=$HOME/wrapped HOSTS="i686-w64-mingw32 x86_64-w64-mingw32" CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests" diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh index 2cbbbf22882b9..3bd575fe040c6 100755 --- a/contrib/install_db4.sh +++ b/contrib/install_db4.sh @@ -6,10 +6,10 @@ export LC_ALL=C set -e if [ -z "${1}" ]; then - echo "Usage: ./install_db4.sh [ ...]" + echo "Usage: $0 [ ...]" echo echo "Must specify a single argument: the directory in which db4 will be built." - echo "This is probably \`pwd\` if you're at the root of the bitcoin repository." + echo "This is probably \`pwd\` if you're at the root of the ion repository." exit 1 fi @@ -51,7 +51,7 @@ http_get() { if [ -f "${2}" ]; then echo "File ${2} already exists; not downloading again" elif check_exists curl; then - curl --insecure "${1}" -o "${2}" + curl --insecure --retry 5 "${1}" -o "${2}" else wget --no-check-certificate "${1}" -O "${2}" fi @@ -70,6 +70,20 @@ CLANG_CXX11_PATCH_HASH='7a9a47b03fd5fb93a16ef42235fa9512db9b0829cfc3bdf90edd3ec1 http_get "${CLANG_CXX11_PATCH_URL}" clang.patch "${CLANG_CXX11_PATCH_HASH}" patch -p2 < clang.patch +# The packaged config.guess and config.sub are ancient (2009) and can cause build issues. +# Replace them with modern versions. +# See https://github.com/bitcoin/bitcoin/issues/16064 +CONFIG_GUESS_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=55eaf3e779455c4e5cc9f82efb5278be8f8f900b' +CONFIG_GUESS_HASH='2d1ff7bca773d2ec3c6217118129220fa72d8adda67c7d2bf79994b3129232c1' +CONFIG_SUB_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=55eaf3e779455c4e5cc9f82efb5278be8f8f900b' +CONFIG_SUB_HASH='3a4befde9bcdf0fdb2763fc1bfa74e8696df94e1ad7aac8042d133c8ff1d2e32' + +rm -f "dist/config.guess" +rm -f "dist/config.sub" + +http_get "${CONFIG_GUESS_URL}" dist/config.guess "${CONFIG_GUESS_HASH}" +http_get "${CONFIG_SUB_URL}" dist/config.sub "${CONFIG_SUB_HASH}" + cd build_unix/ "${BDB_PREFIX}/${BDB_VERSION}/dist/configure" \ diff --git a/contrib/ion-qt.pro b/contrib/ion-qt.pro index 443ac472a383e..978c784e33b63 100644 --- a/contrib/ion-qt.pro +++ b/contrib/ion-qt.pro @@ -119,7 +119,7 @@ HEADERS += src/activemasternode.h \ src/tinyformat.h \ src/txdb.h \ src/txmempool.h \ - src/ui_interface.h \ + src/guiinterface.h \ src/uint256.h \ src/undo.h \ src/util.h \ diff --git a/depends/Makefile b/depends/Makefile index 19f3c52e34762..fa2417885dd5b 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -6,6 +6,7 @@ BASE_CACHE ?= $(BASEDIR)/built SDK_PATH ?= $(BASEDIR)/SDKs NO_QT ?= NO_WALLET ?= +NO_ZMQ ?= NO_UPNP ?= FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources FALLBACK_DOWNLOAD_PATH_ION ?= https://github.com/ioncoincore/ion-depends/releases/download/latest @@ -15,7 +16,7 @@ HOST ?= $(BUILD) PATCHES_PATH = $(BASEDIR)/patches BASEDIR = $(CURDIR) HASH_LENGTH:=11 -DOWNLOAD_CONNECT_TIMEOUT:=10 +DOWNLOAD_CONNECT_TIMEOUT:=30 DOWNLOAD_RETRIES:=3 HOST_ID_SALT ?= salt BUILD_ID_SALT ?= salt @@ -93,6 +94,7 @@ $(host_arch)_$(host_os)_id_string+=$(shell $(host_STRIP) --version 2>/dev/null) qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch)_$(host_os)_packages) wallet_packages_$(NO_WALLET) = $(wallet_packages) upnp_packages_$(NO_UPNP) = $(upnp_packages) +zmq_packages_$(NO_ZMQ) = $(zmq_packages) packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) @@ -101,6 +103,10 @@ ifneq ($(qt_packages_),) native_packages += $(qt_native_packages) endif +ifneq ($(zmq_packages_),) +packages += $(zmq_packages) +endif + all_packages = $(packages) $(native_packages) meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk @@ -137,6 +143,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_ -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \ -e 's|@allow_host_packages@|$(ALLOW_HOST_PACKAGES)|' \ -e 's|@no_qt@|$(NO_QT)|' \ + -e 's|@no_zmq@|$(NO_ZMQ)|' \ -e 's|@no_wallet@|$(NO_WALLET)|' \ -e 's|@no_upnp@|$(NO_UPNP)|' \ -e 's|@debug@|$(DEBUG)|' \ @@ -186,4 +193,6 @@ download-win: @$(MAKE) -s HOST=x86_64-w64-mingw32 download-one download: download-osx download-linux download-win +$(foreach package,$(all_packages),$(eval $(call ext_add_stages,$(package)))) + .PHONY: install cached clean clean-all download-one download-osx download-linux download-win download check-packages check-sources diff --git a/depends/README.md b/depends/README.md index ed5f467d5f0ab..34832ab90827b 100644 --- a/depends/README.md +++ b/depends/README.md @@ -47,7 +47,7 @@ No other options are needed, the paths are automatically configured. #### For macOS cross compilation - sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python-setuptools + sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python3-setuptools #### For Win32/Win64 cross compilation @@ -57,7 +57,7 @@ No other options are needed, the paths are automatically configured. Common linux dependencies: - sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3 + sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3 patch For linux ARM cross compilation: @@ -83,6 +83,7 @@ The following can be set when running make: make FOO=bar FALLBACK_DOWNLOAD_PATH_ION: If a source file can't be fetched, try first from our alternative github sources FALLBACK_DOWNLOAD_PATH: If a source file can't be fetched, try here before giving up NO_QT: Don't download/build/cache qt and its dependencies + NO_ZMQ: Don't download/build/cache packages needed for enabling zeromq NO_WALLET: Don't download/build/cache libs needed to enable the wallet NO_UPNP: Don't download/build/cache packages needed for enabling upnp DEBUG: disable some optimizations and enable more runtime checking diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk index 27f550ab036ae..c7671c1548b77 100644 --- a/depends/builders/darwin.mk +++ b/depends/builders/darwin.mk @@ -1,13 +1,13 @@ -build_darwin_CC: = $(shell xcrun -f clang) -build_darwin_CXX: = $(shell xcrun -f clang++) -build_darwin_AR: = $(shell xcrun -f ar) -build_darwin_RANLIB: = $(shell xcrun -f ranlib) -build_darwin_STRIP: = $(shell xcrun -f strip) -build_darwin_OTOOL: = $(shell xcrun -f otool) -build_darwin_NM: = $(shell xcrun -f nm) +build_darwin_CC:=$(shell xcrun -f clang) +build_darwin_CXX:=$(shell xcrun -f clang++) +build_darwin_AR:=$(shell xcrun -f ar) +build_darwin_RANLIB:=$(shell xcrun -f ranlib) +build_darwin_STRIP:=$(shell xcrun -f strip) +build_darwin_OTOOL:=$(shell xcrun -f otool) +build_darwin_NM:=$(shell xcrun -f nm) build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) -build_darwin_SHA256SUM = shasum -a 256 -build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o +build_darwin_SHA256SUM=shasum -a 256 +build_darwin_DOWNLOAD=curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o #darwin host on darwin builder. overrides darwin host preferences. darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) diff --git a/depends/config.site.in b/depends/config.site.in index b7a5e795c8940..e633752066534 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -33,6 +33,10 @@ if test -z $with_gui && test -n "@no_qt@"; then with_gui=no fi +if test -z $enable_zmq && test -n "@no_zmq@"; then + enable_zmq=no +fi + if test x@host_os@ = xdarwin; then BREW=no PORT=no @@ -67,7 +71,7 @@ fi if test -n "@CXX@" -a -z "${CXX}"; then CXX="@CXX@" fi -PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH +PYTHONPATH=$depends_prefix/native/lib/python3/dist-packages:$PYTHONPATH if test -n "@AR@"; then AR=@AR@ diff --git a/depends/funcs.mk b/depends/funcs.mk index bae113e5294cc..598535ae11b02 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -77,8 +77,9 @@ $(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path)) #default commands +# The default behavior for tar will try to set ownership when running as uid 0 and may not succeed, --no-same-owner disables this behavior $(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash)) -$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --strip-components=1 -xf $$($(1)_source) +$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --no-same-owner --strip-components=1 -xf $$($(1)_source) $(1)_preprocess_cmds ?= $(1)_build_cmds ?= $(1)_config_cmds ?= @@ -171,15 +172,15 @@ $($(1)_extracted): | $($(1)_fetched) $(AT)mkdir -p $$(@D) $(AT)cd $$(@D); $(call $(1)_extract_cmds,$(1)) $(AT)touch $$@ -$($(1)_preprocessed): | $($(1)_dependencies) $($(1)_extracted) +$($(1)_preprocessed): | $($(1)_extracted) $(AT)echo Preprocessing $(1)... $(AT)mkdir -p $$(@D) $($(1)_patch_dir) $(AT)$(foreach patch,$($(1)_patches),cd $(PATCHES_PATH)/$(1); cp $(patch) $($(1)_patch_dir) ;) $(AT)cd $$(@D); $(call $(1)_preprocess_cmds, $(1)) $(AT)touch $$@ -$($(1)_configured): | $($(1)_preprocessed) +$($(1)_configured): | $($(1)_dependencies) $($(1)_preprocessed) $(AT)echo Configuring $(1)... - $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar xf $($(package)_cached); ) + $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar --no-same-owner -xf $($(package)_cached); ) $(AT)mkdir -p $$(@D) $(AT)+cd $$(@D); $($(1)_config_env) $(call $(1)_config_cmds, $(1)) $(AT)touch $$@ @@ -214,6 +215,14 @@ $(1): | $($(1)_cached_checksum) endef +stages = fetched extracted preprocessed configured built staged postprocessed cached cached_checksum + +define ext_add_stages +$(foreach stage,$(stages), + $(1)_$(stage): $($(1)_$(stage)) + .PHONY: $(1)_$(stage)) +endef + # These functions create the build targets for each package. They must be # broken down into small steps so that each part is done for all packages # before moving on to the next step. Otherwise, a package's info diff --git a/depends/packages.md b/depends/packages.md index 7c80362509e98..7d2bd4670d42a 100644 --- a/depends/packages.md +++ b/depends/packages.md @@ -14,8 +14,9 @@ Each package is required to define at least these variables: placeholder such as 1.0 can be used. $(package)_download_path: - Location of the upstream source, without the file-name. Usually http or - ftp. + Location of the upstream source, without the file-name. Usually http, https + or ftp. Secure transmission options like https should be preferred if + available. $(package)_file_name: The upstream source filename available at the download path. diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index 6c9876c2c7c7c..6cdb79592b615 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -1,6 +1,6 @@ package=bdb $(package)_version=4.8.30 -$(package)_download_path=http://download.oracle.com/berkeley-db +$(package)_download_path=https://download.oracle.com/berkeley-db $(package)_file_name=db-$($(package)_version).NC.tar.gz $(package)_sha256_hash=12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef $(package)_build_subdir=build_unix @@ -10,6 +10,7 @@ $(package)_config_opts=--disable-shared --enable-cxx --disable-replication $(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_linux=--with-pic $(package)_cxxflags=-std=c++11 +$(package)_cppflags_mingw32=-DUNICODE -D_UNICODE endef define $(package)_preprocess_cmds diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk index acbc60eea3e8a..8d06882cdb50e 100644 --- a/depends/packages/expat.mk +++ b/depends/packages/expat.mk @@ -1,11 +1,11 @@ package=expat -$(package)_version=2.2.5 -$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_2_5/ +$(package)_version=2.2.6 +$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_2_6/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 -$(package)_sha256_hash=d9dc32efba7e74f788fcc4f212a43216fc37cf5f23f4c2339664d473353aedf6 +$(package)_sha256_hash=17b43c2716d521369f82fc2dc70f359860e90fa440bea65b3b85f0b246ea81f2 define $(package)_set_vars -$(package)_config_opts=--disable-static +$(package)_config_opts=--disable-static --without-docbook endef define $(package)_config_cmds diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk index 12695db4b9f78..d0996b4534eb7 100644 --- a/depends/packages/fontconfig.mk +++ b/depends/packages/fontconfig.mk @@ -1,6 +1,6 @@ package=fontconfig $(package)_version=2.12.1 -$(package)_download_path=http://www.freedesktop.org/software/fontconfig/release/ +$(package)_download_path=https://www.freedesktop.org/software/fontconfig/release/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=b449a3e10c47e1d1c7a6ec6e2016cca73d3bd68fbbd4f0ae5cc6b573f7d6c7f3 $(package)_dependencies=freetype expat diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk index 41e02e2030df8..a98e82ed168bd 100644 --- a/depends/packages/freetype.mk +++ b/depends/packages/freetype.mk @@ -1,6 +1,6 @@ package=freetype $(package)_version=2.7.1 -$(package)_download_path=http://download.savannah.gnu.org/releases/$(package) +$(package)_download_path=https://download.savannah.gnu.org/releases/$(package) $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=3a3bb2c4e15ffb433f2032f50a5b5a92558206822e22bfe8cbe339af4aa82f88 diff --git a/depends/packages/libX11.mk b/depends/packages/libX11.mk index 298616bea42ac..a013da51925ee 100644 --- a/depends/packages/libX11.mk +++ b/depends/packages/libX11.mk @@ -1,6 +1,6 @@ package=libX11 $(package)_version=1.6.2 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=2aa027e837231d2eeea90f3a4afe19948a6eb4c8b2bec0241eba7dbc8106bd16 $(package)_dependencies=libxcb xtrans xextproto xproto diff --git a/depends/packages/libXau.mk b/depends/packages/libXau.mk index 304494e3c5e4c..ce42140689c2e 100644 --- a/depends/packages/libXau.mk +++ b/depends/packages/libXau.mk @@ -1,6 +1,6 @@ package=libXau $(package)_version=1.0.8 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=fdd477320aeb5cdd67272838722d6b7d544887dfe7de46e1e7cc0c27c2bea4f2 $(package)_dependencies=xproto diff --git a/depends/packages/libXext.mk b/depends/packages/libXext.mk index c0565dd6720f9..458b967784183 100644 --- a/depends/packages/libXext.mk +++ b/depends/packages/libXext.mk @@ -1,6 +1,6 @@ package=libXext $(package)_version=1.3.2 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=f829075bc646cdc085fa25d98d5885d83b1759ceb355933127c257e8e50432e0 $(package)_dependencies=xproto xextproto libX11 libXau diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk index 3f346d9728eba..3ddd5a7dd99c1 100644 --- a/depends/packages/libxcb.mk +++ b/depends/packages/libxcb.mk @@ -1,6 +1,6 @@ package=libxcb $(package)_version=1.10 -$(package)_download_path=http://xcb.freedesktop.org/dist +$(package)_download_path=https://xcb.freedesktop.org/dist $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=98d9ab05b636dd088603b64229dd1ab2d2cc02ab807892e107d674f9c3f2d5b5 $(package)_dependencies=xcb_proto libXau xproto diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk index 5ad2b580d2ea9..fdbe22cda63d4 100644 --- a/depends/packages/miniupnpc.mk +++ b/depends/packages/miniupnpc.mk @@ -1,6 +1,6 @@ package=miniupnpc $(package)_version=2.0.20180203 -$(package)_download_path=http://miniupnp.free.fr/files +$(package)_download_path=https://miniupnp.tuxfamily.org/files/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=90dda8c7563ca6cd4a83e23b3c66dbbea89603a1675bfdb852897c2c9cc220b7 diff --git a/depends/packages/native_biplist.mk b/depends/packages/native_biplist.mk index 5f247e9bf3487..c3054cbd1a16e 100644 --- a/depends/packages/native_biplist.mk +++ b/depends/packages/native_biplist.mk @@ -3,13 +3,13 @@ $(package)_version=1.0.3 $(package)_download_path=https://bitbucket.org/wooster/biplist/downloads $(package)_file_name=biplist-$($(package)_version).tar.gz $(package)_sha256_hash=4c0549764c5fe50b28042ec21aa2e14fe1a2224e239a1dae77d9e7f3932aa4c6 -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk index 44d238cc4c2a6..a065256c1c1ef 100644 --- a/depends/packages/native_cctools.mk +++ b/depends/packages/native_cctools.mk @@ -5,7 +5,7 @@ $(package)_file_name=$($(package)_version).tar.gz $(package)_sha256_hash=a09c9ba4684670a0375e42d9d67e7f12c1f62581a27f28f7c825d6d7032ccc6a $(package)_build_subdir=cctools $(package)_clang_version=3.7.1 -$(package)_clang_download_path=http://llvm.org/releases/$($(package)_clang_version) +$(package)_clang_download_path=https://llvm.org/releases/$($(package)_clang_version) $(package)_clang_download_file=clang+llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz $(package)_clang_file_name=clang-llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz $(package)_clang_sha256_hash=99b28a6b48e793705228a390471991386daa33a9717cd9ca007fcdde69608fd9 @@ -22,12 +22,12 @@ define $(package)_extract_cmds echo "$($(package)_clang_sha256_hash) $($(package)_source_dir)/$($(package)_clang_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ mkdir -p toolchain/bin toolchain/lib/clang/3.5/include && \ - tar --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \ + tar --no-same-owner --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \ rm -f toolchain/lib/libc++abi.so* && \ echo "#!/bin/sh" > toolchain/bin/$(host)-dsymutil && \ echo "exit 0" >> toolchain/bin/$(host)-dsymutil && \ chmod +x toolchain/bin/$(host)-dsymutil && \ - tar --strip-components=1 -xf $($(package)_source) + tar --no-same-owner --strip-components=1 -xf $($(package)_source) endef define $(package)_set_vars diff --git a/depends/packages/native_cdrkit.mk b/depends/packages/native_cdrkit.mk index cf694edb30e92..8243458ec858e 100644 --- a/depends/packages/native_cdrkit.mk +++ b/depends/packages/native_cdrkit.mk @@ -1,6 +1,6 @@ package=native_cdrkit $(package)_version=1.1.11 -$(package)_download_path=http://distro.ibiblio.org/fatdog/source/600/c +$(package)_download_path=https://distro.ibiblio.org/fatdog/source/600/c $(package)_file_name=cdrkit-$($(package)_version).tar.bz2 $(package)_sha256_hash=b50d64c214a65b1a79afe3a964c691931a4233e2ba605d793eb85d0ac3652564 $(package)_patches=cdrkit-deterministic.patch diff --git a/depends/packages/native_ds_store.mk b/depends/packages/native_ds_store.mk index 116fa25d38197..f99b689ecdc74 100644 --- a/depends/packages/native_ds_store.mk +++ b/depends/packages/native_ds_store.mk @@ -3,14 +3,14 @@ $(package)_version=1.1.2 $(package)_download_path=https://github.com/al45tair/ds_store/archive/ $(package)_file_name=v$($(package)_version).tar.gz $(package)_sha256_hash=3b3ecb7bf0a5157f5b6010bc3af7c141fb0ad3527084e63336220d22744bc20c -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages $(package)_dependencies=native_biplist define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_mac_alias.mk b/depends/packages/native_mac_alias.mk index 306c8356567bc..e60b99dccc98c 100644 --- a/depends/packages/native_mac_alias.mk +++ b/depends/packages/native_mac_alias.mk @@ -3,13 +3,13 @@ $(package)_version=2.0.7 $(package)_download_path=https://github.com/al45tair/mac_alias/archive/ $(package)_file_name=v$($(package)_version).tar.gz $(package)_sha256_hash=6f606d3b6bccd2112aeabf1a063f5b5ece87005a5d7e97c8faca23b916e88838 -$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages +$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages define $(package)_build_cmds - python setup.py build + python3 setup.py build endef define $(package)_stage_cmds mkdir -p $($(package)_install_libdir) && \ - python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) + python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) endef diff --git a/depends/packages/native_protobuf.mk b/depends/packages/native_protobuf.mk index ce50b366fa74f..1de8c37d362aa 100644 --- a/depends/packages/native_protobuf.mk +++ b/depends/packages/native_protobuf.mk @@ -5,7 +5,7 @@ $(package)_file_name=protobuf-$($(package)_version).tar.bz2 $(package)_sha256_hash=ee445612d544d885ae240ffbcbf9267faa9f593b7b101f21d58beceb92661910 define $(package)_set_vars -$(package)_config_opts=--disable-shared +$(package)_config_opts=--disable-shared --without-zlib endef define $(package)_config_cmds diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 4e8ab35998d5a..c8b2ce8608c81 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,4 +1,4 @@ -packages:=boost openssl libevent zeromq gmp +packages:=boost openssl libevent gmp qt_native_packages = native_protobuf qt_packages = qrencode protobuf zlib @@ -10,6 +10,8 @@ qt_mingw32_packages=qt wallet_packages=bdb +zmq_packages=zeromq + upnp_packages=miniupnpc darwin_native_packages = native_biplist native_ds_store native_mac_alias diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 4161f6a7213b3..0ef8348d3e61c 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -132,11 +132,11 @@ define $(package)_extract_cmds echo "$($(package)_qttools_sha256_hash) $($(package)_source_dir)/$($(package)_qttools_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ mkdir qtbase && \ - tar --strip-components=1 -xf $($(package)_source) -C qtbase && \ + tar --no-same-owner --strip-components=1 -xf $($(package)_source) -C qtbase && \ mkdir qttranslations && \ - tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \ + tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \ mkdir qttools && \ - tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools + tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools endef define $(package)_preprocess_cmds @@ -145,7 +145,7 @@ define $(package)_preprocess_cmds sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \ sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \ sed -i.old "s|X11/extensions/XIproto.h|X11/X.h|" qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp && \ - sed -i.old 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' qtbase/configure && \ + sed -i.old -e 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' -e 's|/bin/pwd|pwd|' qtbase/configure && \ sed -i.old 's/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0)/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft)/' qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm && \ mkdir -p qtbase/mkspecs/macx-clang-linux &&\ cp -f qtbase/mkspecs/macx-clang/Info.plist.lib qtbase/mkspecs/macx-clang-linux/ &&\ diff --git a/depends/packages/xcb_proto.mk b/depends/packages/xcb_proto.mk index 0c7c958d62d42..44110394bddae 100644 --- a/depends/packages/xcb_proto.mk +++ b/depends/packages/xcb_proto.mk @@ -1,6 +1,6 @@ package=xcb_proto $(package)_version=1.10 -$(package)_download_path=http://xcb.freedesktop.org/dist +$(package)_download_path=https://xcb.freedesktop.org/dist $(package)_file_name=xcb-proto-$($(package)_version).tar.bz2 $(package)_sha256_hash=7ef40ddd855b750bc597d2a435da21e55e502a0fefa85b274f2c922800baaf05 diff --git a/depends/packages/xextproto.mk b/depends/packages/xextproto.mk index 7065237bd562b..157b76edf6fca 100644 --- a/depends/packages/xextproto.mk +++ b/depends/packages/xextproto.mk @@ -1,6 +1,6 @@ package=xextproto $(package)_version=7.3.0 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/proto +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=f3f4b23ac8db9c3a9e0d8edb591713f3d70ef9c3b175970dd8823dfc92aa5bb0 diff --git a/depends/packages/xproto.mk b/depends/packages/xproto.mk index 5328ec84819d1..23ad5ffa1088d 100644 --- a/depends/packages/xproto.mk +++ b/depends/packages/xproto.mk @@ -1,6 +1,6 @@ package=xproto $(package)_version=7.0.26 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/proto +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=636162c1759805a5a0114a369dffdeccb8af8c859ef6e1445f26a4e6e046514f diff --git a/depends/packages/xtrans.mk b/depends/packages/xtrans.mk index c313b1f609b0b..67d2d976c413b 100644 --- a/depends/packages/xtrans.mk +++ b/depends/packages/xtrans.mk @@ -1,6 +1,6 @@ package=xtrans $(package)_version=1.3.4 -$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/ +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ $(package)_file_name=$(package)-$($(package)_version).tar.bz2 $(package)_sha256_hash=054d4ee3efd52508c753e9f7bc655ef185a29bd2850dd9e2fc2ccc33544f583a $(package)_dependencies= diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk index 589490800f8bd..1600b11a01ec5 100644 --- a/depends/packages/zlib.mk +++ b/depends/packages/zlib.mk @@ -1,6 +1,6 @@ package=zlib $(package)_version=1.2.11 -$(package)_download_path=http://www.zlib.net +$(package)_download_path=https://www.zlib.net $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index e360f6b5d08fe..a2238b7317cd4 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -8,9 +8,9 @@ # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: -# TAG = value [value, ...] +# TAG = value [value, ...] # For lists, items can also be appended using: -# TAG += value [value, ...] +# TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- @@ -103,7 +103,7 @@ BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. @@ -128,10 +128,10 @@ ABBREVIATE_BRIEF = "The $name class" \ represents \ a \ an \ - the + the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief +# doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. @@ -488,7 +488,7 @@ EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. @@ -503,7 +503,7 @@ HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. @@ -556,6 +556,7 @@ SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. + FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the @@ -941,7 +942,7 @@ IMAGE_PATH = INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the +# basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the @@ -1062,7 +1063,7 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index +# Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all @@ -1416,7 +1417,7 @@ QHG_LOCATION = GENERATE_ECLIPSEHELP = NO -# A unique identifier for the eclipse help plugin. When installing the plugin +# A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. @@ -2099,9 +2100,9 @@ SKIP_FUNCTION_MACROS = YES # The TAGFILES tag can be used to specify one or more tag files. For each tag # file the location of the external documentation should be added. The format of # a tag file without this location is as follows: -# TAGFILES = file1 file2 ... +# TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... +# TAGFILES = file1=loc1 "file2 = loc2" ... # where loc1 and loc2 can be relative or absolute paths or URLs. See the # section "Linking to external documentation" for more information about the use # of tag files. @@ -2176,6 +2177,7 @@ DIA_PATH = # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. + HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is diff --git a/doc/README.md b/doc/README.md index acd90462c10ff..074e080e260a8 100644 --- a/doc/README.md +++ b/doc/README.md @@ -2,64 +2,65 @@ Table of Contents ----------------- -- [Ion Core Documentation](#ion-core-documentation) - - [Setup](#setup) - - [Running](#running) - - [Unix](#unix) - - [Windows](#windows) - - [OSX](#osx) - - [Need Help?](#need-help) - - [Building](#building) - - [Development](#development) - - [Resources](#resources) - - [Miscellaneous](#miscellaneous) - - [License](#license) +- [Ion Core Documentation](#Ion-Core-Documentation) + - [Table of Contents](#Table-of-Contents) + - [Setup](#Setup) + - [Running](#Running) + - [Unix](#Unix) + - [Windows](#Windows) + - [macOS](#macOS) + - [Need Help?](#Need-Help) + - [Building](#Building) + - [Development](#Development) + - [Resources](#Resources) + - [Miscellaneous](#Miscellaneous) + - [License](#License) ## Setup [Ion Core](http://core.ioncoin.org/) is the original ION client and it builds the backbone of the network. However, it downloads and stores the entire history of ION transactions; depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more. Thankfully you only have to do this once. ## Running -The following are some helpful notes on how to run ION on your native platform. +The following are some helpful notes on how to run ION Core on your native platform. ### Unix Unpack the files into a directory and run: -- bin/ion-qt (GUI, 32-bit) or bin/iond (headless, 32-bit) -- bin/ion-qt (GUI, 64-bit) or bin/iond (headless, 64-bit) +- `bin/ion-qt` (GUI) or +- `bin/iond` (headless) ### Windows Unpack the files into a directory, and then run ion-qt.exe. -### OSX +### macOS Drag Ion-Qt to your applications folder, and then run Ion-Qt. ### Need Help? -- See the documentation at the [Ion Wiki](https://github.com/cevap/ion/wiki) and [Bitcoin Wiki](https://en.bitcoin.it/wiki/Main_Page) +- See the documentation at the [Ion Wiki](https://github.com/cevap/ion/wiki) and [Ionomy Wiki](https://github.com/ionomy/ion/wiki) for help and more information. -- Ask for help on [Discord chat]() - - [BitcoinTalk](https://bitcointalk.org/index.php?topic=1443633.0) -- Join our Discord [Discord](https://discord.gg/vuZn7gC) +- Ask for help on [Discord chat](https://discord.gg/vuZn7gC) ## Building -The following are developer notes on how to build ION on your native platform. They are not complete guides, but include notes on the necessary libraries, compile flags, etc. +The following are developer notes on how to build ION Core on your native platform. They are not complete guides, but include notes on the necessary libraries, compile flags, etc. -- [OSX Build Notes](build-osx.md) +- [Dependencies](dependencies.md) +- [macOS Build Notes](build-osx.md) - [Unix Build Notes](build-unix.md) +- [Windows Build Notes](build-windows.md) - [Gitian Building Guide](gitian-building.md) ## Development -The Ion repo's [root README](https://github.com/cevap/ion/blob/master/README.md) contains relevant information on the development process and automated testing. +The ION Core repo's [root README](/README.md) contains relevant information on the development process and automated testing. - [Developer Notes](developer-notes.md) - [Multiwallet Qt Development](multiwallet-qt.md) - [Release Notes](release-notes.md) - [Release Process](release-process.md) -- [Source Code Documentation (External Link)](https://dev.visucore.com/bitcoin/doxygen/) ***TODO*** +- [Source Code Documentation](https://cevap.github.io/ion-docs/) - [Translation Process](translation_process.md) - [Unit Tests](unit-tests.md) - [Unauthenticated REST Interface](REST-interface.md) @@ -67,7 +68,7 @@ The Ion repo's [root README](https://github.com/cevap/ion/blob/master/README.md) ## Resources -- Discuss on the [BitcoinTalk](https://bitcointalk.org/index.php?topic=1443633.0) or the [ION](http://forum.ioncoin.org/) forum. +- Discuss on the [ION community](https://ion.community/) forum. - Join [Ion Discord](https://discord.gg/vuZn7gC). ## Miscellaneous @@ -77,6 +78,6 @@ The Ion repo's [root README](https://github.com/cevap/ion/blob/master/README.md) - [Init Scripts (systemd/upstart/openrc)](init.md) ## License -Distributed under the [MIT/X11 software license](http://www.opensource.org/licenses/mit-license.php). +Distributed under the [MIT software license](/COPYING). This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](https://www.openssl.org/). This product includes -cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. \ No newline at end of file +cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. diff --git a/doc/README_osx.md b/doc/README_osx.md deleted file mode 100644 index 78fc12724363f..0000000000000 --- a/doc/README_osx.md +++ /dev/null @@ -1,97 +0,0 @@ -Deterministic OS X Dmg Notes. - -Working OS X DMGs are created in Linux by combining a recent clang, -the Apple binutils (ld, ar, etc) and DMG authoring tools. - -Apple uses clang extensively for development and has upstreamed the necessary -functionality so that a vanilla clang can take advantage. It supports the use -of -F, -target, -mmacosx-version-min, and --sysroot, which are all necessary -when building for OS X. - -Apple's version of binutils (called cctools) contains lots of functionality -missing in the FSF's binutils. In addition to extra linker options for -frameworks and sysroots, several other tools are needed as well such as -install_name_tool, lipo, and nmedit. These do not build under linux, so they -have been patched to do so. The work here was used as a starting point: -[mingwandroid/toolchain4](https://github.com/mingwandroid/toolchain4). - -In order to build a working toolchain, the following source packages are needed -from Apple: cctools, dyld, and ld64. - -These tools inject timestamps by default, which produce non-deterministic -binaries. The ZERO_AR_DATE environment variable is used to disable that. - -This version of cctools has been patched to use the current version of clang's -headers and its libLTO.so rather than those from llvmgcc, as it was -originally done in toolchain4. - -To complicate things further, all builds must target an Apple SDK. These SDKs -are free to download, but not redistributable. -To obtain it, register for a developer account, then download the [Xcode 7.3.1 dmg](https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/Xcode_7.3.1/Xcode_7.3.1.dmg). - -This file is several gigabytes in size, but only a single directory inside is -needed: -``` -Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk -``` - -Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file. -To create a tarball suitable for Gitian input, there are two options: - -Using Mac OS X, you can mount the dmg, and then create it with: -``` - $ hdiutil attach Xcode_7.3.1.dmg - $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -cJf MacOSX10.11.sdk.tar.xz MacOSX10.11.sdk -``` - -Alternatively, you can use 7zip and SleuthKit to extract the files one by one. -The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure -the dmg file is in the current directory, and then run the script. You may wish -to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when -you've confirmed the extraction succeeded. - -```bash -apt-get install p7zip-full sleuthkit -contrib/macdeploy/extract-osx-sdk.sh -rm -rf 5.hfs MacOSX10.11.sdk -``` - -The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries -which are created using these tools. The build process has been designed to -avoid including the SDK's files in Gitian's outputs. All interim tarballs are -fully deterministic and may be freely redistributed. - -genisoimage is used to create the initial DMG. It is not deterministic as-is, -so it has been patched. A system genisoimage will work fine, but it will not -be deterministic because the file-order will change between invocations. -The patch can be seen here: [theuni/osx-cross-depends](https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff). -No effort was made to fix this cleanly, so it likely leaks memory badly. But -it's only used for a single invocation, so that's no real concern. - -genisoimage cannot compress DMGs, so afterwards, the 'dmg' tool from the -libdmg-hfsplus project is used to compress it. There are several bugs in this -tool and its maintainer has seemingly abandoned the project. It has been forked -and is available (with fixes) here: [theuni/libdmg-hfsplus](https://github.com/theuni/libdmg-hfsplus). - -The 'dmg' tool has the ability to create DMGs from scratch as well, but this -functionality is broken. Only the compression feature is currently used. -Ideally, the creation could be fixed and genisoimage would no longer be necessary. - -Background images and other features can be added to DMG files by inserting a -.DS_Store before creation. This is generated by the script -contrib/macdeploy/custom_dsstore.py. - -As of OS X Mavericks (10.9), using an Apple-blessed key to sign binaries is a -requirement in order to satisfy the new Gatekeeper requirements. Because this -private key cannot be shared, we'll have to be a bit creative in order for the -build process to remain somewhat deterministic. Here's how it works: - -- Builders use Gitian to create an unsigned release. This outputs an unsigned - dmg which users may choose to bless and run. It also outputs an unsigned app - structure in the form of a tarball, which also contains all of the tools - that have been previously (deterministically) built in order to create a - final dmg. -- **TODO** The Apple keyholder uses this unsigned app to create a detached signature, - using the script that is also included there. Detached signatures are available from this [repository](https://github.com/gitianuser/ion-detached-sigs). -- Builders feed the unsigned app + detached signature back into Gitian. It - uses the pre-built tools to recombine the pieces into a deterministic dmg. diff --git a/doc/build-osx.md b/doc/build-osx.md index 3e80f9f48e213..991211b9aeef7 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -1,132 +1,223 @@ -# Mac OS X Build Instructions and Notes -This guide will show you how to build iond (headless client) for OSX. +macOS Build Instructions and Notes +==================================== +The commands in this guide should be executed in a Terminal application. +The built-in one is located in `/Applications/Utilities/Terminal.app`. Table of Contents ------------------ -- [Mac OS X Build Instructions and Notes](#mac-os-x-build-instructions-and-notes) - - [Table of Contents](#table-of-contents) - - [Notes](#notes) - - [Preparation](#preparation) - - [Instructions: Homebrew](#instructions-homebrew) - - [Install dependencies using Homebrew](#install-dependencies-using-homebrew) - - [Building `iond`](#building-iond) - - [Use Qt Creator as IDE](#use-qt-creator-as-ide) - - [Creating a release build](#creating-a-release-build) - - [Running](#running) - - [Other commands:](#other-commands) +- [macOS Build Instructions and Notes](#macOS-Build-Instructions-and-Notes) + - [Table of Contents](#Table-of-Contents) + - [Preparation](#Preparation) + - [Dependencies](#Dependencies) + - [Berkeley DB](#Berkeley-DB) + - [Build ION Core](#Build-ION-Core) + - [Disable-wallet mode](#Disable-wallet-mode) + - [Running](#Running) + - [Other commands:](#Other-commands) + - [Notes](#Notes) + - [Deterministic macOS DMG Notes](#Deterministic-macOS-DMG-Notes) -## Notes +Preparation +----------- +Install the macOS command line tools: -- Tested on OS X 10.7 through 10.10 on 64-bit Intel processors only. +`xcode-select --install` -- All of the commands should be executed in a Terminal application. The -built-in one is located in `/Applications/Utilities`. +When the popup appears, click `Install`. -## Preparation +Then install [Homebrew](https://brew.sh). -You need to install XCode with all the options checked so that the compiler -and everything is available in /usr not just /Developer. XCode should be -available on your OS X installation media, but if not, you can get the -current version from https://developer.apple.com/xcode/. If you install -Xcode 4.3 or later, you'll need to install its command line tools. This can -be done in `Xcode > Preferences > Downloads > Components` and generally must -be re-done or updated every time Xcode is updated. +Dependencies +---------------------- -There's also an assumption that you already have `git` installed. If -not, it's the path of least resistance to install [Github for Mac](https://mac.github.com/) -(OS X 10.7+) or -[Git for OS X](https://code.google.com/p/git-osx-installer/). It is also -available via Homebrew. + brew install autoconf automake berkeley-db4 libtool boost miniupnpc openssl pkg-config protobuf python3 qt5 zmq libevent qrencode gmp -You will also need to install [Homebrew](http://brew.sh) in order to install library -dependencies. +See [dependencies.md](dependencies.md) for a complete overview. -The installation of the actual dependencies is covered in the Instructions -sections below. +If you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG: -## Instructions: Homebrew + brew install librsvg -#### Install dependencies using Homebrew +Berkeley DB +----------- +It is recommended to use Berkeley DB 4.8. If you have to build it yourself, +you can use [the installation script included in contrib/](/contrib/install_db4.sh) +like so: - brew install autoconf automake berkeley-db4 libtool boost miniupnpc openssl pkg-config protobuf qt5 zmq libevent +```shell +./contrib/install_db4.sh . +``` -### Building `iond` +from the root of the repository. -1. Clone the github tree to get the source code and go into the directory. +**Note**: You only need Berkeley DB if the wallet is enabled (see [*Disable-wallet mode*](/doc/build-osx.md#disable-wallet-mode)). - git clone https://github.com/cevap/ion.git - cd ION +Build ION Core +------------------------ + +1. Clone the ION Core source code: + + git clone https://github.com/ioncoincore/ion + cd ion 2. Make the Homebrew OpenSSL headers visible to the configure script (do ```brew info openssl``` to find out why this is necessary, or if you use Homebrew with installation folders different from the default). export LDFLAGS+=-L/usr/local/opt/openssl/lib export CPPFLAGS+=-I/usr/local/opt/openssl/include -3. Build iond: +3. Build ION Core: ./autogen.sh - ./configure --with-gui=qt5 + ./configure make -4. It is also a good idea to build and run the unit tests: +4. It is recommended to build and run the unit tests: make check -5. (Optional) You can also install iond to your path: - - make install +5. You can also create a .dmg that contains the .app bundle (optional): -## Use Qt Creator as IDE -You can use Qt Creator as IDE, for debugging and for manipulating forms, etc. -Download Qt Creator from http://www.qt.io/download/. Download the "community edition" and only install Qt Creator (uncheck the rest during the installation process). + make deploy -1. Make sure you installed everything through homebrew mentioned above -2. Do a proper ./configure --with-gui=qt5 --enable-debug -3. In Qt Creator do "New Project" -> Import Project -> Import Existing Project -4. Enter "ion-qt" as project name, enter src/qt as location -5. Leave the file selection as it is -6. Confirm the "summary page" -7. In the "Projects" tab select "Manage Kits..." -8. Select the default "Desktop" kit and select "Clang (x86 64bit in /usr/bin)" as compiler -9. Select LLDB as debugger (you might need to set the path to your installtion) -10. Start debugging with Qt Creator +Disable-wallet mode +-------------------- +**Note:** This functionality is not yet completely implemented, and compilation using the below option will currently fail. -## Creating a release build -You can ignore this section if you are building `iond` for your own use. +When the intention is to run only a P2P node without a wallet, ION Core may be compiled in +disable-wallet mode with: -iond/ion-cli binaries are not included in the ion-Qt.app bundle. + ./configure --disable-wallet -If you are building `iond` or `ion-qt` for others, your build machine should be set up -as follows for maximum compatibility: +In this case there is no dependency on Berkeley DB 4.8. -All dependencies should be compiled with these flags: +Running +------- - -mmacosx-version-min=10.7 - -arch x86_64 - -isysroot $(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk +ION Core is now available at `./src/iond` -Once dependencies are compiled, see release-process.md for how the ION-Qt.app -bundle is packaged and signed to create the .dmg disk image that is distributed. +Before running, you may create an empty configuration file: -## Running + mkdir -p "/Users/${USER}/Library/Application Support/ioncoin" -It's now available at `./iond`, provided that you are still in the `src` -directory. We have to first create the RPC configuration file, though. + touch "/Users/${USER}/Library/Application Support/ioncoin/ioncoin.conf" -Run `./iond` to get the filename where it should be put, or just try these -commands: - - echo -e "rpcuser=ionrpc\nrpcpassword=$(xxd -l 16 -p /dev/urandom)" > "/Users/${USER}/Library/Application Support/ioncoin/ioncoin.conf" chmod 600 "/Users/${USER}/Library/Application Support/ioncoin/ioncoin.conf" -The next time you run it, it will start downloading the blockchain, but it won't -output anything while it's doing this. This process may take several hours; -you can monitor its process by looking at the debug.log file, like this: +The first time you run iond, it will start downloading the blockchain. This process could take many hours, or even days on slower than average systems. - tail -f $HOME/Library/Application\ Support/ioncoin/debug.log +You can monitor the download process by looking at the debug.log file: -## Other commands: + tail -f $HOME/Library/Application\ Support/ioncoin/debug.log - ./iond -daemon # to start the ion daemon. - ./ion-cli --help # for a list of command-line options. - ./ion-cli help # When the daemon is running, to get a list of RPC commands +Other commands: +------- + + ./src/iond -daemon # Starts the ion daemon. + ./src/ion-cli --help # Outputs a list of command-line options. + ./src/ion-cli help # Outputs a list of RPC commands when the daemon is running. + +Notes +----- + +* Tested on OS X 10.10 Yosemite through macOS 10.13 High Sierra on 64-bit Intel processors only. + +* Building with downloaded Qt binaries is not officially supported. See the notes in [#7714](https://github.com/bitcoin/bitcoin/issues/7714) + +Deterministic macOS DMG Notes +----------------------------- + +Working macOS DMGs are created in Linux by combining a recent clang, +the Apple binutils (ld, ar, etc) and DMG authoring tools. + +Apple uses clang extensively for development and has upstreamed the necessary +functionality so that a vanilla clang can take advantage. It supports the use +of -F, -target, -mmacosx-version-min, and --sysroot, which are all necessary +when building for macOS. + +Apple's version of binutils (called cctools) contains lots of functionality +missing in the FSF's binutils. In addition to extra linker options for +frameworks and sysroots, several other tools are needed as well such as +install_name_tool, lipo, and nmedit. These do not build under linux, so they +have been patched to do so. The work here was used as a starting point: +[mingwandroid/toolchain4](https://github.com/mingwandroid/toolchain4). + +In order to build a working toolchain, the following source packages are needed +from Apple: cctools, dyld, and ld64. + +These tools inject timestamps by default, which produce non-deterministic +binaries. The ZERO_AR_DATE environment variable is used to disable that. + +This version of cctools has been patched to use the current version of clang's +headers and its libLTO.so rather than those from llvmgcc, as it was +originally done in toolchain4. + +To complicate things further, all builds must target an Apple SDK. These SDKs +are free to download, but not redistributable. +To obtain it, register for a developer account, then download the [Xcode 7.3.1 dmg](https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/Xcode_7.3.1/Xcode_7.3.1.dmg). + +This file is several gigabytes in size, but only a single directory inside is +needed: +``` +Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk +``` + +Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file. +To create a tarball suitable for Gitian input, there are two options: + +Using macOS, you can mount the dmg, and then create it with: +``` + $ hdiutil attach Xcode_7.3.1.dmg + $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -xJf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk +``` + +Alternatively, you can use 7zip and SleuthKit to extract the files one by one. +The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure +the dmg file is in the current directory, and then run the script. You may wish +to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when +you've confirmed the extraction succeeded. + +```bash +apt-get install p7zip-full sleuthkit +contrib/macdeploy/extract-osx-sdk.sh +rm -rf 5.hfs MacOSX10.11.sdk +``` + +The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries +which are created using these tools. The build process has been designed to +avoid including the SDK's files in Gitian's outputs. All interim tarballs are +fully deterministic and may be freely redistributed. + +genisoimage is used to create the initial DMG. It is not deterministic as-is, +so it has been patched. A system genisoimage will work fine, but it will not +be deterministic because the file-order will change between invocations. +The patch can be seen here: [theuni/osx-cross-depends](https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff). +No effort was made to fix this cleanly, so it likely leaks memory badly. But +it's only used for a single invocation, so that's no real concern. + +genisoimage cannot compress DMGs, so afterwards, the 'dmg' tool from the +libdmg-hfsplus project is used to compress it. There are several bugs in this +tool and its maintainer has seemingly abandoned the project. It has been forked +and is available (with fixes) here: [theuni/libdmg-hfsplus](https://github.com/theuni/libdmg-hfsplus). + +The 'dmg' tool has the ability to create DMGs from scratch as well, but this +functionality is broken. Only the compression feature is currently used. +Ideally, the creation could be fixed and genisoimage would no longer be necessary. + +Background images and other features can be added to DMG files by inserting a +.DS_Store before creation. This is generated by the script +contrib/macdeploy/custom_dsstore.py. + +As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a +requirement in order to satisfy the new Gatekeeper requirements. Because this +private key cannot be shared, we'll have to be a bit creative in order for the +build process to remain somewhat deterministic. Here's how it works: + +- Builders use Gitian to create an unsigned release. This outputs an unsigned + dmg which users may choose to bless and run. It also outputs an unsigned app + structure in the form of a tarball, which also contains all of the tools + that have been previously (deterministically) built in order to create a + final dmg. +- The Apple keyholder uses this unsigned app to create a detached signature, + using the script that is also included there. Detached signatures are available from this [repository](https://github.com/gitianuser/ion-detached-sigs). +- Builders feed the unsigned app + detached signature back into Gitian. It + uses the pre-built tools to recombine the pieces into a deterministic dmg. diff --git a/doc/build-unix.md b/doc/build-unix.md index b0faeeeb288d4..d28e98a861a56 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -1,34 +1,35 @@ # UNIX BUILD NOTES -Some notes on how to build ION in Unix. +Some notes on how to build ION Core in Unix. Table of Contents ------------------ -- [UNIX BUILD NOTES](#unix-build-notes) - - [Table of Contents](#table-of-contents) - - [Note](#note) - - [To Build](#to-build) - - [Dependencies](#dependencies) - - [System requirements](#system-requirements) - - [Linux Distribution Specific Instructions](#linux-distribution-specific-instructions) - - [Ubuntu & Debian](#ubuntu--debian) - - [Dependency Build Instructions](#dependency-build-instructions) - - [Fedora](#fedora) - - [Dependency Build Instructions](#dependency-build-instructions-1) - - [Notes](#notes) +- [UNIX BUILD NOTES](#UNIX-BUILD-NOTES) + - [Table of Contents](#Table-of-Contents) + - [Note](#Note) + - [To Build](#To-Build) + - [Dependencies](#Dependencies) + - [Memory requirements](#Memory-requirements) + - [Linux Distribution Specific Instructions](#Linux-Distribution-Specific-Instructions) + - [Ubuntu & Debian](#Ubuntu--Debian) + - [Dependency Build Instructions](#Dependency-Build-Instructions) + - [Fedora](#Fedora) + - [Dependency Build Instructions](#Dependency-Build-Instructions-1) + - [Notes](#Notes) - [miniupnpc](#miniupnpc) - - [Berkeley DB](#berkeley-db) - - [Boost](#boost) - - [Security](#security) - - [Disable-wallet mode](#disable-wallet-mode) - - [Additional Configure Flags](#additional-configure-flags) + - [Berkeley DB](#Berkeley-DB) + - [Boost](#Boost) + - [Security](#Security) + - [Disable-wallet mode](#Disable-wallet-mode) + - [Additional Configure Flags](#Additional-Configure-Flags) + - [ARM Cross-compilation](#ARM-Cross-compilation) ## Note -Always use absolute paths to configure and compile ion and the dependencies, +Always use absolute paths to configure and compile ION Core and the dependencies, for example, when specifying the path of the dependency: ../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX -Here BDB_PREFIX must absolute path - it is defined using $(pwd) which ensures +Here BDB_PREFIX must be an absolute path - it is defined using $(pwd) which ensures the usage of the absolute path. ## To Build @@ -40,7 +41,7 @@ make make install # optional ``` -This will build ion-qt as well if the dependencies are met. +This will build ion-qt as well, if the dependencies are met. ## Dependencies @@ -48,9 +49,9 @@ These dependencies are required: Library | Purpose | Description ------------|--------------------|---------------------- - libssl | SSL Support | Secure communications - libboost | Boost | C++ Library - libevent | Events | Asynchronous event notification + libssl | Crypto | Random Number Generation, Elliptic Curve Cryptography + libboost | Utility | Library for threading, data structures, etc + libevent | Networking | OS independent asynchronous networking libgmp | Bignum Arithmetic | Precision arithmetic Optional dependencies: @@ -65,23 +66,26 @@ Optional dependencies: univalue | Utility | JSON parsing and encoding (bundled version will be used unless --with-system-univalue passed to configure) libzmq3 | ZMQ notification | Optional, allows generating ZMQ notifications (requires ZMQ version >= 4.0.0) -For the versions used in the release, see [release-process.md](release-process.md) under *Fetch and build inputs*. +For the versions used, see [dependencies.md](dependencies.md) -## System requirements +## Memory requirements -C++ compilers are memory-hungry. It is recommended to have at least 1 GB of -memory available when compiling Ion Core. With 512MB of memory or less -compilation will take much longer due to swap thrashing. +C++ compilers are memory-hungry. It is recommended to have at least 1.5 GB of +memory available when compiling ION Core. On systems with less, gcc can be +tuned to conserve memory with additional CXXFLAGS: + + + ./configure CXXFLAGS="--param ggc-min-expand=1 --param ggc-min-heapsize=32768" ## Linux Distribution Specific Instructions -### Ubuntu & Debian +### Ubuntu & Debian #### Dependency Build Instructions -Build Requirements: +Build requirements: - sudo apt-get install build-essential libtool bsdmainutils autotools-dev autoconf pkg-config automake python3 + sudo apt-get install build-essential libtool bsdmainutils autotools-dev autoconf pkg-config automake python3 Now, you can either build from self-compiled [depends](/depends/README.md) or install the required dependencies: @@ -96,17 +100,20 @@ BerkeleyDB is required for the wallet. **For Ubuntu only:** db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). You can add the repository using the following command: - sudo apt-get install software-properties-common - sudo add-apt-repository ppa:bitcoin/bitcoin - sudo apt-get update - sudo apt-get install libdb4.8-dev libdb4.8++-dev + sudo apt-get install software-properties-common + sudo add-apt-repository ppa:bitcoin/bitcoin + sudo apt-get update + sudo apt-get install libdb4.8-dev libdb4.8++-dev Ubuntu and Debian have their own libdb-dev and libdb++-dev packages, but these will install BerkeleyDB 5.1 or later. This will break binary wallet compatibility with the distributed executables, which are based on BerkeleyDB 4.8. If you do not care about wallet compatibility, pass `--with-incompatible-bdb` to configure. -To build Bitcoin Core without wallet, see [*Disable-wallet mode*](/doc/build-unix.md#disable-wallet-mode) +Otherwise, you can build from self-compiled `depends` (see above). + +To build ION Core without wallet, see [*Disable-wallet mode*](/doc/build-unix.md#disable-wallet-mode) + Optional (see --with-miniupnpc and --enable-upnp-default): @@ -120,10 +127,9 @@ GUI dependencies: If you want to build ion-qt, make sure that the required packages for Qt development are installed. Qt 5 is necessary to build the GUI. -If both Qt 4 and Qt 5 are installed, Qt 5 will be used. To build without GUI pass `--without-gui`. -For Qt 5 you need the following: +To build with Qt 5 you need the following: sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler @@ -172,11 +178,11 @@ turned off by default. See the configure options for upnp behavior desired: To build: - tar -xzvf miniupnpc-1.6.tar.gz - cd miniupnpc-1.6 - make - sudo su - make install + tar -xzvf miniupnpc-1.6.tar.gz + cd miniupnpc-1.6 + make + sudo su + make install ## Berkeley DB @@ -202,7 +208,7 @@ If you need to build Boost yourself: ## Security -To help make your ION installation more secure by making certain attacks impossible to +To help make your ION Core installation more secure by making certain attacks impossible to exploit even if a vulnerability is found, binaries are hardened by default. This can be disabled with: @@ -211,15 +217,15 @@ Hardening Flags: ./configure --enable-hardening ./configure --disable-hardening -Hardening enables the following features: +Hardening enables the following features: * _Position Independent Executable_: Build position independent code to take advantage of Address Space Layout Randomization - offered by some kernels. An attacker who is able to cause execution of code at an arbitrary - memory location is thwarted if he doesn't know where anything useful is located. - The stack and heap are randomly located by default but this allows the code section to be + offered by some kernels. Attackers who can cause execution of code at an arbitrary memory + location are thwarted if they don't know where anything useful is located. + The stack and heap are randomly located by default, but this allows the code section to be randomly located as well. - On an Amd64 processor where a library was not compiled with -fPIC, this will cause an error + On an AMD64 processor where a library was not compiled with -fPIC, this will cause an error such as: "relocation R_X86_64_32 against `......' can not be used when making a shared object;" To test that you have built PIE executable, install scanelf, part of paxutils, and use: @@ -227,11 +233,12 @@ Hardening enables the following features: scanelf -e ./iond The output should contain: + TYPE ET_DYN -* _Non-executable Stack_: If the stack is executable then trivial stack based buffer overflow exploits are possible if - vulnerable buffers are found. By default, ion should be built with a non-executable stack +* _Non-executable Stack_: If the stack is executable then trivial stack-based buffer overflow exploits are possible if + vulnerable buffers are found. By default, ION Core should be built with a non-executable stack but if one of the libraries it uses asks for an executable stack or someone makes a mistake and uses a compiler extension which requires an executable stack, it will silently build an executable without the non-executable stack protection. @@ -239,7 +246,8 @@ Hardening enables the following features: To verify that the stack is non-executable after compiling use: `scanelf -e ./iond` - the output should contain: + The output should contain: + STK/REL/PTL RW- R-- RW- @@ -260,4 +268,27 @@ Additional Configure Flags -------------------------- A list of additional configure flags can be displayed with: - ./configure --help \ No newline at end of file + ./configure --help + +ARM Cross-compilation +------------------- +These steps can be performed on, for example, an Ubuntu VM. The depends system +will also work on other Linux distributions, however the commands for +installing the toolchain will be different. + +Make sure you install the build requirements mentioned above. +Then, install the toolchain and curl: + + sudo apt-get install g++-arm-linux-gnueabihf curl + +To build executables for ARM: + + cd depends + make HOST=arm-linux-gnueabihf NO_QT=1 + cd .. + ./autogen.sh + ./configure --prefix=$PWD/depends/arm-linux-gnueabihf --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++ + make + + +For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory. diff --git a/doc/build-windows.md b/doc/build-windows.md index da10d7cf2c77d..2b5ad7fe05c2d 100644 --- a/doc/build-windows.md +++ b/doc/build-windows.md @@ -5,15 +5,15 @@ Below are some notes on how to build Ion Core for Windows. The options known to work for building Ion Core on Windows are: -* On Linux using the [Mingw-w64](https://mingw-w64.org/doku.php) cross compiler tool chain. Ubuntu Bionic 18.04 is required +* On Linux, using the [Mingw-w64](https://mingw-w64.org/doku.php) cross compiler tool chain. Ubuntu Bionic 18.04 is required and is the platform used to build the Ion Core Windows release binaries. -* On Windows using [Windows +* On Windows, using [Windows Subsystem for Linux (WSL)](https://msdn.microsoft.com/commandline/wsl/about) and the Mingw-w64 cross compiler tool chain. Other options which may work, but which have not been extensively tested are (please contribute instructions): -* On Windows using a POSIX compatibility layer application such as [cygwin](http://www.cygwin.com/) or [msys2](http://www.msys2.org/). -* On Windows using a native compiler tool chain such as [Visual Studio](https://www.visualstudio.com). +* On Windows, using a POSIX compatibility layer application such as [cygwin](http://www.cygwin.com/) or [msys2](http://www.msys2.org/). +* On Windows, using a native compiler tool chain such as [Visual Studio](https://www.visualstudio.com). Installing Windows Subsystem for Linux --------------------------------------- @@ -65,11 +65,20 @@ A host toolchain (`build-essential`) is necessary because some dependency packages (such as `protobuf`) need to build host utilities that are used in the build process. -See also: [dependencies.md](dependencies.md). +See [dependencies.md](dependencies.md) for a complete overview. + +If you want to build the windows installer with `make deploy` you need [NSIS](https://nsis.sourceforge.io/Main_Page): + + sudo apt install nsis + +Acquire the source in the usual way: + + git clone https://github.com/cevap/ion.git + cd ion ## Building for 64-bit Windows -The first step is to install the mingw-w64 cross-compilation tool chain. +The first step is to install the mingw-w64 cross-compilation tool chain: sudo apt install g++-mingw-w64-x86-64 @@ -79,18 +88,14 @@ Ubuntu Bionic 18.04 [1](#footnote1): Once the toolchain is installed the build steps are common: -Note that for WSL the Ion Core source path should be somewhere in the default mount file system, for -example /usr/src/ion, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts may fail. -This means you should not use a directory that is located directly on the host Windows file system to perform the build. - -Acquire the source in the usual way: - - git clone https://github.com/cevap/ION.git +Note that for WSL the Ion Core source path MUST be somewhere in the default mount file system, for +example /usr/src/ion, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts will fail. +This means you cannot use a directory that is located directly on the host Windows file system to perform the build. -Once the source code is ready the build steps are below. +Build using: PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var - cd ION/depends/ + cd depends make HOST=x86_64-w64-mingw32 cd .. ./autogen.sh # not required when building from tarball @@ -103,22 +108,14 @@ To build executables for Windows 32-bit, install the following dependencies: sudo apt install g++-mingw-w64-i686 mingw-w64-i686-dev -For Ubuntu Bionic 18.04 and Windows Subsystem for Linux [1](#footnote1): +Ubuntu Bionic 18.04 [1](#footnote1): sudo update-alternatives --config i686-w64-mingw32-g++ # Set the default mingw32 g++ compiler option to posix. -Note that for WSL the Ion Core source path should be somewhere in the default mount file system, for -example /usr/src/ion, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts may fail. -This means you should not use a directory that is located directly on the host Windows file system to perform the build. - -Acquire the source in the usual way: - - git clone https://github.com/cevap/ION.git - -Then build using: +Build using: PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var - cd ION/depends/ + cd depends make HOST=i686-w64-mingw32 cd .. ./autogen.sh # not required when building from tarball @@ -139,12 +136,16 @@ way. This will install to `c:\workspace\ion`, for example: make install DESTDIR=/mnt/c/workspace/ion +You can also create an installer using: + + make deploy + Footnotes --------- -1: Starting from Ubuntu Xenial 16.04 both the 32 and 64 bit Mingw-w64 packages install two different +1: Starting from Ubuntu Xenial 16.04, both the 32 and 64 bit Mingw-w64 packages install two different compiler options to allow a choice between either posix or win32 threads. The default option is win32 threads which is the more efficient since it will result in binary code that links directly with the Windows kernel32.lib. Unfortunately, the headers -required to support win32 threads conflict with some of the classes in the C++11 standard library in particular std::mutex. +required to support win32 threads conflict with some of the classes in the C++11 standard library, in particular std::mutex. It's not possible to build the Ion Core code using the win32 version of the Mingw-w64 cross compilers (at least not without -modifying headers in the Ion Core source code). \ No newline at end of file +modifying headers in the Ion Core source code). diff --git a/doc/dependencies.md b/doc/dependencies.md index d0870ba4c025e..dc6872c09b3fc 100644 --- a/doc/dependencies.md +++ b/doc/dependencies.md @@ -17,9 +17,9 @@ These are the dependencies currently used by Ion Core. You can find instructions | libevent | [2.1.8-stable](https://github.com/libevent/libevent/releases) | 2.0.22 | No | | | | libjpeg | | | | | [Yes](https://github.com/ioncoincore/ion/blob/master/depends/packages/qt.mk#L65) | | libpng | | | | | [Yes](https://github.com/ioncoincore/ion/blob/master/depends/packages/qt.mk#L64) | -| gmp | [6.1.2](https://gmplib.org/download/gmp/) | | No | | | | MiniUPnPc | [2.0.20180203](http://miniupnp.free.fr/files) | | No | | | | OpenSSL | [1.0.1k](https://www.openssl.org/source) | | Yes | | | +| GMP | [6.1.2](https://gmplib.org/download/gmp/) | | No | | | | PCRE | | | | | [Yes](https://github.com/ioncoincore/ion/blob/master/depends/packages/qt.mk#L66) | | protobuf | [2.6.1](https://github.com/google/protobuf/releases) | | No | | | | Python (tests) | | [3.4](https://www.python.org/downloads) | | | | @@ -29,3 +29,17 @@ These are the dependencies currently used by Ion Core. You can find instructions | xkbcommon | | | | | [Yes](https://github.com/ioncoincore/ion/blob/master/depends/packages/qt.mk#L86) (Linux only) | | ZeroMQ | [4.3.1](https://github.com/zeromq/libzmq/releases) | 4.0.0 | No | | | | zlib | [1.2.11](https://zlib.net/) | | | | No | + +Controlling dependencies +------------------------ +Some dependencies are not needed in all configurations. The following are some factors that affect the dependency list. + +#### Options passed to `./configure` +* MiniUPnPc is not needed with `--with-miniupnpc=no`. +* Berkeley DB is not needed with `--disable-wallet`. +* Qt is not needed with `--without-gui`. +* If the qrencode dependency is absent, QR support won't be added. To force an error when that happens, pass `--with-qrencode`. +* ZeroMQ is needed only with the `--with-zmq` option. + +#### Other +* librsvg is only needed if you need to run `make deploy` on (cross-compilation to) macOS. diff --git a/doc/developer-notes.md b/doc/developer-notes.md index cf308a8df5167..c03c9c9c90ee3 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -1,69 +1,134 @@ -# Developer Notes - -Table of Contents ------------------- -- [Developer Notes](#developer-notes) - - [Doxygen comments](#doxygen-comments) - - [Development tips and tricks](#development-tips-and-tricks) - - [compiling for debugging](#compiling-for-debugging) - - [debugging with VSCode](#debugging-with-vscode) - - [debug.log](#debuglog) - - [testnet mode](#testnet-mode) - - [DEBUG_LOCKORDER](#debuglockorder) - - [Locking/mutex usage notes](#lockingmutex-usage-notes) - - [Threads](#threads) - - [Ignoring IDE/editor files](#ignoring-ideeditor-files) -- [Development guidelines](#development-guidelines) - - [General Ion Core](#general-ion-core) - - [Wallet](#wallet) - - [General C++](#general-c) - - [C++ data structures](#c-data-structures) - - [Strings and formatting](#strings-and-formatting) - - [Threads and synchronization](#threads-and-synchronization) - - [Source code organization](#source-code-organization) - - [GUI](#gui) - - [Git and github tips](#git-and-github-tips) +Developer Notes +=============== + + +**Table of Contents** + +- [Developer Notes](#Developer-Notes) + - [Coding Style (General)](#Coding-Style-General) + - [Coding Style (C++)](#Coding-Style-C) + - [Coding Style (Python)](#Coding-Style-Python) + - [Coding Style (Doxygen-compatible comments)](#Coding-Style-Doxygen-compatible-comments) + - [Development tips and tricks](#Development-tips-and-tricks) + - [Compiling for debugging](#Compiling-for-debugging) + - [Compiling for gprof profiling](#Compiling-for-gprof-profiling) + - [debug.log](#debuglog) + - [Testnet and Regtest modes](#Testnet-and-Regtest-modes) + - [DEBUG_LOCKORDER](#DEBUGLOCKORDER) + - [Valgrind suppressions file](#Valgrind-suppressions-file) + - [Compiling for test coverage](#Compiling-for-test-coverage) + - [Locking/mutex usage notes](#Lockingmutex-usage-notes) + - [Threads](#Threads) + - [Ignoring IDE/editor files](#Ignoring-IDEeditor-files) +- [Development guidelines](#Development-guidelines) + - [General ION Core](#General-ION-Core) + - [Wallet](#Wallet) + - [General C++](#General-C) + - [C++ data structures](#C-data-structures) + - [Strings and formatting](#Strings-and-formatting) + - [Variable names](#Variable-names) + - [Threads and synchronization](#Threads-and-synchronization) + - [Scripts](#Scripts) + - [Shebang](#Shebang) + - [Source code organization](#Source-code-organization) + - [GUI](#GUI) + - [Subtrees](#Subtrees) + - [Upgrading LevelDB](#Upgrading-LevelDB) + - [File Descriptor Counts](#File-Descriptor-Counts) + - [Consensus Compatibility](#Consensus-Compatibility) + - [Scripted diffs](#Scripted-diffs) + - [Git and GitHub tips](#Git-and-GitHub-tips) + - [Release notes](#Release-notes) + - [RPC interface guidelines](#RPC-interface-guidelines) + + + +Coding Style (General) +---------------------- Various coding styles have been used during the history of the codebase, and the result is not very consistent. However, we're now trying to converge to -a single style, so please use it in new code. Old code will be converted -gradually. -- Basic rules specified in [src/.clang-format](/src/.clang-format). - Use a recent clang-format to format automatically using one of the [dev scripts] - (/contrib/devtools/README.md#clang-formatpy). - - Braces on new lines for namespaces, classes, functions, methods. +a single style, which is specified below. When writing patches, favor the new +style over attempting to mimic the surrounding style, except for move-only +commits. + +Coding Style (C++) +------------------ + +- **Indentation and whitespace rules** as specified in +[src/.clang-format](/src/.clang-format). You can use the provided +[clang-format-diff script](/contrib/devtools/README.md#clang-format-diffpy) +tool to clean up patches automatically before submission. + - Braces on new lines for classes, functions, methods. - Braces on the same line for everything else. - 4 space indentation (no tabs) for every block except namespaces. - - No indentation for public/protected/private or for namespaces. + - No indentation for `public`/`protected`/`private` or for `namespace`. - No extra spaces inside parenthesis; don't do ( this ) - - No space after function names; one space after if, for and while. + - No space after function names; one space after `if`, `for` and `while`. + - If an `if` only has a single-statement `then`-clause, it can appear + on the same line as the `if`, without braces. In every other case, + braces are required, and the `then` and `else` clauses must appear + correctly indented on a new line. + +- **Symbol naming conventions**. These are preferred in new code, but are not +required when doing so would need changes to significant pieces of existing +code. + - Constant names are all uppercase, and use `_` to separate words. + - Class names, function names and method names are UpperCamelCase + (PascalCase). Do not prefix class names with `C`. + - Test suite naming convention: The Boost test suite in file + `src/test/foo_tests.cpp` should be named `foo_tests`. Test suite names + must be unique. + +- **Miscellaneous** + - `++i` is preferred over `i++`. + - `nullptr` is preferred over `NULL` or `(void*)0`. + - `static_assert` is preferred over `assert` where possible. Generally; compile-time checking is preferred over run-time checking. + - `enum class` is preferred over `enum` where possible. Scoped enumerations avoid two potential pitfalls/problems with traditional C++ enumerations: implicit conversions to int, and name clashes due to enumerators being exported to the surrounding scope. Block style example: ```c++ -namespace foo -{ +int g_count = 0; + +namespace foo { class Class { - bool Function(char* psz, int n) + std::string m_name; + +public: + bool Function(const std::string& s, int n) { // Comment summarising what this section of code does - for (int i = 0; i < n; i++) { + for (int i = 0; i < n; ++i) { + int total_sum = 0; // When something fails, return early - if (!Something()) - return false; + if (!Something()) return false; ... + if (SomethingElse(i)) { + total_sum += ComputeSomething(g_count); + } else { + DoSomething(m_name, total_sum); + } } // Success return is usually at the end return true; } } -} +} // namespace foo ``` -## Doxygen comments +Coding Style (Python) +--------------------- + +Refer to [/test/functional/README.md#style-guidelines](/test/functional/README.md#style-guidelines). -To facilitate the generation of documentation, use doxygen-compatible comment blocks for functions, methods and fields. +Coding Style (Doxygen-compatible comments) +------------------------------------------ + +ION Core uses [Doxygen](http://www.doxygen.nl/) to generate its official documentation. + +Use Doxygen-compatible comment blocks for functions, methods, and fields. For example, to describe a function use: ```c++ @@ -75,7 +140,7 @@ For example, to describe a function use: */ bool function(int arg1, const char *arg2) ``` -A complete list of `@xxx` commands can be found at http://www.stack.nl/~dimitri/doxygen/manual/commands.html. +A complete list of `@xxx` commands can be found at http://www.doxygen.nl/manual/commands.html. As Doxygen recognizes the comments by the delimiters (`/**` and `*/` in this case), you don't *need* to provide any commands for a comment to be valid; just a description text is fine. @@ -96,7 +161,7 @@ int var; //!< Detailed description after the member ``` or -```cpp +```c++ //! Description before the member int var; ``` @@ -116,85 +181,142 @@ Not OK (used plenty in the current source, but not picked up): // ``` -A full list of comment syntaxes picked up by doxygen can be found at http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html, -but if possible use one of the above styles. +A full list of comment syntaxes picked up by Doxygen can be found at http://www.doxygen.nl/manual/docblocks.html, +but the above styles are favored. -## Development tips and tricks +Documentation can be generated with `make docs` and cleaned up with `make clean-docs`. The resulting files are located in `doc/doxygen/html`; open `index.html` to view the homepage. -### compiling for debugging +Before running `make docs`, you will need to install dependencies `doxygen` and `dot`. For example, on MacOS via Homebrew: +``` +brew install doxygen +``` + +Development tips and tricks +--------------------------- -Run configure with the --enable-debug option, then make. Or run configure with -CXXFLAGS="-g -ggdb -O0" or whatever debug flags you need. +### Compiling for debugging -### debugging with VSCode +Run configure with `--enable-debug` to add additional compiler flags that +produce better debugging builds. -For VSCode user we supply debugger config wihtin the repository. By pressing **CTRL+SHIFT+D** (_or debug icon on left_) +### Compiling for gprof profiling -**Note¹**: you have to compile first normally (_not using depends folder_) -**Note²**: _If you use default configs, it automaticly uses ../datadir folder as default folder_ +Run configure with the `--enable-gprof` option, then make. ### debug.log If the code is behaving strangely, take a look in the debug.log file in the data directory; error and debugging messages are written there. -The -debug=... command-line option controls debugging; running with just -debug or -debug=1 will turn +The `-debug=...` command-line option controls debugging; running with just `-debug` or `-debug=1` will turn on all categories (and give you a very large debug.log file). -The Qt code routes qDebug() output to debug.log under category "qt": run with -debug=qt +The Qt code routes `qDebug()` output to debug.log under category "qt": run with `-debug=qt` to see it. -### testnet mode +### Testnet and Regtest modes -Run with the -testnet option to run with "play IONs (tION)" on the test network, if you +Run with the `-testnet` option to run with "play IONs (tION)" on the test network, if you are testing multi-machine code that needs to operate across the internet. +If you are testing something that can run on one machine, run with the `-regtest` option. +In regression test mode, blocks can be created on-demand; see [test/functional/](/test/functional) for tests +that run in `-regtest` mode. + ### DEBUG_LOCKORDER -Ion Core is a multithreaded application, and deadlocks or other multithreading bugs -can be very difficult to track down. Compiling with -DDEBUG_LOCKORDER (configure -CXXFLAGS="-DDEBUG_LOCKORDER -g") inserts run-time checks to keep track of which locks -are held, and adds warnings to the debug.log file if inconsistencies are detected. +ION Core is a multi-threaded application, and deadlocks or other +multi-threading bugs can be very difficult to track down. The `--enable-debug` +configure option adds `-DDEBUG_LOCKORDER` to the compiler flags. This inserts +run-time checks to keep track of which locks are held, and adds warnings to the +debug.log file if inconsistencies are detected. + +### Valgrind suppressions file + +Valgrind is a programming tool for memory debugging, memory leak detection, and +profiling. The repo contains a Valgrind suppressions file +([`valgrind.supp`](https://github.com/cevap/ion/blob/master/contrib/valgrind.supp)) +which includes known Valgrind warnings in our dependencies that cannot be fixed +in-tree. Example use: + +```shell +$ valgrind --suppressions=contrib/valgrind.supp src/test/test_ion +$ valgrind --suppressions=contrib/valgrind.supp --leak-check=full \ + --show-leak-kinds=all src/test/test_ion --log_level=test_suite +$ valgrind -v --leak-check=full src/iond -printtoconsole +``` -## Locking/mutex usage notes +### Compiling for test coverage + +LCOV can be used to generate a test coverage report based upon `make check` +execution. LCOV must be installed on your system (e.g. the `lcov` package +on Debian/Ubuntu). + +To enable LCOV report generation during test runs: + +```shell +./configure --enable-lcov +make +make cov + +# A coverage report will now be accessible at `./test_ion.coverage/index.html`. +``` + +Locking/mutex usage notes +------------------------- The code is multi-threaded, and uses mutexes and the -LOCK/TRY_LOCK macros to protect data structures. +`LOCK` and `TRY_LOCK` macros to protect data structures. -Deadlocks due to inconsistent lock ordering (thread 1 locks cs_main -and then cs_wallet, while thread 2 locks them in the opposite order: -result, deadlock as each waits for the other to release its lock) are -a problem. Compile with -DDEBUG_LOCKORDER to get lock order -inconsistencies reported in the debug.log file. +Deadlocks due to inconsistent lock ordering (thread 1 locks `cs_main` and then +`cs_wallet`, while thread 2 locks them in the opposite order: result, deadlock +as each waits for the other to release its lock) are a problem. Compile with +`-DDEBUG_LOCKORDER` (or use `--enable-debug`) to get lock order inconsistencies +reported in the debug.log file. Re-architecting the core code so there are better-defined interfaces between the various components is a goal, with any necessary locking -done by the components (e.g. see the self-contained CKeyStore class -and its cs_KeyStore lock for example). +done by the components (e.g. see the self-contained `CKeyStore` class +and its `cs_KeyStore` lock for example). -## Threads +Threads +------- - ThreadScriptCheck : Verifies block scripts. + - ThreadImport : Loads blocks from blk*.dat files or bootstrap.dat. + - StartNode : Starts other threads. + - ThreadDNSAddressSeed : Loads addresses of peers from the DNS. + - ThreadMapPort : Universal plug-and-play startup/shutdown + - ThreadSocketHandler : Sends/Receives data from peers on port 8333. + - ThreadOpenAddedConnections : Opens network connections to added nodes. + - ThreadOpenConnections : Initiates new connections to peers. + - ThreadMessageHandler : Higher-level message handling (sending and receiving). + - DumpAddresses : Dumps IP addresses of nodes to peers.dat. + - ThreadFlushWalletDB : Close the wallet.dat file if it hasn't been used in 500ms. + - ThreadRPCServer : Remote procedure call handler, listens on port 8332 for connections and services them. -- BitcoinMiner : Generates bitcoins (if wallet is enabled). + +- IONMiner : Generates IONs (if wallet is enabled). + - Shutdown : Does an orderly shutdown of everything. -## Ignoring IDE/editor files +Ignoring IDE/editor files +-------------------------- In closed-source environments in which everyone uses the same IDE it is common to add temporary files it produces to the project-wide `.gitignore` file. -However, in open source software such as Ion Core, where everyone uses +However, in open source software such as ION Core, where everyone uses their own editors/IDE/tools, it is less common. Only you know what files your editor produces and this may change from version to version. The canonical way to do this is thus to create your local gitignore. Add this to `~/.gitconfig`: @@ -220,13 +342,14 @@ If a set of tools is used by the build system or scripts the repository (for example, lcov) it is perfectly acceptable to add its files to `.gitignore` and commit them. -# Development guidelines - +Development guidelines +============================ A few non-style-related recommendations for developers, as well as points to -pay attention to for reviewers of Ion Core code. +pay attention to for reviewers of ION Core code. -## General Ion Core +General ION Core +---------------------- - New features should be exposed on RPC first, then can be made available in the GUI @@ -242,24 +365,34 @@ pay attention to for reviewers of Ion Core code. - *Explanation*: If the test suite is to be updated for a change, this has to be done first -## Wallet +Wallet +------- - Make sure that no crashes happen with run-time option `-disablewallet`. - *Rationale*: In RPC code that conditionally uses the wallet (such as `validateaddress`) it is easy to forget that global pointer `pwalletMain` - can be NULL. See `qa/rpc-tests/disablewallet.py` for functional tests + can be nullptr. See `test/functional/disablewallet.py` for functional tests exercising the API with `-disablewallet` - Include `db_cxx.h` (BerkeleyDB header) only when `ENABLE_WALLET` is set - *Rationale*: Otherwise compilation of the disable-wallet build will fail in environments without BerkeleyDB -## General C++ +General C++ +------------- + +For general C++ guidelines, you may refer to the [C++ Core +Guidelines](https://isocpp.github.io/CppCoreGuidelines/). + +Common misconceptions are clarified in those sections: + +- Passing (non-)fundamental types in the [C++ Core + Guideline](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-conventional) - Assertions should not have side-effects - - *Rationale*: Even though the source code is set to to refuse to compile + - *Rationale*: Even though the source code is set to refuse to compile with assertions disabled, having side-effects in assertions is unexpected and makes the code harder to understand @@ -274,7 +407,8 @@ pay attention to for reviewers of Ion Core code. - *Rationale*: This avoids memory and resource leaks, and ensures exception safety -## C++ data structures +C++ data structures +-------------------- - Never use the `std::map []` syntax when reading from a map, but instead use `.find()` @@ -294,12 +428,27 @@ pay attention to for reviewers of Ion Core code. - Vector bounds checking is only enabled in debug mode. Do not rely on it -- Make sure that constructors initialize all fields. If this is skipped for a - good reason (i.e., optimization on the critical path), add an explicit - comment about this +- Initialize all non-static class members where they are defined. + If this is skipped for a good reason (i.e., optimization on the critical + path), add an explicit comment about this - *Rationale*: Ensure determinism by avoiding accidental use of uninitialized values. Also, static analyzers balk about this. + Initializing the members in the declaration makes it easy to + spot uninitialized ones. + +```cpp +class A +{ + uint32_t m_count{0}; +} +``` + +- By default, declare single-argument constructors `explicit`. + + - *Rationale*: This is a precaution to avoid unintended conversions that might + arise when single-argument constructors are used as implicit conversion + functions. - Use explicitly signed or unsigned `char`s, or even better `uint8_t` and `int8_t`. Do not use bare `char` unless it is to pass to a third-party API. @@ -312,7 +461,8 @@ pay attention to for reviewers of Ion Core code. - *Rationale*: Easier to understand what is happening, thus easier to spot mistakes, even for those that are not language lawyers -## Strings and formatting +Strings and formatting +------------------------ - Be careful of `LogPrint` versus `LogPrintf`. `LogPrint` takes a `category` argument, `LogPrintf` does not. @@ -327,16 +477,71 @@ pay attention to for reviewers of Ion Core code. - Use `ParseInt32`, `ParseInt64`, `ParseUInt32`, `ParseUInt64`, `ParseDouble` from `utilstrencodings.h` for number parsing - - *Rationale*: These functions do overflow checking, and avoid pesky locale issues + - *Rationale*: These functions do overflow checking, and avoid pesky locale issues. + +- Avoid using locale dependent functions if possible. You can use the provided + [`lint-locale-dependence.sh`](/test/lint/lint-locale-dependence.sh) + to check for accidental use of locale dependent functions. + + - *Rationale*: Unnecessary locale dependence can cause bugs that are very tricky to isolate and fix. + + - These functions are known to be locale dependent: + `alphasort`, `asctime`, `asprintf`, `atof`, `atoi`, `atol`, `atoll`, `atoq`, + `btowc`, `ctime`, `dprintf`, `fgetwc`, `fgetws`, `fprintf`, `fputwc`, + `fputws`, `fscanf`, `fwprintf`, `getdate`, `getwc`, `getwchar`, `isalnum`, + `isalpha`, `isblank`, `iscntrl`, `isdigit`, `isgraph`, `islower`, `isprint`, + `ispunct`, `isspace`, `isupper`, `iswalnum`, `iswalpha`, `iswblank`, + `iswcntrl`, `iswctype`, `iswdigit`, `iswgraph`, `iswlower`, `iswprint`, + `iswpunct`, `iswspace`, `iswupper`, `iswxdigit`, `isxdigit`, `mblen`, + `mbrlen`, `mbrtowc`, `mbsinit`, `mbsnrtowcs`, `mbsrtowcs`, `mbstowcs`, + `mbtowc`, `mktime`, `putwc`, `putwchar`, `scanf`, `snprintf`, `sprintf`, + `sscanf`, `stoi`, `stol`, `stoll`, `strcasecmp`, `strcasestr`, `strcoll`, + `strfmon`, `strftime`, `strncasecmp`, `strptime`, `strtod`, `strtof`, + `strtoimax`, `strtol`, `strtold`, `strtoll`, `strtoq`, `strtoul`, + `strtoull`, `strtoumax`, `strtouq`, `strxfrm`, `swprintf`, `tolower`, + `toupper`, `towctrans`, `towlower`, `towupper`, `ungetwc`, `vasprintf`, + `vdprintf`, `versionsort`, `vfprintf`, `vfscanf`, `vfwprintf`, `vprintf`, + `vscanf`, `vsnprintf`, `vsprintf`, `vsscanf`, `vswprintf`, `vwprintf`, + `wcrtomb`, `wcscasecmp`, `wcscoll`, `wcsftime`, `wcsncasecmp`, `wcsnrtombs`, + `wcsrtombs`, `wcstod`, `wcstof`, `wcstoimax`, `wcstol`, `wcstold`, + `wcstoll`, `wcstombs`, `wcstoul`, `wcstoull`, `wcstoumax`, `wcswidth`, + `wcsxfrm`, `wctob`, `wctomb`, `wctrans`, `wctype`, `wcwidth`, `wprintf` - For `strprintf`, `LogPrint`, `LogPrintf` formatting characters don't need size specifiers - - *Rationale*: Ion Core uses tinyformat, which is type safe. Leave them out to avoid confusion + - *Rationale*: ION Core uses tinyformat, which is type safe. Leave them out to avoid confusion + +Variable names +-------------- -## Threads and synchronization +Although the shadowing warning (`-Wshadow`) is not enabled by default (it prevents issues rising +from using a different variable with the same name), +please name variables so that their names do not shadow variables defined in the source code. + +E.g. in member initializers, prepend `_` to the argument name shadowing the +member name: + +```c++ +class AddressBookPage +{ + Mode m_mode; +} + +AddressBookPage::AddressBookPage(Mode _mode) + : m_mode(_mode) +... +``` + +When using nested cycles, do not name the inner cycle variable the same as in +upper cycle etc. + + +Threads and synchronization +---------------------------- - Build and run tests with `-DDEBUG_LOCKORDER` to verify that no potential - deadlocks are introduced. + deadlocks are introduced. This is defined by default when configuring + with `--enable-debug` - When using `LOCK`/`TRY_LOCK` be aware that the lock exists in the context of the current scope, so surround the statement and the code that needs the lock @@ -360,19 +565,84 @@ TRY_LOCK(cs_vNodes, lockNodes); } ``` -## Source code organization +Scripts +-------------------------- + +### Shebang + +- Use `#!/usr/bin/env bash` instead of obsolete `#!/bin/bash`. + + - [*Rationale*](https://github.com/dylanaraps/pure-bash-bible#shebang): + + `#!/bin/bash` assumes it is always installed to /bin/ which can cause issues; + + `#!/usr/bin/env bash` searches the user's PATH to find the bash binary. + + OK: + +```bash +#!/usr/bin/env bash +``` + + Wrong: + +```bash +#!/bin/bash +``` + +Source code organization +-------------------------- - Implementation code should go into the `.cpp` file and not the `.h`, unless necessary due to template usage or when performance due to inlining is critical - *Rationale*: Shorter and simpler header files are easier to read, and reduce compile time +- Use only the lowercase alphanumerics (`a-z0-9`), underscore (`_`) and hyphen (`-`) in source code filenames. + + - *Rationale*: `grep`:ing and auto-completing filenames is easier when using a consistent + naming pattern. Potential problems when building on case-insensitive filesystems are + avoided when using only lowercase characters in source code filenames. + +- Every `.cpp` and `.h` file should `#include` every header file it directly uses classes, functions or other + definitions from, even if those headers are already included indirectly through other headers. + + - *Rationale*: Excluding headers because they are already indirectly included results in compilation + failures when those indirect dependencies change. Furthermore, it obscures what the real code + dependencies are. + - Don't import anything into the global namespace (`using namespace ...`). Use fully specified types such as `std::string`. - *Rationale*: Avoids symbol conflicts -## GUI +- Terminate namespaces with a comment (`// namespace mynamespace`). The comment + should be placed on the same line as the brace closing the namespace, e.g. + +```c++ +namespace mynamespace { +... +} // namespace mynamespace + +namespace { +... +} // namespace +``` + + - *Rationale*: Avoids confusion about the namespace context + +- Use include guards to avoid the problem of double inclusion. The header file + `foo/bar.h` should use the include guard identifier `BITCOIN_FOO_BAR_H`, e.g. + +```c++ +#ifndef BITCOIN_FOO_BAR_H +#define BITCOIN_FOO_BAR_H +... +#endif // BITCOIN_FOO_BAR_H +``` + +GUI +----- - Do not display or manipulate dialogs in model code (classes `*Model`) @@ -380,14 +650,114 @@ TRY_LOCK(cs_vNodes, lockNodes); should not interact with the user. That's where View classes come in. The converse also holds: try to not directly access core data structures from Views. -### Add/change artworks +Subtrees +---------- + +Several parts of the repository are subtrees of software maintained elsewhere. + +Some of these are maintained by active developers of Bitcoin Core, in which case changes should probably go +directly upstream without being PRed directly against the project. They will be merged back in the next +subtree merge. + +Others are external projects without a tight relationship with our project. Changes to these should also +be sent upstream but bugfixes may also be prudent to PR against ION Core so that they can be integrated +quickly. Cosmetic changes should be purely taken upstream. + +There is a tool in `test/lint/git-subtree-check.sh` to check a subtree directory for consistency with +its upstream repository. + +Current subtrees include: + +- src/leveldb + - Upstream at https://github.com/google/leveldb ; Maintained by Google, but + open important PRs to Core to avoid delay. + - **Note**: Follow the instructions in [Upgrading LevelDB](#upgrading-leveldb) when + merging upstream changes to the LevelDB subtree. + +- src/libsecp256k1 + - Upstream at https://github.com/bitcoin-core/secp256k1/ ; actively maintained by Core contributors. + +- src/univalue + - Upstream at https://github.com/bitcoin-core/univalue ; actively maintained by Core contributors, deviates from upstream https://github.com/jgarzik/univalue + +Upgrading LevelDB +--------------------- + +Extra care must be taken when upgrading LevelDB. This section explains issues +you must be aware of. + +### File Descriptor Counts + +In most configurations we use the default LevelDB value for `max_open_files`, +which is 1000 at the time of this writing. If LevelDB actually uses this many +file descriptors it will cause problems with ION's `select()` loop, because +it may cause new sockets to be created where the fd value is >= 1024. For this +reason, on 64-bit Unix systems we rely on an internal LevelDB optimization that +uses `mmap()` + `close()` to open table files without actually retaining +references to the table file descriptors. If you are upgrading LevelDB, you must +sanity check the changes to make sure that this assumption remains valid. + +In addition to reviewing the upstream changes in `env_posix.cc`, you can use `lsof` to +check this. For example, on Linux this command will show open `.ldb` file counts: + +```bash +$ lsof -p $(pidof iond) |\ + awk 'BEGIN { fd=0; mem=0; } /ldb$/ { if ($4 == "mem") mem++; else fd++ } END { printf "mem = %s, fd = %s\n", mem, fd}' +mem = 119, fd = 0 +``` + +The `mem` value shows how many files are mmap'ed, and the `fd` value shows you +many file descriptors these files are using. You should check that `fd` is a +small number (usually 0 on 64-bit hosts). + +See the notes in the `SetMaxOpenFiles()` function in `dbwrapper.cc` for more +details. + +### Consensus Compatibility + +It is possible for LevelDB changes to inadvertently change consensus +compatibility between nodes. This happened in Bitcoin 0.8 (when LevelDB was +first introduced). When upgrading LevelDB you should review the upstream changes +to check for issues affecting consensus compatibility. + +For example, if LevelDB had a bug that accidentally prevented a key from being +returned in an edge case, and that bug was fixed upstream, the bug "fix" would +be an incompatible consensus change. In this situation the correct behavior +would be to revert the upstream fix before applying the updates to Bitcoin's +copy of LevelDB. In general you should be wary of any upstream changes affecting +what data is returned from LevelDB queries. + +Scripted diffs +-------------- + +For reformatting and refactoring commits where the changes can be easily automated using a bash script, we use +scripted-diff commits. The bash script is included in the commit message and our Travis CI job checks that +the result of the script is identical to the commit. This aids reviewers since they can verify that the script +does exactly what it's supposed to do. It is also helpful for rebasing (since the same script can just be re-run +on the new master commit). + +To create a scripted-diff: -- all artworks must have source as vector graphics - - use only open source software for creation/editing vector graphics (_suggested software for SVG:_ [Inkscape](https://inkscape.org/)) -- format to be used: [SVG](https://www.w3.org/TR/2003/REC-SVG11-20030114/). -- all artworks source must have a license and full metadata and descriptioins +- start the commit message with `scripted-diff:` (and then a description of the diff on the same line) +- in the commit message include the bash script between lines containing just the following text: + - `-BEGIN VERIFY SCRIPT-` + - `-END VERIFY SCRIPT-` -## Git and github tips +The scripted-diff is verified by the tool `test/lint/commit-script-check.sh`. The tool's default behavior when supplied +with a commit is to verify all scripted-diffs from the beginning of time up to said commit. Internally, the tool passes +the first supplied argument to `git rev-list --reverse` to determine which commits to verify script-diffs for, ignoring +commits that don't conform to the commit message format described above. + +For development, it might be more convenient to verify all scripted-diffs in a range `A..B`, for example: + +```bash +test/lint/commit-script-check.sh origin/master..HEAD +``` + +Commit [`bb81e173`](https://github.com/bitcoin/bitcoin/commit/bb81e173) is an example of a scripted-diff. + +Git and GitHub tips +------------- - For resolving merge/rebase conflicts, it can be useful to enable diff3 style using `git config merge.conflictstyle diff3`. Instead of @@ -433,3 +803,104 @@ TRY_LOCK(cs_vNodes, lockNodes); This will add an `upstream-pull` remote to your git repository, which can be fetched using `git fetch --all` or `git fetch upstream-pull`. Afterwards, you can use `upstream-pull/NUMBER/head` in arguments to `git show`, `git checkout` and anywhere a commit id would be acceptable to see the changes from pull request NUMBER. + +Release notes +------------- + +Release notes should be written for any PR that: + +- introduces a notable new feature +- fixes a significant bug +- changes an API or configuration model +- makes any other visible change to the end-user experience. + +Release notes should be added to a PR-specific release note file at +`/doc/release-notes-.md` to avoid conflicts between multiple PRs. +All `release-notes*` files are merged into a single +[/doc/release-notes.md](/doc/release-notes.md) file prior to the release. + +RPC interface guidelines +-------------------------- + +A few guidelines for introducing and reviewing new RPC interfaces: + +- Method naming: use consecutive lower-case names such as `getrawtransaction` and `submitblock` + + - *Rationale*: Consistency with existing interface. + +- Argument naming: use snake case `fee_delta` (and not, e.g. camel case `feeDelta`) + + - *Rationale*: Consistency with existing interface. + +- Use the JSON parser for parsing, don't manually parse integers or strings from + arguments unless absolutely necessary. + + - *Rationale*: Introduces hand-rolled string manipulation code at both the caller and callee sites, + which is error prone, and it is easy to get things such as escaping wrong. + JSON already supports nested data structures, no need to re-invent the wheel. + + - *Exception*: AmountFromValue can parse amounts as string. This was introduced because many JSON + parsers and formatters hard-code handling decimal numbers as floating point + values, resulting in potential loss of precision. This is unacceptable for + monetary values. **Always** use `AmountFromValue` and `ValueFromAmount` when + inputting or outputting monetary values. The only exceptions to this are + `prioritisetransaction` and `getblocktemplate` because their interface + is specified as-is in BIP22. + +- Missing arguments and 'null' should be treated the same: as default values. If there is no + default value, both cases should fail in the same way. The easiest way to follow this + guideline is detect unspecified arguments with `params[x].isNull()` instead of + `params.size() <= x`. The former returns true if the argument is either null or missing, + while the latter returns true if is missing, and false if it is null. + + - *Rationale*: Avoids surprises when switching to name-based arguments. Missing name-based arguments + are passed as 'null'. + +- Try not to overload methods on argument type. E.g. don't make `getblock(true)` and `getblock("hash")` + do different things. + + - *Rationale*: This is impossible to use with `ion-cli`, and can be surprising to users. + + - *Exception*: Some RPC calls can take both an `int` and `bool`, most notably when a bool was switched + to a multi-value, or due to other historical reasons. **Always** have false map to 0 and + true to 1 in this case. + +- Don't forget to fill in the argument names correctly in the RPC command table. + + - *Rationale*: If not, the call can not be used with name-based arguments. + +- Set okSafeMode in the RPC command table to a sensible value: safe mode is when the + blockchain is regarded to be in a confused state, and the client deems it unsafe to + do anything irreversible such as send. Anything that just queries should be permitted. + + - *Rationale*: Troubleshooting a node in safe mode is difficult if half the + RPCs don't work. + +- Add every non-string RPC argument `(method, idx, name)` to the table `vRPCConvertParams` in `rpc/client.cpp`. + + - *Rationale*: `ion-cli` and the GUI debug console use this table to determine how to + convert a plaintext command line to JSON. If the types don't match, the method can be unusable + from there. + +- A RPC method must either be a wallet method or a non-wallet method. Do not + introduce new methods that differ in behavior based on presence of a wallet. + + - *Rationale*: as well as complicating the implementation and interfering + with the introduction of multi-wallet, wallet and non-wallet code should be + separated to avoid introducing circular dependencies between code units. + +- Try to make the RPC response a JSON object. + + - *Rationale*: If a RPC response is not a JSON object then it is harder to avoid API breakage if + new data in the response is needed. + +- Be aware of RPC method aliases and generally avoid registering the same + callback function pointer for different RPCs. + + - *Rationale*: RPC methods registered with the same function pointer will be + considered aliases and only the first method name will show up in the + `help` rpc command list. + + - *Exception*: Using RPC method aliases may be appropriate in cases where a + new RPC is replacing a deprecated RPC, to avoid both RPCs confusingly + showing up in the command list. diff --git a/doc/dnsseed-policy.md b/doc/dnsseed-policy.md index c783c5c1f14fd..cb0706036afdd 100644 --- a/doc/dnsseed-policy.md +++ b/doc/dnsseed-policy.md @@ -19,15 +19,13 @@ As such, DNS seeds must be run by entities which have some minimum level of trust within the ION community. Other implementations of ION software may also use the same -seeds and may be more exposed. In light of this exposure this -document establishes some basic expectations for the expectations -for the operation of dnsseeds. +seeds and may be more exposed. In light of this exposure, this +document establishes some basic expectations for operating dnsseeds. -### 1. A DNS seed operating organization or person is expected -to follow good host security practices and maintain control of -their serving infrastructure and not sell or transfer control of their -DNS seed. Any hosting services contracted by the operator are -equally expected to uphold these expectations. +### 1. A DNS seed operating organization or person is expected to follow good +host security practices, maintain control of applicable infrastructure, +and not sell or transfer control of the DNS seed. Any hosting services +contracted by the operator are equally expected to uphold these expectations. ### 2. The DNS seed results must consist exclusively of fairly selected and functioning ION nodes from the public network to the best of the @@ -41,7 +39,7 @@ urgent technical necessity and disclosed. ### 5. Any logging of DNS queries should be only that which is necessary for the operation of the service or urgent health of the ION -network and must not be retained longer than necessary or disclosed +network and must not be retained longer than necessary nor disclosed to any third party. ### 6. Information gathered as a result of the operators node-spidering diff --git a/doc/files.md b/doc/files.md index 5d3d867176b9f..5618e9c0e0577 100644 --- a/doc/files.md +++ b/doc/files.md @@ -1,39 +1,22 @@ -# Files +Filename | Description +--------------------|---------------------------------------------------------------------------------------------------------------------------- +banlist.dat | stores the IPs/Subnets of banned nodes +ioncoin.conf | contains configuration settings for iond or ion-qt +iond.pid | stores the process id of iond while running +blocks/blk000??.dat | block data (custom, 128 MiB per file); since 0.8.0 +blocks/rev000??.dat | block undo data (custom); since 0.8.0 (format changed since pre-0.8) +blocks/index/* | block index (LevelDB); since 0.8.0 +chainstate/* | blockchain state database (LevelDB); since 0.8.0 +database/* | BDB database environment; only used for wallet since 0.8.0; moved to wallets/ directory on new installs since 0.16.0 +db.log | wallet database log file; moved to wallets/ directory on new installs since 0.16.0 +debug.log | contains debug information and general logging generated by iond or ion-qt +fee_estimates.dat | stores statistics used to estimate minimum transaction fees and priorities required for confirmation; since 0.10.0 +budget.dat | stores data for budget objects +masternode.conf | contains configuration settings for remote masternodes +mncache.dat | stores data for masternode list +mnpayments.dat | stores data for masternode payments +peers.dat | peer IP address database (custom format); since 0.7.0 +wallet.dat | personal wallet (BDB) with keys and transactions; moved to wallets/ directory on new installs since 0.16.0 +.cookie | session RPC authentication cookie (written at start when cookie authentication is used, deleted on shutdown): since 0.12.0 +onion_private_key | cached Tor hidden service private key for `-listenonion`: since 0.12.0 -Table of Contents ------------------- -- [Files](#files) - - [Overview](#overview) - - [Only used in pre-0.8.0](#only-used-in-pre-080) - - [Only used before 0.8.0](#only-used-before-080) - - [Only used before 0.7.0](#only-used-before-070) - - -## Overview -- ioncoin.conf: contains configuration settings for iond or ion-qt -- iond.pid: stores the process id of iond while running -- blocks/blk000??.dat: block data (custom, 128 MiB per file); since 0.8.0 -- blocks/rev000??.dat; block undo data (custom); since 0.8.0 (format changed since pre-0.8) -- blocks/index/*; block index (LevelDB); since 0.8.0 -- chainstate/*; block chain state database (LevelDB); since 0.8.0 -- database/*: BDB database environment; only used for wallet since 0.8.0 -- db.log: wallet database log file -- debug.log: contains debug information and general logging generated by iond or ion-qt -- fee_estimates.dat: stores statistics used to estimate minimum transaction fees and priorities required for confirmation: since 0.10.0 -- budget.dat: stores data for budget objects -- masternode.conf: contains configuration settings for remote masternodes -- mncache.dat: stores data for masternode list -- mnpayments.dat: stores data for masternode payments -- peers.dat: peer IP address database (custom format); since 0.7.0 -- wallet.dat: personal wallet (BDB) with keys and transactions - -## Only used in pre-0.8.0 -- blktree/*; block chain index (LevelDB); since pre-0.8, replaced by blocks/index/* in 0.8.0 -- coins/*; unspent transaction output database (LevelDB); since pre-0.8, replaced by chainstate/* in 0.8.0 - -## Only used before 0.8.0 -- blkindex.dat: block chain index database (BDB); replaced by {chainstate/*,blocks/index/*,blocks/rev000??.dat} in 0.8.0 -- blk000?.dat: block data (custom, 2 GiB per file); replaced by blocks/blk000??.dat in 0.8.0 - -## Only used before 0.7.0 -- addr.dat: peer IP address database (BDB); replaced by peers.dat in 0.7.0 diff --git a/doc/init.md b/doc/init.md index 73065810379be..54084d0ba6e71 100644 --- a/doc/init.md +++ b/doc/init.md @@ -11,24 +11,30 @@ can be found in the contrib/init folder. Table of Contents ----------------- -- [Sample init scripts and service configuration for iond](#sample-init-scripts-and-service-configuration-for-iond) - - [Table of Contents](#table-of-contents) - - [1. Service User](#1-service-user) - - [2. Configuration](#2-configuration) - - [3. Paths](#3-paths) - - [4. Installing Service Configuration](#4-installing-service-configuration) - - [4(a) systemd](#4a-systemd) - - [4(b) OpenRC](#4b-openrc) - - [4(c) Upstart (for Debian/Ubuntu based distributions)](#4c-upstart-for-debianubuntu-based-distributions) - - [4(d) CentOS](#4d-centos) - - [5. Auto-respawn](#5-auto-respawn) +- [Sample init scripts and service configuration for iond](#Sample-init-scripts-and-service-configuration-for-iond) + - [Table of Contents](#Table-of-Contents) + - [1. Service User](#1-Service-User) + - [2. Configuration](#2-Configuration) + - [3. Paths](#3-Paths) + - [Linux](#Linux) + - [macOS](#macOS) + - [4. Installing Service Configuration](#4-Installing-Service-Configuration) + - [systemd](#systemd) + - [OpenRC](#OpenRC) + - [Upstart (for Debian/Ubuntu based distributions)](#Upstart-for-DebianUbuntu-based-distributions) + - [CentOS](#CentOS) + - [macOS](#macOS-1) + - [5. Auto-respawn](#5-Auto-respawn) ## 1. Service User -All three startup configurations assume the existence of a "ion" user + +All three Linux startup configurations assume the existence of a "ion" user and group. They must be created before attempting to use these scripts. +The macOS configuration assumes iond will be set up for the current user. ## 2. Configuration + At a bare minimum, iond requires that the rpcpassword setting be set when running as a daemon. If the configuration file does not exist or this setting is not set, iond will shutdown promptly after startup. @@ -39,25 +45,33 @@ file, however it is recommended that a strong and secure password be used as this password is security critical to securing the wallet should the wallet be enabled. -If iond is run with "-daemon" flag, and no rpcpassword is set, it will -print a randomly generated suitable password to stderr. You can also -generate one from the shell yourself like this: +If iond is run with the "-server" flag (set by default), and no rpcpassword is set, +it will use a special cookie file for authentication. The cookie is generated with random +content when the daemon starts, and deleted when it exits. Read access to this file +controls who can access it through RPC. -bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo' +By default the cookie is stored in the data directory, but it's location can be overridden +with the option '-rpccookiefile'. -Once you have a password in hand, set rpcpassword= in /etc/ioncoin/ioncoin.conf +This allows for running iond without having to do any manual configuration. + +`conf`, `pid`, and `wallet` accept relative paths which are interpreted as +relative to the data directory. `wallet` *only* supports relative paths. For an example configuration file that describes the configuration settings, -see debian/examples/ioncoin.conf. +see contrib/debian/examples/ioncoin.conf. ## 3. Paths + +### Linux + All three configurations assume several paths that might need to be adjusted. Binary: /usr/bin/iond -Configuration file: /etc/ioncoin/ioncoin.conf +Configuration file: /etc/ion/ioncoin.conf Data directory: /var/lib/iond -PID file: /var/run/iond/iond.pid (OpenRC and Upstart) - /var/lib/iond/iond.pid (systemd) +PID file: `/var/run/iond/iond.pid` (OpenRC and Upstart) or `/run/iond/iond.pid` (systemd) +Lock file: `/var/lock/subsys/iond` (CentOS) The configuration file, PID directory (if applicable) and data directory should all be owned by the ion user and group. It is advised for security @@ -65,40 +79,79 @@ reasons to make the configuration file and data directory only readable by the ion user and group. Access to ion-cli and other iond rpc clients can then be controlled by group membership. +NOTE: When using the systemd .service file, the creation of the aforementioned +directories and the setting of their permissions is automatically handled by +systemd. Directories are given a permission of 710, giving the ion group +access to files under it _if_ the files themselves give permission to the +ion group to do so (e.g. when `-sysperms` is specified). This does not allow +for the listing of files under the directory. + +NOTE: It is not currently possible to override `datadir` in +`/etc/ion/ioncoin.conf` with the current systemd, OpenRC, and Upstart init +files out-of-the-box. This is because the command line options specified in the +init files take precedence over the configurations in +`/etc/ion/ioncoin.conf`. However, some init systems have their own +configuration mechanisms that would allow for overriding the command line +options specified in the init files (e.g. setting `BITCOIND_DATADIR` for +OpenRC). + +### macOS + +Binary: `/usr/local/bin/iond` +Configuration file: `~/Library/Application Support/ioncoin/ioncoin.conf` +Data directory: `~/Library/Application Support/ioncoin` +Lock file: `~/Library/Application Support/ioncoin/.lock` + ## 4. Installing Service Configuration -### 4(a) systemd +### systemd -Installing this .service file consists on just copying it to +Installing this .service file consists of just copying it to /usr/lib/systemd/system directory, followed by the command -"systemctl daemon-reload" in order to update running systemd configuration. +`systemctl daemon-reload` in order to update running systemd configuration. + +To test, run `systemctl start iond` and to enable for system startup run +`systemctl enable iond` -To test, run "systemctl start iond" and to enable for system startup run -"systemctl enable iond" +NOTE: When installing for systemd in Debian/Ubuntu the .service file needs to be copied to the /lib/systemd/system directory instead. -### 4(b) OpenRC +### OpenRC Rename iond.openrc to iond and drop it in /etc/init.d. Double check ownership and permissions and make it executable. Test it with -"/etc/init.d/iond start" and configure it to run on startup with -"rc-update add iond" +`/etc/init.d/iond start` and configure it to run on startup with +`rc-update add iond` -### 4(c) Upstart (for Debian/Ubuntu based distributions) +### Upstart (for Debian/Ubuntu based distributions) -Drop iond.conf in /etc/init. Test by running "service iond start" +Upstart is the default init system for Debian/Ubuntu versions older than 15.04. If you are using version 15.04 or newer and haven't manually configured upstart you should follow the systemd instructions instead. + +Drop iond.conf in /etc/init. Test by running `service iond start` it will automatically start on reboot. NOTE: This script is incompatible with CentOS 5 and Amazon Linux 2014 as they -use old versions of Upstart and do not supply the start-stop-daemon uitility. +use old versions of Upstart and do not supply the start-stop-daemon utility. -### 4(d) CentOS +### CentOS -Copy iond.init to /etc/init.d/iond. Test by running "service iond start". +Copy iond.init to /etc/init.d/iond. Test by running `service iond start`. Using this script, you can adjust the path and flags to the iond program by setting the IOND and FLAGS environment variables in the file /etc/sysconfig/iond. You can also use the DAEMONOPTS environment variable here. +### macOS + +Copy org.ion.iond.plist into ~/Library/LaunchAgents. Load the launch agent by +running `launchctl load ~/Library/LaunchAgents/org.ion.iond.plist`. + +This Launch Agent will cause iond to start whenever the user logs in. + +NOTE: This approach is intended for those wanting to run iond as the current user. +You will need to modify org.ion.iond.plist if you intend to use it as a +Launch Daemon with a dedicated ion user. + ## 5. Auto-respawn + Auto respawning is currently only configured for Upstart and systemd. Reasonable defaults have been chosen but YMMV. diff --git a/doc/release-process.md b/doc/release-process.md index f5757891fe769..d652a77bbda2c 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -2,34 +2,65 @@ Table of Contents ----------------- -- [Release Process](#release-process) - - [Table of Contents](#table-of-contents) - - [First time / New builders](#first-time--new-builders) - - [ION maintainers/release engineers, suggestion for writing release notes](#ion-maintainersrelease-engineers-suggestion-for-writing-release-notes) - - [Setup and perform Gitian builds](#setup-and-perform-gitian-builds) - - [Fetch and create inputs: (first time, or when dependency versions change)](#fetch-and-create-inputs-first-time-or-when-dependency-versions-change) - - [Optional: Seed the Gitian sources cache and offline git repositories](#optional-seed-the-gitian-sources-cache-and-offline-git-repositories) - - [Build and sign Ion Core for Linux, Windows, and OS X:](#build-and-sign-ion-core-for-linux-windows-and-os-x) - - [Verify other gitian builders signatures to your own. (Optional)](#verify-other-gitian-builders-signatures-to-your-own-optional) - - [Next steps:](#next-steps) - - [After 3 or more people have gitian-built and their results match:](#after-3-or-more-people-have-gitian-built-and-their-results-match) +- [Release Process](#Release-Process) + - [Table of Contents](#Table-of-Contents) + - [Branch updates](#Branch-updates) + - [Before every release candidate](#Before-every-release-candidate) + - [Before every major and minor release](#Before-every-major-and-minor-release) + - [Before every major release:](#Before-every-major-release) + - [After branch-off (on master)](#After-branch-off-on-master) + - [After branch-off (on the major release branch)](#After-branch-off-on-the-major-release-branch) + - [Before final release](#Before-final-release) + - [Building](#Building) + - [First time / New builders](#First-time--New-builders) + - [ION maintainers/release engineers, suggestion for writing release notes](#ION-maintainersrelease-engineers-suggestion-for-writing-release-notes) + - [Setup and perform Gitian builds](#Setup-and-perform-Gitian-builds) + - [Fetch and create inputs: (first time, or when dependency versions change)](#Fetch-and-create-inputs-first-time-or-when-dependency-versions-change) + - [Optional: Seed the Gitian sources cache and offline git repositories](#Optional-Seed-the-Gitian-sources-cache-and-offline-git-repositories) + - [Build and sign ION Core for Linux, Windows, and macOS:](#Build-and-sign-ION-Core-for-Linux-Windows-and-macOS) + - [Verify other gitian builders signatures to your own. (Optional)](#Verify-other-gitian-builders-signatures-to-your-own-Optional) + - [Next steps:](#Next-steps) + - [After 3 or more people have gitian-built and their results match:](#After-3-or-more-people-have-gitian-built-and-their-results-match) -Before every release candidate: +## Branch updates -- Update translations (ask for more info on discord or support) see [translation_process.md](https://github.com/cevap/ion/blob/master/doc/translation_process.md#synchronising-translations). +### Before every release candidate -Before every minor and major release: +* Update translations (ask for more info on discord or support) see [translation_process.md](https://github.com/cevap/ion/blob/master/doc/translation_process.md#synchronising-translations). +* Update manpages, see [gen-manpages.sh](https://github.com/ion-project/ion/blob/master/contrib/devtools/README.md#gen-manpagessh). -- Update version in `configure.ac` (don't forget to set `CLIENT_VERSION_IS_RELEASE` to `true`) -- Write release notes (see below) +### Before every major and minor release -Before every major release: +* Update version in `configure.ac` (don't forget to set `CLIENT_VERSION_IS_RELEASE` to `true`) +* Write release notes (see below) -- Update hardcoded [seeds](/contrib/seeds/README.md), see [this pull request](https://github.com/bitcoin/bitcoin/pull/7415) for an example. -- Update [`BLOCK_CHAIN_SIZE`](/src/qt/intro.cpp) to the current size plus some overhead. -- Update `src/chainparams.cpp` with statistics about the transaction count and rate. -- Update version of `contrib/gitian-descriptors/*.yml`: usually one'd want to do this on master after branching off the release - but be sure to at least do it before a new major release +### Before every major release: + +* Update hardcoded [seeds](/contrib/seeds/README.md), see [this pull request](https://github.com/bitcoin/bitcoin/pull/7415) for an example. +* Update [`BLOCK_CHAIN_SIZE`](/src/qt/intro.cpp) to the current size plus some overhead. +* Update `src/chainparams.cpp` with statistics about the transaction count and rate. +* On both the master branch and the new release branch: + - update `CLIENT_VERSION_MINOR` in [`configure.ac`](../configure.ac) +* On the new release branch in [`configure.ac`](../configure.ac): + - set `CLIENT_VERSION_REVISION` to `0` + - set `CLIENT_VERSION_IS_RELEASE` to `true` + + +#### After branch-off (on master) + +- Update the version of `contrib/gitian-descriptors/*.yml`. + +#### After branch-off (on the major release branch) + +- Update the versions and the link to the release notes draft in `doc/release-notes.md`. + +#### Before final release + +- Merge the release notes into the branch. +- Ensure the "Needs release note" label is removed from all relevant pull requests and issues. + +## Building ### First time / New builders @@ -47,16 +78,16 @@ Check out the source code in the following directory hierarchy. Write release notes. git shortlog helps a lot, for example: - git shortlog --email --no-merges --format="* [%h] %s" v(current version, e.g. 3.1.00-beta1)..(new version, e.g. v3.1.0-rc1) + git shortlog --email --no-merges --format="* [%h] %s" v(current version, e.g. 3.2.00-beta1)..(new version, e.g. v3.2.0-rc1) Generate list of authors: - git log --format='- %aN <%aE>' v(current version, e.g. 3.1.00-beta1)..(new version, e.g. v3.1.0-rc1) | sort -fiu + git log --format='- %aN <%aE>' v(current version, e.g. 3.1.00-beta1)..(new version, e.g. v3.2.0-rc1) | sort -fiu -Tag version (or release candidate) in git +Tag the version (or release candidate) in git: - git tag -s v(new version, e.g. 3.1.0) + git tag -s v(new version, e.g. 3.2.0) ### Setup and perform Gitian builds @@ -92,11 +123,13 @@ Ensure gitian-builder is up-to-date: wget -P inputs https://github.com/gitianuser/MacOSX-SDKs/releases/download/MacOSX10.11.sdk/MacOSX10.11.sdk.tar.xz popd -Create the OS X SDK tarball, see the [OS X readme](README_osx.md) for details, and copy it into the inputs directory. +Create the macOS SDK tarball, see the [macOS build instructions](build-osx.md#deterministic-macos-dmg-notes) for details, and copy it into the inputs directory. ### Optional: Seed the Gitian sources cache and offline git repositories -By default, Gitian will fetch source files as needed. To cache them ahead of time: +NOTE: Gitian is sometimes unable to download files. If you have errors, try the step below. + +By default, Gitian will fetch source files as needed. To cache them ahead of time, make sure you have checked out the tag you want to build in ion, then: pushd ./gitian-builder make -C ../ion/depends download SOURCES_PATH=`pwd`/cache/common @@ -112,26 +145,22 @@ NOTE: Offline builds must use the --url flag to ensure Gitian fetches only from The gbuild invocations below DO NOT DO THIS by default. -### Build and sign Ion Core for Linux, Windows, and OS X: +### Build and sign ION Core for Linux, Windows, and macOS: pushd ./gitian-builder - ./bin/gbuild --memory 3000 --commit ion=v${VERSION} ../ion/contrib/gitian-descriptors/gitian-linux.yml - ./bin/gsign --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-linux.yml + ./bin/gbuild --num-make 2 --memory 3000 --commit ion=v${VERSION} ../ion/contrib/gitian-descriptors/gitian-linux.yml + ./bin/gsign --signer "$SIGNER" --release ${VERSION}-linux --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-linux.yml mv build/out/ion-*.tar.gz build/out/src/ion-*.tar.gz ../ - ./bin/gbuild --memory 3000 --commit ion=v${VERSION} ../ion/contrib/gitian-descriptors/gitian-win.yml - ./bin/gsign --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-win.yml + ./bin/gbuild --num-make 2 --memory 3000 --commit ion=v${VERSION} ../ion/contrib/gitian-descriptors/gitian-win.yml + ./bin/gsign --signer "$SIGNER" --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-win.yml mv build/out/ion-*-win-unsigned.tar.gz inputs/ion-win-unsigned.tar.gz mv build/out/ion-*.zip build/out/ion-*.exe ../ - ./bin/gbuild --memory 3000 --commit ion=v${VERSION} ../ion/contrib/gitian-descriptors/gitian-osx.yml - ./bin/gsign --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-osx.yml + ./bin/gbuild --num-make 2 --memory 3000 --commit ion=v${VERSION} ../ion/contrib/gitian-descriptors/gitian-osx.yml + ./bin/gsign --signer "$SIGNER" --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-osx.yml mv build/out/ion-*-osx-unsigned.tar.gz inputs/ion-osx-unsigned.tar.gz mv build/out/ion-*.tar.gz build/out/ion-*.dmg ../ - - ./bin/gbuild --memory 3000 --commit ion=v${VERSION} ../ion/contrib/gitian-descriptors/gitian-aarch64.yml - ./bin/gsign --signer $SIGNER --release ${VERSION}-aarch64 --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-aarch64.yml - mv build/out/ion-*.tar.gz build/out/src/ion-*.tar.gz ../ popd Build output expected: @@ -139,7 +168,7 @@ Build output expected: 1. source tarball (`ion-${VERSION}.tar.gz`) 2. linux 32-bit and 64-bit dist tarballs (`ion-${VERSION}-linux[32|64].tar.gz`) 3. windows 32-bit and 64-bit unsigned installers and dist zips (`ion-${VERSION}-win[32|64]-setup-unsigned.exe`, `ion-${VERSION}-win[32|64].zip`) - 4. OS X unsigned installer and dist tarball (`ion-${VERSION}-osx-unsigned.dmg`, `ion-${VERSION}-osx64.tar.gz`) + 4. macOS unsigned installer and dist tarball (`ion-${VERSION}-osx-unsigned.dmg`, `ion-${VERSION}-osx64.tar.gz`) 5. Gitian signatures (in `gitian.sigs/${VERSION}-/(your Gitian key)/`) ### Verify other gitian builders signatures to your own. (Optional) @@ -155,7 +184,6 @@ Verify the signatures ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../ion/contrib/gitian-descriptors/gitian-linux.yml ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../ion/contrib/gitian-descriptors/gitian-win.yml ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../ion/contrib/gitian-descriptors/gitian-osx.yml - ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-aarch64 ../ion/contrib/gitian-descriptors/gitian-aarch64.yml popd ### Next steps: @@ -163,19 +191,18 @@ Verify the signatures Commit your signature to gitian.sigs: pushd gitian.sigs - git add ${VERSION}-linux/${SIGNER} - git add ${VERSION}-win-unsigned/${SIGNER} - git add ${VERSION}-osx-unsigned/${SIGNER} - git add ${VERSION}-aarch64/${SIGNER} + git add ${VERSION}-linux/"${SIGNER}" + git add ${VERSION}-win-unsigned/$"${SIGNER}" + git add ${VERSION}-osx-unsigned/"${SIGNER}" git commit -a git push # Assuming you can push to the gitian.sigs tree popd -Codesigner only: Create Windows/OS X detached signatures: +Codesigner only: Create Windows/macOS detached signatures: - Only one person handles codesigning. Everyone else should skip to the next step. -- Only once the Windows/OS X builds each have 3 matching signatures may they be signed with their respective release keys. +- Only once the Windows/macOS builds each have 3 matching signatures may they be signed with their respective release keys. -Codesigner only: Sign the osx binary: +Codesigner only: Sign the macOS binary: transfer ion-osx-unsigned.tar.gz to osx for signing tar xf ion-osx-unsigned.tar.gz @@ -202,16 +229,16 @@ Codesigner only: Commit the detached codesign payloads: git tag -s v${VERSION} HEAD git push the current branch and new tag -Non-codesigners: wait for Windows/OS X detached signatures: +Non-codesigners: wait for Windows/macOS detached signatures: -- Once the Windows/OS X builds each have 3 matching signatures, they will be signed with their respective release keys. +- Once the Windows/macOS builds each have 3 matching signatures, they will be signed with their respective release keys. - Detached signatures will then be committed to the [ion-detached-sigs](https://github.com/gitianuser/ion-detached-sigs) repository, which can be combined with the unsigned apps to create signed binaries. -Create (and optionally verify) the signed OS X binary: +Create (and optionally verify) the signed macOS binary: pushd ./gitian-builder ./bin/gbuild -i --commit signature=v${VERSION} ../ion/contrib/gitian-descriptors/gitian-osx-signer.yml - ./bin/gsign --signer $SIGNER --release ${VERSION}-osx-signed --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-osx-signer.yml + ./bin/gsign --signer "$SIGNER" --release ${VERSION}-osx-signed --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-osx-signer.yml ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../ion/contrib/gitian-descriptors/gitian-osx-signer.yml mv build/out/ion-osx-signed.dmg ../ion-${VERSION}-osx.dmg popd @@ -220,18 +247,18 @@ Create (and optionally verify) the signed Windows binaries: pushd ./gitian-builder ./bin/gbuild -i --commit signature=v${VERSION} ../ion/contrib/gitian-descriptors/gitian-win-signer.yml - ./bin/gsign --signer $SIGNER --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-win-signer.yml + ./bin/gsign --signer "$SIGNER" --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../ion/contrib/gitian-descriptors/gitian-win-signer.yml ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-signed ../ion/contrib/gitian-descriptors/gitian-win-signer.yml mv build/out/ion-*win64-setup.exe ../ion-${VERSION}-win64-setup.exe mv build/out/ion-*win32-setup.exe ../ion-${VERSION}-win32-setup.exe popd -Commit your signature for the signed OS X/Windows binaries: +Commit your signature for the signed macOS/Windows binaries: pushd gitian.sigs - git add ${VERSION}-osx-signed/${SIGNER} - git add ${VERSION}-win-signed/${SIGNER} - git commit -a + git add ${VERSION}-osx-signed/"${SIGNER}" + git add ${VERSION}-win-signed/"${SIGNER}" + git commit -m "Add ${SIGNER} ${VERSION} signed binaries signatures" git push # Assuming you can push to the gitian.sigs tree popd @@ -248,6 +275,7 @@ The list of files should be: ion-${VERSION}-aarch64-linux-gnu.tar.gz ion-${VERSION}-arm-linux-gnueabihf.tar.gz ion-${VERSION}-i686-pc-linux-gnu.tar.gz +ion-${VERSION}-riscv64-linux-gnu.tar.gz ion-${VERSION}-x86_64-linux-gnu.tar.gz ion-${VERSION}-osx64.tar.gz ion-${VERSION}-osx.dmg @@ -261,7 +289,7 @@ The `*-debug*` files generated by the gitian build contain debug symbols for troubleshooting by developers. It is assumed that anyone that is interested in debugging can run gitian to generate the files for themselves. To avoid end-user confusion about which file to pick, as well as save storage -space *do not upload these to the ioncoin.org server*. +space *do not upload these to github*. - GPG-sign it, delete the unsigned file: ``` diff --git a/doc/tor.md b/doc/tor.md index 49146a6a24f1d..c9308f06e01e5 100644 --- a/doc/tor.md +++ b/doc/tor.md @@ -2,12 +2,14 @@ Table of Contents ----------------- -- [TOR SUPPORT IN ION](#tor-support-in-ion) - - [Run ION behind a Tor proxy](#run-ion-behind-a-tor-proxy) - - [Run a ION hidden server](#run-a-ion-hidden-server) - - [List of known ION Tor relays](#list-of-known-ion-tor-relays) +- [TOR SUPPORT IN ION](#TOR-SUPPORT-IN-ION) + - [Table of Contents](#Table-of-Contents) + - [Run ION Core behind a Tor proxy](#Run-ION-Core-behind-a-Tor-proxy) + - [Run a ION Core hidden server](#Run-a-ION-Core-hidden-server) + - [3. Automatically listen on Tor](#3-Automatically-listen-on-Tor) + - [4. Privacy recommendations](#4-Privacy-recommendations) -It is possible to run ION as a Tor hidden service, and connect to such services. +It is possible to run ION Core as a Tor hidden service, and connect to such services. The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others @@ -16,103 +18,124 @@ port. See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.htm for how to properly configure Tor. -## Run ION behind a Tor proxy -The first step is running ION behind a Tor proxy. This will already make all -outgoing connections be anonymized, but more is possible. -``` --proxy=ip:port Set the proxy server. If SOCKS5 is selected (default), this proxy - server will be used to try to reach .onion addresses as well. +## Run ION Core behind a Tor proxy --onion=ip:port Set the proxy server to use for tor hidden services. You do not - need to set this if it's the same as -proxy. You can use -noonion - to explicitly disable access to hidden service. +The first step is running ION Core behind a Tor proxy. This will already make all +outgoing connections be anonymized, but more is possible. + -proxy=ip:port Set the proxy server. If SOCKS5 is selected (default), this proxy + server will be used to try to reach .onion addresses as well. --listen When using -proxy, listening is disabled by default. If you want - to run a hidden service (see next section), you'll need to enable - it explicitly. + -onion=ip:port Set the proxy server to use for Tor hidden services. You do not + need to set this if it's the same as -proxy. You can use -noonion + to explicitly disable access to hidden services. --connect=X When behind a Tor proxy, you can specify .onion addresses instead --addnode=X of IP addresses or hostnames in these parameters. It requires --seednode=X SOCKS5. In Tor mode, such addresses can also be exchanged with - other P2P nodes. + -listen When using -proxy, listening is disabled by default. If you want + to run a hidden service (see next section), you'll need to enable + it explicitly. --onlynet=tor Only connect to .onion nodes and drop IPv4/6 connections. -``` + -connect=X When behind a Tor proxy, you can specify .onion addresses instead + -addnode=X of IP addresses or hostnames in these parameters. It requires + -seednode=X SOCKS5. In Tor mode, such addresses can also be exchanged with + other P2P nodes. -An example how to start the client if the Tor proxy is running on local host on -port 9050 and only allows .onion nodes to connect: -``` -./iond -onion=127.0.0.1:9050 -onlynet=tor -listen=0 -addnode=dnetzj6l4cvo2fxy.onion:989 -``` + -onlynet=onion Make outgoing connections only to .onion addresses. Incoming + connections are not affected by this option. This option can be + specified multiple times to allow multiple network types, e.g. + ipv4, ipv6, or onion. In a typical situation, this suffices to run behind a Tor proxy: -``` -./iond -proxy=127.0.0.1:9050 -``` -## Run a ION hidden server + ./iond -proxy=127.0.0.1:9050 + + +## Run a ION Core hidden server + If you configure your Tor system accordingly, it is possible to make your node also reachable from the Tor network. Add these lines to your /etc/tor/torrc (or equivalent -config file): -``` -ClientOnly 1 -SOCKSPort 9050 -SOCKSPolicy accept 127.0.0.1/8 -Log notice file /var/log/tor/notices.log -ControlPort 9051 -HiddenServiceDir /var/lib/tor/dnet/ -HiddenServicePort 989 127.0.0.1:12700 -HiddenServiceStatistics 0 -ORPort 9001 -LongLivedPorts 989 -ExitPolicy reject *:* -DisableDebuggerAttachment 0 -NumEntryGuards 8 -``` +config file): *Needed for Tor version 0.2.7.0 and older versions of Tor only. For newer +versions of Tor see [Section 3](#3-automatically-listen-on-tor).* + + HiddenServiceDir /var/lib/tor/ion-service/ + HiddenServicePort 12700 127.0.0.1:12700 The directory can be different of course, but (both) port numbers should be equal to -your iond's P2P listen port (12700 by default). -``` --externalip=X You can tell ion about its publicly reachable address using - this option, and this can be a .onion address. Given the above - configuration, you can find your onion address in - /var/lib/tor/ion-service/hostname. Onion addresses are given - preference for your node to advertize itself with, for connections - coming from unroutable addresses (such as 127.0.0.1, where the - Tor proxy typically runs). - --listen You'll need to enable listening for incoming connections, as this - is off by default behind a proxy. - --discover When -externalip is specified, no attempt is made to discover local - IPv4 or IPv6 addresses. If you want to run a dual stack, reachable - from both Tor and IPv4 (or IPv6), you'll need to either pass your - other addresses using -externalip, or explicitly enable -discover. - Note that both addresses of a dual-stack system may be easily - linkable using traffic analysis. -``` +your iond's P2P listen port (51472 by default). + + -externalip=X You can tell ion about its publicly reachable address using + this option, and this can be a .onion address. Given the above + configuration, you can find your .onion address in + /var/lib/tor/ion-service/hostname. For connections + coming from unroutable addresses (such as 127.0.0.1, where the + Tor proxy typically runs), .onion addresses are given + preference for your node to advertise itself with. + + -listen You'll need to enable listening for incoming connections, as this + is off by default behind a proxy. + + -discover When -externalip is specified, no attempt is made to discover local + IPv4 or IPv6 addresses. If you want to run a dual stack, reachable + from both Tor and IPv4 (or IPv6), you'll need to either pass your + other addresses using -externalip, or explicitly enable -discover. + Note that both addresses of a dual-stack system may be easily + linkable using traffic analysis. In a typical situation, where you're only reachable via Tor, this should suffice: -``` -./iond -proxy=127.0.0.1:9050 -externalip=dnetzj6l4cvo2fxy.onion:989 -listen -``` -(obviously, replace the Onion address with your own). If you don't care too much -about hiding your node, and want to be reachable on IPv4 as well, additionally -specify: -``` -./iond ... -discover -``` + ./iond -proxy=127.0.0.1:9050 -externalip=ionvj7kcklujarx.onion:12700 -listen -and open port 12700 on your firewall (or use -upnp). +(obviously, replace the .onion address with your own). It should be noted that you still +listen on all devices and another node could establish a clearnet connection, when knowing +your address. To mitigate this, additionally bind the address of your Tor proxy: -If you only want to use Tor to reach onion addresses, but not use it as a proxy + ./iond ... -bind=127.0.0.1 + +If you don't care too much about hiding your node, and want to be reachable on IPv4 +as well, use `discover` instead: + + ./iond ... -discover + +and open port 51472 on your firewall (or use -upnp). + +If you only want to use Tor to reach .onion addresses, but not use it as a proxy for normal IPv4/IPv6 communication, use: -``` -./iond -onion=127.0.0.1:9050 -externalip=dnetzj6l4cvo2fxy.onion:989 -discover -``` - -## List of known ION Tor relays -``` -COMMING SOON -``` + + ./iond -onion=127.0.0.1:9050 -externalip=ionvj7kcklujarx.onion:12700 -discover + +## 3. Automatically listen on Tor + +Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket +API, to create and destroy 'ephemeral' hidden services programmatically. +ION Core has been updated to make use of this. + +This means that if Tor is running (and proper authentication has been configured), +ION Core automatically creates a hidden service to listen on. This will positively +affect the number of available .onion nodes. + +This new feature is enabled by default if ION Core is listening (`-listen`), and +requires a Tor connection to work. It can be explicitly disabled with `-listenonion=0` +and, if not disabled, configured using the `-torcontrol` and `-torpassword` settings. +To show verbose debugging information, pass `-debug=tor`. + +Connecting to Tor's control socket API requires one of two authentication methods to be +configured. It also requires the control socket to be enabled, e.g. put `ControlPort 9051` +in `torrc` config file. For cookie authentication the user running iond must have read +access to the `CookieAuthFile` specified in Tor configuration. In some cases this is +preconfigured and the creation of a hidden service is automatic. If permission problems +are seen with `-debug=tor` they can be resolved by adding both the user running Tor and +the user running iond to the same group and setting permissions appropriately. On +Debian-based systems the user running iond can be added to the debian-tor group, +which has the appropriate permissions. + +An alternative authentication method is the use +of the `-torpassword=password` option. The `password` is the clear text form that +was used when generating the hashed password for the `HashedControlPassword` option +in the tor configuration file. The hashed password can be obtained with the command +`tor --hash-password password` (read the tor manual for more details). + +## 4. Privacy recommendations + +- Do not add anything but ION Core ports to the hidden service created in section 2. + If you run a web service too, create a new hidden service for that. + Otherwise it is trivial to link them, which may reduce privacy. Hidden + services created automatically (as in section 3) always have only one port + open. diff --git a/doc/translation_process.md b/doc/translation_process.md index 9479b505c92ef..e28ada3dbd0b2 100644 --- a/doc/translation_process.md +++ b/doc/translation_process.md @@ -2,20 +2,18 @@ Table of Contents ----------------- -- [Translations](#translations) - - [Table of Contents](#table-of-contents) - - [Helping to translate (using Transifex)](#helping-to-translate-using-transifex) - - [Writing code with translations](#writing-code-with-translations) - - [Example Qt translation](#example-qt-translation) - - [Creating a pull-request](#creating-a-pull-request) - - [Creating a Transifex account](#creating-a-transifex-account) - - [Installing the Transifex client command-line tool](#installing-the-transifex-client-command-line-tool) - - [For Linux and Mac](#for-linux-and-mac) - - [For Windows](#for-windows) - - [Synchronising translations](#synchronising-translations) - - [Handling Plurals (in source files)](#handling-plurals-in-source-files) - - [Translating a new language](#translating-a-new-language) - - [Questions and general assistance](#questions-and-general-assistance) +- [Translations](#Translations) + - [Table of Contents](#Table-of-Contents) + - [Helping to translate (using Transifex)](#Helping-to-translate-using-Transifex) + - [Writing code with translations](#Writing-code-with-translations) + - [Example Qt translation](#Example-Qt-translation) + - [Creating a pull-request](#Creating-a-pull-request) + - [Creating a Transifex account](#Creating-a-Transifex-account) + - [Installing the Transifex client command-line tool](#Installing-the-Transifex-client-command-line-tool) + - [Synchronising translations](#Synchronising-translations) + - [Handling Plurals (in source files)](#Handling-Plurals-in-source-files) + - [Translating a new language](#Translating-a-new-language) + - [Questions and general assistance](#Questions-and-general-assistance) The Ion Core project has been designed to support multiple localisations. This makes adding new phrases, and completely new languages easily achievable. For managing all application translations, Ion Core makes use of the Transifex online translation management tool. @@ -62,13 +60,11 @@ Visit the [Transifex Signup](https://www.transifex.com/signup/) page to create a You can find the ION translation project at [https://www.transifex.com/ioncoincore/ioncore/](https://www.transifex.com/ioncoincore/ioncore/). ### Installing the Transifex client command-line tool -The client it used to fetch updated translations. If you are having problems, or need more details, see [http://docs.transifex.com/developer/client/setup](http://docs.transifex.com/developer/client/setup) - -#### For Linux and Mac +The client it used to fetch updated translations. If you are having problems, or need more details, see [https://docs.transifex.com/client/installing-the-client](https://docs.transifex.com/client/installing-the-client) `pip install transifex-client` -Setup your transifex client config as follows. Please *ignore the token field*. +Setup your Transifex client config as follows. Please *ignore the token field*. ```ini nano ~/.transifexrc @@ -80,21 +76,21 @@ token = username = USERNAME ``` -#### For Windows - -Please see [http://docs.transifex.com/developer/client/setup#windows](http://docs.transifex.com/developer/client/setup#windows) for details on installation. - -The Transifex ION project config file is included as part of the repo. It can be found at `.tx/config`, however you shouldn’t need change anything. +The Transifex ION project config file is included as part of the repo. It can be found at `.tx/config`, however you shouldn’t need to change anything. ### Synchronising translations To assist in updating translations, we have created a script to help. 1. `python contrib/devtools/update-translations.py` -2. Update `src/qt/ion_locale.qrc` manually or via - `ls src/qt/locale/*ts|xargs -n1 basename|sed 's/\(ion_\(.*\)\).ts/locale\/\1.qm<\/file>/'` -3. Update `src/Makefile.qt.include` manually or via - `ls src/qt/locale/*ts|xargs -n1 basename|sed 's/\(ion_\(.*\)\).ts/ qt\/locale\/\1.ts \\/'` -4. `git add` new translations from `src/qt/locale/` +2. `git add` new translations from `src/qt/locale/` +3. Update `src/qt/ion_locale.qrc` manually or via +```bash +git ls-files src/qt/locale/*ts|xargs -n1 basename|sed 's/\(ion_\(.*\)\).ts/locale\/\1.qm<\/file>/' +``` +4. Update `src/Makefile.qt.include` manually or via +```bash +git ls-files src/qt/locale/*ts|xargs -n1 basename|sed 's/\(ion_\(.*\)\).ts/ qt\/locale\/\1.ts \\/' +``` **Do not directly download translations** one by one from the Transifex website, as we do a few post-processing steps before committing the translations. diff --git a/doc/translation_strings_policy.md b/doc/translation_strings_policy.md new file mode 100644 index 0000000000000..7f380b471a3ec --- /dev/null +++ b/doc/translation_strings_policy.md @@ -0,0 +1,99 @@ +Translation Strings Policy +=========================== + +This document provides guidelines for internationalization of the ION Core software. + +How to translate? +------------------ + +To mark a message as translatable + +- In GUI source code (under `src/qt`): use `tr("...")` + +- In non-GUI source code (under `src`): use `_("...")` + +No internationalization is used for e.g. developer scripts outside `src`. + +Strings to be translated +------------------------- + +On a high level, these strings are to be translated: + +- GUI strings, anything that appears in a dialog or window + +### GUI strings + +Anything that appears to the user in the GUI is to be translated. This includes labels, menu items, button texts, tooltips and window titles. +This includes messages passed to the GUI through the UI interface through `InitMessage`, `ThreadSafeMessageBox` or `ShowProgress`. + +General recommendations +------------------------ + +### Avoid unnecessary translation strings + +Try not to burden translators with translating messages that are e.g. slight variations of other messages. +In the GUI, avoid the use of text where an icon or symbol will do. +Make sure that placeholder texts in forms do not end up in the list of strings to be translated (use ``). + +### Make translated strings understandable + +Try to write translation strings in an understandable way, for both the user and the translator. Avoid overly technical or detailed messages. + +### Do not translate internal errors + +Do not translate internal errors, log messages, or messages that appear on the RPC interface. If an error is to be shown to the user, +use a translatable generic message, then log the detailed message to the log. E.g., "A fatal internal error occurred, see debug.log for details". +This helps troubleshooting; if the error is the same for everyone, the likelihood is increased that it can be found using a search engine. + +### Avoid fragments + +Avoid dividing up a message into fragments. Translators see every string separately, so they may misunderstand the context if the messages are not self-contained. + +### Avoid HTML in translation strings + +There have been difficulties with the use of HTML in translation strings; translators should not be able to accidentally affect the formatting of messages. +This may sometimes be at conflict with the recommendation in the previous section. + +### Plurals + +Plurals can be complex in some languages. A quote from the gettext documentation: + + In Polish we use e.g. plik (file) this way: + 1 plik, + 2,3,4 pliki, + 5-21 pliko'w, + 22-24 pliki, + 25-31 pliko'w + and so on + +In Qt code, use tr's third argument for optional plurality. For example: + + tr("%n hour(s)","",secs/HOUR_IN_SECONDS); + tr("%n day(s)","",secs/DAY_IN_SECONDS); + tr("%n week(s)","",secs/WEEK_IN_SECONDS); + +This adds ``s to the respective `.ts` file, which can be translated separately depending on the language. In English, this is simply: + + + %n active connection(s) to ION network + + %n active connection to ION network + %n active connections to ION network + + + +Where possible, try to avoid embedding numbers into the flow of the string at all. E.g., + + WARNING: check your network connection, %d blocks received in the last %d hours (%d expected) + +versus + + WARNING: check your network connection, less blocks (%d) were received in the last %n hours than expected (%d). + +The second example reduces the number of pluralized words that translators have to handle from three to one, at no cost to comprehensibility of the sentence. + +### String freezes + +During a string freeze (often before a major release), no translation strings are to be added, modified or removed. + +This can be checked by executing `make translate` in the `src` directory, then verifying that `ion_en.ts` remains unchanged. diff --git a/doc/unit-tests.md b/doc/unit-tests.md deleted file mode 100644 index a647e75088aec..0000000000000 --- a/doc/unit-tests.md +++ /dev/null @@ -1,16 +0,0 @@ -## Compiling/running unit tests -Unit tests will be automatically compiled if dependencies were met in configure -and tests weren't explicitly disabled. - -After configuring, they can be run with 'make check'. - -To run the iond tests manually, launch src/test/test_ion . - -To add more iond tests, add `BOOST_AUTO_TEST_CASE` functions to the existing -.cpp files in the test/ directory or add new .cpp files that -implement new BOOST_AUTO_TEST_SUITE sections. - -To run the ion-qt tests manually, launch src/qt/test/ion-qt_test - -To add more ion-qt tests, add them to the `src/qt/test/` directory and -the `src/qt/test/test_main.cpp` file. diff --git a/doc/zmq.md b/doc/zmq.md index 98a5b8bc4f37f..e317e0d1b0698 100644 --- a/doc/zmq.md +++ b/doc/zmq.md @@ -1,12 +1,13 @@ -# Block and Transaction Broadcasting With ZeroMQ +# Block and Transaction Broadcasting with ZeroMQ Table of Contents ----------------- -- [Block and Transaction Broadcasting With ZeroMQ](#block-and-transaction-broadcasting-with-zeromq) - - [Prerequisites](#prerequisites) - - [Enabling](#enabling) - - [Usage](#usage) - - [Remarks](#remarks) +- [Block and Transaction Broadcasting with ZeroMQ](#Block-and-Transaction-Broadcasting-with-ZeroMQ) + - [Table of Contents](#Table-of-Contents) + - [Prerequisites](#Prerequisites) + - [Enabling](#Enabling) + - [Usage](#Usage) + - [Remarks](#Remarks) [ZeroMQ](http://zeromq.org/) is a lightweight wrapper around TCP connections, inter-process communication, and shared-memory, @@ -41,12 +42,14 @@ buffering or reassembly. ## Prerequisites -The ZeroMQ feature in Ion Core requires ZeroMQ API version 4.x or -newer. Typically, it is packaged by distributions as something like +The ZeroMQ feature in ION Core requires the ZeroMQ API >= 4.0.0 +[libzmq](https://github.com/zeromq/libzmq/releases). +For version information, see [dependencies.md](dependencies.md). +Typically, it is packaged by distributions as something like *libzmq3-dev*. The C++ wrapper for ZeroMQ is *not* needed. In order to run the example Python client scripts in contrib/ one must -also install *python-zmq*, though this is not necessary for daemon +also install *python3-zmq*, though this is not necessary for daemon operation. ## Enabling @@ -58,7 +61,7 @@ during the *configure* step of building iond: $ ./configure --disable-zmq (other options) To actually enable operation, one must set the appropriate options on -the commandline or in the configuration file. +the command line or in the configuration file. ## Usage @@ -111,6 +114,6 @@ and just the tip will be notified. It is up to the subscriber to retrieve the chain from the last known block to the new tip. There are several possibilities that ZMQ notification can get lost -during transmission depending on the communication type your are +during transmission depending on the communication type you are using. iond appends an up-counting sequence number to each notification which allows listeners to detect lost notifications. diff --git a/src/Makefile.am b/src/Makefile.am index f1aa2e84b460a..cc1cfedf5d1e8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -168,7 +168,7 @@ BITCOIN_CORE_H = \ torcontrol.h \ txdb.h \ txmempool.h \ - ui_interface.h \ + guiinterface.h \ uint256.h \ undo.h \ util.h \ @@ -191,6 +191,7 @@ BITCOIN_CORE_H = \ xion/zerocoin.h \ xion/xiontracker.h \ xion/xionwallet.h \ + xion/xionmodule.h \ genwit.h \ concurrentqueue.h \ lightxionthread.h \ @@ -287,6 +288,7 @@ libbitcoin_wallet_a_SOURCES = \ xion/xiontracker.cpp \ stakeinput.cpp \ genwit.cpp \ + xion/xionmodule.cpp \ lightxionthread.cpp \ $(BITCOIN_CORE_H) @@ -342,6 +344,7 @@ libzerocoin_libbitcoin_zerocoin_a_SOURCES = \ libzerocoin/SerialNumberSignatureOfKnowledge.h \ libzerocoin/SpendType.h \ libzerocoin/ZerocoinDefines.h \ + libzerocoin/bignum.cpp \ libzerocoin/Accumulator.cpp \ libzerocoin/AccumulatorProofOfKnowledge.cpp \ libzerocoin/Coin.cpp \ @@ -351,6 +354,12 @@ libzerocoin_libbitcoin_zerocoin_a_SOURCES = \ libzerocoin/ParamGeneration.cpp \ libzerocoin/Params.cpp \ libzerocoin/SerialNumberSignatureOfKnowledge.cpp +if USE_NUM_GMP + libzerocoin_libbitcoin_zerocoin_a_SOURCES += libzerocoin/bignum_gmp.cpp +endif +if USE_NUM_OPENSSL + libzerocoin_libbitcoin_zerocoin_a_SOURCES += libzerocoin/bignum_openssl.cpp +endif # common: shared between iond, and ion-qt and non-server tools libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) @@ -532,10 +541,16 @@ CLEANFILES = $(EXTRA_LIBRARIES) CLEANFILES += *.gcda *.gcno CLEANFILES += compat/*.gcda compat/*.gcno CLEANFILES += crypto/*.gcda crypto/*.gcno +CLEANFILES += libzerocoin/*.gcda libzerocoin/*.gcno CLEANFILES += primitives/*.gcda primitives/*.gcno +CLEANFILES += rpc/*.gcda rpc/*.gcno CLEANFILES += script/*.gcda script/*.gcno +CLEANFILES += support/*.gcda support/*.gcno CLEANFILES += univalue/*.gcda univalue/*.gcno +CLEANFILES += wallet/*.gcda wallet/*.gcno +CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno CLEANFILES += zmq/*.gcda zmq/*.gcno +CLEANFILES += xion/*.gcda xion/*.gcno CLEANFILES += obj/build.h EXTRA_DIST = @@ -563,13 +578,13 @@ clean-local: check-symbols: $(bin_PROGRAMS) if GLIBC_BACK_COMPAT @echo "Checking glibc back compat..." - $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS) + $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS) endif check-security: $(bin_PROGRAMS) if HARDEN @echo "Checking binary security..." - $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) + $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS) endif %.pb.cc %.pb.h: %.proto diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 6955d65c601cb..4fca10e893a6e 100755 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -47,7 +47,6 @@ QT_FORMS_UI = \ qt/forms/bip38tooldialog.ui \ qt/forms/coincontroldialog.ui \ qt/forms/blockexplorer.ui \ - qt/forms/obfuscationconfig.ui \ qt/forms/editaddressdialog.ui \ qt/forms/governancepage.ui \ qt/forms/helpmessagedialog.ui \ @@ -83,7 +82,6 @@ QT_MOC_CPP = \ qt/moc_coincontroldialog.cpp \ qt/moc_coincontroltreewidget.cpp \ qt/moc_csvmodelwriter.cpp \ - qt/moc_obfuscationconfig.cpp \ qt/moc_editaddressdialog.cpp \ qt/moc_governancepage.cpp \ qt/moc_guiutil.cpp \ @@ -159,7 +157,6 @@ BITCOIN_QT_H = \ qt/coincontroldialog.h \ qt/coincontroltreewidget.h \ qt/csvmodelwriter.h \ - qt/obfuscationconfig.h \ qt/editaddressdialog.h \ qt/governancepage.h \ qt/guiconstants.h \ @@ -330,7 +327,6 @@ BITCOIN_QT_WALLET_CPP = \ qt/blockexplorer.cpp \ qt/coincontroldialog.cpp \ qt/coincontroltreewidget.cpp \ - qt/obfuscationconfig.cpp \ qt/editaddressdialog.cpp \ qt/governancepage.cpp \ qt/masternodelist.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 522d9180eb8ac..913f95c739909 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -23,6 +23,7 @@ RAW_TEST_FILES = test/data/alertTests.raw GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) BITCOIN_TEST_SUITE = \ + test/test_ion.h \ test/test_ion.cpp # test_ion binary # BITCOIN_TESTS =\ @@ -30,12 +31,14 @@ BITCOIN_TESTS =\ test/zerocoin_denomination_tests.cpp\ test/zerocoin_transactions_tests.cpp \ test/zerocoin_coinspend_tests.cpp \ + test/zerocoin_bignum_tests.cpp \ test/benchmark_zerocoin.cpp \ test/tutorial_zerocoin.cpp \ test/libzerocoin_tests.cpp \ + test/addrman_tests.cpp \ test/allocator_tests.cpp \ test/base32_tests.cpp \ - #test/base58_tests.cpp \ + test/base58_tests.cpp \ test/base64_tests.cpp \ test/budget_tests.cpp \ test/checkblock_tests.cpp \ diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index bcb29acbe227d..ea30dc6cad4bd 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -219,7 +219,7 @@ bool CActiveMasternode::SendMasternodePing(std::string& errorMessage) LogPrint("masternode", "dseep - relaying from active mn, %s \n", vin.ToString().c_str()); LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) pnode->PushMessage("dseep", vin, vchMasterNodeSignature, masterNodeSignatureTime, false); /* @@ -327,7 +327,7 @@ bool CActiveMasternode::CreateBroadcast(CTxIn vin, CService service, CKey keyCol } LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) pnode->PushMessage("dsee", vin, service, vchMasterNodeSignature, masterNodeSignatureTime, pubKeyCollateralAddress, pubKeyMasternode, -1, -1, masterNodeSignatureTime, PROTOCOL_VERSION, donationAddress, donationPercantage); /* @@ -367,7 +367,7 @@ bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secr } bool found = false; - BOOST_FOREACH (COutput& out, possibleCoins) { + for (COutput& out : possibleCoins) { if (out.tx->GetHash() == txHash && out.i == outputIndex) { selectedOutput = &out; found = true; @@ -432,9 +432,9 @@ vector CActiveMasternode::SelectCoinsMasternode() // Temporary unlock MN coins from masternode.conf if (GetBoolArg("-mnconflock", true)) { uint256 mnTxHash; - LOCK(pwalletMain->cs_wallet); + LOCK(pwalletMain->cs_wallet); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { mnTxHash.SetHex(mne.getTxHash()); int nIndex; @@ -454,12 +454,12 @@ vector CActiveMasternode::SelectCoinsMasternode() if (!confLockedCoins.empty()) { LOCK(pwalletMain->cs_wallet); - BOOST_FOREACH (COutPoint outpoint, confLockedCoins) + for (COutPoint outpoint : confLockedCoins) pwalletMain->LockCoin(outpoint); } // Filter - BOOST_FOREACH (const COutput& out, vCoins) { + for (const COutput& out : vCoins) { if (out.tx->vout[out.i].nValue == MASTERNODE_COLLATERAL_AMOUNT * COIN) { //exactly filteredCoins.push_back(out); } diff --git a/src/addrman.cpp b/src/addrman.cpp index ff1706e9019ba..9ef8460bbb004 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -225,7 +225,7 @@ void CAddrMan::Good_(const CService& addr, int64_t nTime) return; // find a bucket it is in now - int nRnd = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT); + int nRnd = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); int nUBucket = -1; for (unsigned int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; n++) { int nB = (n + nRnd) % ADDRMAN_NEW_BUCKET_COUNT; @@ -282,7 +282,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP int nFactor = 1; for (int n = 0; n < pinfo->nRefCount; n++) nFactor *= 2; - if (nFactor > 1 && (GetRandInt(nFactor) != 0)) + if (nFactor > 1 && (RandomInt(nFactor) != 0)) return false; } else { pinfo = Create(addr, source, &nId); @@ -334,18 +334,21 @@ void CAddrMan::Attempt_(const CService& addr, int64_t nTime) info.nAttempts++; } -CAddrInfo CAddrMan::Select_() +CAddrInfo CAddrMan::Select_(bool newOnly) { if (size() == 0) return CAddrInfo(); + if (newOnly && nNew == 0) + return CAddrInfo(); + // Use a 50% chance for choosing between tried and new table entries. - if (nTried > 0 && (nNew == 0 || GetRandInt(2) == 0)) { + if (!newOnly && (nTried > 0 && (nNew == 0 || RandomInt(2) == 0))) { // use a tried node double fChanceFactor = 1.0; while (1) { - int nKBucket = GetRandInt(ADDRMAN_TRIED_BUCKET_COUNT); - int nKBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); + int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT); + int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); while (vvTried[nKBucket][nKBucketPos] == -1) { nKBucket = (nKBucket + insecure_rand()) % ADDRMAN_TRIED_BUCKET_COUNT; nKBucketPos = (nKBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; @@ -353,7 +356,7 @@ CAddrInfo CAddrMan::Select_() int nId = vvTried[nKBucket][nKBucketPos]; assert(mapInfo.count(nId) == 1); CAddrInfo& info = mapInfo[nId]; - if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) + if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) return info; fChanceFactor *= 1.2; } @@ -361,8 +364,8 @@ CAddrInfo CAddrMan::Select_() // use a new node double fChanceFactor = 1.0; while (1) { - int nUBucket = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT); - int nUBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE); + int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT); + int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE); while (vvNew[nUBucket][nUBucketPos] == -1) { nUBucket = (nUBucket + insecure_rand()) % ADDRMAN_NEW_BUCKET_COUNT; nUBucketPos = (nUBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE; @@ -370,7 +373,7 @@ CAddrInfo CAddrMan::Select_() int nId = vvNew[nUBucket][nUBucketPos]; assert(mapInfo.count(nId) == 1); CAddrInfo& info = mapInfo[nId]; - if (GetRandInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) + if (RandomInt(1 << 30) < fChanceFactor * info.GetChance() * (1 << 30)) return info; fChanceFactor *= 1.2; } @@ -466,7 +469,7 @@ void CAddrMan::GetAddr_(std::vector& vAddr) if (vAddr.size() >= nNodes) break; - int nRndPos = GetRandInt(vRandom.size() - n) + n; + int nRndPos = RandomInt(vRandom.size() - n) + n; SwapRandom(n, nRndPos); assert(mapInfo.count(vRandom[n]) == 1); @@ -495,3 +498,7 @@ void CAddrMan::Connected_(const CService& addr, int64_t nTime) if (nTime - info.nTime > nUpdateInterval) info.nTime = nTime; } + +int CAddrMan::RandomInt(int nMax){ + return GetRandInt(nMax); +} \ No newline at end of file diff --git a/src/addrman.h b/src/addrman.h index c1804a5198d11..fc81efa324c5f 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -20,11 +20,13 @@ #include #include -/** - * Extended statistics about a CAddress +/** + * Extended statistics about a CAddress */ class CAddrInfo : public CAddress { + + public: //! last try whatsoever by us (memory only) int64_t nLastTry; @@ -166,8 +168,8 @@ class CAddrInfo : public CAddress //! the maximum number of nodes to return in a getaddr call #define ADDRMAN_GETADDR_MAX 2500 -/** - * Stochastical (IP) address manager +/** + * Stochastical (IP) address manager */ class CAddrMan { @@ -175,9 +177,6 @@ class CAddrMan //! critical section to protect the inner data structures mutable CCriticalSection cs; - //! secret key to randomize bucket select with - uint256 nKey; - //! last used nId int nIdCount; @@ -203,6 +202,9 @@ class CAddrMan int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE]; protected: + //! secret key to randomize bucket select with + uint256 nKey; + //! Find an entry. CAddrInfo* Find(const CNetAddr& addr, int* pnId = NULL); @@ -231,9 +233,11 @@ class CAddrMan //! Mark an entry as attempted to connect. void Attempt_(const CService& addr, int64_t nTime); - //! Select an address to connect to. - //! nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100) - CAddrInfo Select_(); + //! Select an address to connect to, if newOnly is set to true, only the new table is selected from. + CAddrInfo Select_(bool newOnly); + + //! Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic. + virtual int RandomInt(int nMax); #ifdef DEBUG_ADDRMAN //! Perform consistency check. Returns an error code or zero. @@ -535,13 +539,13 @@ class CAddrMan * Choose an address to connect to. * nUnkBias determines how much "new" entries are favored over "tried" ones (0-100). */ - CAddrInfo Select() + CAddrInfo Select(bool newOnly = false) { CAddrInfo addrRet; { LOCK(cs); Check(); - addrRet = Select_(); + addrRet = Select_(newOnly); Check(); } return addrRet; diff --git a/src/alert.cpp b/src/alert.cpp index 750977fefd896..5bea4e67e3796 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -12,7 +12,7 @@ #include "net.h" #include "pubkey.h" #include "timedata.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include @@ -21,7 +21,6 @@ #include #include -#include #include using namespace std; @@ -53,7 +52,7 @@ std::string CUnsignedAlert::ToString() const for (auto& n: setCancel) strSetCancel += strprintf("%d ", n); std::string strSetSubVer; - BOOST_FOREACH (std::string str, setSubVer) + for (std::string str : setSubVer) strSetSubVer += "\"" + str + "\" "; return strprintf( "CAlert(\n" @@ -214,7 +213,7 @@ bool CAlert::ProcessAlert(bool fThread) } // Check if this alert has been cancelled - BOOST_FOREACH (PAIRTYPE(const uint256, CAlert) & item, mapAlerts) { + for (PAIRTYPE(const uint256, CAlert) & item : mapAlerts) { const CAlert& alert = item.second; if (alert.Cancels(*this)) { LogPrint("alert", "alert already cancelled by %d\n", alert.nID); diff --git a/src/blocksignature.cpp b/src/blocksignature.cpp index 3d0aa14aa847e..850bbd079d7a6 100644 --- a/src/blocksignature.cpp +++ b/src/blocksignature.cpp @@ -68,7 +68,7 @@ bool CheckBlockSignature(const CBlock& block) * UTXO: The public key that signs must match the public key associated with the first utxo of the coinstake tx. */ CPubKey pubkey; - bool fxIONStake = block.vtx[1].IsZerocoinSpend(); + bool fxIONStake = block.vtx[1].vin[0].IsZerocoinSpend(); if (fxIONStake) { libzerocoin::CoinSpend spend = TxInToZerocoinSpend(block.vtx[1].vin[0]); pubkey = spend.getPubKey(); diff --git a/src/bloom.cpp b/src/bloom.cpp index 9a0137d268754..31facc8a9d7da 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -19,7 +19,6 @@ #include #include -#include #define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455 #define LN2 0.6931471805599453094172321214581765680755001343602552 @@ -208,7 +207,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx) if (fFound) return true; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { // Match if the filter contains an outpoint tx spends if (contains(txin.prevout)) return true; @@ -220,7 +219,7 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx) opcodetype opcode; if (!txin.scriptSig.GetOp(pc, opcode, data)) break; - if (txin.scriptSig.IsZerocoinSpend()){ + if (txin.IsZerocoinSpend()) { CDataStream s(vector(txin.scriptSig.begin() + 44, txin.scriptSig.end()), SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/chain.h b/src/chain.h index b86b9c2061846..2b4d81f2210a5 100644 --- a/src/chain.h +++ b/src/chain.h @@ -17,7 +17,6 @@ #include -#include struct CDiskBlockPos { int nFile; @@ -177,11 +176,11 @@ class CBlockIndex //! (memory only) Sequential id assigned to distinguish order in which blocks are received. uint32_t nSequenceId; - + //! zerocoin specific fields std::map mapZerocoinSupply; std::vector vMintDenominationsInBlock; - + void SetNull() { phashBlock = NULL; @@ -253,7 +252,7 @@ class CBlockIndex nStakeTime = 0; } } - + CDiskBlockPos GetBlockPos() const { @@ -395,7 +394,7 @@ class CBlockIndex /** * Returns true if there are nRequired or more blocks of minVersion or above - * in the last Params().ToCheckBlockUpgradeMajority() blocks, starting at pstart + * in the last Params().ToCheckBlockUpgradeMajority() blocks, starting at pstart * and going backwards. */ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired); @@ -452,9 +451,9 @@ class CDiskBlockIndex : public CBlockIndex hashNext = uint256(); } - explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) + explicit CDiskBlockIndex(const CBlockIndex* pindex) : CBlockIndex(*pindex) { - hashPrev = (pprev ? pprev->GetBlockHash() : uint256()); + hashPrev = (pprev ? pprev->GetBlockHash() : uint256(0)); } ADD_SERIALIZE_METHODS; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7521164e98604..75e78e471f9e2 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -168,6 +168,9 @@ class CMainParams : public CChainParams nDGWStartHeight = 550000; // Startheight of DGW nDGWStartTime = 1521851265; // GMT: Saturday, March 24, 2018 12:27:45 AM - Exact time when DGW algorithm starts and old MIDAS stops + // Public coin spend enforcement + nPublicZCSpends = 9999999; + // Fake Serial Attack nFakeSerialBlockheightEnd = 1073534; nSupplyBeforeFakeSerial = 1308446 * COIN; // zerocoin supply at block nFakeSerialBlockheightEnd @@ -241,6 +244,7 @@ class CMainParams : public CChainParams "8441436038339044149526344321901146575444541784240209246165157233507787077498171257724679629263863563732899121548" "31438167899885040445364023527381951378636564391212010397122822120720357"; nMaxZerocoinSpendsPerTransaction = 7; // Assume about 20kb each + nMaxZerocoinPublicSpendsPerTransaction = 637; // Assume about 220 bytes each input nMinZerocoinMintFee = 1 * CENT; //high fee required for zerocoin mints nMintRequiredConfirmations = 20; //the maximum amount of confirmations until accumulated in 19 nRequiredAccumulation = 1; @@ -249,6 +253,7 @@ class CMainParams : public CChainParams nZerocoinRequiredStakeDepth = 200; //The required confirmations for a xion to be stakable nBudget_Fee_Confirmations = 6; // Number of confirmations for the finalization fee + nProposalEstablishmentTime = 60 * 60 * 24; // Proposals must be at least a day old to make it into a budget } const Checkpoints::CCheckpointData& Checkpoints() const @@ -303,6 +308,9 @@ class CTestNetParams : public CMainParams nDGWStartHeight = nZerocoinStartHeight; nDGWStartTime = nZerocoinStartTime; + // Public coin spend enforcement + nPublicZCSpends = 9999999; + // Fake Serial Attack nFakeSerialBlockheightEnd = -1; nSupplyBeforeFakeSerial = 0; @@ -349,6 +357,8 @@ class CTestNetParams : public CMainParams nStartMasternodePayments = 1558696183; // GMT: Thursday, 15. February 2018 12:03:03 nBudget_Fee_Confirmations = 3; // Number of confirmations for the finalization fee. We have to make this very short // here because we only have a 8 block finalization window on testnet + + nProposalEstablishmentTime = 60 * 5; // Proposals must be at least 5 mns old to make it into a test budget nZerocoinHeaderVersion = 8; //Block headers must be this version once zerocoin is active } const Checkpoints::CCheckpointData& Checkpoints() const @@ -406,6 +416,9 @@ class CRegTestParams : public CTestNetParams nDGWStartHeight = nZerocoinStartHeight; nDGWStartTime = nZerocoinStartTime; + // Public coin spend enforcement + nPublicZCSpends = 350; + //! Modify the regtest genesis block so the timestamp is valid for a later start. genesis.nTime = 1491737471; // GMT: Thursday, February 2, 2017 14:30:00 genesis.nNonce = 574753; diff --git a/src/chainparams.h b/src/chainparams.h index d1142b794a73b..67e4e3ec06afb 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -98,6 +98,7 @@ class CChainParams int PoolMaxTransactions() const { return nPoolMaxTransactions; } /** Return the number of blocks in a budget cycle */ int GetBudgetCycleBlocks() const { return nBudgetCycleBlocks; } + int64_t GetProposalEstablishmentTime() const { return nProposalEstablishmentTime; } /** Spork key and Masternode Handling **/ std::string SporkKey() const { return strSporkKey; } @@ -114,6 +115,7 @@ class CChainParams std::string Zerocoin_Modulus() const { return zerocoinModulus; } libzerocoin::ZerocoinParams* Zerocoin_Params(bool useModulusV1) const; int Zerocoin_MaxSpendsPerTransaction() const { return nMaxZerocoinSpendsPerTransaction; } + int Zerocoin_MaxPublicSpendsPerTransaction() const { return nMaxZerocoinPublicSpendsPerTransaction; } CAmount Zerocoin_MintFee() const { return nMinZerocoinMintFee; } int Zerocoin_MintRequiredConfirmations() const { return nMintRequiredConfirmations; } int Zerocoin_RequiredAccumulation() const { return nRequiredAccumulation; } @@ -144,6 +146,8 @@ class CChainParams int DGWStartHeight() const { return nDGWStartHeight; } int DGWStartTime() const { return nDGWStartTime; } + int Zerocoin_Block_Public_Spend_Enabled() const { return nPublicZCSpends; } + protected: CChainParams() {} @@ -193,6 +197,7 @@ class CChainParams int64_t nStartMasternodePayments; std::string zerocoinModulus; int nMaxZerocoinSpendsPerTransaction; + int nMaxZerocoinPublicSpendsPerTransaction; CAmount nMinZerocoinMintFee; CAmount nInvalidAmountFiltered; int nMintRequiredConfirmations; @@ -203,6 +208,7 @@ class CChainParams int nZerocoinStartHeight; int nZerocoinStartTime; int nZerocoinRequiredStakeDepth; + int64_t nProposalEstablishmentTime; int nBlockEnforceSerialRange; int nBlockRecalculateAccumulators; @@ -210,6 +216,7 @@ class CChainParams int nBlockLastGoodCheckpoint; int nBlockEnforceInvalidUTXO; int nBlockZerocoinV2; + int nPublicZCSpends; // fake serial attack int nFakeSerialBlockheightEnd = 0; diff --git a/src/checkqueue.h b/src/checkqueue.h index 9648347c6653a..41ffea64b2d29 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -119,7 +118,7 @@ class CCheckQueue fOk = fAllOk; } // execute work - BOOST_FOREACH (T& check, vChecks) + for (T& check : vChecks) if (fOk) fOk = check(); vChecks.clear(); @@ -146,7 +145,7 @@ class CCheckQueue void Add(std::vector& vChecks) { boost::unique_lock lock(mutex); - BOOST_FOREACH (T& check, vChecks) { + for (T& check : vChecks) { queue.push_back(T()); check.swap(queue.back()); } diff --git a/src/coins.cpp b/src/coins.cpp index 34bede50453a6..32ad9431e29bb 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -230,7 +230,7 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const return 0; //todo are there any security precautions to take here? - if (tx.IsZerocoinSpend()) + if (tx.HasZerocoinSpendInputs()) return tx.GetZerocoinSpent(); CAmount nResult = 0; @@ -242,7 +242,7 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const { - if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { + if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) { for (unsigned int i = 0; i < tx.vin.size(); i++) { const COutPoint& prevout = tx.vin[i].prevout; const CCoins* coins = AccessCoins(prevout.hash); diff --git a/src/coins.h b/src/coins.h index ed6ae3159d2e8..479802c00afcc 100644 --- a/src/coins.h +++ b/src/coins.h @@ -18,7 +18,6 @@ #include #include -#include #include /** @@ -130,7 +129,7 @@ class CCoins void ClearUnspendable() { - BOOST_FOREACH (CTxOut& txout, vout) { + for (CTxOut& txout : vout) { if (txout.scriptPubKey.IsUnspendable()) txout.SetNull(); } @@ -274,14 +273,14 @@ class CCoins //! check whether a particular output is still available bool IsAvailable(unsigned int nPos) const { - return (nPos < vout.size() && !vout[nPos].IsNull() && !vout[nPos].scriptPubKey.IsZerocoinMint()); + return (nPos < vout.size() && !vout[nPos].IsNull() && !vout[nPos].IsZerocoinMint()); } //! check whether the entire CCoins is spent //! note that only !IsPruned() CCoins can be serialized bool IsPruned() const { - BOOST_FOREACH (const CTxOut& out, vout) + for (const CTxOut& out : vout) if (!out.IsNull()) return false; return true; diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h index c331af2b5e646..0db2c69d47a3f 100644 --- a/src/compat/byteswap.h +++ b/src/compat/byteswap.h @@ -6,7 +6,7 @@ #define BITCOIN_COMPAT_BYTESWAP_H #if defined(HAVE_CONFIG_H) -#include +#include #endif #include diff --git a/src/compat/endian.h b/src/compat/endian.h index 4f244c39303da..d0dab0560d56d 100644 --- a/src/compat/endian.h +++ b/src/compat/endian.h @@ -6,7 +6,7 @@ #define BITCOIN_COMPAT_ENDIAN_H #if defined(HAVE_CONFIG_H) -#include +#include #endif #include diff --git a/src/core_write.cpp b/src/core_write.cpp index 68e30b5f761d5..8de578cabf391 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -17,7 +17,6 @@ #include "utilmoneystr.h" #include "utilstrencodings.h" -#include using namespace std; @@ -84,7 +83,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("type", GetTxnOutputType(type)); UniValue a(UniValue::VARR); - BOOST_FOREACH (const CTxDestination& addr, addresses) + for (const CTxDestination& addr : addresses) a.push_back(CBitcoinAddress(addr).ToString()); out.pushKV("addresses", a); } diff --git a/src/crypter.cpp b/src/crypter.cpp index 63e5fdde24923..ae9d51bbcec3e 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -12,7 +12,6 @@ #include "init.h" #include "uint256.h" -#include #include #include #include "wallet/wallet.h" @@ -360,7 +359,7 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) return false; fUseCrypto = true; - BOOST_FOREACH (KeyMap::value_type& mKey, mapKeys) { + for (KeyMap::value_type& mKey : mapKeys) { const CKey& key = mKey.second; CPubKey vchPubKey = key.GetPubKey(); CKeyingMaterial vchSecret(key.begin(), key.end()); diff --git a/src/ui_interface.h b/src/guiinterface.h similarity index 99% rename from src/ui_interface.h rename to src/guiinterface.h index 91a5754aa8ab0..30847589ed1c9 100644 --- a/src/ui_interface.h +++ b/src/guiinterface.h @@ -123,4 +123,4 @@ inline std::string _(const char* psz) return rv ? (*rv) : psz; } -#endif // BITCOIN_UI_INTERFACE_H +#endif // BITCOIN_UI_INTERFACE_H \ No newline at end of file diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 416cf40a5369b..53c69014da8ac 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -15,7 +15,7 @@ #include "sync.h" #include "util.h" #include "utilstrencodings.h" -#include "ui_interface.h" +#include "guiinterface.h" #include // boost::trim diff --git a/src/httpserver.cpp b/src/httpserver.cpp index df1a06703ea4b..438d94cc7dd0d 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -12,7 +12,7 @@ #include "netbase.h" #include "rpc/protocol.h" // For HTTP status codes #include "sync.h" -#include "ui_interface.h" +#include "guiinterface.h" #include #include diff --git a/src/init.cpp b/src/init.cpp index 6f7e3fc88917f..e40563245fa89 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -38,7 +38,7 @@ #include "sporkdb.h" #include "txdb.h" #include "torcontrol.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "utilmoneystr.h" #include "validationinterface.h" @@ -65,6 +65,7 @@ #include #include #include +#include #include #if ENABLE_ZMQ @@ -515,6 +516,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-relaypriority", strprintf(_("Require high priority for relaying free or low-fee transactions (default:%u)"), 1)); 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 ION/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK()))); strUsage += HelpMessageOpt("-printtoconsole", strprintf(_("Send trace/debug info to console instead of debug.log file (default: %u)"), 0)); if (GetBoolArg("-help-debug", false)) { @@ -561,9 +563,6 @@ std::string HelpMessage(HelpMessageMode mode) #endif // ENABLE_WALLET strUsage += HelpMessageOpt("-reindexzerocoin=", strprintf(_("Delete all zerocoin spends and mints that have been recorded to the blockchain database and reindex them (0-1, default: %u)"), 0)); -// strUsage += " -anonymizeionamount= " + strprintf(_("Keep N ION anonymized (default: %u)"), 0) + "\n"; -// strUsage += " -liquidityprovider= " + strprintf(_("Provide liquidity to Obfuscation by infrequently mixing coins on a continual basis (0-100, default: %u, 1=very frequent, high fees, 100=very infrequent, low fees)"), 0) + "\n"; - strUsage += HelpMessageGroup(_("SwiftX options:")); strUsage += HelpMessageOpt("-enableswifttx=", strprintf(_("Enable SwiftX, show confirmations for locked transactions (bool, default: %s)"), "true")); strUsage += HelpMessageOpt("-swifttxdepth=", strprintf(_("Show N confirmations for a successfully locked transaction (0-9999, default: %u)"), nSwiftTXDepth)); @@ -693,7 +692,7 @@ void ThreadImport(std::vector vImportFiles) } // -loadblock= - BOOST_FOREACH (boost::filesystem::path& path, vImportFiles) { + for (boost::filesystem::path& path : vImportFiles) { FILE* file = fopen(path.string().c_str(), "rb"); if (file) { CImportingNow imp; @@ -1016,6 +1015,8 @@ bool AppInit2() } + nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log // Initialize elliptic curve code @@ -1262,7 +1263,7 @@ bool AppInit2() if (mapArgs.count("-onlynet")) { std::set nets; - BOOST_FOREACH (std::string snet, mapMultiArgs["-onlynet"]) { + for (std::string snet : mapMultiArgs["-onlynet"]) { enum Network net = ParseNetwork(snet); if (net == NET_UNROUTABLE) return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet)); @@ -1276,7 +1277,7 @@ bool AppInit2() } if (mapArgs.count("-whitelist")) { - BOOST_FOREACH (const std::string& net, mapMultiArgs["-whitelist"]) { + for (const std::string& net : mapMultiArgs["-whitelist"]) { CSubNet subnet(net); if (!subnet.IsValid()) return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net)); @@ -1336,13 +1337,13 @@ bool AppInit2() bool fBound = false; if (fListen) { if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) { - BOOST_FOREACH (std::string strBind, mapMultiArgs["-bind"]) { + for (std::string strBind : mapMultiArgs["-bind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind)); fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); } - BOOST_FOREACH (std::string strBind, mapMultiArgs["-whitebind"]) { + for (std::string strBind : mapMultiArgs["-whitebind"]) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, 0, false)) return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind)); @@ -1361,7 +1362,7 @@ bool AppInit2() } if (mapArgs.count("-externalip")) { - BOOST_FOREACH (string strAddr, mapMultiArgs["-externalip"]) { + for (string strAddr : mapMultiArgs["-externalip"]) { CService addrLocal(strAddr, GetListenPort(), fNameLookup); if (!addrLocal.IsValid()) return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr)); @@ -1369,7 +1370,7 @@ bool AppInit2() } } - BOOST_FOREACH (string strDest, mapMultiArgs["-seednode"]) + for (string strDest : mapMultiArgs["-seednode"]) AddOneShot(strDest); #if ENABLE_ZMQ @@ -1743,7 +1744,7 @@ bool AppInit2() // Restore wallet transaction metadata after -zapwallettxes=1 if (GetBoolArg("-zapwallettxes", false) && GetArg("-zapwallettxes", "1") != "2") { - BOOST_FOREACH (const CWalletTx& wtxOld, vWtx) { + for (const CWalletTx& wtxOld : vWtx) { uint256 hash = wtxOld.GetHash(); std::map::iterator mi = pwalletMain->mapWallet.find(hash); if (mi != pwalletMain->mapWallet.end()) { @@ -1794,7 +1795,7 @@ bool AppInit2() std::vector vImportFiles; if (mapArgs.count("-loadblock")) { - BOOST_FOREACH (string strFile, mapMultiArgs["-loadblock"]) + for (string strFile : mapMultiArgs["-loadblock"]) vImportFiles.push_back(strFile); } threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); @@ -1900,7 +1901,7 @@ bool AppInit2() LOCK(pwalletMain->cs_wallet); LogPrintf("Locking Masternodes:\n"); uint256 mnTxHash; - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { LogPrintf(" %s %s\n", mne.getTxHash(), mne.getOutputIndex()); mnTxHash.SetHex(mne.getTxHash()); COutPoint outpoint = COutPoint(mnTxHash, (unsigned int) std::stoul(mne.getOutputIndex().c_str())); @@ -1921,20 +1922,6 @@ bool AppInit2() nPreferredDenom = 0; } -// XX42 Remove/refactor code below. Until then provide safe defaults - nAnonymizeIonAmount = 2; - -// nLiquidityProvider = GetArg("-liquidityprovider", 0); //0-100 -// if (nLiquidityProvider != 0) { -// obfuScationPool.SetMinBlockSpacing(std::min(nLiquidityProvider, 100) * 15); -// fEnableZeromint = true; -// nZeromintPercentage = 99999; -// } -// -// nAnonymizeIonAmount = GetArg("-anonymizeionamount", 0); -// if (nAnonymizeIonAmount > 999999) nAnonymizeIonAmount = 999999; -// if (nAnonymizeIonAmount < 2) nAnonymizeIonAmount = 2; - fEnableSwiftTX = GetBoolArg("-enableswifttx", fEnableSwiftTX); nSwiftTXDepth = GetArg("-swifttxdepth", nSwiftTXDepth); nSwiftTXDepth = std::min(std::max(nSwiftTXDepth, 0), 60); @@ -1947,7 +1934,6 @@ bool AppInit2() LogPrintf("fLiteMode %d\n", fLiteMode); LogPrintf("nSwiftTXDepth %d\n", nSwiftTXDepth); - LogPrintf("Anonymize ION Amount %d\n", nAnonymizeIonAmount); LogPrintf("Budget Mode %s\n", strBudgetMode.c_str()); /* Denominations @@ -1965,10 +1951,6 @@ bool AppInit2() obfuScationDenominations.push_back((10 * COIN) + 10000); obfuScationDenominations.push_back((1 * COIN) + 1000); obfuScationDenominations.push_back((.1 * COIN) + 100); - /* Disabled till we need them - obfuScationDenominations.push_back( (.01 * COIN)+10 ); - obfuScationDenominations.push_back( (.001 * COIN)+1 ); - */ obfuScationPool.InitCollateralAddress(); @@ -2021,6 +2003,11 @@ bool AppInit2() // Run a thread to flush wallet periodically threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile))); + + if (GetBoolArg("-precompute", false)) { + // Run a thread to precompute any xION spends + threadGroup.create_thread(boost::bind(&ThreadPrecomputeSpends)); + } } #endif diff --git a/src/ion-tx.cpp b/src/ion-tx.cpp index b8023d9b89613..c3f28394fe8b0 100644 --- a/src/ion-tx.cpp +++ b/src/ion-tx.cpp @@ -14,7 +14,7 @@ #include "primitives/transaction.h" #include "script/script.h" #include "script/sign.h" -#include "ui_interface.h" // for _(...) +#include "guiinterface.h" // for _(...) #include #include "util.h" #include "utilmoneystr.h" @@ -434,7 +434,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); // ... and merge in other signatures: - BOOST_FOREACH (const CTransaction& txv, txVariants) { + for (const CTransaction& txv : txVariants) { txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); } if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i))) diff --git a/src/iond.cpp b/src/iond.cpp index ae023067c2598..acf8ab5de2799 100644 --- a/src/iond.cpp +++ b/src/iond.cpp @@ -12,7 +12,7 @@ #include "masternodeconfig.h" #include "noui.h" #include "rpc/server.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "httpserver.h" #include "httprpc.h" diff --git a/src/kernel.cpp b/src/kernel.cpp index 3e4803da02e63..47330173fd332 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -85,7 +85,7 @@ static bool SelectBlockFromCandidates( bool fSelected = false; uint256 hashBest = 0; *pindexSelected = (const CBlockIndex*)0; - BOOST_FOREACH (const PAIRTYPE(int64_t, uint256) & item, vSortedByTimestamp) { + for (const PAIRTYPE(int64_t, uint256) & item : vSortedByTimestamp) { if (!mapBlockIndex.count(item.second)) return error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString().c_str()); @@ -213,7 +213,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod strSelectionMap.replace(pindex->nHeight - nHeightFirstCandidate, 1, "="); pindex = pindex->pprev; } - BOOST_FOREACH (const PAIRTYPE(uint256, const CBlockIndex*) & item, mapSelectedBlocks) { + for (const std::pair &item : mapSelectedBlocks) { // 'S' indicates selected proof-of-stake blocks // 'W' indicates selected proof-of-work blocks strSelectionMap.replace(item.second->nHeight - nHeightFirstCandidate, 1, item.second->IsProofOfStake() ? "S" : "W"); @@ -356,8 +356,33 @@ bool Stake(CStakeInput* stakeInput, unsigned int nBits, unsigned int nTimeBlockF return fSuccess; } +bool ContextualCheckZerocoinStake(int nPreviousBlockHeight, CStakeInput* stake) +{ + if (nPreviousBlockHeight < Params().Zerocoin_Block_V2_Start()) + return error("%s: xION stake block is less than allowed start height", __func__); + + if (CXIonStake* xION = dynamic_cast(stake)) { + CBlockIndex* pindexFrom = xION->GetIndexFrom(); + if (!pindexFrom) + return error("%s: failed to get index associated with xION stake checksum", __func__); + + if (chainActive.Height() - pindexFrom->nHeight < Params().Zerocoin_RequiredStakeDepth()) + return error("%s: xION stake does not have required confirmation depth. Current height %d, stakeInput height %d.", __func__, chainActive.Height(), pindexFrom->nHeight); + + //The checksum needs to be the exact checksum from 200 blocks ago + uint256 nCheckpoint200 = chainActive[nPreviousBlockHeight - Params().Zerocoin_RequiredStakeDepth()]->nAccumulatorCheckpoint; + uint32_t nChecksum200 = ParseChecksum(nCheckpoint200, libzerocoin::AmountToZerocoinDenomination(xION->GetValue())); + if (nChecksum200 != xION->GetChecksum()) + return error("%s: accumulator checksum is different than the block 200 blocks previous. stake=%d block200=%d", __func__, xION->GetChecksum(), nChecksum200); + } else { + return error("%s: dynamic_cast of stake ptr failed", __func__); + } + + return true; +} + // Check kernel hash target and coinstake signature -bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake, std::unique_ptr& stake, int nHeight) +bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake, std::unique_ptr& stake, int nPreviousBlockHeight) { const CTransaction tx = block.vtx[1]; if (!tx.IsCoinStake()) @@ -367,18 +392,22 @@ bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake, std::uniqu const CTxIn& txin = tx.vin[0]; //Construct the stakeinput object - if (tx.IsZerocoinSpend()) { + if (txin.IsZerocoinSpend()) { libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txin); if (spend.getSpendType() != libzerocoin::SpendType::STAKE) return error("%s: spend is using the wrong SpendType (%d)", __func__, (int)spend.getSpendType()); stake = std::unique_ptr(new CXIonStake(spend)); + + if (!ContextualCheckZerocoinStake(nPreviousBlockHeight, stake.get())) + return error("%s: staked xION fails context checks", __func__); } else { // First try finding the previous transaction in database uint256 hashBlock; CTransaction txPrev; if (!GetTransaction(txin.prevout.hash, txPrev, hashBlock, true)) - return error("CheckProofOfStake() : INFO: read txPrev failed"); + return error("CheckProofOfStake() : INFO: read txPrev failed, tx id prev: %s, block id %s", + txin.prevout.hash.GetHex(), block.GetHash().GetHex()); //verify signature and script if (!VerifyScript(txin.scriptSig, txPrev.vout[txin.prevout.n].scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&tx, 0))) @@ -389,13 +418,14 @@ bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake, std::uniqu stake = std::unique_ptr(ionInput); } - CBlockIndex* pindex = stake->GetIndexFrom(); - if (!pindex) - return error("%s: Failed to find the block index", __func__); + //Get the + CBlockIndex* pindexfrom = stake->GetIndexFrom(); + if (!pindexfrom) + return error("%s: Failed to find the block index for stake origin", __func__); // Read block header - CBlock blockprev; - if (!ReadBlockFromDisk(blockprev, pindex->GetBlockPos())) + CBlock blockfrom; + if (!ReadBlockFromDisk(blockfrom, pindexfrom->GetBlockPos())) return error("CheckProofOfStake(): INFO: failed to find block"); uint256 bnTargetPerCoinDay; @@ -405,9 +435,14 @@ bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake, std::uniqu if (!stake->GetModifier(nStakeModifier)) return error("%s failed to get modifier for stake input\n", __func__); - unsigned int nBlockFromTime = blockprev.nTime; + unsigned int nBlockFromTime = blockfrom.nTime; unsigned int nTxTime = block.nTime; - // CEVAP: **TODO** - CheckProofOfStake not working + if (!txin.IsZerocoinSpend() && nPreviousBlockHeight >= Params().Zerocoin_Block_Public_Spend_Enabled() - 1) { //Equivalent for xION is checked above in ContextualCheckZerocoinStake() + if (nTxTime < nBlockFromTime) // Transaction timestamp nTxTime + return error("CheckStakeKernelHash() : nTime violation - nBlockFromTime=%d nTimeTx=%d", nBlockFromTime, nTxTime); + if (nBlockFromTime + nStakeMinAge > nTxTime) // Min age requirement + return error("CheckStakeKernelHash() : min age violation - nBlockFromTime=%d nStakeMinAge=%d nTimeTx=%d", nBlockFromTime, nStakeMinAge, nTxTime); + } if (!CheckStake(stake->GetUniqueness(), stake->GetValue(), nStakeModifier, bnTargetPerCoinDay, nBlockFromTime, nTxTime, hashProofOfStake)) return error("CheckProofOfStake() : INFO: check kernel failed on coinstake %s, hashProof=%s \n", diff --git a/src/kernel.h b/src/kernel.h index 2eb56f93ac123..77bdae48b611b 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -30,7 +30,7 @@ bool Stake(CStakeInput* stakeInput, unsigned int nBits, unsigned int nTimeBlockF // Check kernel hash target and coinstake signature // Sets hashProofOfStake on success return -bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake, std::unique_ptr& stake, int nHeight); +bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake, std::unique_ptr& stake, int nPreviousBlockHeight); // Check whether the coinstake timestamp meets protocol bool CheckCoinStakeTimestamp(int64_t nTimeBlock, int64_t nTimeTx); @@ -47,4 +47,6 @@ bool GetKernelStakeModifierPreDGW(uint256 hashBlockFrom, uint64_t& nStakeModifie // Get time weight using supplied timestamps int64_t GetWeight(int64_t nIntervalBeginning, int64_t nIntervalEnd); +bool ContextualCheckZerocoinStake(int nPreviousBlockHeight, CStakeInput* stake); + #endif // BITCOIN_KERNEL_H diff --git a/src/keystore.cpp b/src/keystore.cpp index 7ebd632954075..1c3fedd57be17 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -13,7 +13,6 @@ #include "script/standard.h" #include "util.h" -#include bool CKeyStore::GetPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const { diff --git a/src/libzerocoin/AccumulatorProofOfKnowledge.h b/src/libzerocoin/AccumulatorProofOfKnowledge.h index 924ca592e0ee4..f1f7e5038b7a0 100644 --- a/src/libzerocoin/AccumulatorProofOfKnowledge.h +++ b/src/libzerocoin/AccumulatorProofOfKnowledge.h @@ -24,6 +24,7 @@ namespace libzerocoin { */ class AccumulatorProofOfKnowledge { public: + AccumulatorProofOfKnowledge(){}; AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p); /** Generates a proof that a commitment to a coin c was accumulated diff --git a/src/libzerocoin/CoinSpend.cpp b/src/libzerocoin/CoinSpend.cpp index a6074448c67bb..3e34d7dc725d6 100644 --- a/src/libzerocoin/CoinSpend.cpp +++ b/src/libzerocoin/CoinSpend.cpp @@ -18,14 +18,15 @@ namespace libzerocoin { CoinSpend::CoinSpend(const ZerocoinParams* paramsCoin, const ZerocoinParams* paramsAcc, const PrivateCoin& coin, Accumulator& a, const uint32_t& checksum, - const AccumulatorWitness& witness, const uint256& ptxHash, const SpendType& spendType) : accChecksum(checksum), - ptxHash(ptxHash), + const AccumulatorWitness& witness, const uint256& ptxHash, const SpendType& spendType) : coinSerialNumber((coin.getSerialNumber())), + spendType(spendType), + ptxHash(ptxHash), + accChecksum(checksum), accumulatorPoK(¶msAcc->accumulatorParams), serialNumberSoK(paramsCoin), commitmentPoK(¶msCoin->serialNumberSoKCommitmentGroup, - ¶msAcc->accumulatorParams.accumulatorPoKCommitmentGroup), - spendType(spendType) + ¶msAcc->accumulatorParams.accumulatorPoKCommitmentGroup) { denomination = coin.getPublicCoin().getDenomination(); version = coin.getVersion(); diff --git a/src/libzerocoin/CoinSpend.h b/src/libzerocoin/CoinSpend.h index 890a3cd54c2b1..1af5d31b51c68 100644 --- a/src/libzerocoin/CoinSpend.h +++ b/src/libzerocoin/CoinSpend.h @@ -38,6 +38,8 @@ class CoinSpend { public: + CoinSpend(){}; + //! \param paramsV1 - if this is a V1 zerocoin, then use params that existed with initial modulus, ignored otherwise //! \param paramsV2 - params that begin when V2 zerocoins begin on the ION network //! \param strm - a serialized CoinSpend @@ -87,6 +89,9 @@ class CoinSpend CoinSpend(const ZerocoinParams* paramsCoin, const ZerocoinParams* paramsAcc, const PrivateCoin& coin, Accumulator& a, const uint32_t& checksum, const AccumulatorWitness& witness, const uint256& ptxHash, const SpendType& spendType); + + virtual ~CoinSpend(){}; + /** Returns the serial number of the coin spend by this proof. * * @return the coin's serial number @@ -119,10 +124,13 @@ class CoinSpend static std::vector ParseSerial(CDataStream& s); - const uint256 signatureHash() const; - bool Verify(const Accumulator& a, bool verifyParams = true) const; + virtual const uint256 signatureHash() const; + virtual bool Verify(const Accumulator& a, bool verifyParams = true) const; bool HasValidSerial(ZerocoinParams* params) const; bool HasValidSignature() const; + void setTxOutHash(uint256 txOutHash) { this->ptxHash = txOutHash; }; + void setDenom(libzerocoin::CoinDenomination denom) { this->denomination = denom; } + CBigNum CalculateValidSerial(ZerocoinParams* params); std::string ToString() const; @@ -150,22 +158,24 @@ class CoinSpend } } +protected: + CoinDenomination denomination = ZQ_ERROR; + CBigNum coinSerialNumber; + uint8_t version; + //As of version 2 + CPubKey pubkey; + std::vector vchSig; + SpendType spendType; + uint256 ptxHash; + private: - CoinDenomination denomination; uint32_t accChecksum; - uint256 ptxHash; CBigNum accCommitmentToCoinValue; CBigNum serialCommitmentToCoinValue; - CBigNum coinSerialNumber; AccumulatorProofOfKnowledge accumulatorPoK; SerialNumberSignatureOfKnowledge serialNumberSoK; CommitmentProofOfKnowledge commitmentPoK; - uint8_t version; - //As of version 2 - CPubKey pubkey; - std::vector vchSig; - SpendType spendType; }; } /* namespace libzerocoin */ diff --git a/src/libzerocoin/Commitment.h b/src/libzerocoin/Commitment.h index 572c3367b7c66..e63cfebafeeb1 100644 --- a/src/libzerocoin/Commitment.h +++ b/src/libzerocoin/Commitment.h @@ -60,6 +60,7 @@ class Commitment { */ class CommitmentProofOfKnowledge { public: + CommitmentProofOfKnowledge(){}; CommitmentProofOfKnowledge(const IntegerGroupParams* ap, const IntegerGroupParams* bp); /** Generates a proof that two commitments, a and b, open to the same value. * diff --git a/src/libzerocoin/SerialNumberSignatureOfKnowledge.h b/src/libzerocoin/SerialNumberSignatureOfKnowledge.h index ca7d69c3860d2..64fa2c7bb0434 100644 --- a/src/libzerocoin/SerialNumberSignatureOfKnowledge.h +++ b/src/libzerocoin/SerialNumberSignatureOfKnowledge.h @@ -34,6 +34,7 @@ namespace libzerocoin { */ class SerialNumberSignatureOfKnowledge { public: + SerialNumberSignatureOfKnowledge(){}; SerialNumberSignatureOfKnowledge(const ZerocoinParams* p); /** Creates a Signature of knowledge object that a commitment to a coin contains a coin with serial number x * diff --git a/src/libzerocoin/bignum.cpp b/src/libzerocoin/bignum.cpp new file mode 100644 index 0000000000000..6b19ea1bd4161 --- /dev/null +++ b/src/libzerocoin/bignum.cpp @@ -0,0 +1,63 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2017-2019 The PIVX developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bignum.h" + +#if defined(USE_NUM_GMP) +#include "bignum_gmp.cpp" +#endif + +#if defined(USE_NUM_OPENSSL) +#include "bignum_openssl.cpp" +#endif + +std::string CBigNum::GetHex() const +{ + return ToString(16); +} + +std::string CBigNum::GetDec() const +{ + return ToString(10); +} + +CBigNum CBigNum::pow(const int e) const +{ + return this->pow(CBigNum(e)); +} + +void CBigNum::SetHex(const std::string& str) +{ + SetHexBool(str); +} + +CBigNum& CBigNum::operator/=(const CBigNum& b) +{ + *this = *this / b; + return *this; +} + +CBigNum& CBigNum::operator%=(const CBigNum& b) +{ + *this = *this % b; + return *this; +} + +const CBigNum CBigNum::operator++(int) +{ + // postfix operator + const CBigNum ret = *this; + ++(*this); + return ret; +} + +const CBigNum CBigNum::operator--(int) +{ + // postfix operator + const CBigNum ret = *this; + --(*this); + return ret; +} diff --git a/src/libzerocoin/bignum.h b/src/libzerocoin/bignum.h index 08fefc175ba4a..d1a464aa67755 100755 --- a/src/libzerocoin/bignum.h +++ b/src/libzerocoin/bignum.h @@ -1,8 +1,9 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2017-2018 The PIVX developers +// Copyright (c) 2017-2019 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef BITCOIN_BIGNUM_H #define BITCOIN_BIGNUM_H @@ -10,15 +11,16 @@ #include "config/ion-config.h" #endif -#include -#include -#include -#if defined(USE_NUM_GMP) -#include -#endif #if defined(USE_NUM_OPENSSL) #include #endif +#if defined(USE_NUM_GMP) +#include +#endif + +#include +#include +#include #include "serialize.h" #include "uint256.h" @@ -32,368 +34,69 @@ class bignum_error : public std::runtime_error explicit bignum_error(const std::string& str) : std::runtime_error(str) {} }; -#if defined(USE_NUM_OPENSSL) - - -/** RAII encapsulated BN_CTX (OpenSSL bignum context) */ -class CAutoBN_CTX -{ -protected: - BN_CTX* pctx; - BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } - -public: - CAutoBN_CTX() - { - pctx = BN_CTX_new(); - if (pctx == NULL) - throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); - } - - ~CAutoBN_CTX() - { - if (pctx != NULL) - BN_CTX_free(pctx); - } - - operator BN_CTX*() { return pctx; } - BN_CTX& operator*() { return *pctx; } - BN_CTX** operator&() { return &pctx; } - bool operator!() { return (pctx == NULL); } -}; - -/** C++ wrapper for BIGNUM (OpenSSL bignum) */ +/** C++ wrapper for BIGNUM */ class CBigNum { +#if defined(USE_NUM_OPENSSL) BIGNUM* bn; +#endif +#if defined(USE_NUM_GMP) + mpz_t bn; +#endif public: - CBigNum() - { - bn = BN_new(); - } - - CBigNum(const CBigNum& b) - { - bn = BN_new(); - if (!BN_copy(bn, b.bn)) - { - BN_clear_free(bn); - throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); - } - } - - CBigNum& operator=(const CBigNum& b) - { - if (!BN_copy(bn, b.bn)) - throw bignum_error("CBigNum::operator= : BN_copy failed"); - return (*this); - } - - ~CBigNum() - { - BN_clear_free(bn); - } + CBigNum(); + CBigNum(const CBigNum& b); + CBigNum& operator=(const CBigNum& b); + ~CBigNum(); //CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. - CBigNum(signed char n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(short n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(int n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(long n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(long long n) { bn = BN_new(); setint64(n); } - CBigNum(unsigned char n) { bn = BN_new(); setulong(n); } - CBigNum(unsigned short n) { bn = BN_new(); setulong(n); } - CBigNum(unsigned int n) { bn = BN_new(); setulong(n); } - CBigNum(unsigned long n) { bn = BN_new(); setulong(n); } - CBigNum(unsigned long long n) { bn = BN_new(); setuint64(n); } - explicit CBigNum(uint256 n) { bn = BN_new(); setuint256(n); } - - explicit CBigNum(const std::vector& vch) - { - bn = BN_new(); - setvch(vch); - } + CBigNum(signed char n); + CBigNum(short n); + CBigNum(int n); + CBigNum(long n); + CBigNum(long long n); + CBigNum(unsigned char n); + CBigNum(unsigned short n); + CBigNum(unsigned int n); + CBigNum(unsigned long n); + CBigNum(unsigned long long n); + explicit CBigNum(uint256 n); + explicit CBigNum(const std::vector& vch); /** Generates a cryptographically secure random number between zero and range exclusive * i.e. 0 < returned number < range * @param range The upper bound on the number. * @return */ - static CBigNum randBignum(const CBigNum& range) { - CBigNum ret; - if(!BN_rand_range(ret.bn, range.bn)){ - throw bignum_error("CBigNum:rand element : BN_rand_range failed"); - } - return ret; - } + static CBigNum randBignum(const CBigNum& range); /** Generates a cryptographically secure random k-bit number * @param k The bit length of the number. * @return */ - static CBigNum RandKBitBigum(const uint32_t k){ - CBigNum ret; - if(!BN_rand(ret.bn, k, -1, 0)){ - throw bignum_error("CBigNum:rand element : BN_rand failed"); - } - return ret; - } + static CBigNum randKBitBignum(const uint32_t k); /**Returns the size in bits of the underlying bignum. * * @return the size */ - int bitSize() const{ - return BN_num_bits(bn); - } - - void setulong(unsigned long n) - { - if (!BN_set_word(bn, n)) - throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); - } - - unsigned long getulong() const - { - return BN_get_word(bn); - } - - unsigned int getuint() const - { - return BN_get_word(bn); - } - - int getint() const - { - unsigned long n = BN_get_word(bn); - if (!BN_is_negative(bn)) - return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::max() : n); - else - return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::min() : -(int)n); - } - - void setint64(int64_t sn) - { - unsigned char pch[sizeof(sn) + 6]; - unsigned char* p = pch + 4; - bool fNegative; - uint64_t n; - - if (sn < (int64_t)0) - { - // Since the minimum signed integer cannot be represented as positive so long as its type is signed, - // and it's not well-defined what happens if you make it unsigned before negating it, - // we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate - n = -(sn + 1); - ++n; - fNegative = true; - } else { - n = sn; - fNegative = false; - } - - bool fLeadingZeroes = true; - for (int i = 0; i < 8; i++) - { - unsigned char c = (n >> 56) & 0xff; - n <<= 8; - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = (fNegative ? 0x80 : 0); - else if (fNegative) - c |= 0x80; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize) & 0xff; - BN_mpi2bn(pch, p - pch, bn); - } - - void setuint64(uint64_t n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - for (int i = 0; i < 8; i++) - { - unsigned char c = (n >> 56) & 0xff; - n <<= 8; - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize) & 0xff; - BN_mpi2bn(pch, p - pch, bn); - } - - void setuint256(uint256 n) - { - unsigned char pch[sizeof(n) + 6]; - unsigned char* p = pch + 4; - bool fLeadingZeroes = true; - unsigned char* pbegin = (unsigned char*)&n; - unsigned char* psrc = pbegin + sizeof(n); - while (psrc != pbegin) - { - unsigned char c = *(--psrc); - if (fLeadingZeroes) - { - if (c == 0) - continue; - if (c & 0x80) - *p++ = 0; - fLeadingZeroes = false; - } - *p++ = c; - } - unsigned int nSize = p - (pch + 4); - pch[0] = (nSize >> 24) & 0xff; - pch[1] = (nSize >> 16) & 0xff; - pch[2] = (nSize >> 8) & 0xff; - pch[3] = (nSize >> 0) & 0xff; - BN_mpi2bn(pch, p - pch, bn); - } - - uint256 getuint256() const - { - if(bitSize() > 256){ - throw std::range_error("cannot convert to uint256, bignum longer than 256 bits"); - } - unsigned int nSize = BN_bn2mpi(bn, NULL); - if (nSize < 4) - return 0; - std::vector vch(nSize); - BN_bn2mpi(bn, &vch[0]); - if (vch.size() > 4) - vch[4] &= 0x7f; - uint256 n = 0; - for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) - ((unsigned char*)&n)[i] = vch[j]; - return n; - } - - void setvch(const std::vector& vch) - { - std::vector vch2(vch.size() + 4); - unsigned int nSize = vch.size(); - // BIGNUM's byte stream format expects 4 bytes of - // big endian size data info at the front - vch2[0] = (nSize >> 24) & 0xff; - vch2[1] = (nSize >> 16) & 0xff; - vch2[2] = (nSize >> 8) & 0xff; - vch2[3] = (nSize >> 0) & 0xff; - // swap data to big endian - reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); - BN_mpi2bn(&vch2[0], vch2.size(), bn); - } - - std::vector getvch() const - { - unsigned int nSize = BN_bn2mpi(bn, NULL); - if (nSize <= 4) - return std::vector(); - std::vector vch(nSize); - BN_bn2mpi(bn, &vch[0]); - vch.erase(vch.begin(), vch.begin() + 4); - reverse(vch.begin(), vch.end()); - return vch; - } - - void SetDec(const std::string& str) - { - BN_dec2bn(&bn, str.c_str()); - } - - void SetHex(const std::string& str) - { - SetHexBool(str); - } - - bool SetHexBool(const std::string& str) - { - // skip 0x - const char* psz = str.c_str(); - while (isspace(*psz)) - psz++; - bool fNegative = false; - if (*psz == '-') - { - fNegative = true; - psz++; - } - if (psz[0] == '0' && tolower(psz[1]) == 'x') - psz += 2; - while (isspace(*psz)) - psz++; - - // hex string to bignum - static const signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; - *this = 0; - while (isxdigit(*psz)) - { - *this <<= 4; - int n = phexdigit[(unsigned char)*psz++]; - *this += n; - } - if (fNegative) - *this = 0 - *this; - - return true; - } - - - std::string ToString(int nBase=10) const - { - CAutoBN_CTX pctx; - CBigNum bnBase = nBase; - CBigNum bn0 = 0; - CBigNum locBn = *this; - std::string str; - BN_set_negative(locBn.bn, false); - CBigNum dv; - CBigNum rem; - if (BN_cmp(locBn.bn, bn0.bn) == 0) - return "0"; - while (BN_cmp(locBn.bn, bn0.bn) > 0) - { - if (!BN_div(dv.bn, rem.bn, locBn.bn, bnBase.bn, pctx)) - throw bignum_error("CBigNum::ToString() : BN_div failed"); - locBn = dv; - unsigned int c = rem.getulong(); - str += "0123456789abcdef"[c]; - } - if (BN_is_negative(bn)) - str += "-"; - reverse(str.begin(), str.end()); - return str; - } - - std::string GetHex() const - { - return ToString(16); - } - - std::string GetDec() const - { - return ToString(10); - } + int bitSize() const; + void setulong(unsigned long n); + unsigned long getulong() const; + unsigned int getuint() const; + int getint() const; + void setint64(int64_t sn); + void setuint64(uint64_t n); + void setuint256(uint256 n); + uint256 getuint256() const; + void setvch(const std::vector& vch); + std::vector getvch() const; + void SetDec(const std::string& str); + void SetHex(const std::string& str); + bool SetHexBool(const std::string& str); + std::string ToString(int nBase=10) const; + std::string GetHex() const; + std::string GetDec() const; unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const { @@ -419,71 +122,36 @@ class CBigNum * @param e the exponent as an int * @return */ - CBigNum pow(const int e) const { - return this->pow(CBigNum(e)); - } + CBigNum pow(const int e) const; /** * exponentiation this^e * @param e the exponent * @return */ - CBigNum pow(const CBigNum& e) const { - CAutoBN_CTX pctx; - CBigNum ret; - if (!BN_exp(ret.bn, bn, e.bn, pctx)) - throw bignum_error("CBigNum::pow : BN_exp failed"); - return ret; - } + CBigNum pow(const CBigNum& e) const; /** * modular multiplication: (this * b) mod m * @param b operand * @param m modulus */ - CBigNum mul_mod(const CBigNum& b, const CBigNum& m) const { - CAutoBN_CTX pctx; - CBigNum ret; - if (!BN_mod_mul(ret.bn, bn, b.bn, m.bn, pctx)) - throw bignum_error("CBigNum::mul_mod : BN_mod_mul failed"); - - return ret; - } + CBigNum mul_mod(const CBigNum& b, const CBigNum& m) const; /** * modular exponentiation: this^e mod n * @param e exponent * @param m modulus */ - CBigNum pow_mod(const CBigNum& e, const CBigNum& m) const { - CAutoBN_CTX pctx; - CBigNum ret; - if( e < 0){ - // g^-x = (g^-1)^x - CBigNum inv = this->inverse(m); - CBigNum posE = e * -1; - if (!BN_mod_exp(ret.bn, inv.bn, posE.bn, m.bn, pctx)) - throw bignum_error("CBigNum::pow_mod: BN_mod_exp failed on negative exponent"); - }else - if (!BN_mod_exp(ret.bn, bn, e.bn, m.bn, pctx)) - throw bignum_error("CBigNum::pow_mod : BN_mod_exp failed"); + CBigNum pow_mod(const CBigNum& e, const CBigNum& m) const; - return ret; - } - - /** + /** * Calculates the inverse of this element mod m. * i.e. i such this*i = 1 mod m * @param m the modu * @return the inverse */ - CBigNum inverse(const CBigNum& m) const { - CAutoBN_CTX pctx; - CBigNum ret; - if (!BN_mod_inverse(ret.bn, bn, m.bn, pctx)) - throw bignum_error("CBigNum::inverse*= :BN_mod_inverse"); - return ret; - } + CBigNum inverse(const CBigNum& m) const; /** * Generates a random (safe) prime of numBits bits @@ -491,144 +159,41 @@ class CBigNum * @param safe true for a safe prime * @return the prime */ - static CBigNum generatePrime(const unsigned int numBits, bool safe = false) { - CBigNum ret; - if(!BN_generate_prime_ex(ret.bn, numBits, (safe == true), NULL, NULL, NULL)) - throw bignum_error("CBigNum::generatePrime*= :BN_generate_prime_ex"); - return ret; - } + static CBigNum generatePrime(const unsigned int numBits, bool safe = false); /** * Calculates the greatest common divisor (GCD) of two numbers. * @param m the second element * @return the GCD */ - CBigNum gcd( const CBigNum& b) const{ - CAutoBN_CTX pctx; - CBigNum ret; - if (!BN_gcd(ret.bn, bn, b.bn, pctx)) - throw bignum_error("CBigNum::gcd*= :BN_gcd"); - return ret; - } + CBigNum gcd( const CBigNum& b) const; - /** + /** * Miller-Rabin primality test on this element * @param checks: optional, the number of Miller-Rabin tests to run * default causes error rate of 2^-80. * @return true if prime */ - bool isPrime(const int checks=BN_prime_checks) const { - CAutoBN_CTX pctx; - int ret = BN_is_prime_ex(bn, checks, pctx, NULL); - if(ret < 0){ - throw bignum_error("CBigNum::isPrime :BN_is_prime"); - } - return ret; - } - - bool isOne() const { - return BN_is_one(bn); - } - - - - bool operator!() const - { - return BN_is_zero(bn); - } - - CBigNum& operator+=(const CBigNum& b) - { - if (!BN_add(bn, bn, b.bn)) - throw bignum_error("CBigNum::operator+= : BN_add failed"); - return *this; - } - - CBigNum& operator-=(const CBigNum& b) - { - if (!BN_sub(bn, bn, b.bn)) - throw bignum_error("CBigNum::operator-= : BN_sub failed"); - return *this; - } - - CBigNum& operator*=(const CBigNum& b) - { - CAutoBN_CTX pctx; - if (!BN_mul(bn, bn, b.bn, pctx)) - throw bignum_error("CBigNum::operator*= : BN_mul failed"); - return *this; - } - - CBigNum& operator/=(const CBigNum& b) - { - *this = *this / b; - return *this; - } - - CBigNum& operator%=(const CBigNum& b) - { - *this = *this % b; - return *this; - } - - CBigNum& operator<<=(unsigned int shift) - { - if (!BN_lshift(bn, bn, shift)) - throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); - return *this; - } - - CBigNum& operator>>=(unsigned int shift) - { - // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number - // if built on ubuntu 9.04 or 9.10, probably depends on version of OpenSSL - CBigNum a = 1; - a <<= shift; - if (BN_cmp(a.bn, bn) > 0) - { - bn = 0; - return *this; - } - - if (!BN_rshift(bn, bn, shift)) - throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); - return *this; - } - - - CBigNum& operator++() - { - // prefix operator - if (!BN_add(bn, bn, BN_value_one())) - throw bignum_error("CBigNum::operator++ : BN_add failed"); - return *this; - } - - const CBigNum operator++(int) - { - // postfix operator - const CBigNum ret = *this; - ++(*this); - return ret; - } - - CBigNum& operator--() - { - // prefix operator - CBigNum r; - if (!BN_sub(r.bn, bn, BN_value_one())) - throw bignum_error("CBigNum::operator-- : BN_sub failed"); - bn = r.bn; - return *this; - } +#if defined(USE_NUM_OPENSSL) + bool isPrime(const int checks=BN_prime_checks) const; +#endif +#if defined(USE_NUM_GMP) + bool isPrime(const int checks=15) const; +#endif - const CBigNum operator--(int) - { - // postfix operator - const CBigNum ret = *this; - --(*this); - return ret; - } + bool isOne() const; + bool operator!() const; + CBigNum& operator+=(const CBigNum& b); + CBigNum& operator-=(const CBigNum& b); + CBigNum& operator*=(const CBigNum& b); + CBigNum& operator/=(const CBigNum& b); + CBigNum& operator%=(const CBigNum& b); + CBigNum& operator<<=(unsigned int shift); + CBigNum& operator>>=(unsigned int shift); + CBigNum& operator++(); + const CBigNum operator++(int); + CBigNum& operator--(); + const CBigNum operator--(int); friend inline const CBigNum operator+(const CBigNum& a, const CBigNum& b); friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); @@ -645,562 +210,140 @@ class CBigNum friend inline bool operator>(const CBigNum& a, const CBigNum& b); }; -inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) +#if defined(USE_NUM_OPENSSL) +class CAutoBN_CTX { +protected: + BN_CTX* pctx; + BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } + +public: + CAutoBN_CTX() + { + pctx = BN_CTX_new(); + if (pctx == NULL) + throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL"); + } + + ~CAutoBN_CTX() + { + if (pctx != NULL) + BN_CTX_free(pctx); + } + + operator BN_CTX*() { return pctx; } + BN_CTX& operator*() { return *pctx; } + BN_CTX** operator&() { return &pctx; } + bool operator!() { return (pctx == NULL); } +}; + +inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) { CBigNum r; if (!BN_add(r.bn, a.bn, b.bn)) throw bignum_error("CBigNum::operator+ : BN_add failed"); return r; } - -inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) { CBigNum r; if (!BN_sub(r.bn, a.bn, b.bn)) throw bignum_error("CBigNum::operator- : BN_sub failed"); return r; } - -inline const CBigNum operator-(const CBigNum& a) -{ +inline const CBigNum operator-(const CBigNum& a) { CBigNum r(a); BN_set_negative(r.bn, !BN_is_negative(r.bn)); return r; } - -inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) { CAutoBN_CTX pctx; CBigNum r; if (!BN_mul(r.bn, a.bn, b.bn, pctx)) throw bignum_error("CBigNum::operator* : BN_mul failed"); return r; } - -inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) { CAutoBN_CTX pctx; CBigNum r; if (!BN_div(r.bn, NULL, a.bn, b.bn, pctx)) throw bignum_error("CBigNum::operator/ : BN_div failed"); return r; } - -inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) { CAutoBN_CTX pctx; CBigNum r; if (!BN_nnmod(r.bn, a.bn, b.bn, pctx)) throw bignum_error("CBigNum::operator% : BN_div failed"); return r; } - -inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) -{ +inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) { CBigNum r; if (!BN_lshift(r.bn, a.bn, shift)) throw bignum_error("CBigNum:operator<< : BN_lshift failed"); return r; } - -inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) -{ +inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) { CBigNum r = a; r >>= shift; return r; } - inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) == 0); } inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) != 0); } inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) <= 0); } inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) >= 0); } inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) < 0); } inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.bn, b.bn) > 0); } -inline std::ostream& operator<<(std::ostream &strm, const CBigNum &b) { return strm << b.ToString(10); } - #endif -#if defined(USE_NUM_GMP) -/** C++ wrapper for BIGNUM (Gmp bignum) */ -class CBigNum -{ - mpz_t bn; -public: - CBigNum() - { - mpz_init(bn); - } - CBigNum(const CBigNum& b) - { - mpz_init(bn); - mpz_set(bn, b.bn); - } - - CBigNum& operator=(const CBigNum& b) - { - mpz_set(bn, b.bn); - return (*this); - } - - ~CBigNum() - { - mpz_clear(bn); - } - - //CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. - CBigNum(signed char n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } - CBigNum(short n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } - CBigNum(int n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } - CBigNum(long n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } - CBigNum(long long n) { mpz_init(bn); mpz_set_si(bn, n); } - CBigNum(unsigned char n) { mpz_init(bn); mpz_set_ui(bn, n); } - CBigNum(unsigned short n) { mpz_init(bn); mpz_set_ui(bn, n); } - CBigNum(unsigned int n) { mpz_init(bn); mpz_set_ui(bn, n); } - CBigNum(unsigned long n) { mpz_init(bn); mpz_set_ui(bn, n); } - - explicit CBigNum(uint256 n) { mpz_init(bn); setuint256(n); } - - explicit CBigNum(const std::vector& vch) - { - mpz_init(bn); - setvch(vch); - } - - /** Generates a cryptographically secure random number between zero and range exclusive - * i.e. 0 < returned number < range - * @param range The upper bound on the number. - * @return - */ - static CBigNum randBignum(const CBigNum& range) { - size_t size = (mpz_sizeinbase (range.bn, 2) + CHAR_BIT-1) / CHAR_BIT; - std::vector buf(size); - - RandAddSeed(); - GetRandBytes(buf.data(), size); - - CBigNum ret(buf); - if (ret < 0) - mpz_neg(ret.bn, ret.bn); - return ret; - } - - /** Generates a cryptographically secure random k-bit number - * @param k The bit length of the number. - * @return - */ - static CBigNum RandKBitBigum(const uint32_t k){ - std::vector buf((k+7)/8); - - RandAddSeed(); - GetRandBytes(buf.data(), (k+7)/8); - - CBigNum ret(buf); - if (ret < 0) - mpz_neg(ret.bn, ret.bn); - return ret; - } - - /**Returns the size in bits of the underlying bignum. - * - * @return the size - */ - int bitSize() const{ - return mpz_sizeinbase(bn, 2); - } - - void setulong(unsigned long n) - { - mpz_set_ui(bn, n); - } - - unsigned long getulong() const - { - return mpz_get_ui(bn); - } - - unsigned int getuint() const - { - return mpz_get_ui(bn); - } - - int getint() const - { - unsigned long n = getulong(); - if (mpz_cmp(bn, CBigNum(0).bn) >= 0) { - return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::max() : n); - } else { - return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::min() : -(int)n); - } - } - - void setuint256(uint256 n) - { - mpz_import(bn, n.size(), -1, 1, 0, 0, (unsigned char*)&n); - } - - uint256 getuint256() const - { - if(bitSize() > 256){ - throw std::range_error("cannot convert to uint256, bignum longer than 256 bits"); - } - uint256 n = 0; - mpz_export((unsigned char*)&n, NULL, -1, 1, 0, 0, bn); - return n; - } - - void setvch(const std::vector& vch) - { - std::vector vch2 = vch; - unsigned char sign = 0; - if (vch2.size() > 0) { - sign = vch2[vch2.size()-1] & 0x80; - vch2[vch2.size()-1] = vch2[vch2.size()-1] & 0x7f; - mpz_import(bn, vch2.size(), -1, 1, 0, 0, &vch2[0]); - if (sign) - mpz_neg(bn, bn); - } - else { - mpz_set_si(bn, 0); - } - } - - std::vector getvch() const - { - if (mpz_cmp(bn, CBigNum(0).bn) == 0) { - return std::vector(0); - } - size_t size = (mpz_sizeinbase (bn, 2) + CHAR_BIT-1) / CHAR_BIT; - if (size <= 0) - return std::vector(); - std::vector v(size + 1); - mpz_export(&v[0], &size, -1, 1, 0, 0, bn); - if (v[v.size()-2] & 0x80) { - if (mpz_sgn(bn)<0) { - v[v.size()-1] = 0x80; - } else { - v[v.size()-1] = 0x00; - } - } else { - v.pop_back(); - if (mpz_sgn(bn)<0) { - v[v.size()-1] |= 0x80; - } - } - return v; - } - - void SetDec(const std::string& str) - { - const char* psz = str.c_str(); - mpz_set_str(bn, psz, 10); - } - - void SetHex(const std::string& str) - { - SetHexBool(str); - } - - bool SetHexBool(const std::string& str) - { - const char* psz = str.c_str(); - int ret = 1 + mpz_set_str(bn, psz, 16); - return (bool) ret; - } - - std::string ToString(int nBase=10) const - { - char* c_str = mpz_get_str(NULL, nBase, bn); - std::string str(c_str); - return str; - } - - std::string GetHex() const - { - return ToString(16); - } - - std::string GetDec() const - { - return ToString(10); - } - - unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const - { - return ::GetSerializeSize(getvch(), nType, nVersion); - } - - template - void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const - { - ::Serialize(s, getvch(), nType, nVersion); - } - - template - void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) - { - std::vector vch; - ::Unserialize(s, vch, nType, nVersion); - setvch(vch); - } - - /** - * exponentiation with an int. this^e - * @param e the exponent as an int - * @return - */ - CBigNum pow(const int e) const { - return this->pow(CBigNum(e)); - } - - /** - * exponentiation this^e - * @param e the exponent - * @return - */ - CBigNum pow(const CBigNum& e) const { - CBigNum ret; - long unsigned int ei = mpz_get_ui (e.bn); - mpz_pow_ui(ret.bn, bn, ei); - return ret; - } - - /** - * modular multiplication: (this * b) mod m - * @param b operand - * @param m modulus - */ - CBigNum mul_mod(const CBigNum& b, const CBigNum& m) const { - CBigNum ret; - mpz_mul (ret.bn, bn, b.bn); - mpz_mod (ret.bn, ret.bn, m.bn); - return ret; - } - - /** - * modular exponentiation: this^e mod n - * @param e exponent - * @param m modulus - */ - CBigNum pow_mod(const CBigNum& e, const CBigNum& m) const { - CBigNum ret; - if (e > CBigNum(0) && mpz_odd_p(m.bn)) - mpz_powm_sec (ret.bn, bn, e.bn, m.bn); - else - mpz_powm (ret.bn, bn, e.bn, m.bn); - return ret; - } - - /** - * Calculates the inverse of this element mod m. - * i.e. i such this*i = 1 mod m - * @param m the modu - * @return the inverse - */ - CBigNum inverse(const CBigNum& m) const { - CBigNum ret; - mpz_invert(ret.bn, bn, m.bn); - return ret; - } - - /** - * Generates a random (safe) prime of numBits bits - * @param numBits the number of bits - * @param safe true for a safe prime - * @return the prime - */ - static CBigNum generatePrime(const unsigned int numBits, bool safe = false) { - CBigNum rand = RandKBitBigum(numBits); - CBigNum prime; - mpz_nextprime(prime.bn, rand.bn); - return prime; - } - - /** - * Calculates the greatest common divisor (GCD) of two numbers. - * @param m the second element - * @return the GCD - */ - CBigNum gcd( const CBigNum& b) const{ - CBigNum ret; - mpz_gcd(ret.bn, bn, b.bn); - return ret; - } - - /** - * Miller-Rabin primality test on this element - * @param checks: optional, the number of Miller-Rabin tests to run - * default causes error rate of 2^-80. - * @return true if prime - */ - bool isPrime(const int checks=15) const { - int ret = mpz_probab_prime_p(bn, checks); - return ret; - } - - bool isOne() const - { - return mpz_cmp(bn, CBigNum(1).bn) == 0; - } - - bool operator!() const - { - return mpz_cmp(bn, CBigNum(0).bn) == 0; - } - - CBigNum& operator+=(const CBigNum& b) - { - mpz_add(bn, bn, b.bn); - return *this; - } - - CBigNum& operator-=(const CBigNum& b) - { - mpz_sub(bn, bn, b.bn); - return *this; - } - - CBigNum& operator*=(const CBigNum& b) - { - mpz_mul(bn, bn, b.bn); - return *this; - } - - CBigNum& operator/=(const CBigNum& b) - { - *this = *this / b; - return *this; - } - - CBigNum& operator%=(const CBigNum& b) - { - *this = *this % b; - return *this; - } - - CBigNum& operator<<=(unsigned int shift) - { - mpz_mul_2exp(bn, bn, shift); - return *this; - } - - CBigNum& operator>>=(unsigned int shift) - { - mpz_div_2exp(bn, bn, shift); - return *this; - } - - - CBigNum& operator++() - { - // prefix operator - mpz_add(bn, bn, CBigNum(1).bn); - return *this; - } - - const CBigNum operator++(int) - { - // postfix operator - const CBigNum ret = *this; - ++(*this); - return ret; - } - - CBigNum& operator--() - { - // prefix operator - mpz_sub(bn, bn, CBigNum(1).bn); - return *this; - } - - const CBigNum operator--(int) - { - // postfix operator - const CBigNum ret = *this; - --(*this); - return ret; - } - - friend inline const CBigNum operator+(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator*(const CBigNum& a, const CBigNum& b); - friend inline const CBigNum operator<<(const CBigNum& a, unsigned int shift); - friend inline const CBigNum operator-(const CBigNum& a); - friend inline bool operator==(const CBigNum& a, const CBigNum& b); - friend inline bool operator!=(const CBigNum& a, const CBigNum& b); - friend inline bool operator<=(const CBigNum& a, const CBigNum& b); - friend inline bool operator>=(const CBigNum& a, const CBigNum& b); - friend inline bool operator<(const CBigNum& a, const CBigNum& b); - friend inline bool operator>(const CBigNum& a, const CBigNum& b); -}; - -inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) -{ +#if defined(USE_NUM_GMP) +inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) { CBigNum r; mpz_add(r.bn, a.bn, b.bn); return r; } - -inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) { CBigNum r; mpz_sub(r.bn, a.bn, b.bn); return r; } - -inline const CBigNum operator-(const CBigNum& a) -{ +inline const CBigNum operator-(const CBigNum& a) { CBigNum r; mpz_neg(r.bn, a.bn); return r; } - -inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) { CBigNum r; mpz_mul(r.bn, a.bn, b.bn); return r; } - -inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) { CBigNum r; mpz_tdiv_q(r.bn, a.bn, b.bn); return r; } - -inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) -{ +inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) { CBigNum r; mpz_mmod(r.bn, a.bn, b.bn); return r; } - -inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) -{ +inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) { CBigNum r; mpz_mul_2exp(r.bn, a.bn, shift); return r; } - -inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) -{ +inline const CBigNum operator>>(const CBigNum& a, unsigned int shift) { CBigNum r = a; r >>= shift; return r; } - inline bool operator==(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) == 0); } inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) != 0); } inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) <= 0); } inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) >= 0); } inline bool operator<(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) < 0); } inline bool operator>(const CBigNum& a, const CBigNum& b) { return (mpz_cmp(a.bn, b.bn) > 0); } -inline std::ostream& operator<<(std::ostream &strm, const CBigNum &b) { return strm << b.ToString(10); } #endif -typedef CBigNum Bignum; - +inline std::ostream& operator<<(std::ostream &strm, const CBigNum &b) { return strm << b.ToString(10); } +typedef CBigNum Bignum; #endif diff --git a/src/libzerocoin/bignum_gmp.cpp b/src/libzerocoin/bignum_gmp.cpp new file mode 100644 index 0000000000000..0d9ac4c4385da --- /dev/null +++ b/src/libzerocoin/bignum_gmp.cpp @@ -0,0 +1,351 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2017-201 The PIVX developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bignum.h" + +/** C++ wrapper for BIGNUM (Gmp bignum) */ +CBigNum::CBigNum() +{ + mpz_init(bn); +} + +CBigNum::CBigNum(const CBigNum& b) +{ + mpz_init(bn); + mpz_set(bn, b.bn); +} + +CBigNum& CBigNum::operator=(const CBigNum& b) +{ + mpz_set(bn, b.bn); + return (*this); +} + +CBigNum::~CBigNum() +{ + mpz_clear(bn); +} + +//CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. +CBigNum::CBigNum(signed char n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } +CBigNum::CBigNum(short n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } +CBigNum::CBigNum(int n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } +CBigNum::CBigNum(long n) { mpz_init(bn); if (n >= 0) mpz_set_ui(bn, n); else mpz_set_si(bn, n); } +CBigNum::CBigNum(long long n) { mpz_init(bn); mpz_set_si(bn, n); } +CBigNum::CBigNum(unsigned char n) { mpz_init(bn); mpz_set_ui(bn, n); } +CBigNum::CBigNum(unsigned short n) { mpz_init(bn); mpz_set_ui(bn, n); } +CBigNum::CBigNum(unsigned int n) { mpz_init(bn); mpz_set_ui(bn, n); } +CBigNum::CBigNum(unsigned long n) { mpz_init(bn); mpz_set_ui(bn, n); } + +CBigNum::CBigNum(uint256 n) { mpz_init(bn); setuint256(n); } + +CBigNum::CBigNum(const std::vector& vch) +{ + mpz_init(bn); + setvch(vch); +} + +/** PRNGs use OpenSSL for consistency with seed initialization **/ + +/** Generates a cryptographically secure random number between zero and range-1 (inclusive) +* i.e. 0 <= returned number < range +* @param range The upper bound on the number. +* @return +*/ +CBigNum CBigNum::randBignum(const CBigNum& range) +{ + if (range < 2) + return 0; + + size_t size = (mpz_sizeinbase (range.bn, 2) + CHAR_BIT-1) / CHAR_BIT; + std::vector buf(size); + + RandAddSeed(); + GetRandBytes(buf.data(), size); + + CBigNum ret(buf); + if (ret < 0) + mpz_neg(ret.bn, ret.bn); + return (ret % range); +} + +/** Generates a cryptographically secure random k-bit number +* @param k The bit length of the number. +* @return +*/ +CBigNum CBigNum::randKBitBignum(const uint32_t k) +{ + std::vector buf((k+7)/8); + + RandAddSeed(); + GetRandBytes(buf.data(), (k+7)/8); + + CBigNum ret(buf); + if (ret < 0) + mpz_neg(ret.bn, ret.bn); + return ret % (CBigNum(1) << k); +} + +/**Returns the size in bits of the underlying bignum. + * + * @return the size + */ +int CBigNum::bitSize() const +{ + return mpz_sizeinbase(bn, 2); +} + +void CBigNum::setulong(unsigned long n) +{ + mpz_set_ui(bn, n); +} + +unsigned long CBigNum::getulong() const +{ + return mpz_get_ui(bn); +} + +unsigned int CBigNum::getuint() const +{ + return mpz_get_ui(bn); +} + +int CBigNum::getint() const +{ + unsigned long n = getulong(); + if (mpz_cmp(bn, CBigNum(0).bn) >= 0) { + return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::max() : n); + } else { + return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::min() : -(int)n); + } +} + +void CBigNum::setuint256(uint256 n) +{ + mpz_import(bn, n.size(), -1, 1, 0, 0, (unsigned char*)&n); +} + +uint256 CBigNum::getuint256() const +{ + if(bitSize() > 256) { + throw std::range_error("cannot convert to uint256, bignum longer than 256 bits"); + } + uint256 n = uint256(0); + mpz_export((unsigned char*)&n, NULL, -1, 1, 0, 0, bn); + return n; +} + +void CBigNum::setvch(const std::vector& vch) +{ + std::vector vch2 = vch; + unsigned char sign = 0; + if (vch2.size() > 0) { + sign = vch2[vch2.size()-1] & 0x80; + vch2[vch2.size()-1] = vch2[vch2.size()-1] & 0x7f; + mpz_import(bn, vch2.size(), -1, 1, 0, 0, &vch2[0]); + if (sign) + mpz_neg(bn, bn); + } + else { + mpz_set_si(bn, 0); + } +} + +std::vector CBigNum::getvch() const +{ + if (mpz_cmp(bn, CBigNum(0).bn) == 0) { + return std::vector(0); + } + size_t size = (mpz_sizeinbase (bn, 2) + CHAR_BIT-1) / CHAR_BIT; + if (size <= 0) + return std::vector(); + std::vector v(size + 1); + mpz_export(&v[0], &size, -1, 1, 0, 0, bn); + if (v[v.size()-2] & 0x80) { + if (mpz_sgn(bn)<0) { + v[v.size()-1] = 0x80; + } else { + v[v.size()-1] = 0x00; + } + } else { + v.pop_back(); + if (mpz_sgn(bn)<0) { + v[v.size()-1] |= 0x80; + } + } + return v; +} + +void CBigNum::SetDec(const std::string& str) +{ + const char* psz = str.c_str(); + mpz_set_str(bn, psz, 10); +} + +bool CBigNum::SetHexBool(const std::string& str) +{ + const char* psz = str.c_str(); + int ret = 1 + mpz_set_str(bn, psz, 16); + return (bool) ret; +} + +std::string CBigNum::ToString(int nBase) const +{ + char* c_str = mpz_get_str(NULL, nBase, bn); + std::string str(c_str); + // Free c_str with the right free function: + void (*freefunc)(void *, size_t); + mp_get_memory_functions (NULL, NULL, &freefunc); + freefunc(c_str, strlen(c_str) + 1); + + return str; +} + +/** + * exponentiation this^e + * @param e the exponent + * @return + */ +CBigNum CBigNum::pow(const CBigNum& e) const +{ + CBigNum ret; + long unsigned int ei = mpz_get_ui (e.bn); + mpz_pow_ui(ret.bn, bn, ei); + return ret; +} + +/** + * modular multiplication: (this * b) mod m + * @param b operand + * @param m modulus + */ +CBigNum CBigNum::mul_mod(const CBigNum& b, const CBigNum& m) const +{ + CBigNum ret; + mpz_mul (ret.bn, bn, b.bn); + mpz_mod (ret.bn, ret.bn, m.bn); + return ret; +} + +/** + * modular exponentiation: this^e mod n + * @param e exponent + * @param m modulus + */ +CBigNum CBigNum::pow_mod(const CBigNum& e, const CBigNum& m) const +{ + CBigNum ret; + if (e > CBigNum(0) && mpz_odd_p(m.bn)) + mpz_powm_sec (ret.bn, bn, e.bn, m.bn); + else + mpz_powm (ret.bn, bn, e.bn, m.bn); + return ret; +} + +/** +* Calculates the inverse of this element mod m. +* i.e. i such this*i = 1 mod m +* @param m the modu +* @return the inverse +*/ +CBigNum CBigNum::inverse(const CBigNum& m) const +{ + CBigNum ret; + mpz_invert(ret.bn, bn, m.bn); + return ret; +} + +/** + * Generates a random (safe) prime of numBits bits + * @param numBits the number of bits + * @param safe true for a safe prime + * @return the prime + */ +CBigNum CBigNum::generatePrime(const unsigned int numBits, bool safe) +{ + CBigNum rand = randKBitBignum(numBits); + CBigNum prime; + mpz_nextprime(prime.bn, rand.bn); + return prime; +} + +/** + * Calculates the greatest common divisor (GCD) of two numbers. + * @param m the second element + * @return the GCD + */ +CBigNum CBigNum::gcd( const CBigNum& b) const +{ + CBigNum ret; + mpz_gcd(ret.bn, bn, b.bn); + return ret; +} + +/** +* Miller-Rabin primality test on this element +* @param checks: optional, the number of Miller-Rabin tests to run +* default causes error rate of 2^-80. +* @return true if prime +*/ +bool CBigNum::isPrime(const int checks) const +{ + int ret = mpz_probab_prime_p(bn, checks); + return ret; +} + +bool CBigNum::isOne() const +{ + return mpz_cmp(bn, CBigNum(1).bn) == 0; +} + +bool CBigNum::operator!() const +{ + return mpz_cmp(bn, CBigNum(0).bn) == 0; +} + +CBigNum& CBigNum::operator+=(const CBigNum& b) +{ + mpz_add(bn, bn, b.bn); + return *this; +} + +CBigNum& CBigNum::operator-=(const CBigNum& b) +{ + mpz_sub(bn, bn, b.bn); + return *this; +} + +CBigNum& CBigNum::operator*=(const CBigNum& b) +{ + mpz_mul(bn, bn, b.bn); + return *this; +} + +CBigNum& CBigNum::operator<<=(unsigned int shift) +{ + mpz_mul_2exp(bn, bn, shift); + return *this; +} + +CBigNum& CBigNum::operator>>=(unsigned int shift) +{ + mpz_div_2exp(bn, bn, shift); + return *this; +} + +CBigNum& CBigNum::operator++() +{ + // prefix operator + mpz_add(bn, bn, CBigNum(1).bn); + return *this; +} + +CBigNum& CBigNum::operator--() +{ + // prefix operator + mpz_sub(bn, bn, CBigNum(1).bn); + return *this; +} diff --git a/src/libzerocoin/bignum_openssl.cpp b/src/libzerocoin/bignum_openssl.cpp new file mode 100644 index 0000000000000..30e38b2dd1734 --- /dev/null +++ b/src/libzerocoin/bignum_openssl.cpp @@ -0,0 +1,508 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2017-2019 The PIVX developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bignum.h" + +CBigNum::CBigNum() +{ + bn = BN_new(); +} + +CBigNum::CBigNum(const CBigNum& b) +{ + bn = BN_new(); + if (!BN_copy(bn, b.bn)) + { + BN_clear_free(bn); + throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); + } +} + +CBigNum& CBigNum::operator=(const CBigNum& b) +{ + if (!BN_copy(bn, b.bn)) + throw bignum_error("CBigNum::operator= : BN_copy failed"); + return (*this); +} + +CBigNum::~CBigNum() +{ + BN_clear_free(bn); +} + +//CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. +CBigNum::CBigNum(signed char n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } +CBigNum::CBigNum(short n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } +CBigNum::CBigNum(int n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } +CBigNum::CBigNum(long n) { bn = BN_new(); if (n >= 0) setulong(n); else setint64(n); } +CBigNum::CBigNum(long long n) { bn = BN_new(); setint64(n); } +CBigNum::CBigNum(unsigned char n) { bn = BN_new(); setulong(n); } +CBigNum::CBigNum(unsigned short n) { bn = BN_new(); setulong(n); } +CBigNum::CBigNum(unsigned int n) { bn = BN_new(); setulong(n); } +CBigNum::CBigNum(unsigned long n) { bn = BN_new(); setulong(n); } +CBigNum::CBigNum(unsigned long long n) { bn = BN_new(); setuint64(n); } +CBigNum::CBigNum(uint256 n) { bn = BN_new(); setuint256(n); } + +CBigNum::CBigNum(const std::vector& vch) +{ + bn = BN_new(); + setvch(vch); +} + +/** Generates a cryptographically secure random number between zero and range-1 (inclusive) +* i.e. 0 <= returned number < range +* @param range The upper bound on the number. +* @return +*/ +CBigNum CBigNum::randBignum(const CBigNum& range) +{ + CBigNum ret; + if(!BN_rand_range(ret.bn, range.bn)){ + throw bignum_error("CBigNum:rand element : BN_rand_range failed"); + } + return ret; +} + +/** Generates a cryptographically secure random k-bit number +* @param k The bit length of the number. +* @return +*/ +CBigNum CBigNum::randKBitBignum(const uint32_t k) +{ + CBigNum ret; + if(!BN_rand(ret.bn, k, -1, 0)){ + throw bignum_error("CBigNum:rand element : BN_rand failed"); + } + return ret; +} + +/**Returns the size in bits of the underlying bignum. + * + * @return the size + */ +int CBigNum::bitSize() const +{ + return BN_num_bits(bn); +} + +void CBigNum::setulong(unsigned long n) +{ + if (!BN_set_word(bn, n)) + throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); +} + +unsigned long CBigNum::getulong() const +{ + return BN_get_word(bn); +} + +unsigned int CBigNum::getuint() const +{ + return BN_get_word(bn); +} + +int CBigNum::getint() const +{ + unsigned long n = BN_get_word(bn); + if (!BN_is_negative(bn)) + return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::max() : n); + else + return (n > (unsigned long)std::numeric_limits::max() ? std::numeric_limits::min() : -(int)n); +} + +void CBigNum::setint64(int64_t sn) +{ + unsigned char pch[sizeof(sn) + 6]; + unsigned char* p = pch + 4; + bool fNegative; + uint64_t n; + + if (sn < (int64_t)0) + { + // Since the minimum signed integer cannot be represented as positive so long as its type is signed, + // and it's not well-defined what happens if you make it unsigned before negating it, + // we instead increment the negative integer by 1, convert it, then increment the (now positive) unsigned integer by 1 to compensate + n = -(sn + 1); + ++n; + fNegative = true; + } else { + n = sn; + fNegative = false; + } + + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = (fNegative ? 0x80 : 0); + else if (fNegative) + c |= 0x80; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, bn); +} + +void CBigNum::setuint64(uint64_t n) +{ + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fLeadingZeroes = true; + for (int i = 0; i < 8; i++) + { + unsigned char c = (n >> 56) & 0xff; + n <<= 8; + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize) & 0xff; + BN_mpi2bn(pch, p - pch, bn); +} + +void CBigNum::setuint256(uint256 n) +{ + unsigned char pch[sizeof(n) + 6]; + unsigned char* p = pch + 4; + bool fLeadingZeroes = true; + unsigned char* pbegin = (unsigned char*)&n; + unsigned char* psrc = pbegin + sizeof(n); + while (psrc != pbegin) + { + unsigned char c = *(--psrc); + if (fLeadingZeroes) + { + if (c == 0) + continue; + if (c & 0x80) + *p++ = 0; + fLeadingZeroes = false; + } + *p++ = c; + } + unsigned int nSize = p - (pch + 4); + pch[0] = (nSize >> 24) & 0xff; + pch[1] = (nSize >> 16) & 0xff; + pch[2] = (nSize >> 8) & 0xff; + pch[3] = (nSize >> 0) & 0xff; + BN_mpi2bn(pch, p - pch, bn); +} + +uint256 CBigNum::getuint256() const +{ + if(bitSize() > 256) { + throw std::range_error("cannot convert to uint256, bignum longer than 256 bits"); + } + unsigned int nSize = BN_bn2mpi(bn, NULL); + if (nSize < 4) + return 0; + std::vector vch(nSize); + BN_bn2mpi(bn, &vch[0]); + if (vch.size() > 4) + vch[4] &= 0x7f; + uint256 n = 0; + for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) + ((unsigned char*)&n)[i] = vch[j]; + return n; +} + +void CBigNum::setvch(const std::vector& vch) +{ + std::vector vch2(vch.size() + 4); + unsigned int nSize = vch.size(); + // BIGNUM's byte stream format expects 4 bytes of + // big endian size data info at the front + vch2[0] = (nSize >> 24) & 0xff; + vch2[1] = (nSize >> 16) & 0xff; + vch2[2] = (nSize >> 8) & 0xff; + vch2[3] = (nSize >> 0) & 0xff; + // swap data to big endian + reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4); + BN_mpi2bn(&vch2[0], vch2.size(), bn); +} + +std::vector CBigNum::getvch() const +{ + unsigned int nSize = BN_bn2mpi(bn, NULL); + if (nSize <= 4) + return std::vector(); + std::vector vch(nSize); + BN_bn2mpi(bn, &vch[0]); + vch.erase(vch.begin(), vch.begin() + 4); + reverse(vch.begin(), vch.end()); + return vch; +} + +void CBigNum::SetDec(const std::string& str) +{ + BN_dec2bn(&bn, str.c_str()); +} + +bool CBigNum::SetHexBool(const std::string& str) +{ + // skip 0x + const char* psz = str.c_str(); + while (isspace(*psz)) + psz++; + bool fNegative = false; + if (*psz == '-') + { + fNegative = true; + psz++; + } + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + while (isspace(*psz)) + psz++; + + // hex string to bignum + static const signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 }; + *this = 0; + while (isxdigit(*psz)) + { + *this <<= 4; + int n = phexdigit[(unsigned char)*psz++]; + *this += n; + } + if (fNegative) + *this = 0 - *this; + + return true; +} + + +std::string CBigNum::ToString(int nBase) const +{ + CAutoBN_CTX pctx; + CBigNum bnBase = nBase; + CBigNum bn0 = 0; + CBigNum locBn = *this; + std::string str; + BN_set_negative(locBn.bn, false); + CBigNum dv; + CBigNum rem; + if (BN_cmp(locBn.bn, bn0.bn) == 0) + return "0"; + while (BN_cmp(locBn.bn, bn0.bn) > 0) + { + if (!BN_div(dv.bn, rem.bn, locBn.bn, bnBase.bn, pctx)) + throw bignum_error("CBigNum::ToString() : BN_div failed"); + locBn = dv; + unsigned int c = rem.getulong(); + str += "0123456789abcdef"[c]; + } + if (BN_is_negative(bn)) + str += "-"; + reverse(str.begin(), str.end()); + return str; +} + +/** + * exponentiation this^e + * @param e the exponent + * @return + */ +CBigNum CBigNum::pow(const CBigNum& e) const +{ + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_exp(ret.bn, bn, e.bn, pctx)) + throw bignum_error("CBigNum::pow : BN_exp failed"); + return ret; +} + +/** + * modular multiplication: (this * b) mod m + * @param b operand + * @param m modulus + */ +CBigNum CBigNum::mul_mod(const CBigNum& b, const CBigNum& m) const +{ + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_mod_mul(ret.bn, bn, b.bn, m.bn, pctx)) + throw bignum_error("CBigNum::mul_mod : BN_mod_mul failed"); + + return ret; +} + +/** + * modular exponentiation: this^e mod n + * @param e exponent + * @param m modulus + */ +CBigNum CBigNum::pow_mod(const CBigNum& e, const CBigNum& m) const +{ + CAutoBN_CTX pctx; + CBigNum ret; + if( e < 0){ + // g^-x = (g^-1)^x + CBigNum inv = this->inverse(m); + CBigNum posE = e * -1; + if (!BN_mod_exp(ret.bn, inv.bn, posE.bn, m.bn, pctx)) + throw bignum_error("CBigNum::pow_mod: BN_mod_exp failed on negative exponent"); + }else + if (!BN_mod_exp(ret.bn, bn, e.bn, m.bn, pctx)) + throw bignum_error("CBigNum::pow_mod : BN_mod_exp failed"); + + return ret; +} + +/** +* Calculates the inverse of this element mod m. +* i.e. i such this*i = 1 mod m +* @param m the modu +* @return the inverse +*/ +CBigNum CBigNum::inverse(const CBigNum& m) const +{ + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_mod_inverse(ret.bn, bn, m.bn, pctx)) + throw bignum_error("CBigNum::inverse*= :BN_mod_inverse"); + return ret; +} + +/** + * Generates a random (safe) prime of numBits bits + * @param numBits the number of bits + * @param safe true for a safe prime + * @return the prime + */ +CBigNum CBigNum::generatePrime(const unsigned int numBits, bool safe) +{ + CBigNum ret; + if(!BN_generate_prime_ex(ret.bn, numBits, (safe == true), NULL, NULL, NULL)) + throw bignum_error("CBigNum::generatePrime*= :BN_generate_prime_ex"); + return ret; +} + +/** + * Calculates the greatest common divisor (GCD) of two numbers. + * @param m the second element + * @return the GCD + */ +CBigNum CBigNum::gcd( const CBigNum& b) const +{ + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_gcd(ret.bn, bn, b.bn, pctx)) + throw bignum_error("CBigNum::gcd*= :BN_gcd"); + return ret; +} + +/** +* Miller-Rabin primality test on this element +* @param checks: optional, the number of Miller-Rabin tests to run +* default causes error rate of 2^-80. +* @return true if prime +*/ +bool CBigNum::isPrime(const int checks) const +{ + CAutoBN_CTX pctx; + int ret = BN_is_prime_ex(bn, checks, pctx, NULL); + if(ret < 0){ + throw bignum_error("CBigNum::isPrime :BN_is_prime"); + } + return ret; +} + +bool CBigNum::isOne() const +{ + return BN_is_one(bn); +} + +bool CBigNum::operator!() const +{ + return BN_is_zero(bn); +} + +CBigNum& CBigNum::operator+=(const CBigNum& b) +{ + if (!BN_add(bn, bn, b.bn)) + throw bignum_error("CBigNum::operator+= : BN_add failed"); + return *this; +} + +CBigNum& CBigNum::operator-=(const CBigNum& b) +{ + if (!BN_sub(bn, bn, b.bn)) + throw bignum_error("CBigNum::operator-= : BN_sub failed"); + return *this; +} + +CBigNum& CBigNum::operator*=(const CBigNum& b) +{ + CAutoBN_CTX pctx; + if (!BN_mul(bn, bn, b.bn, pctx)) + throw bignum_error("CBigNum::operator*= : BN_mul failed"); + return *this; +} + +CBigNum& CBigNum::operator<<=(unsigned int shift) +{ + if (!BN_lshift(bn, bn, shift)) + throw bignum_error("CBigNum:operator<<= : BN_lshift failed"); + return *this; +} + +CBigNum& CBigNum::operator>>=(unsigned int shift) +{ + // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number + // if built on ubuntu 9.04 or 9.10, probably depends on version of OpenSSL + CBigNum a = 1; + a <<= shift; + if (BN_cmp(a.bn, bn) > 0) + { + bn = 0; + return *this; + } + + if (!BN_rshift(bn, bn, shift)) + throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); + return *this; +} + + +CBigNum& CBigNum::operator++() +{ + // prefix operator + if (!BN_add(bn, bn, BN_value_one())) + throw bignum_error("CBigNum::operator++ : BN_add failed"); + return *this; +} + +CBigNum& CBigNum::operator--() +{ + // prefix operator + CBigNum r; + if (!BN_sub(r.bn, bn, BN_value_one())) + throw bignum_error("CBigNum::operator-- : BN_sub failed"); + bn = r.bn; + return *this; +} diff --git a/src/main.cpp b/src/main.cpp index 58ecc74d662c5..14e42010dd6f9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,7 +31,7 @@ #include "swifttx.h" #include "txdb.h" #include "txmempool.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "utilmoneystr.h" #include "validationinterface.h" @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -65,7 +66,6 @@ CCriticalSection cs_main; BlockMap mapBlockIndex; map mapProofOfStake; -set > setStakeSeen; map mapHashedBlocks; CChain chainActive; CBlockIndex* pindexBestHeader = NULL; @@ -83,6 +83,9 @@ unsigned int nCoinCacheSize = 5000; bool fAlerts = DEFAULT_ALERTS; bool fClearSpendCache = false; +/* If the tip is older than this (in seconds), the node is considered to be in initial block download. */ +int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; + unsigned int nStakeMinAge = 60 * 60; int64_t nReserveBalance = 0; @@ -387,7 +390,7 @@ void FinalizeNode(NodeId nodeid) AddressCurrentlyConnected(state->address); } - BOOST_FOREACH (const QueuedBlock& entry, state->vBlocksInFlight) + for (const QueuedBlock& entry : state->vBlocksInFlight) mapBlocksInFlight.erase(entry.hash); EraseOrphansFor(nodeid); nPreferredDownload -= state->fPreferredDownload; @@ -534,7 +537,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vectorIsValid(BLOCK_VALID_TREE)) { // We consider the chain that this peer is on invalid. return; @@ -593,7 +596,7 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) stats.nMisbehavior = state->nMisbehavior; stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1; stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1; - BOOST_FOREACH (const QueuedBlock& queue, state->vBlocksInFlight) { + for (const QueuedBlock& queue : state->vBlocksInFlight) { if (queue.pindex) stats.vHeightInFlight.push_back(queue.pindex->nHeight); } @@ -621,7 +624,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals) CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) { // Find the first block the caller has in the main chain - BOOST_FOREACH (const uint256& hash, locator.vHave) { + for (const uint256& hash : locator.vHave) { BlockMap::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { CBlockIndex* pindex = (*mi).second; @@ -664,7 +667,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) mapOrphanTransactions[hash].tx = tx; mapOrphanTransactions[hash].fromPeer = peer; - BOOST_FOREACH (const CTxIn& txin, tx.vin) + for (const CTxIn& txin : tx.vin) mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(), @@ -677,7 +680,7 @@ void static EraseOrphanTx(uint256 hash) map::iterator it = mapOrphanTransactions.find(hash); if (it == mapOrphanTransactions.end()) return; - BOOST_FOREACH (const CTxIn& txin, it->second.tx.vin) { + for (const CTxIn& txin : it->second.tx.vin) { map >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash); if (itPrev == mapOrphanTransactionsByPrev.end()) continue; @@ -760,7 +763,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) } for (const CTxIn& txin : tx.vin) { - if (txin.scriptSig.IsZerocoinSpend()) + if (txin.IsZerocoinSpend() || txin.IsZerocoinPublicSpend()) continue; // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed // keys. (remember the 520 byte limit on redeemScript size) That works @@ -781,7 +784,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason) unsigned int nDataOut = 0; txnouttype whichType; - BOOST_FOREACH (const CTxOut& txout, tx.vout) { + for (const CTxOut& txout : tx.vout) { if (!::IsStandard(txout.scriptPubKey, whichType)) { reason = "scriptpubkey"; return false; @@ -819,7 +822,7 @@ bool IsFinalTx(const CTransaction& tx, int nBlockHeight, int64_t nBlockTime) nBlockTime = GetAdjustedTime(); if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) return true; - BOOST_FOREACH (const CTxIn& txin, tx.vin) + for (const CTxIn& txin : tx.vin) if (!txin.IsFinal()) return false; return true; @@ -836,7 +839,7 @@ bool IsFinalTx(const CTransaction& tx, int nBlockHeight, int64_t nBlockTime) */ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { - if (tx.IsCoinBase() || tx.IsZerocoinSpend()) + if (tx.IsCoinBase() || tx.HasZerocoinSpendInputs()) return true; // coinbase has no inputs and zerocoinspend has a special input //todo should there be a check for a 'standard' zerocoinspend here? @@ -892,10 +895,10 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) unsigned int GetLegacySigOpCount(const CTransaction& tx) { unsigned int nSigOps = 0; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { nSigOps += txin.scriptSig.GetSigOpCount(false); } - BOOST_FOREACH (const CTxOut& txout, tx.vout) { + for (const CTxOut& txout : tx.vout) { nSigOps += txout.scriptPubKey.GetSigOpCount(false); } return nSigOps; @@ -903,7 +906,8 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx) unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs) { - if (tx.IsCoinBase() || tx.IsZerocoinSpend()) + if (tx.IsCoinBase() || tx.HasZerocoinSpendInputs()) + // a tx containing a zc spend can have only zc inputs return 0; unsigned int nSigOps = 0; @@ -987,6 +991,11 @@ bool CheckZerocoinMint(const uint256& txHash, const CTxOut& txout, CValidationSt bool ContextualCheckZerocoinMint(const CTransaction& tx, const PublicCoin& coin, const CBlockIndex* pindex) { + if (pindex->nHeight >= Params().Zerocoin_Block_Public_Spend_Enabled()) { + // Zerocoin MINTs have been disabled + return error("%s: Mints disabled at height %d - unable to add pubcoin %s", __func__, + pindex->nHeight, coin.getValue().GetHex().substr(0, 10)); + } if (pindex->nHeight >= Params().Zerocoin_Block_V2_Start() && Params().NetworkID() != CBaseChainParams::TESTNET) { //See if this coin has already been added to the blockchain uint256 txid; @@ -1008,7 +1017,22 @@ bool isBlockBetweenFakeSerialAttackRange(int nHeight) return nHeight <= Params().Zerocoin_Block_EndFakeSerial(); } -bool ContextualCheckZerocoinSpend(const CTransaction& tx, const CoinSpend& spend, CBlockIndex* pindex, const uint256& hashBlock) +bool CheckPublicCoinSpendEnforced(int blockHeight, bool isPublicSpend) { + if (blockHeight >= Params().Zerocoin_Block_Public_Spend_Enabled()) { + // reject old coin spend + if (!isPublicSpend) { + return error("%s: failed to add block with older zc spend version", __func__); + } + + } else { + if (isPublicSpend) { + return error("%s: failed to add block, public spend enforcement not activated", __func__); + } + } + return true; +} + +bool ContextualCheckZerocoinSpend(const CTransaction& tx, const CoinSpend* spend, CBlockIndex* pindex, const uint256& hashBlock) { if(!ContextualCheckZerocoinSpendNoSerialCheck(tx, spend, pindex, hashBlock)){ return false; @@ -1016,19 +1040,19 @@ bool ContextualCheckZerocoinSpend(const CTransaction& tx, const CoinSpend& spend //Reject serial's that are already in the blockchain int nHeightTx = 0; - if (IsSerialInBlockchain(spend.getCoinSerialNumber(), nHeightTx)) + if (IsSerialInBlockchain(spend->getCoinSerialNumber(), nHeightTx)) return error("%s : xION spend with serial %s is already in block %d\n", __func__, - spend.getCoinSerialNumber().GetHex(), nHeightTx); + spend->getCoinSerialNumber().GetHex(), nHeightTx); return true; } -bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const CoinSpend& spend, CBlockIndex* pindex, const uint256& hashBlock) +bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const CoinSpend* spend, CBlockIndex* pindex, const uint256& hashBlock) { //Check to see if the xION is properly signed if (pindex->nHeight >= Params().Zerocoin_Block_V2_Start()) { try { - if (!spend.HasValidSignature()) + if (!spend->HasValidSignature()) return error("%s: V2 xION spend does not have a valid signature\n", __func__); } catch (libzerocoin::InvalidSerialException &e) { // Check if we are in the range of the attack @@ -1041,19 +1065,27 @@ bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const Coi libzerocoin::SpendType expectedType = libzerocoin::SpendType::SPEND; if (tx.IsCoinStake()) expectedType = libzerocoin::SpendType::STAKE; - if (spend.getSpendType() != expectedType) { + if (spend->getSpendType() != expectedType) { return error("%s: trying to spend xION without the correct spend type. txid=%s\n", __func__, tx.GetHash().GetHex()); } } + bool v1Serial = spend->getVersion() < libzerocoin::PrivateCoin::PUBKEY_VERSION; + if (pindex->nHeight >= Params().Zerocoin_Block_Public_Spend_Enabled()) { + //Reject V1 old serials. + if (v1Serial) { + return error("%s : xION v1 serial spend not spendable, serial %s, tx %s\n", __func__, + spend->getCoinSerialNumber().GetHex(), tx.GetHash().GetHex()); + } + } + //Reject serial's that are not in the acceptable value range - bool fUseV1Params = spend.getVersion() < libzerocoin::PrivateCoin::PUBKEY_VERSION; - if (!spend.HasValidSerial(Params().Zerocoin_Params(fUseV1Params))) { + if (!spend->HasValidSerial(Params().Zerocoin_Params(v1Serial))) { // Up until this block our chain was not checking serials correctly.. if (!isBlockBetweenFakeSerialAttackRange(pindex->nHeight)) return error("%s : xION spend with serial %s from tx %s is not in valid range\n", __func__, - spend.getCoinSerialNumber().GetHex(), tx.GetHash().GetHex()); + spend->getCoinSerialNumber().GetHex(), tx.GetHash().GetHex()); else LogPrintf("%s:: HasValidSerial :: Invalid serial detected within range in block %d\n", __func__, pindex->nHeight); } @@ -1086,16 +1118,29 @@ bool CheckZerocoinSpend(const CTransaction& tx, bool fVerifySignature, CValidati bool fValidated = false; set serials; - list vSpends; CAmount nTotalRedeemed = 0; for (const CTxIn& txin : tx.vin) { //only check txin that is a zcspend - if (!txin.scriptSig.IsZerocoinSpend()) + bool isPublicSpend = txin.IsZerocoinPublicSpend(); + if (!txin.IsZerocoinSpend() && !isPublicSpend) continue; - CoinSpend newSpend = TxInToZerocoinSpend(txin); - vSpends.push_back(newSpend); + CoinSpend newSpend; + CTxOut prevOut; + if (isPublicSpend) { + if(!GetOutput(txin.prevout.hash, txin.prevout.n, state, prevOut)){ + return state.DoS(100, error("CheckZerocoinSpend(): public zerocoin spend prev output not found, prevTx %s, index %d", txin.prevout.hash.GetHex(), txin.prevout.n)); + } + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + if (!XIONModule::parseCoinSpend(txin, tx, prevOut, publicSpend)){ + return state.DoS(100, error("CheckZerocoinSpend(): public zerocoin spend parse failed")); + } + newSpend = publicSpend; + }else { + newSpend = TxInToZerocoinSpend(txin); + } //check that the denomination is valid if (newSpend.getDenomination() == ZQ_ERROR) @@ -1109,22 +1154,29 @@ bool CheckZerocoinSpend(const CTransaction& tx, bool fVerifySignature, CValidati if (newSpend.getTxOutHash() != hashTxOut) return state.DoS(100, error("Zerocoinspend does not use the same txout that was used in the SoK")); - // Skip signature verification during initial block download - if (fVerifySignature) { - //see if we have record of the accumulator used in the spend tx - CBigNum bnAccumulatorValue = 0; - if (!zerocoinDB->ReadAccumulatorValue(newSpend.getAccumulatorChecksum(), bnAccumulatorValue)) { - uint32_t nChecksum = newSpend.getAccumulatorChecksum(); - return state.DoS(100, error("%s: Zerocoinspend could not find accumulator associated with checksum %s", __func__, HexStr(BEGIN(nChecksum), END(nChecksum)))); + if (isPublicSpend) { + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + PublicCoinSpend ret(params); + if (!XIONModule::validateInput(txin, prevOut, tx, ret)){ + return state.DoS(100, error("CheckZerocoinSpend(): public zerocoin spend did not verify")); } + } else + // Skip signature verification during initial block download + if (fVerifySignature) { + //see if we have record of the accumulator used in the spend tx + CBigNum bnAccumulatorValue = 0; + if (!zerocoinDB->ReadAccumulatorValue(newSpend.getAccumulatorChecksum(), bnAccumulatorValue)) { + uint32_t nChecksum = newSpend.getAccumulatorChecksum(); + return state.DoS(100, error("%s: Zerocoinspend could not find accumulator associated with checksum %s", __func__, HexStr(BEGIN(nChecksum), END(nChecksum)))); + } - Accumulator accumulator(Params().Zerocoin_Params(chainActive.Height() < Params().Zerocoin_Block_V2_Start()), - newSpend.getDenomination(), bnAccumulatorValue); + Accumulator accumulator(Params().Zerocoin_Params(chainActive.Height() < Params().Zerocoin_Block_V2_Start()), + newSpend.getDenomination(), bnAccumulatorValue); - //Check that the coin has been accumulated - if(!newSpend.Verify(accumulator, !fFakeSerialAttack)) - return state.DoS(100, error("CheckZerocoinSpend(): zerocoin spend did not verify")); - } + //Check that the coin has been accumulated + if(!newSpend.Verify(accumulator, !fFakeSerialAttack)) + return state.DoS(100, error("CheckZerocoinSpend(): zerocoin spend did not verify")); + } if (serials.count(newSpend.getCoinSerialNumber())) return state.DoS(100, error("Zerocoinspend serial is used twice in the same tx")); @@ -1162,8 +1214,7 @@ bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fReject // Check for negative or overflow output values CAmount nValueOut = 0; - int nZCSpendCount = 0; - BOOST_FOREACH (const CTxOut& txout, tx.vout) { + for (const CTxOut& txout : tx.vout) { if (txout.IsEmpty() && !tx.IsCoinBase() && !tx.IsCoinStake()) return state.DoS(100, error("CheckTransaction(): txout empty for user transaction")); @@ -1181,18 +1232,33 @@ bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fReject if(!CheckZerocoinMint(tx.GetHash(), txout, state, true)) return state.DoS(100, error("CheckTransaction() : invalid zerocoin mint")); } - if (fZerocoinActive && txout.scriptPubKey.IsZerocoinSpend()) + } + + set vInOutPoints; + set vZerocoinSpendSerials; + int nZCSpendCount = 0; + for (const CTxIn& txin : tx.vin) { + // Check for duplicate inputs + if (vInOutPoints.count(txin.prevout)) + return state.DoS(100, error("CheckTransaction() : duplicate inputs"), + REJECT_INVALID, "bad-txns-inputs-duplicate"); + + //duplicate zcspend serials are checked in CheckZerocoinSpend() + if (!txin.IsZerocoinSpend()) { + vInOutPoints.insert(txin.prevout); + } else if (!txin.IsZerocoinPublicSpend()) { nZCSpendCount++; + } } if (fZerocoinActive) { if (nZCSpendCount > Params().Zerocoin_MaxSpendsPerTransaction()) return state.DoS(100, error("CheckTransaction() : there are more zerocoin spends than are allowed in one transaction")); - if (tx.IsZerocoinSpend()) { - //require that a zerocoinspend only has inputs that are zerocoins + //require that a zerocoinspend only has inputs that are zerocoins + if (tx.HasZerocoinSpendInputs()) { for (const CTxIn& in : tx.vin) { - if (!in.scriptSig.IsZerocoinSpend()) + if (!in.IsZerocoinSpend() && !in.IsZerocoinPublicSpend()) return state.DoS(100, error("CheckTransaction() : zerocoinspend contains inputs that are not zerocoins")); } @@ -1204,29 +1270,26 @@ bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fReject } } - // Check for duplicate inputs - set vInOutPoints; - set vZerocoinSpendSerials; - for (const CTxIn& txin : tx.vin) { - if (vInOutPoints.count(txin.prevout)) - return state.DoS(100, error("CheckTransaction() : duplicate inputs"), - REJECT_INVALID, "bad-txns-inputs-duplicate"); - - //duplicate zcspend serials are checked in CheckZerocoinSpend() - if (!txin.scriptSig.IsZerocoinSpend()) - vInOutPoints.insert(txin.prevout); - } - if (tx.IsCoinBase()) { if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 150) return state.DoS(100, error("CheckTransaction() : coinbase script size=%d", tx.vin[0].scriptSig.size()), REJECT_INVALID, "bad-cb-length"); - } else if (fZerocoinActive && tx.IsZerocoinSpend()) { - if(tx.vin.size() < 1 || static_cast(tx.vin.size()) > Params().Zerocoin_MaxSpendsPerTransaction()) - return state.DoS(10, error("CheckTransaction() : Zerocoin Spend has more than allowed txin's"), REJECT_INVALID, "bad-zerocoinspend"); + } else if (fZerocoinActive && tx.HasZerocoinSpendInputs()) { + if (tx.vin.size() < 1) + return state.DoS(10, error("CheckTransaction() : Zerocoin Spend has less than allowed txin's"), REJECT_INVALID, "bad-zerocoinspend"); + if (tx.HasZerocoinPublicSpendInputs()) { + // tx has public zerocoin spend inputs + if(static_cast(tx.vin.size()) > Params().Zerocoin_MaxPublicSpendsPerTransaction()) + return state.DoS(10, error("CheckTransaction() : Zerocoin Spend has more than allowed txin's"), REJECT_INVALID, "bad-zerocoinspend"); + } else { + // tx has regular zerocoin spend inputs + if(static_cast(tx.vin.size()) > Params().Zerocoin_MaxSpendsPerTransaction()) + return state.DoS(10, error("CheckTransaction() : Zerocoin Spend has more than allowed txin's"), REJECT_INVALID, "bad-zerocoinspend"); + } + } else { - BOOST_FOREACH (const CTxIn& txin, tx.vin) - if (txin.prevout.IsNull() && (fZerocoinActive && !txin.scriptSig.IsZerocoinSpend())) + for (const CTxIn& txin : tx.vin) + if (txin.prevout.IsNull() && (fZerocoinActive && !txin.IsZerocoinSpend())) return state.DoS(10, error("CheckTransaction() : prevout is null"), REJECT_INVALID, "bad-txns-prevout-null"); } @@ -1338,7 +1401,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa // ----------- swiftTX transaction scanning ----------- - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (mapLockedInputs.count(in.prevout)) { if (mapLockedInputs[in.prevout] != tx.GetHash()) { return state.DoS(0, @@ -1349,7 +1412,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa } // Check for conflicts with in-memory transactions - if (!tx.IsZerocoinSpend()) { + if (!tx.HasZerocoinSpendInputs()) { LOCK(pool.cs); // protect pool.mapNextTx for (unsigned int i = 0; i < tx.vin.size(); i++) { COutPoint outpoint = tx.vin[i].prevout; @@ -1366,7 +1429,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa CCoinsViewCache view(&dummy); CAmount nValueIn = 0; - if(tx.IsZerocoinSpend()){ + if (tx.HasZerocoinSpendInputs()) { nValueIn = tx.GetZerocoinSpent(); //Check that txid is not already in the chain @@ -1377,12 +1440,36 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa //Check for double spending of serial #'s for (const CTxIn& txIn : tx.vin) { - if (!txIn.scriptSig.IsZerocoinSpend()) - continue; - CoinSpend spend = TxInToZerocoinSpend(txIn); - if (!ContextualCheckZerocoinSpend(tx, spend, chainActive.Tip(), 0)) - return state.Invalid(error("%s: ContextualCheckZerocoinSpend failed for tx %s", __func__, + // Only allow for zc spends inputs + bool isPublicSpend = txIn.IsZerocoinPublicSpend(); + bool isPrivZerocoinSpend = txIn.IsZerocoinSpend(); + if (!isPrivZerocoinSpend && !isPublicSpend) { + return state.Invalid(error("%s: AcceptToMemoryPool failed for tx %s, every input must be a zcspend or zcpublicspend", __func__, + tx.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-xion"); + } + + // Check enforcement + if (!CheckPublicCoinSpendEnforced(chainActive.Height(), isPublicSpend)){ + return state.Invalid(error("%s: AcceptToMemoryPool failed for tx %s", __func__, tx.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-xion"); + } + + if (isPublicSpend) { + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + if (!XIONModule::ParseZerocoinPublicSpend(txIn, tx, state, publicSpend)){ + return false; + } + if (!ContextualCheckZerocoinSpend(tx, &publicSpend, chainActive.Tip(), 0)) + return state.Invalid(error("%s: ContextualCheckZerocoinSpend failed for tx %s", __func__, + tx.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-xion"); + } else { + CoinSpend spend = TxInToZerocoinSpend(txIn); + if (!ContextualCheckZerocoinSpend(tx, &spend, chainActive.Tip(), 0)) + return state.Invalid(error("%s: ContextualCheckZerocoinSpend failed for tx %s", __func__, + tx.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-xion"); + } + } } else { LOCK(pool.cs); @@ -1410,25 +1497,23 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa } } - // Check that xION mints are not already known - if (tx.IsZerocoinMint()) { - for (auto& out : tx.vout) { - if (!out.IsZerocoinMint()) - continue; + // Check that xION mints (if included) are not already known + for (auto& out : tx.vout) { + if (!out.IsZerocoinMint()) + continue; - PublicCoin coin(Params().Zerocoin_Params(false)); - if (!TxOutToPublicCoin(out, coin, state)) - return state.Invalid(error("%s: failed final check of zerocoinmint for tx %s", __func__, tx.GetHash().GetHex())); + PublicCoin coin(Params().Zerocoin_Params(false)); + if (!TxOutToPublicCoin(out, coin, state)) + return state.Invalid(error("%s: failed final check of zerocoinmint for tx %s", __func__, tx.GetHash().GetHex())); - if (!ContextualCheckZerocoinMint(tx, coin, chainActive.Tip())) - return state.Invalid(error("%s: zerocoin mint failed contextual check", __func__)); - } + if (!ContextualCheckZerocoinMint(tx, coin, chainActive.Tip())) + return state.Invalid(error("%s: zerocoin mint failed contextual check", __func__)); } // are the actual inputs available? if (!view.HaveInputs(tx)) return state.Invalid(error("AcceptToMemoryPool : inputs already spent"), - REJECT_DUPLICATE, "bad-txns-inputs-spent"); + REJECT_DUPLICATE, "bad-txns-inputs-spent"); // Bring the best block into scope view.GetBestBlock(); @@ -1448,7 +1533,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa // itself can contain sigops MAX_TX_SIGOPS is less than // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than // merely non-standard transaction. - if (!tx.IsZerocoinSpend()) { + if (!tx.HasZerocoinSpendInputs()) { unsigned int nSigOps = GetLegacySigOpCount(tx); unsigned int nMaxSigOps = MAX_TX_SIGOPS_CURRENT; nSigOps += GetP2SHSigOpCount(tx, view); @@ -1462,7 +1547,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa CAmount nValueOut = tx.GetValueOut(); CAmount nFees = nValueIn - nValueOut; double dPriority = 0; - if (!tx.IsZerocoinSpend()) + if (!tx.HasZerocoinSpendInputs()) view.GetPriority(tx, chainActive.Height()); CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height()); @@ -1474,23 +1559,23 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa mempool.PrioritiseTransaction(hash, hash.ToString(), 1000, 0.1 * COIN); } else if (!ignoreFees) { CAmount txMinFee = GetMinRelayFee(tx, nSize, true); - if (fLimitFree && nFees < txMinFee && !tx.IsZerocoinSpend()) + if (fLimitFree && nFees < txMinFee && !tx.HasZerocoinSpendInputs()) return state.DoS(0, error("AcceptToMemoryPool : not enough fees %s, %d < %d", hash.ToString(), nFees, txMinFee), REJECT_INSUFFICIENTFEE, "insufficient fee"); // Require that free transactions have sufficient priority to be mined in the next block. - if (tx.IsZerocoinMint()) { + if (tx.HasZerocoinMintOutputs()) { if(nFees < Params().Zerocoin_MintFee() * tx.GetZerocoinMintCount()) return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee for zerocoinmint"); - } else if (!tx.IsZerocoinSpend() && GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { + } else if (!tx.HasZerocoinSpendInputs() && GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); } // Continuously rate-limit free (really, very-low-fee) transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. - if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.IsZerocoinSpend()) { + if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.HasZerocoinSpendInputs()) { static CCriticalSection csFreeLimiter; static double dFreeCount; static int64_t nLastTime; @@ -1551,7 +1636,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa SyncWithWallets(tx, NULL); //Track zerocoinspends and ensure that they are given priority to make it into the blockchain - if (tx.IsZerocoinSpend()) + if (tx.HasZerocoinSpendInputs()) mapZerocoinspends[tx.GetHash()] = GetAdjustedTime(); return true; @@ -1587,7 +1672,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact // ----------- swiftTX transaction scanning ----------- - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (mapLockedInputs.count(in.prevout)) { if (mapLockedInputs[in.prevout] != tx.GetHash()) { return state.DoS(0, @@ -1598,7 +1683,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact } // Check for conflicts with in-memory transactions - if (!tx.IsZerocoinSpend()) { + if (!tx.HasZerocoinSpendInputs()) { LOCK(pool.cs); // protect pool.mapNextTx for (unsigned int i = 0; i < tx.vin.size(); i++) { COutPoint outpoint = tx.vin[i].prevout; @@ -1687,9 +1772,8 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact mempool.PrioritiseTransaction(hash, hash.ToString(), 1000, 0.1 * COIN); } else { // same as !ignoreFees for AcceptToMemoryPool CAmount txMinFee = GetMinRelayFee(tx, nSize, true); - if (fLimitFree && nFees < txMinFee && !tx.IsZerocoinSpend()) - return state.DoS(0, error("AcceptableInputs : not enough fees %s, %d < %d", - hash.ToString(), nFees, txMinFee), + if (fLimitFree && nFees < txMinFee && !tx.HasZerocoinSpendInputs()) + return state.DoS(0, error("AcceptableInputs : not enough fees %s, %d < %d", hash.ToString(), nFees, txMinFee), REJECT_INSUFFICIENTFEE, "insufficient fee"); // Require that free transactions have sufficient priority to be mined in the next block. @@ -1700,7 +1784,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact // Continuously rate-limit free (really, very-low-fee) transactions // This mitigates 'penny-flooding' -- sending thousands of free transactions just to // be annoying or make others' transactions take longer to confirm. - if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.IsZerocoinSpend()) { + if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.HasZerocoinSpendInputs()) { static CCriticalSection csFreeLimiter; static double dFreeCount; static int64_t nLastTime; @@ -1761,6 +1845,20 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact return true; } +bool GetOutput(const uint256& hash, unsigned int index, CValidationState& state, CTxOut& out) +{ + CTransaction txPrev; + uint256 hashBlock; + if (!GetTransaction(hash, txPrev, hashBlock, true)) { + return state.DoS(100, error("Output not found")); + } + if (index > txPrev.vout.size()) { + return state.DoS(100, error("Output not found, invalid index %d for %s",index, hash.GetHex())); + } + out = txPrev.vout[index]; + return true; +} + /** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ bool GetTransaction(const uint256& hash, CTransaction& txOut, uint256& hashBlock, bool fAllowSlow, CBlockIndex* blockIndex) { @@ -1813,7 +1911,7 @@ bool GetTransaction(const uint256& hash, CTransaction& txOut, uint256& hashBlock if (pindexSlow) { CBlock block; if (ReadBlockFromDisk(block, pindexSlow)) { - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { if (tx.GetHash() == hash) { txOut = tx; hashBlock = pindexSlow->GetBlockHash(); @@ -2226,7 +2324,7 @@ bool IsInitialBlockDownload() if (lockIBDState) return false; bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || - pindexBestHeader->GetBlockTime() < GetTime() - 6 * 60 * 60); // ~144 blocks behind -> 2 x fork detection time + pindexBestHeader->GetBlockTime() < GetTime() - nMaxTipAge); if (!state) lockIBDState = true; return state; @@ -2362,9 +2460,9 @@ void static InvalidBlockFound(CBlockIndex* pindex, const CValidationState& state void UpdateCoins(const CTransaction& tx, CValidationState& state, CCoinsViewCache& inputs, CTxUndo& txundo, int nHeight) { // mark inputs spent - if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { + if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) { txundo.vprevout.reserve(tx.vin.size()); - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { txundo.vprevout.push_back(CTxInUndo()); bool ret = inputs.ModifyCoins(txin.prevout.hash)->Spend(txin.prevout, txundo.vprevout.back()); assert(ret); @@ -2394,19 +2492,33 @@ void AddInvalidSpendsToMap(const CBlock& block) //Check all zerocoinspends for bad serials for (const CTxIn& in : tx.vin) { - if (in.scriptSig.IsZerocoinSpend()) { - CoinSpend spend = TxInToZerocoinSpend(in); + bool isPublicSpend = in.IsZerocoinPublicSpend(); + if (in.IsZerocoinSpend() || isPublicSpend) { + + CoinSpend* spend; + if (isPublicSpend) { + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + CValidationState state; + if (!XIONModule::ParseZerocoinPublicSpend(in, tx, state, publicSpend)){ + throw runtime_error("Failed to parse public spend"); + } + spend = &publicSpend; + } else { + CoinSpend spendObj = TxInToZerocoinSpend(in); + spend = &spendObj; + } //If serial is not valid, mark all outputs as bad - if (!spend.HasValidSerial(Params().Zerocoin_Params(false))) { - mapInvalidSerials[spend.getCoinSerialNumber()] = spend.getDenomination() * COIN; + if (!spend->HasValidSerial(Params().Zerocoin_Params(false))) { + mapInvalidSerials[spend->getCoinSerialNumber()] = spend->getDenomination() * COIN; // Derive the actual valid serial from the invalid serial if possible - CBigNum bnActualSerial = spend.CalculateValidSerial(Params().Zerocoin_Params(false)); + CBigNum bnActualSerial = spend->CalculateValidSerial(Params().Zerocoin_Params(false)); uint256 txHash; if (zerocoinDB->ReadCoinSpend(bnActualSerial, txHash)) { - mapInvalidSerials[bnActualSerial] = spend.getDenomination() * COIN; + mapInvalidSerials[bnActualSerial] = spend->getDenomination() * COIN; CTransaction txPrev; uint256 hashBlock; @@ -2456,7 +2568,7 @@ CAmount GetInvalidUTXOValue() bool CheckInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector* pvChecks) { - if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { + if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) { if (pvChecks) pvChecks->reserve(tx.vin.size()); @@ -2584,18 +2696,32 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex * addresses should still be handled by the typical bitcoin based undo code * */ if (tx.ContainsZerocoins()) { - if (tx.IsZerocoinSpend()) { + if (tx.HasZerocoinSpendInputs()) { //erase all zerocoinspends in this transaction - for (const CTxIn& txin : tx.vin) { - if (txin.scriptSig.IsZerocoinSpend()) { - CoinSpend spend = TxInToZerocoinSpend(txin); - if (!zerocoinDB->EraseCoinSpend(spend.getCoinSerialNumber())) + for (const CTxIn &txin : tx.vin) { + bool isPublicSpend = txin.IsZerocoinPublicSpend(); + if (txin.scriptSig.IsZerocoinSpend() || isPublicSpend) { + CBigNum serial; + if (isPublicSpend) { + libzerocoin::ZerocoinParams *params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + CValidationState state; + if (!XIONModule::ParseZerocoinPublicSpend(txin, tx, state, publicSpend)) { + return error("Failed to parse public spend"); + } + serial = publicSpend.getCoinSerialNumber(); + } else { + CoinSpend spend = TxInToZerocoinSpend(txin); + serial = spend.getCoinSerialNumber(); + } + + if (!zerocoinDB->EraseCoinSpend(serial)) return error("failed to erase spent zerocoin in block"); //if this was our spend, then mark it unspent now if (pwalletMain) { - if (pwalletMain->IsMyZerocoinSpend(spend.getCoinSerialNumber())) { - if (!pwalletMain->SetMintUnspent(spend.getCoinSerialNumber())) + if (pwalletMain->IsMyZerocoinSpend(serial)) { + if (!pwalletMain->SetMintUnspent(serial)) LogPrintf("%s: failed to automatically reset mint", __func__); } } @@ -2604,17 +2730,17 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex } } - if (tx.IsZerocoinMint()) { + if (tx.HasZerocoinMintOutputs()) { //erase all zerocoinmints in this transaction - for (const CTxOut& txout : tx.vout) { - if (txout.scriptPubKey.empty() || !txout.scriptPubKey.IsZerocoinMint()) + for (const CTxOut &txout : tx.vout) { + if (txout.scriptPubKey.empty() || !txout.IsZerocoinMint()) continue; PublicCoin pubCoin(Params().Zerocoin_Params(false)); if (!TxOutToPublicCoin(txout, pubCoin, state)) return error("DisconnectBlock(): TxOutToPublicCoin() failed"); - if(!zerocoinDB->EraseCoinMint(pubCoin.getValue())) + if (!zerocoinDB->EraseCoinMint(pubCoin.getValue())) return error("DisconnectBlock(): Failed to erase coin mint"); } } @@ -2645,7 +2771,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex } // restore inputs - if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { // not coinbases or zerocoinspend because they dont have traditional inputs + if (!tx.IsCoinBase() && !tx.HasZerocoinSpendInputs()) { // not coinbases or zerocoinspend because they dont have traditional inputs const CTxUndo& txundo = blockUndo.vtxundo[i - 1]; if (txundo.vprevout.size() != tx.vin.size()) return error("DisconnectBlock() : transaction and undo data inconsistent - txundo.vprevout.siz=%d tx.vin.siz=%d", txundo.vprevout.size(), tx.vin.size()); @@ -2863,7 +2989,7 @@ bool RecalculateIONSupply(int nHeightStart) if (tx.IsCoinBase()) break; - if (tx.vin[i].scriptSig.IsZerocoinSpend()) { + if (tx.vin[i].IsZerocoinSpend()) { nValueIn += tx.vin[i].nSequence * COIN; continue; } @@ -3109,7 +3235,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin !((pindex->nHeight == 91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || (pindex->nHeight == 91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); if (fEnforceBIP30) { - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { const CCoins* coins = view.AccessCoins(tx.GetHash()); if (coins && !coins->IsPruned()) return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"), @@ -3148,7 +3274,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock() : zerocoin transactions are currently in maintenance mode")); } - if (tx.IsZerocoinSpend()) { + if (tx.HasZerocoinSpendInputs()) { int nHeightTx = 0; uint256 txid = tx.GetHash(); vSpendsInBlock.emplace_back(txid); @@ -3163,19 +3289,39 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin //Check for double spending of serial #'s set setSerials; for (const CTxIn& txIn : tx.vin) { - if (!txIn.scriptSig.IsZerocoinSpend()) + bool isPublicSpend = txIn.IsZerocoinPublicSpend(); + bool isPrivZerocoinSpend = txIn.IsZerocoinSpend(); + if (!isPrivZerocoinSpend && !isPublicSpend) continue; - CoinSpend spend = TxInToZerocoinSpend(txIn); - nValueIn += spend.getDenomination() * COIN; - //queue for db write after the 'justcheck' section has concluded - vSpends.emplace_back(make_pair(spend, tx.GetHash())); - if (!ContextualCheckZerocoinSpend(tx, spend, pindex, hashBlock)) - return state.DoS(100, error("%s: failed to add block %s with invalid zerocoinspend", __func__, tx.GetHash().GetHex()), REJECT_INVALID); + // Check enforcement + if (!CheckPublicCoinSpendEnforced(pindex->nHeight, isPublicSpend)){ + return false; + } + + if (isPublicSpend) { + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + if (!XIONModule::ParseZerocoinPublicSpend(txIn, tx, state, publicSpend)){ + return false; + } + nValueIn += publicSpend.getDenomination() * COIN; + //queue for db write after the 'justcheck' section has concluded + vSpends.emplace_back(make_pair(publicSpend, tx.GetHash())); + if (!ContextualCheckZerocoinSpend(tx, &publicSpend, pindex, hashBlock)) + return state.DoS(100, error("%s: failed to add block %s with invalid public zc spend", __func__, tx.GetHash().GetHex()), REJECT_INVALID); + } else { + CoinSpend spend = TxInToZerocoinSpend(txIn); + nValueIn += spend.getDenomination() * COIN; + //queue for db write after the 'justcheck' section has concluded + vSpends.emplace_back(make_pair(spend, tx.GetHash())); + if (!ContextualCheckZerocoinSpend(tx, &spend, pindex, hashBlock)) + return state.DoS(100, error("%s: failed to add block %s with invalid zerocoinspend", __func__, tx.GetHash().GetHex()), REJECT_INVALID); + } } // Check that xION mints are not already known - if (tx.IsZerocoinMint()) { + if (tx.HasZerocoinMintOutputs()) { for (auto& out : tx.vout) { if (!out.IsZerocoinMint()) continue; @@ -3204,7 +3350,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } // Check that xION mints are not already known - if (tx.IsZerocoinMint()) { + if (tx.HasZerocoinMintOutputs()) { for (auto& out : tx.vout) { if (!out.IsZerocoinMint()) continue; @@ -3436,25 +3582,23 @@ bool static FlushStateToDisk(CValidationState& state, FlushStateMode mode) // First make sure all block and undo data is flushed to disk. FlushBlockFile(); // Then update all block file information (which may refer to block and undo files). - bool fileschanged = false; - for (set::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end();) { - if (!pblocktree->WriteBlockFileInfo(*it, vinfoBlockFile[*it])) { - return AbortNode(state, "Failed to write to block index"); + { + std::vector > vFiles; + vFiles.reserve(setDirtyFileInfo.size()); + for (set::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) { + vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it])); + setDirtyFileInfo.erase(it++); } - fileschanged = true; - setDirtyFileInfo.erase(it++); - } - if (fileschanged && !pblocktree->WriteLastBlockFile(nLastBlockFile)) { - return AbortNode(state, "Failed to write to block index"); - } - for (set::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end();) { - if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(*it))) { - return AbortNode(state, "Failed to write to block index"); + std::vector vBlocks; + vBlocks.reserve(setDirtyBlockIndex.size()); + for (set::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) { + vBlocks.push_back(*it); + setDirtyBlockIndex.erase(it++); + } + if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { + return AbortNode(state, "Files to write to block index database"); } - setDirtyBlockIndex.erase(it++); } - - pblocktree->Sync(); // Finally flush the chainstate (which may refer to block index entries). if (!pcoinsTip->Flush()) return AbortNode(state, "Failed to write to coin database"); @@ -3481,11 +3625,15 @@ void static UpdateTip(CBlockIndex* pindexNew) { chainActive.SetTip(pindexNew); + /* Zerocoin minting is disabled + * #ifdef ENABLE_WALLET // If turned on AutoZeromint will automatically convert ION to xION if (pwalletMain && pwalletMain->isZeromintEnabled()) pwalletMain->AutoZeromint(); #endif // ENABLE_WALLET + * + */ // New best block nTimeBestReceived = GetTime(); @@ -3542,7 +3690,7 @@ bool static DisconnectTip(CValidationState& state) if (!FlushStateToDisk(state, FLUSH_STATE_ALWAYS)) return false; // Resurrect mempool transactions from the disconnected block. - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { // ignore validation errors in resurrected transactions list removed; CValidationState stateDummy; @@ -3555,7 +3703,7 @@ bool static DisconnectTip(CValidationState& state) UpdateTip(pindexDelete->pprev); // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { SyncWithWallets(tx, NULL); } return true; @@ -3630,11 +3778,11 @@ bool static ConnectTip(CValidationState& state, CBlockIndex* pindexNew, CBlock* UpdateTip(pindexNew); // Tell wallet about transactions that went from mempool // to conflicted: - BOOST_FOREACH (const CTransaction& tx, txConflicted) { + for (const CTransaction& tx : txConflicted) { SyncWithWallets(tx, NULL); } // ... and about transactions that got confirmed: - BOOST_FOREACH (const CTransaction& tx, pblock->vtx) { + for (const CTransaction& tx : pblock->vtx) { SyncWithWallets(tx, pblock); } @@ -3696,10 +3844,10 @@ bool DisconnectBlockAndInputs(CValidationState& state, CTransaction txLock) // Queue memory transactions to resurrect. // We only do this for blocks after the last checkpoint (reorganisation before that // point should only happen with -reindex/-loadblock, or a misbehaving peer. - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { if (!tx.IsCoinBase()) { - BOOST_FOREACH (const CTxIn& in1, txLock.vin) { - BOOST_FOREACH (const CTxIn& in2, tx.vin) { + for (const CTxIn& in1 : txLock.vin) { + for (const CTxIn& in2 : tx.vin) { if (in1.prevout == in2.prevout) foundConflictingTx = true; } } @@ -3720,7 +3868,7 @@ bool DisconnectBlockAndInputs(CValidationState& state, CTransaction txLock) if (vDisconnect.size() > 0) { LogPrintf("REORGANIZE: Disconnect Conflicting Blocks %lli blocks; %s..\n", vDisconnect.size(), pindexNew->GetBlockHash().ToString()); - BOOST_FOREACH (CBlockIndex* pindex, vDisconnect) { + for (CBlockIndex* pindex : vDisconnect) { LogPrintf(" -- disconnect %s\n", pindex->GetBlockHash().ToString()); DisconnectTip(state); } @@ -3915,7 +4063,7 @@ bool ActivateBestChain(CValidationState& state, CBlock* pblock, bool fAlreadyChe int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); } @@ -4029,10 +4177,6 @@ CBlockIndex* AddToBlockIndex(const CBlock& block) pindexNew->nSequenceId = 0; BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - //mark as PoS seen - if (pindexNew->IsProofOfStake()) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); - pindexNew->phashBlock = &((*mi).first); BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); if (miPrev != mapBlockIndex.end()) { @@ -4293,10 +4437,10 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // ----------- swiftTX transaction scanning ----------- if (IsSporkActive(SPORK_2_SWIFTTX_BLOCK_FILTERING)) { - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { if (!tx.IsCoinBase()) { //only reject blocks when it's based on complete consensus - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (mapLockedInputs.count(in.prevout)) { if (mapLockedInputs[in.prevout] != tx.GetHash()) { mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); @@ -4358,10 +4502,21 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo return error("CheckBlock() : CheckTransaction failed"); // double check that there are no double spent xION spends in this block - if (tx.IsZerocoinSpend()) { + if (tx.HasZerocoinSpendInputs()) { for (const CTxIn& txIn : tx.vin) { - if (txIn.scriptSig.IsZerocoinSpend()) { - libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txIn); + bool isPublicSpend = txIn.IsZerocoinPublicSpend(); + if (txIn.IsZerocoinSpend() || isPublicSpend) { + libzerocoin::CoinSpend spend; + if (isPublicSpend) { + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + if (!XIONModule::ParseZerocoinPublicSpend(txIn, tx, state, publicSpend)){ + return false; + } + spend = publicSpend; + } else { + spend = TxInToZerocoinSpend(txIn); + } if (count(vBlockSerials.begin(), vBlockSerials.end(), spend.getCoinSerialNumber())) return state.DoS(100, error("%s : Double spending of xION serial %s in block\n Block: %s", __func__, spend.getCoinSerialNumber().GetHex(), block.ToString())); @@ -4373,7 +4528,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo unsigned int nSigOps = 0; - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { nSigOps += GetLegacySigOpCount(tx); } unsigned int nMaxBlockSigOps = fZerocoinActive ? MAX_BLOCK_SIGOPS_CURRENT : MAX_BLOCK_SIGOPS_LEGACY; @@ -4490,7 +4645,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; // Check that all transactions are finalized - BOOST_FOREACH (const CTransaction& tx, block.vtx) + for (const CTransaction& tx : block.vtx) if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) { return state.DoS(10, error("%s : contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); } @@ -4570,31 +4725,6 @@ bool AcceptBlockHeader(const CBlock& block, CValidationState& state, CBlockIndex return true; } -bool ContextualCheckZerocoinStake(int nHeight, CStakeInput* stake) -{ - if (nHeight < Params().Zerocoin_Block_V2_Start()) - return error("%s: xION stake block is less than allowed start height", __func__); - - if (CXIonStake* xION = dynamic_cast(stake)) { - CBlockIndex* pindexFrom = xION->GetIndexFrom(); - if (!pindexFrom) - return error("%s: failed to get index associated with xION stake checksum", __func__); - - if (chainActive.Height() - pindexFrom->nHeight < Params().Zerocoin_RequiredStakeDepth()) - return error("%s: xION stake does not have required confirmation depth. Current height %d, stakeInput height %d.", __func__, chainActive.Height(), pindexFrom->nHeight); - - //The checksum needs to be the exact checksum from 200 blocks ago - uint256 nCheckpoint200 = chainActive[nHeight - Params().Zerocoin_RequiredStakeDepth()]->nAccumulatorCheckpoint; - uint32_t nChecksum200 = ParseChecksum(nCheckpoint200, libzerocoin::AmountToZerocoinDenomination(xION->GetValue())); - if (nChecksum200 != xION->GetChecksum()) - return error("%s: accumulator checksum is different than the block 200 blocks previous. stake=%d block200=%d", __func__, xION->GetChecksum(), nChecksum200); - } else { - return error("%s: dynamic_cast of stake ptr failed", __func__); - } - - return true; -} - bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp, bool fAlreadyCheckedBlock) { AssertLockHeld(cs_main); @@ -4639,9 +4769,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, if (!stake) return error("%s: null stake ptr", __func__); - if (stake->IsXION() && !ContextualCheckZerocoinStake(pindexPrev->nHeight, stake.get())) - return state.DoS(100, error("%s: staked xION fails context checks", __func__)); - uint256 hash = block.GetHash(); if(!mapProofOfStake.count(hash)) // add to mapProofOfStake mapProofOfStake.insert(make_pair(hash, hashProofOfStake)); @@ -4683,7 +4810,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, std::vector xIONInputs; for (const CTxIn& stakeIn : stakeTxIn.vin) { - if(stakeIn.scriptSig.IsZerocoinSpend()){ + if(stakeIn.IsZerocoinSpend()){ xIONInputs.push_back(stakeIn); }else{ ionInputs.push_back(stakeIn); @@ -4699,8 +4826,26 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, for (const CTransaction& tx : block.vtx) { for (const CTxIn& in: tx.vin) { if(nHeight >= Params().Zerocoin_StartHeight()) { - if (in.scriptSig.IsZerocoinSpend()) { - CoinSpend spend = TxInToZerocoinSpend(in); + bool isPublicSpend = in.IsZerocoinPublicSpend(); + bool isPrivZerocoinSpend = in.IsZerocoinSpend(); + if (isPrivZerocoinSpend || isPublicSpend) { + + // Check enforcement + if (!CheckPublicCoinSpendEnforced(pindex->nHeight, isPublicSpend)){ + return false; + } + + libzerocoin::CoinSpend spend; + if (isPublicSpend) { + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + if (!XIONModule::ParseZerocoinPublicSpend(in, tx, state, publicSpend)){ + return false; + } + spend = publicSpend; + } else { + spend = TxInToZerocoinSpend(in); + } // Check for serials double spending in the same block if (std::find(inBlockSerials.begin(), inBlockSerials.end(), spend.getCoinSerialNumber()) != inBlockSerials.end()) { @@ -4729,37 +4874,39 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, // Start at the block we're adding on to CBlockIndex *prev = pindexPrev; - int readBlock = 0; - vector vBlockSerials; CBlock bl; + if (!ReadBlockFromDisk(bl, prev)) + return error("%s: previous block %s not on disk", __func__, prev->GetBlockHash().GetHex()); + + vector vBlockSerials; + int readBlock = 0; // Go backwards on the forked chain up to the split - do { + while (!chainActive.Contains(prev)) { + + // Increase amount of read blocks + readBlock++; // Check if the forked chain is longer than the max reorg limit - if(readBlock == Params().MaxReorganizationDepth()){ + if (readBlock == Params().MaxReorganizationDepth()) { // TODO: Remove this chain from disk. return error("%s: forked chain longer than maximum reorg limit", __func__); } - if(!ReadBlockFromDisk(bl, prev)) - // Previous block not on disk - return error("%s: previous block %s not on disk", __func__, prev->GetBlockHash().GetHex()); - // Increase amount of read blocks - readBlock++; // Loop through every input from said block - for (const CTransaction& t : bl.vtx) { - for (const CTxIn& in: t.vin) { + for (const CTransaction &t : bl.vtx) { + for (const CTxIn &in: t.vin) { // Loop through every input of the staking tx - for (const CTxIn& stakeIn : ionInputs) { + for (const CTxIn &stakeIn : ionInputs) { // if it's already spent // First regular staking check - if(hasIONInputs) { + if (hasIONInputs) { if (stakeIn.prevout == in.prevout) { - return state.DoS(100, error("%s: input already spent on a previous block", __func__)); + return state.DoS(100, error("%s: input already spent on a previous block", + __func__)); } // Second, if there is zPoS staking then store the serials for later check - if(in.scriptSig.IsZerocoinSpend()){ + if(in.IsZerocoinSpend()){ vBlockSerials.push_back(TxInToZerocoinSpend(in).getCoinSerialNumber()); } } @@ -4767,9 +4914,13 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, } } + // Prev block prev = prev->pprev; + if (!ReadBlockFromDisk(bl, prev)) + // Previous block not on disk + return error("%s: previous block %s not on disk", __func__, prev->GetBlockHash().GetHex()); - } while (!chainActive.Contains(prev)); + } // Split height splitHeight = prev->nHeight; @@ -4795,7 +4946,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, return state.DoS(100, error("%s: serial double spent on main chain", __func__)); } - if (!ContextualCheckZerocoinSpendNoSerialCheck(stakeTxIn, spend, pindex, 0)) + if (!ContextualCheckZerocoinSpendNoSerialCheck(stakeTxIn, &spend, pindex, 0)) return state.DoS(100,error("%s: forked chain ContextualCheckZerocoinSpend failed for tx %s", __func__, stakeTxIn.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-xion"); @@ -4822,7 +4973,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, // If the stake is not a zPoS then let's check if the inputs were spent on the main chain const CCoinsViewCache coins(pcoinsTip.get()); - if(!stakeTxIn.IsZerocoinSpend()) { + if(!stakeTxIn.HasZerocoinSpendInputs()) { for (const CTxIn& in: stakeTxIn.vin) { const CCoins* coin = coins.AccessCoins(in.prevout.hash); @@ -4831,9 +4982,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, return error("%s: coin stake inputs not available on main chain, received height %d vs current %d", __func__, nHeight, chainActive.Height()); } if(coin && !coin->IsAvailable(in.prevout.n)){ - // If this is not available get the height of the spent and validate it with the forked height - // Check if this occurred before the chain split - if(!(isBlockFromFork && coin->nHeight > splitHeight)){ + if(!isBlockFromFork){ // Coins not available return error("%s: coin stake inputs already spent in main chain", __func__); } @@ -4843,7 +4992,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, if(!isBlockFromFork) for (const CTxIn& xIonInput : xIONInputs) { CoinSpend spend = TxInToZerocoinSpend(xIonInput); - if (!ContextualCheckZerocoinSpend(stakeTxIn, spend, pindex, 0)) + if (!ContextualCheckZerocoinSpend(stakeTxIn, &spend, pindex, 0)) return state.DoS(100,error("%s: main chain ContextualCheckZerocoinSpend failed for tx %s", __func__, stakeTxIn.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-xion"); } @@ -4944,7 +5093,7 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDis for (const CTransaction& tx : pblock->vtx) { if (tx.ContainsZerocoins()) { for (const CTxIn& in : tx.vin) { - if (in.scriptSig.IsZerocoinSpend()) + if (in.IsZerocoinSpend()) nSpends++; } for (const CTxOut& out : tx.vout) { @@ -5036,7 +5185,11 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDis bool TestBlockValidity(CValidationState& state, const CBlock& block, CBlockIndex* const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) { AssertLockHeld(cs_main); - assert(pindexPrev && pindexPrev == chainActive.Tip()); + assert(pindexPrev); + if (pindexPrev != chainActive.Tip()) { + LogPrintf("%s : No longer working on chain tip\n", __func__); + return false; + } CCoinsViewCache viewNew(pcoinsTip.get()); CBlockIndex indexDummy(block); @@ -5122,10 +5275,6 @@ CBlockIndex* InsertBlockIndex(uint256 hash) throw runtime_error("LoadBlockIndex() : new CBlockIndex failed"); mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - //mark as PoS seen - if (pindexNew->IsProofOfStake()) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); - pindexNew->phashBlock = &((*mi).first); return pindexNew; @@ -5146,7 +5295,7 @@ bool static LoadBlockIndexDB(string& strError) vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); } sort(vSortedByHeight.begin(), vSortedByHeight.end()); - BOOST_FOREACH (const PAIRTYPE(int, CBlockIndex*) & item, vSortedByHeight) { + for (const PAIRTYPE(int, CBlockIndex*) & item : vSortedByHeight) { CBlockIndex* pindex = item.second; pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); if (pindex->nStatus & BLOCK_HAVE_DATA) { @@ -5326,10 +5475,31 @@ bool CVerifyDB::VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth void UnloadBlockIndex() { - mapBlockIndex.clear(); + LOCK(cs_main); setBlockIndexCandidates.clear(); chainActive.SetTip(NULL); pindexBestInvalid = NULL; + pindexBestHeader = NULL; + mempool.clear(); + mapOrphanTransactions.clear(); + mapOrphanTransactionsByPrev.clear(); + nSyncStarted = 0; + mapBlocksUnlinked.clear(); + vinfoBlockFile.clear(); + nLastBlockFile = 0; + nBlockSequenceId = 1; + mapBlockSource.clear(); + mapBlocksInFlight.clear(); + nQueuedValidatedHeaders = 0; + nPreferredDownload = 0; + setDirtyBlockIndex.clear(); + setDirtyFileInfo.clear(); + mapNodeState.clear(); + + for (BlockMap::value_type& entry : mapBlockIndex) { + delete entry.second; + } + mapBlockIndex.clear(); } bool LoadBlockIndex(string& strError) @@ -5658,7 +5828,7 @@ string GetWarnings(string strFor) // Alerts { LOCK(cs_mapAlerts); - BOOST_FOREACH (PAIRTYPE(const uint256, CAlert) & item, mapAlerts) { + for (PAIRTYPE(const uint256, CAlert) & item : mapAlerts) { const CAlert& alert = item.second; if (alert.AppliesToMe() && alert.nPriority > nPriority) { nPriority = alert.nPriority; @@ -5803,7 +5973,7 @@ void static ProcessGetData(CNode* pfrom) // Thus, the protocol spec specified allows for us to provide duplicate txn here, // however we MUST always provide at least what the remote peer needs typedef std::pair PairType; - BOOST_FOREACH (PairType& pair, merkleBlock.vMatchedTxn) + for (PairType& pair : merkleBlock.vMatchedTxn) if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second))) pfrom->PushMessage("tx", block.vtx[pair.first]); } @@ -6130,7 +6300,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Relay alerts { LOCK(cs_mapAlerts); - BOOST_FOREACH (PAIRTYPE(const uint256, CAlert) & item, mapAlerts) + for (PAIRTYPE(const uint256, CAlert) & item : mapAlerts) item.second.RelayTo(pfrom); } @@ -6187,7 +6357,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, vector vAddrOk; int64_t nNow = GetAdjustedTime(); int64_t nSince = nNow - 10 * 60; - BOOST_FOREACH (CAddress& addr, vAddr) { + for (CAddress& addr : vAddr) { boost::this_thread::interruption_point(); if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) @@ -6207,7 +6377,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, uint256 hashRand = hashSalt ^ (hashAddr << 32) ^ ((GetTime() + hashAddr) / (24 * 60 * 60)); hashRand = Hash(BEGIN(hashRand), END(hashRand)); multimap mapMix; - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (pnode->nVersion < CADDR_TIME_VERSION) continue; unsigned int nPointer; @@ -6434,7 +6604,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mapAlreadyAskedFor.erase(inv); - if (!tx.IsZerocoinSpend() && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, false, ignoreFees)) { + if (!tx.HasZerocoinSpendInputs() && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, false, ignoreFees)) { mempool.check(pcoinsTip.get()); RelayTransaction(tx); vWorkQueue.push_back(inv.hash); @@ -6487,8 +6657,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } - BOOST_FOREACH (uint256 hash, vEraseQueue)EraseOrphanTx(hash); - } else if (tx.IsZerocoinSpend() && AcceptToMemoryPool(mempool, state, tx, true, &fMissingZerocoinInputs, false, ignoreFees)) { + for (uint256 hash : vEraseQueue) EraseOrphanTx(hash); + + } else if (tx.HasZerocoinSpendInputs() && AcceptToMemoryPool(mempool, state, tx, true, &fMissingZerocoinInputs, false, ignoreFees)) { //Presstab: ZCoin has a bunch of code commented out here. Is this something that should have more going on? //Also there is nothing that handles fMissingZerocoinInputs. Does there need to be? RelayTransaction(tx); @@ -6554,7 +6725,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } CBlockIndex* pindexLast = NULL; - BOOST_FOREACH (const CBlockHeader& header, headers) { + for (const CBlockHeader& header : headers) { CValidationState state; if (pindexLast != NULL && header.hashPrevBlock != pindexLast->GetBlockHash()) { Misbehaving(pfrom->GetId(), 20); @@ -6693,7 +6864,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if ((strCommand == "getaddr") && (pfrom->fInbound)) { pfrom->vAddrToSend.clear(); vector vAddr = addrman.GetAddr(); - BOOST_FOREACH (const CAddress& addr, vAddr) + for (const CAddress& addr : vAddr) pfrom->PushAddress(addr); } @@ -6704,7 +6875,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, std::vector vtxid; mempool.queryHashes(vtxid); vector vInv; - BOOST_FOREACH (uint256& hash, vtxid) { + for (uint256& hash : vtxid) { CInv inv(MSG_TX, hash); CTransaction tx; bool fInMemPool = mempool.lookup(hash, tx); @@ -6809,7 +6980,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->setKnown.insert(alertHash); { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) alert.RelayTo(pnode); } } else { @@ -6905,7 +7076,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } else { //probably one the extensions - //obfuScationPool.ProcessMessageObfuscation(pfrom, strCommand, vRecv); mnodeman.ProcessMessage(pfrom, strCommand, vRecv); budget.ProcessMessage(pfrom, strCommand, vRecv); masternodePayments.ProcessMessageMasternodePayments(pfrom, strCommand, vRecv); @@ -7085,7 +7255,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) static int64_t nLastRebroadcast; if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { // Periodically clear setAddrKnown to allow refresh broadcasts if (nLastRebroadcast) pnode->setAddrKnown.clear(); @@ -7103,7 +7273,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) if (fSendTrickle) { vector vAddr; vAddr.reserve(pto->vAddrToSend.size()); - BOOST_FOREACH (const CAddress& addr, pto->vAddrToSend) { + for (const CAddress& addr : pto->vAddrToSend) { // returns true if wasn't already contained in the set if (pto->setAddrKnown.insert(addr).second) { vAddr.push_back(addr); @@ -7134,7 +7304,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) state.fShouldBan = false; } - BOOST_FOREACH (const CBlockReject& reject, state.rejects) + for (const CBlockReject& reject : state.rejects) pto->PushMessage("reject", (string) "block", reject.chRejectCode, reject.strRejectReason, reject.hashBlock); state.rejects.clear(); @@ -7170,7 +7340,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) LOCK(pto->cs_inventory); vInv.reserve(pto->vInventoryToSend.size()); vInvWait.reserve(pto->vInventoryToSend.size()); - BOOST_FOREACH (const CInv& inv, pto->vInventoryToSend) { + for (const CInv& inv : pto->vInventoryToSend) { if (pto->setInventoryKnown.count(inv)) continue; @@ -7231,7 +7401,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) vector vToDownload; NodeId staller = -1; FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); - BOOST_FOREACH (CBlockIndex* pindex, vToDownload) { + for (CBlockIndex* pindex : vToDownload) { vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), pindex); LogPrintf("Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), diff --git a/src/main.h b/src/main.h index 71f057541e707..917d02b1be914 100644 --- a/src/main.h +++ b/src/main.h @@ -22,6 +22,7 @@ #include "primitives/block.h" #include "primitives/transaction.h" #include "xion/zerocoin.h" +#include "xion/xionmodule.h" #include "script/script.h" #include "script/sigcache.h" #include "script/standard.h" @@ -113,6 +114,8 @@ static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111; static const bool DEFAULT_PEERBLOOMFILTERS = true; static const bool DEFAULT_PEERBLOOMFILTERS_ZC = false; +/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */ +static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60; /** Default for -blockspamfilter, use header spam filter */ static const bool DEFAULT_BLOCK_SPAM_FILTER = true; @@ -151,6 +154,7 @@ extern bool fCheckBlockIndex; extern unsigned int nCoinCacheSize; extern CFeeRate minRelayTxFee; extern bool fAlerts; +extern int64_t nMaxTipAge; extern bool fVerifyingBlocks; extern bool fClearSpendCache; @@ -164,7 +168,6 @@ extern int64_t nReserveBalance; extern std::map mapRejectedBlocks; extern std::map mapHashedBlocks; -extern std::set > setStakeSeen; extern std::map mapZerocoinspends; //txid, time received /** Best header we've seen so far (used for getheaders queries' starting points). */ @@ -229,6 +232,8 @@ bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256& hash, CTransaction& tx, uint256& hashBlock, bool fAllowSlow = false, CBlockIndex* blockIndex = nullptr); +/** Retrieve an output (from memory pool, or from disk, if possible) */ +bool GetOutput(const uint256& hash, unsigned int index, CValidationState& state, CTxOut& out); /** Find the best known block, and make it the tip of the block chain */ // ***TODO*** @@ -347,8 +352,8 @@ void UpdateCoins(const CTransaction& tx, CValidationState& state, CCoinsViewCach bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fRejectBadUTXO, CValidationState& state, bool fFakeSerialAttack = false); bool CheckZerocoinMint(const uint256& txHash, const CTxOut& txout, CValidationState& state, bool fCheckOnly = false); bool CheckZerocoinSpend(const CTransaction& tx, bool fVerifySignature, CValidationState& state, bool fFakeSerialAttack = false); -bool ContextualCheckZerocoinSpend(const CTransaction& tx, const libzerocoin::CoinSpend& spend, CBlockIndex* pindex, const uint256& hashBlock); -bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const libzerocoin::CoinSpend& spend, CBlockIndex* pindex, const uint256& hashBlock); +bool ContextualCheckZerocoinSpend(const CTransaction& tx, const libzerocoin::CoinSpend* spend, CBlockIndex* pindex, const uint256& hashBlock); +bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const libzerocoin::CoinSpend* spend, CBlockIndex* pindex, const uint256& hashBlock); bool IsTransactionInChain(const uint256& txId, int& nHeightTx, CTransaction& tx); bool IsTransactionInChain(const uint256& txId, int& nHeightTx); bool IsBlockHashInChain(const uint256& hashBlock); @@ -362,6 +367,8 @@ bool ReindexAccumulators(list& listMissingCheckpoints, string& strError // Fake Serial attack Range bool isBlockBetweenFakeSerialAttackRange(int nHeight); +// Public coin spend +bool CheckPublicCoinSpendEnforced(int blockHeight, bool isPublicSpend); /** * Check if transaction will be final in the next block to be created. diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index b455130b8ff25..ba6c415f56f72 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -42,7 +42,7 @@ bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, s findScript << OP_RETURN << ToByteVector(nExpectedHash); bool foundOpReturn = false; - BOOST_FOREACH (const CTxOut o, txCollateral.vout) { + for (const CTxOut &o : txCollateral.vout) { if (!o.scriptPubKey.IsNormalPaymentScript() && !o.scriptPubKey.IsUnspendable()) { strError = strprintf("Invalid Script %s", txCollateral.ToString()); LogPrint("mnbudget","CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); @@ -788,28 +788,29 @@ std::vector CBudgetManager::GetBudget() std::vector vBudgetProposalsRet; CAmount nBudgetAllocated = 0; - CBlockIndex* pindexPrev = chainActive.Tip(); + + CBlockIndex* pindexPrev; + { + LOCK(cs_main); + pindexPrev = chainActive.Tip(); + } if (pindexPrev == NULL) return vBudgetProposalsRet; int nBlockStart = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); int nBlockEnd = nBlockStart + Params().GetBudgetCycleBlocks() - 1; + int mnCount = mnodeman.CountEnabled(ActiveProtocol()); CAmount nTotalBudget = GetTotalBudget(nBlockStart); - std::vector >::iterator it2 = vBudgetPorposalsSort.begin(); while (it2 != vBudgetPorposalsSort.end()) { CBudgetProposal* pbudgetProposal = (*it2).first; LogPrint("mnbudget","CBudgetManager::GetBudget() - Processing Budget %s\n", pbudgetProposal->strProposalName.c_str()); //prop start/end should be inside this period - if (pbudgetProposal->fValid && pbudgetProposal->nBlockStart <= nBlockStart && - pbudgetProposal->nBlockEnd >= nBlockEnd && - pbudgetProposal->GetYeas() - pbudgetProposal->GetNays() > mnodeman.CountEnabled(ActiveProtocol()) / 10 && - pbudgetProposal->IsEstablished()) { - + if (pbudgetProposal->IsPassing(pindexPrev, nBlockStart, nBlockEnd, mnCount)) { LogPrint("mnbudget","CBudgetManager::GetBudget() - Check 1 passed: valid=%d | %ld <= %ld | %ld >= %ld | Yeas=%d Nays=%d Count=%d | established=%d\n", pbudgetProposal->fValid, pbudgetProposal->nBlockStart, nBlockStart, pbudgetProposal->nBlockEnd, - nBlockEnd, pbudgetProposal->GetYeas(), pbudgetProposal->GetNays(), mnodeman.CountEnabled(ActiveProtocol()) / 10, + nBlockEnd, pbudgetProposal->GetYeas(), pbudgetProposal->GetNays(), mnCount / 10, pbudgetProposal->IsEstablished()); if (pbudgetProposal->GetAmount() + nBudgetAllocated <= nTotalBudget) { @@ -966,7 +967,7 @@ void CBudgetManager::NewBlock() } LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->nVersion >= ActiveProtocol()) Sync(pnode, 0, true); @@ -1550,6 +1551,34 @@ bool CBudgetProposal::IsValid(std::string& strError, bool fCheckCollateral) return true; } +bool CBudgetProposal::IsEstablished() +{ + return nTime < GetAdjustedTime() - Params().GetProposalEstablishmentTime(); +} + +bool CBudgetProposal::IsPassing(const CBlockIndex* pindexPrev, int nBlockStartBudget, int nBlockEndBudget, int mnCount) +{ + if (!fValid) + return false; + + if (!pindexPrev) + return false; + + if (this->nBlockStart > nBlockStartBudget) + return false; + + if (this->nBlockEnd < nBlockEndBudget) + return false; + + if (GetYeas() - GetNays() <= mnCount / 10) + return false; + + if (!IsEstablished()) + return false; + + return true; +} + bool CBudgetProposal::AddOrUpdateVote(CBudgetVote& vote, std::string& strError) { std::string strAction = "New vote inserted:"; @@ -1984,7 +2013,7 @@ std::string CFinalizedBudget::GetProposals() LOCK(cs); std::string ret = ""; - BOOST_FOREACH (CTxBudgetPayment& budgetPayment, vecBudgetPayments) { + for (CTxBudgetPayment& budgetPayment : vecBudgetPayments) { CBudgetProposal* pbudgetProposal = budget.FindProposal(budgetPayment.nProposalHash); std::string token = budgetPayment.nProposalHash.ToString(); @@ -2152,7 +2181,7 @@ TrxValidationStatus CFinalizedBudget::IsTransactionValid(const CTransaction& txN bool paid = false; - BOOST_FOREACH (CTxOut out, txNew.vout) { + for (CTxOut out : txNew.vout) { LogPrint("mnbudget","CFinalizedBudget::IsTransactionValid - nCurrentBudgetPayment=%d, payee=%s == out.scriptPubKey=%s, amount=%ld == out.nValue=%ld\n", nCurrentBudgetPayment, vecBudgetPayments[nCurrentBudgetPayment].payee.ToString().c_str(), out.scriptPubKey.ToString().c_str(), vecBudgetPayments[nCurrentBudgetPayment].nAmount, out.nValue); @@ -2230,7 +2259,7 @@ CFinalizedBudgetBroadcast::CFinalizedBudgetBroadcast(const CFinalizedBudget& oth { strBudgetName = other.strBudgetName; nBlockStart = other.nBlockStart; - BOOST_FOREACH (CTxBudgetPayment out, other.vecBudgetPayments) + for (CTxBudgetPayment out : other.vecBudgetPayments) vecBudgetPayments.push_back(out); mapVotes = other.mapVotes; nFeeTXHash = other.nFeeTXHash; @@ -2240,7 +2269,7 @@ CFinalizedBudgetBroadcast::CFinalizedBudgetBroadcast(std::string strBudgetNameIn { strBudgetName = strBudgetNameIn; nBlockStart = nBlockStartIn; - BOOST_FOREACH (CTxBudgetPayment out, vecBudgetPaymentsIn) + for (CTxBudgetPayment out : vecBudgetPaymentsIn) vecBudgetPayments.push_back(out); mapVotes.clear(); nFeeTXHash = nFeeTXHashIn; diff --git a/src/masternode-budget.h b/src/masternode-budget.h index e5cf4765812c0..af4b5db954eae 100644 --- a/src/masternode-budget.h +++ b/src/masternode-budget.h @@ -492,14 +492,8 @@ class CBudgetProposal bool IsValid(std::string& strError, bool fCheckCollateral = true); - bool IsEstablished() - { - // Proposals must be at least a day old to make it into a budget - if (Params().NetworkID() == CBaseChainParams::MAIN) return (nTime < GetTime() - (60 * 60 * 24)); - - // For testing purposes - 5 minutes - return (nTime < GetTime() - (60 * 5)); - } + bool IsEstablished(); + bool IsPassing(const CBlockIndex* pindexPrev, int nBlockStartBudget, int nBlockEndBudget, int mnCount); std::string GetName() { return strProposalName; } std::string GetURL() { return strURL; } diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index d73dda4634912..cbac395f5bfef 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -548,19 +548,19 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) nMasternode_Drift_Count = mnodeman.size() + Params().MasternodeCountDrift(); } - CAmount requiredMasternodePayment = GetMasternodePayment(nBlockHeight, nReward, nMasternode_Drift_Count, txNew.IsZerocoinSpend()); + CAmount requiredMasternodePayment = GetMasternodePayment(nBlockHeight, nReward, nMasternode_Drift_Count, txNew.HasZerocoinSpendInputs()); //require at least 6 signatures - BOOST_FOREACH (CMasternodePayee& payee, vecPayments) + for (CMasternodePayee& payee : vecPayments) if (payee.nVotes >= nMaxSignatures && payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) nMaxSignatures = payee.nVotes; // if we don't have at least 6 signatures on a payee, approve whichever is the longest chain if (nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true; - BOOST_FOREACH (CMasternodePayee& payee, vecPayments) { + for (CMasternodePayee& payee : vecPayments) { bool found = false; - BOOST_FOREACH (CTxOut out, txNew.vout) { + for (CTxOut out : txNew.vout) { if (payee.scriptPubKey == out.scriptPubKey) { if(out.nValue >= requiredMasternodePayment) found = true; @@ -594,7 +594,7 @@ std::string CMasternodeBlockPayees::GetRequiredPaymentsString() std::string ret = "Unknown"; - BOOST_FOREACH (CMasternodePayee& payee, vecPayments) { + for (CMasternodePayee& payee : vecPayments) { CTxDestination address1; ExtractDestination(payee.scriptPubKey, address1); CBitcoinAddress address2(address1); diff --git a/src/masternode-payments.h b/src/masternode-payments.h index 66f20e7ad6db3..7c9bb5c069b08 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -107,7 +107,7 @@ class CMasternodeBlockPayees { LOCK(cs_vecPayments); - BOOST_FOREACH (CMasternodePayee& payee, vecPayments) { + for (CMasternodePayee& payee : vecPayments) { if (payee.scriptPubKey == payeeIn) { payee.nVotes += nIncrement; return; @@ -123,7 +123,7 @@ class CMasternodeBlockPayees LOCK(cs_vecPayments); int nVotes = -1; - BOOST_FOREACH (CMasternodePayee& p, vecPayments) { + for (CMasternodePayee& p : vecPayments) { if (p.nVotes > nVotes) { payee = p.scriptPubKey; nVotes = p.nVotes; @@ -137,7 +137,7 @@ class CMasternodeBlockPayees { LOCK(cs_vecPayments); - BOOST_FOREACH (CMasternodePayee& p, vecPayments) { + for (CMasternodePayee& p : vecPayments) { if (p.nVotes >= nVotesReq && p.scriptPubKey == payee) return true; } diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index dfe821a1a50d0..0798fe29a3b3b 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -222,7 +222,7 @@ void CMasternodeSync::ClearFulfilledRequest() TRY_LOCK(cs_vNodes, lockRecv); if (!lockRecv) return; - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { pnode->ClearFulfilledRequest("getspork"); pnode->ClearFulfilledRequest("mnsync"); pnode->ClearFulfilledRequest("mnwsync"); @@ -264,7 +264,7 @@ void CMasternodeSync::Process() TRY_LOCK(cs_vNodes, lockRecv); if (!lockRecv) return; - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (Params().NetworkID() == CBaseChainParams::REGTEST) { if (RequestedMasternodeAttempt <= 2) { pnode->PushMessage("getsporks"); //get current network sporks diff --git a/src/masternodeconfig.cpp b/src/masternodeconfig.cpp index 80e26c8cdd6b0..0e1aded95e473 100644 --- a/src/masternodeconfig.cpp +++ b/src/masternodeconfig.cpp @@ -6,7 +6,7 @@ #include "netbase.h" #include "masternodeconfig.h" #include "util.h" -#include "ui_interface.h" +#include "guiinterface.h" #include CMasternodeConfig masternodeConfig; diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index c6d187da06408..effe5dacd0176 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -235,7 +235,7 @@ void CMasternodeMan::Check() { LOCK(cs); - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); } } @@ -355,7 +355,7 @@ int CMasternodeMan::stable_size () int64_t nMasternode_Min_Age = MN_WINNER_MINIMUM_AGE; int64_t nMasternode_Age = 0; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.protocolVersion < nMinProtocol) { continue; // Skip obsolete versions } @@ -380,7 +380,7 @@ int CMasternodeMan::CountEnabled(int protocolVersion) int i = 0; protocolVersion = protocolVersion == -1 ? masternodePayments.GetMinMasternodePaymentsProto() : protocolVersion; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); if (mn.protocolVersion < protocolVersion || !mn.IsEnabled()) continue; i++; @@ -393,7 +393,7 @@ void CMasternodeMan::CountNetworks(int protocolVersion, int& ipv4, int& ipv6, in { protocolVersion = protocolVersion == -1 ? masternodePayments.GetMinMasternodePaymentsProto() : protocolVersion; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); std::string strHost; int port; @@ -440,7 +440,7 @@ CMasternode* CMasternodeMan::Find(const CScript& payee) LOCK(cs); CScript payee2; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { payee2 = GetScriptForDestination(mn.pubKeyCollateralAddress.GetID()); if (payee2 == payee) return &mn; @@ -452,7 +452,7 @@ CMasternode* CMasternodeMan::Find(const CTxIn& vin) { LOCK(cs); - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.vin.prevout == vin.prevout) return &mn; } @@ -464,7 +464,7 @@ CMasternode* CMasternodeMan::Find(const CPubKey& pubKeyMasternode) { LOCK(cs); - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.pubKeyMasternode == pubKeyMasternode) return &mn; } @@ -486,7 +486,7 @@ CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight */ int nMnCount = CountEnabled(); - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); if (!mn.IsEnabled()) continue; @@ -520,7 +520,7 @@ CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight int nTenthNetwork = CountEnabled() / 10; int nCountTenth = 0; uint256 nHigh = 0; - BOOST_FOREACH (PAIRTYPE(int64_t, CTxIn) & s, vecMasternodeLastPaid) { + for (PAIRTYPE(int64_t, CTxIn) & s : vecMasternodeLastPaid) { CMasternode* pmn = Find(s.second); if (!pmn) break; @@ -549,10 +549,10 @@ CMasternode* CMasternodeMan::FindRandomNotInVec(std::vector& vecToExclude LogPrint("masternode", "CMasternodeMan::FindRandomNotInVec - rand %d\n", rand); bool found; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.protocolVersion < protocolVersion || !mn.IsEnabled()) continue; found = false; - BOOST_FOREACH (CTxIn& usedVin, vecToExclude) { + for (CTxIn& usedVin : vecToExclude) { if (mn.vin.prevout == usedVin.prevout) { found = true; break; @@ -573,7 +573,7 @@ CMasternode* CMasternodeMan::GetCurrentMasterNode(int mod, int64_t nBlockHeight, CMasternode* winner = NULL; // scan for winner - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); if (mn.protocolVersion < minProtocol || !mn.IsEnabled()) continue; @@ -602,7 +602,7 @@ int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, in if (!GetBlockHash(hash, nBlockHeight)) return -1; // scan for winner - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.protocolVersion < minProtocol) { LogPrint("masternode","Skipping Masternode with obsolete version %d\n", mn.protocolVersion); continue; // Skip obsolete versions @@ -628,7 +628,7 @@ int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, in sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreTxIn()); int rank = 0; - BOOST_FOREACH (PAIRTYPE(int64_t, CTxIn) & s, vecMasternodeScores) { + for (PAIRTYPE(int64_t, CTxIn) & s : vecMasternodeScores) { rank++; if (s.second.prevout == vin.prevout) { return rank; @@ -648,7 +648,7 @@ std::vector > CMasternodeMan::GetMasternodeRanks(int64_t if (!GetBlockHash(hash, nBlockHeight)) return vecMasternodeRanks; // scan for winner - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { mn.Check(); if (mn.protocolVersion < minProtocol) continue; @@ -667,7 +667,7 @@ std::vector > CMasternodeMan::GetMasternodeRanks(int64_t sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN()); int rank = 0; - BOOST_FOREACH (PAIRTYPE(int64_t, CMasternode) & s, vecMasternodeScores) { + for (PAIRTYPE(int64_t, CMasternode) & s : vecMasternodeScores) { rank++; vecMasternodeRanks.push_back(make_pair(rank, s.second)); } @@ -680,7 +680,7 @@ CMasternode* CMasternodeMan::GetMasternodeByRank(int nRank, int64_t nBlockHeight std::vector > vecMasternodeScores; // scan for winner - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.protocolVersion < minProtocol) continue; if (fOnlyActive) { mn.Check(); @@ -696,7 +696,7 @@ CMasternode* CMasternodeMan::GetMasternodeByRank(int nRank, int64_t nBlockHeight sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreTxIn()); int rank = 0; - BOOST_FOREACH (PAIRTYPE(int64_t, CTxIn) & s, vecMasternodeScores) { + for (PAIRTYPE(int64_t, CTxIn) & s : vecMasternodeScores) { rank++; if (rank == nRank) { return Find(s.second); @@ -712,7 +712,7 @@ void CMasternodeMan::ProcessMasternodeConnections() if (Params().NetworkID() == CBaseChainParams::REGTEST) return; LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (pnode->fObfuScationMaster) { if (obfuScationPool.pSubmittedToMasternode != NULL && pnode->addr == obfuScationPool.pSubmittedToMasternode->addr) continue; LogPrint("masternode","Closing Masternode connection peer=%i \n", pnode->GetId()); @@ -823,7 +823,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData int nInvCount = 0; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { if (mn.addr.IsRFC1918()) continue; //local network if (mn.IsEnabled()) { @@ -954,7 +954,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (pmn->IsEnabled()) { TRY_LOCK(cs_vNodes, lockNodes); if (!lockNodes) return; - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) pnode->PushMessage("dsee", vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion, donationAddress, donationPercentage); } @@ -1043,7 +1043,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (mn.IsEnabled()) { TRY_LOCK(cs_vNodes, lockNodes); if (!lockNodes) return; - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) pnode->PushMessage("dsee", vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion, donationAddress, donationPercentage); } @@ -1113,7 +1113,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData TRY_LOCK(cs_vNodes, lockNodes); if (!lockNodes) return; LogPrint("masternode", "dseep - relaying %s \n", vin.prevout.hash.ToString()); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) pnode->PushMessage("dseep", vin, vchSig, sigTime, stop); } diff --git a/src/miner.cpp b/src/miner.cpp index cf797a47af6da..343c09987c1fa 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -222,11 +222,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, CAmount nTotalIn = 0; bool fMissingInputs = false; uint256 txid = tx.GetHash(); + bool hasZerocoinSpends = tx.HasZerocoinSpendInputs(); + if (hasZerocoinSpends) + nTotalIn = tx.GetZerocoinSpent(); + for (const CTxIn& txin : tx.vin) { //zerocoinspend has special vin - if (tx.IsZerocoinSpend()) { - nTotalIn = tx.GetZerocoinSpent(); - + if (hasZerocoinSpends) { //Give a high priority to zerocoinspends to get into the next block //Priority = (age^6+100000)*amount - gives higher priority to xions that have been in mempool long //and higher priority to xions that are large in value @@ -349,7 +351,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, double dPriorityDelta = 0; CAmount nFeeDelta = 0; mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); - if (!tx.IsZerocoinSpend() && fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + if (!tx.HasZerocoinSpendInputs() && fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; // Prioritise by fee once past the priority size or we run out of high-priority @@ -365,25 +367,39 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, continue; // double check that there are no double spent xION spends in this block or tx - if (tx.IsZerocoinSpend()) { + if (tx.HasZerocoinSpendInputs()) { int nHeightTx = 0; if (IsTransactionInChain(tx.GetHash(), nHeightTx)) continue; bool fDoubleSerial = false; for (const CTxIn& txIn : tx.vin) { - if (txIn.scriptSig.IsZerocoinSpend()) { - libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txIn); - bool fUseV1Params = libzerocoin::ExtractVersionFromSerial(spend.getCoinSerialNumber()) < libzerocoin::PrivateCoin::PUBKEY_VERSION; - if (!spend.HasValidSerial(Params().Zerocoin_Params(fUseV1Params))) + bool isPublicSpend = txIn.IsZerocoinPublicSpend(); + if (txIn.IsZerocoinSpend() || isPublicSpend) { + libzerocoin::CoinSpend* spend; + if (isPublicSpend) { + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + CValidationState state; + if (!XIONModule::ParseZerocoinPublicSpend(txIn, tx, state, publicSpend)){ + throw std::runtime_error("Invalid public spend parse"); + } + spend = &publicSpend; + } else { + libzerocoin::CoinSpend spendObj = TxInToZerocoinSpend(txIn); + spend = &spendObj; + } + + bool fUseV1Params = libzerocoin::ExtractVersionFromSerial(spend->getCoinSerialNumber()) < libzerocoin::PrivateCoin::PUBKEY_VERSION; + if (!spend->HasValidSerial(Params().Zerocoin_Params(fUseV1Params))) fDoubleSerial = true; - if (count(vBlockSerials.begin(), vBlockSerials.end(), spend.getCoinSerialNumber())) + if (count(vBlockSerials.begin(), vBlockSerials.end(), spend->getCoinSerialNumber())) fDoubleSerial = true; - if (count(vTxSerials.begin(), vTxSerials.end(), spend.getCoinSerialNumber())) + if (count(vTxSerials.begin(), vTxSerials.end(), spend->getCoinSerialNumber())) fDoubleSerial = true; if (fDoubleSerial) break; - vTxSerials.emplace_back(spend.getCoinSerialNumber()); + vTxSerials.emplace_back(spend->getCoinSerialNumber()); } } //This xION serial has already been included in the block, do not add this tx. @@ -427,7 +443,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, // Add transactions that depend on this one to the priority queue if (mapDependers.count(hash)) { - BOOST_FOREACH (COrphan* porphan, mapDependers[hash]) { + for (COrphan* porphan : mapDependers[hash]) { if (!porphan->setDependsOn.empty()) { porphan->setDependsOn.erase(hash); if (porphan->setDependsOn.empty()) { diff --git a/src/net.cpp b/src/net.cpp index 31173bdea4a61..d7e2b55608d02 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -20,7 +20,7 @@ #include "obfuscation.h" #include "primitives/transaction.h" #include "scheduler.h" -#include "ui_interface.h" +#include "guiinterface.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" @@ -569,7 +569,7 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti uiInterface.BannedListChanged(); { LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (subNet.Match((CNetAddr)pnode->addr)) pnode->fDisconnect = true; } @@ -658,7 +658,7 @@ CCriticalSection CNode::cs_vWhitelistedRange; bool CNode::IsWhitelistedRange(const CNetAddr& addr) { LOCK(cs_vWhitelistedRange); - BOOST_FOREACH (const CSubNet& subnet, vWhitelistedRange) { + for (const CSubNet& subnet : vWhitelistedRange) { if (subnet.Match(addr)) return true; } @@ -851,7 +851,7 @@ void ThreadSocketHandler() LOCK(cs_vNodes); // Disconnect unused nodes vector vNodesCopy = vNodes; - BOOST_FOREACH (CNode* pnode, vNodesCopy) { + for (CNode* pnode : vNodesCopy) { if (pnode->fDisconnect || (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty())) { // remove from vNodes @@ -873,7 +873,7 @@ void ThreadSocketHandler() { // Delete disconnected nodes list vNodesDisconnectedCopy = vNodesDisconnected; - BOOST_FOREACH (CNode* pnode, vNodesDisconnectedCopy) { + for (CNode* pnode : vNodesDisconnectedCopy) { // wait until threads are done using it if (pnode->GetRefCount() <= 0) { bool fDelete = false; @@ -921,7 +921,7 @@ void ThreadSocketHandler() SOCKET hSocketMax = 0; bool have_fds = false; - BOOST_FOREACH (const ListenSocket& hListenSocket, vhListenSocket) { + for (const ListenSocket& hListenSocket : vhListenSocket) { FD_SET(hListenSocket.socket, &fdsetRecv); hSocketMax = max(hSocketMax, hListenSocket.socket); have_fds = true; @@ -929,7 +929,7 @@ void ThreadSocketHandler() { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (pnode->hSocket == INVALID_SOCKET) continue; FD_SET(pnode->hSocket, &fdsetError); @@ -986,7 +986,7 @@ void ThreadSocketHandler() // // Accept new connections // - BOOST_FOREACH (const ListenSocket& hListenSocket, vhListenSocket) { + for (const ListenSocket& hListenSocket : vhListenSocket) { if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv)) { struct sockaddr_storage sockaddr; socklen_t len = sizeof(sockaddr); @@ -1001,7 +1001,7 @@ void ThreadSocketHandler() bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr); { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->fInbound) nInbound++; } @@ -1039,10 +1039,10 @@ void ThreadSocketHandler() { LOCK(cs_vNodes); vNodesCopy = vNodes; - BOOST_FOREACH (CNode* pnode, vNodesCopy) + for (CNode* pnode : vNodesCopy) pnode->AddRef(); } - BOOST_FOREACH (CNode* pnode, vNodesCopy) { + for (CNode* pnode : vNodesCopy) { boost::this_thread::interruption_point(); // @@ -1114,7 +1114,7 @@ void ThreadSocketHandler() } { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodesCopy) + for (CNode* pnode : vNodesCopy) pnode->Release(); } } @@ -1249,14 +1249,14 @@ void ThreadDNSAddressSeed() LogPrintf("Loading addresses from DNS seeds (could take a while)\n"); - BOOST_FOREACH (const CDNSSeedData& seed, vSeeds) { + for (const CDNSSeedData& seed : vSeeds) { if (HaveNameProxy()) { AddOneShot(seed.host); } else { vector vIPs; vector vAdd; if (LookupHost(seed.host.c_str(), vIPs)) { - BOOST_FOREACH (CNetAddr& ip, vIPs) { + for (CNetAddr& ip : vIPs) { int nOneDay = 24 * 3600; CAddress addr = CAddress(CService(ip, Params().GetDefaultPort())); addr.nTime = GetTime() - 3 * nOneDay - GetRand(4 * nOneDay); // use a random age between 3 and 7 days old @@ -1313,7 +1313,7 @@ void ThreadOpenConnections() if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { for (int64_t nLoop = 0;; nLoop++) { ProcessOneShot(); - BOOST_FOREACH (string strAddr, mapMultiArgs["-connect"]) { + for (string strAddr : mapMultiArgs["-connect"]) { CAddress addr; OpenNetworkConnection(addr, NULL, strAddr.c_str()); for (int i = 0; i < 10 && i < nLoop; i++) { @@ -1355,7 +1355,7 @@ void ThreadOpenConnections() set > setConnected; { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (!pnode->fInbound) { setConnected.insert(pnode->addr.GetGroup()); nOutbound++; @@ -1412,10 +1412,10 @@ void ThreadOpenAddedConnections() list lAddresses(0); { LOCK(cs_vAddedNodes); - BOOST_FOREACH (string& strAddNode, vAddedNodes) + for (string& strAddNode : vAddedNodes) lAddresses.push_back(strAddNode); } - BOOST_FOREACH (string& strAddNode, lAddresses) { + for (string& strAddNode : lAddresses) { CAddress addr; CSemaphoreGrant grant(*semOutbound); OpenNetworkConnection(addr, &grant, strAddNode.c_str()); @@ -1429,18 +1429,18 @@ void ThreadOpenAddedConnections() list lAddresses(0); { LOCK(cs_vAddedNodes); - BOOST_FOREACH (string& strAddNode, vAddedNodes) + for (string& strAddNode : vAddedNodes) lAddresses.push_back(strAddNode); } list > lservAddressesToAdd(0); - BOOST_FOREACH (string& strAddNode, lAddresses) { + for (string& strAddNode : lAddresses) { vector vservNode(0); if (Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) { lservAddressesToAdd.push_back(vservNode); { LOCK(cs_setservAddNodeAddresses); - BOOST_FOREACH (CService& serv, vservNode) + for (CService& serv : vservNode) setservAddNodeAddresses.insert(serv); } } @@ -1449,16 +1449,16 @@ void ThreadOpenAddedConnections() // (keeping in mind that addnode entries can have many IPs if fNameLookup) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) for (list >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++) - BOOST_FOREACH (CService& addrNode, *(it)) + for (CService& addrNode : *(it)) if (pnode->addr == addrNode) { it = lservAddressesToAdd.erase(it); it--; break; } } - BOOST_FOREACH (vector& vserv, lservAddressesToAdd) { + for (vector& vserv : lservAddressesToAdd) { CSemaphoreGrant grant(*semOutbound); OpenNetworkConnection(CAddress(vserv[i % vserv.size()]), &grant); MilliSleep(500); @@ -1508,7 +1508,7 @@ void ThreadMessageHandler() { LOCK(cs_vNodes); vNodesCopy = vNodes; - BOOST_FOREACH (CNode* pnode, vNodesCopy) { + for (CNode* pnode : vNodesCopy) { pnode->AddRef(); } } @@ -1520,7 +1520,7 @@ void ThreadMessageHandler() bool fSleep = true; - BOOST_FOREACH (CNode* pnode, vNodesCopy) { + for (CNode* pnode : vNodesCopy) { if (pnode->fDisconnect) continue; @@ -1552,7 +1552,7 @@ void ThreadMessageHandler() { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodesCopy) + for (CNode* pnode : vNodesCopy) pnode->Release(); } @@ -1679,7 +1679,7 @@ void static Discover(boost::thread_group& threadGroup) if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) { vector vaddr; if (LookupHost(pszHostName, vaddr)) { - BOOST_FOREACH (const CNetAddr& addr, vaddr) { + for (const CNetAddr& addr : vaddr) { if (AddLocal(addr, LOCAL_IF)) LogPrintf("%s: %s - %s\n", __func__, pszHostName, addr.ToString()); } @@ -1809,18 +1809,18 @@ class CNetCleanup ~CNetCleanup() { // Close sockets - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->hSocket != INVALID_SOCKET) CloseSocket(pnode->hSocket); - BOOST_FOREACH (ListenSocket& hListenSocket, vhListenSocket) + for (ListenSocket& hListenSocket : vhListenSocket) if (hListenSocket.socket != INVALID_SOCKET) if (!CloseSocket(hListenSocket.socket)) LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); // clean up some globals (to help leak detection) - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) delete pnode; - BOOST_FOREACH (CNode* pnode, vNodesDisconnected) + for (CNode* pnode : vNodesDisconnected) delete pnode; vNodes.clear(); vNodesDisconnected.clear(); @@ -1869,7 +1869,7 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss) vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv)); } LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (!pnode->fRelayTxes) continue; LOCK(pnode->cs_filter); @@ -1887,7 +1887,7 @@ void RelayTransactionLockReq(const CTransaction& tx, bool relayToAll) //broadcast the new lock LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { if (!relayToAll && !pnode->fRelayTxes) continue; @@ -1898,7 +1898,7 @@ void RelayTransactionLockReq(const CTransaction& tx, bool relayToAll) void RelayInv(CInv& inv) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes){ + for (CNode* pnode : vNodes){ if((pnode->nServices == NODE_BLOOM_WITHOUT_MN || pnode->nServices == NODE_BLOOM_LIGHT_ZC) && inv.IsMasterNodeType())continue; if (pnode->nVersion >= ActiveProtocol()) pnode->PushInventory(inv); diff --git a/src/net.h b/src/net.h index 7b96188ec5993..f1251897253da 100644 --- a/src/net.h +++ b/src/net.h @@ -29,7 +29,6 @@ #endif #include -#include #include class CAddrMan; @@ -412,7 +411,7 @@ class CNode unsigned int GetTotalRecvSize() { unsigned int total = 0; - BOOST_FOREACH (const CNetMessage& msg, vRecvMsg) + for (const CNetMessage& msg : vRecvMsg) total += msg.vRecv.size() + 24; return total; } @@ -424,7 +423,7 @@ class CNode void SetRecvVersion(int nVersionIn) { nRecvVersion = nVersionIn; - BOOST_FOREACH (CNetMessage& msg, vRecvMsg) + for (CNetMessage& msg : vRecvMsg) msg.SetVersion(nVersionIn); } @@ -660,7 +659,7 @@ class CNode bool HasFulfilledRequest(std::string strRequest) { - BOOST_FOREACH (std::string& type, vecRequestsFulfilled) { + for (std::string& type : vecRequestsFulfilled) { if (type == strRequest) return true; } return false; diff --git a/src/noui.cpp b/src/noui.cpp index e8969987dc336..dec0b54a76739 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -8,7 +8,7 @@ #include "noui.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include diff --git a/src/obfuscation.cpp b/src/obfuscation.cpp index 237a86a138be4..e7d688bee158d 100644 --- a/src/obfuscation.cpp +++ b/src/obfuscation.cpp @@ -11,11 +11,12 @@ #include "masternodeman.h" #include "script/sign.h" #include "swifttx.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include #include #include +#include #include #include @@ -37,352 +38,12 @@ map mapObfuscationBroadcastTxes; // Keep track of the active Masternode CActiveMasternode activeMasternode; -/* *** BEGIN OBFUSCATION MAGIC - ION ********** - Copyright (c) 2014-2015, Dash Developers - eduffield - evan@dashpay.io - udjinm6 - udjinm6@dashpay.io -*/ - -void CObfuscationPool::ProcessMessageObfuscation(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) -{ - if (fLiteMode) return; //disable all Obfuscation/Masternode related functionality - if (!masternodeSync.IsBlockchainSynced()) return; - - if (strCommand == "dsa") { //Obfuscation Accept Into Pool - - int errorID; - - if (pfrom->nVersion < ActiveProtocol()) { - errorID = ERR_VERSION; - LogPrintf("dsa -- incompatible version! \n"); - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - if (!fMasterNode) { - errorID = ERR_NOT_A_MN; - LogPrintf("dsa -- not a Masternode! \n"); - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - int nDenom; - CTransaction txCollateral; - vRecv >> nDenom >> txCollateral; - - CMasternode* pmn = mnodeman.Find(activeMasternode.vin); - if (pmn == NULL) { - errorID = ERR_MN_LIST; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - if (sessionUsers == 0) { - if (pmn->nLastDsq != 0 && - pmn->nLastDsq + mnodeman.CountEnabled(ActiveProtocol()) / 5 > mnodeman.nDsqCount) { - LogPrintf("dsa -- last dsq too recent, must wait. %s \n", pfrom->addr.ToString()); - errorID = ERR_RECENT; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } - - if (!IsCompatibleWithSession(nDenom, txCollateral, errorID)) { - LogPrintf("dsa -- not compatible with existing transactions! \n"); - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } else { - LogPrintf("dsa -- is compatible, please submit! \n"); - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED, errorID); - return; - } - - } else if (strCommand == "dsq") { //Obfuscation Queue - TRY_LOCK(cs_obfuscation, lockRecv); - if (!lockRecv) return; - - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - CObfuscationQueue dsq; - vRecv >> dsq; - - CService addr; - if (!dsq.GetAddress(addr)) return; - if (!dsq.CheckSignature()) return; - - if (dsq.IsExpired()) return; - - CMasternode* pmn = mnodeman.Find(dsq.vin); - if (pmn == NULL) return; - - // if the queue is ready, submit if we can - if (dsq.ready) { - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)addr) { - LogPrintf("dsq - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), addr.ToString()); - return; - } - - if (state == POOL_STATUS_QUEUE) { - LogPrint("obfuscation", "Obfuscation queue is ready - %s\n", addr.ToString()); - PrepareObfuscationDenominate(); - } - } else { - BOOST_FOREACH (CObfuscationQueue q, vecObfuscationQueue) { - if (q.vin == dsq.vin) return; - } - - LogPrint("obfuscation", "dsq last %d last2 %d count %d\n", pmn->nLastDsq, pmn->nLastDsq + mnodeman.size() / 5, mnodeman.nDsqCount); - //don't allow a few nodes to dominate the queuing process - if (pmn->nLastDsq != 0 && - pmn->nLastDsq + mnodeman.CountEnabled(ActiveProtocol()) / 5 > mnodeman.nDsqCount) { - LogPrint("obfuscation", "dsq -- Masternode sending too many dsq messages. %s \n", pmn->addr.ToString()); - return; - } - mnodeman.nDsqCount++; - pmn->nLastDsq = mnodeman.nDsqCount; - pmn->allowFreeTx = true; - - LogPrint("obfuscation", "dsq - new Obfuscation queue object - %s\n", addr.ToString()); - vecObfuscationQueue.push_back(dsq); - dsq.Relay(); - dsq.time = GetTime(); - } - - } else if (strCommand == "dsi") { //ObfuScation vIn - int errorID; - - if (pfrom->nVersion < ActiveProtocol()) { - LogPrintf("dsi -- incompatible version! \n"); - errorID = ERR_VERSION; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - if (!fMasterNode) { - LogPrintf("dsi -- not a Masternode! \n"); - errorID = ERR_NOT_A_MN; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - - return; - } - - std::vector in; - CAmount nAmount; - CTransaction txCollateral; - std::vector out; - vRecv >> in >> nAmount >> txCollateral >> out; - - //do we have enough users in the current session? - if (!IsSessionReady()) { - LogPrintf("dsi -- session not complete! \n"); - errorID = ERR_SESSION; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - //do we have the same denominations as the current session? - if (!IsCompatibleWithEntries(out)) { - LogPrintf("dsi -- not compatible with existing transactions! \n"); - errorID = ERR_EXISTING_TX; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - //check it like a transaction - { - CAmount nValueIn = 0; - CAmount nValueOut = 0; - bool missingTx = false; - - CValidationState state; - CMutableTransaction tx; - - BOOST_FOREACH (const CTxOut o, out) { - nValueOut += o.nValue; - tx.vout.push_back(o); - - if (o.scriptPubKey.size() != 25) { - LogPrintf("dsi - non-standard pubkey detected! %s\n", o.scriptPubKey.ToString()); - errorID = ERR_NON_STANDARD_PUBKEY; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - if (!o.scriptPubKey.IsNormalPaymentScript()) { - LogPrintf("dsi - invalid script! %s\n", o.scriptPubKey.ToString()); - errorID = ERR_INVALID_SCRIPT; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } - - BOOST_FOREACH (const CTxIn i, in) { - tx.vin.push_back(i); - - LogPrint("obfuscation", "dsi -- tx in %s\n", i.ToString()); - - CTransaction tx2; - uint256 hash; - if (GetTransaction(i.prevout.hash, tx2, hash, true)) { - if (tx2.vout.size() > i.prevout.n) { - nValueIn += tx2.vout[i.prevout.n].nValue; - } - } else { - missingTx = true; - } - } - - if (nValueIn > OBFUSCATION_POOL_MAX) { - LogPrintf("dsi -- more than Obfuscation pool max! %s\n", tx.ToString()); - errorID = ERR_MAXIMUM; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - if (!missingTx) { - if (nValueIn - nValueOut > nValueIn * .01) { - LogPrintf("dsi -- fees are too high! %s\n", tx.ToString()); - errorID = ERR_FEES; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } else { - LogPrintf("dsi -- missing input tx! %s\n", tx.ToString()); - errorID = ERR_MISSING_TX; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - - { - LOCK(cs_main); - if (!AcceptableInputs(mempool, state, CTransaction(tx), false, NULL, false, true)) { - LogPrintf("dsi -- transaction not valid! \n"); - errorID = ERR_INVALID_TX; - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - return; - } - } - } - - if (AddEntry(in, nAmount, txCollateral, out, errorID)) { - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED, errorID); - Check(); - - RelayStatus(sessionID, GetState(), GetEntriesCount(), MASTERNODE_RESET); - } else { - pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID); - } - - } else if (strCommand == "dssu") { //Obfuscation status update - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr) { - //LogPrintf("dssu - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), pfrom->addr.ToString()); - return; - } - - int sessionIDMessage; - int state; - int entriesCount; - int accepted; - int errorID; - vRecv >> sessionIDMessage >> state >> entriesCount >> accepted >> errorID; - - LogPrint("obfuscation", "dssu - state: %i entriesCount: %i accepted: %i error: %s \n", state, entriesCount, accepted, GetMessageByID(errorID)); - - if ((accepted != 1 && accepted != 0) && sessionID != sessionIDMessage) { - LogPrintf("dssu - message doesn't match current Obfuscation session %d %d\n", sessionID, sessionIDMessage); - return; - } - - StatusUpdate(state, entriesCount, accepted, errorID, sessionIDMessage); - - } else if (strCommand == "dss") { //Obfuscation Sign Final Tx - - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - vector sigs; - vRecv >> sigs; - - bool success = false; - int count = 0; - - BOOST_FOREACH (const CTxIn item, sigs) { - if (AddScriptSig(item)) success = true; - LogPrint("obfuscation", " -- sigs count %d %d\n", (int)sigs.size(), count); - count++; - } - - if (success) { - obfuScationPool.Check(); - RelayStatus(obfuScationPool.sessionID, obfuScationPool.GetState(), obfuScationPool.GetEntriesCount(), MASTERNODE_RESET); - } - } else if (strCommand == "dsf") { //Obfuscation Final tx - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr) { - //LogPrintf("dsc - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), pfrom->addr.ToString()); - return; - } - - int sessionIDMessage; - CTransaction txNew; - vRecv >> sessionIDMessage >> txNew; - - if (sessionID != sessionIDMessage) { - LogPrint("obfuscation", "dsf - message doesn't match current Obfuscation session %d %d\n", sessionID, sessionIDMessage); - return; - } - - //check to see if input is spent already? (and probably not confirmed) - SignFinalTransaction(txNew, pfrom); - - } else if (strCommand == "dsc") { //Obfuscation Complete - - if (pfrom->nVersion < ActiveProtocol()) { - return; - } - - if (!pSubmittedToMasternode) return; - if ((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr) { - //LogPrintf("dsc - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), pfrom->addr.ToString()); - return; - } - - int sessionIDMessage; - bool error; - int errorID; - vRecv >> sessionIDMessage >> error >> errorID; - - if (sessionID != sessionIDMessage) { - LogPrint("obfuscation", "dsc - message doesn't match current Obfuscation session %d %d\n", obfuScationPool.sessionID, sessionIDMessage); - return; - } - - obfuScationPool.CompletedTransaction(error, errorID); - } -} - int randomizeList(int i) { return std::rand() % i; } void CObfuscationPool::Reset() { cachedLastSuccess = 0; lastNewBlock = 0; - txCollateral = CMutableTransaction(); vecMasternodesUsed.clear(); UnlockCoins(); SetNull(); @@ -398,7 +59,6 @@ void CObfuscationPool::SetNull() entriesCount = 0; lastEntryAccepted = 0; countEntriesAccepted = 0; - sessionFoundMasternode = false; // Both sides state = POOL_STATUS_IDLE; @@ -440,7 +100,7 @@ void CObfuscationPool::UnlockCoins() MilliSleep(50); continue; } - BOOST_FOREACH (CTxIn v, lockedCoins) + for (CTxIn v : lockedCoins) pwalletMain->UnlockCoin(v.prevout); break; } @@ -448,72 +108,6 @@ void CObfuscationPool::UnlockCoins() lockedCoins.clear(); } -std::string CObfuscationPool::GetStatus() -{ - static int showingObfuScationMessage = 0; - showingObfuScationMessage += 10; - std::string suffix = ""; - - if (chainActive.Tip()->nHeight - cachedLastSuccess < minBlockSpacing || !masternodeSync.IsBlockchainSynced()) { - return strAutoDenomResult; - } - switch (state) { - case POOL_STATUS_IDLE: - return _("Obfuscation is idle."); - case POOL_STATUS_ACCEPTING_ENTRIES: - if (entriesCount == 0) { - showingObfuScationMessage = 0; - return strAutoDenomResult; - } else if (lastEntryAccepted == 1) { - if (showingObfuScationMessage % 10 > 8) { - lastEntryAccepted = 0; - showingObfuScationMessage = 0; - } - return _("Obfuscation request complete:") + " " + _("Your transaction was accepted into the pool!"); - } else { - std::string suffix = ""; - if (showingObfuScationMessage % 70 <= 40) - return strprintf(_("Submitted following entries to masternode: %u / %d"), entriesCount, GetMaxPoolTransactions()); - else if (showingObfuScationMessage % 70 <= 50) - suffix = "."; - else if (showingObfuScationMessage % 70 <= 60) - suffix = ".."; - else if (showingObfuScationMessage % 70 <= 70) - suffix = "..."; - return strprintf(_("Submitted to masternode, waiting for more entries ( %u / %d ) %s"), entriesCount, GetMaxPoolTransactions(), suffix); - } - case POOL_STATUS_SIGNING: - if (showingObfuScationMessage % 70 <= 40) - return _("Found enough users, signing ..."); - else if (showingObfuScationMessage % 70 <= 50) - suffix = "."; - else if (showingObfuScationMessage % 70 <= 60) - suffix = ".."; - else if (showingObfuScationMessage % 70 <= 70) - suffix = "..."; - return strprintf(_("Found enough users, signing ( waiting %s )"), suffix); - case POOL_STATUS_TRANSMISSION: - return _("Transmitting final transaction."); - case POOL_STATUS_FINALIZE_TRANSACTION: - return _("Finalizing transaction."); - case POOL_STATUS_ERROR: - return _("Obfuscation request incomplete:") + " " + lastMessage + " " + _("Will retry..."); - case POOL_STATUS_SUCCESS: - return _("Obfuscation request complete:") + " " + lastMessage; - case POOL_STATUS_QUEUE: - if (showingObfuScationMessage % 70 <= 30) - suffix = "."; - else if (showingObfuScationMessage % 70 <= 50) - suffix = ".."; - else if (showingObfuScationMessage % 70 <= 70) - suffix = "..."; - return strprintf(_("Submitted to masternode, waiting in queue %s"), suffix); - ; - default: - return strprintf(_("Unknown state: id = %u"), state); - } -} - // // Check the Obfuscation progress and send client updates if a Masternode // @@ -542,10 +136,10 @@ void CObfuscationPool::Check() // make our new transaction for (unsigned int i = 0; i < entries.size(); i++) { - BOOST_FOREACH (const CTxOut& v, entries[i].vout) + for (const CTxOut& v : entries[i].vout) txNew.vout.push_back(v); - BOOST_FOREACH (const CTxDSIn& s, entries[i].sev) + for (const CTxDSIn& s : entries[i].sev) txNew.vin.push_back(s); } @@ -674,9 +268,9 @@ void CObfuscationPool::ChargeFees() if (r > 33) return; if (state == POOL_STATUS_ACCEPTING_ENTRIES) { - BOOST_FOREACH (const CTransaction& txCollateral, vecSessionCollateral) { + for (const CTransaction& txCollateral : vecSessionCollateral) { bool found = false; - BOOST_FOREACH (const CObfuScationEntry& v, entries) { + for (const CObfuScationEntry& v : entries) { if (v.collateral == txCollateral) { found = true; } @@ -692,8 +286,8 @@ void CObfuscationPool::ChargeFees() if (state == POOL_STATUS_SIGNING) { // who didn't sign? - BOOST_FOREACH (const CObfuScationEntry v, entries) { - BOOST_FOREACH (const CTxDSIn s, v.sev) { + for (const CObfuScationEntry &v : entries) { + for (const CTxDSIn &s : v.sev) { if (!s.fHasSig) { LogPrintf("CObfuscationPool::ChargeFees -- found uncooperative node (didn't sign). Found offence\n"); offences++; @@ -718,9 +312,9 @@ void CObfuscationPool::ChargeFees() r = rand() % 100; if (state == POOL_STATUS_ACCEPTING_ENTRIES) { - BOOST_FOREACH (const CTransaction& txCollateral, vecSessionCollateral) { + for (const CTransaction& txCollateral : vecSessionCollateral) { bool found = false; - BOOST_FOREACH (const CObfuScationEntry& v, entries) { + for (const CObfuScationEntry& v : entries) { if (v.collateral == txCollateral) { found = true; } @@ -745,8 +339,8 @@ void CObfuscationPool::ChargeFees() if (state == POOL_STATUS_SIGNING) { // who didn't sign? - BOOST_FOREACH (const CObfuScationEntry v, entries) { - BOOST_FOREACH (const CTxDSIn s, v.sev) { + for (const CObfuScationEntry &v : entries) { + for (const CTxDSIn &s : v.sev) { if (!s.fHasSig && r > target) { LogPrintf("CObfuscationPool::ChargeFees -- found uncooperative node (didn't sign). charging fees.\n"); @@ -772,7 +366,7 @@ void CObfuscationPool::ChargeRandomFees() if (fMasterNode) { int i = 0; - BOOST_FOREACH (const CTransaction& txCollateral, vecSessionCollateral) { + for (const CTransaction& txCollateral : vecSessionCollateral) { int r = rand() % 100; /* @@ -910,1383 +504,165 @@ void CObfuscationPool::CheckForCompleteQueue() } } -// check to see if the signature is valid -bool CObfuscationPool::SignatureValid(const CScript& newSig, const CTxIn& newVin) + +// Check to make sure everything is signed +bool CObfuscationPool::SignaturesComplete() +{ + for (const CObfuScationEntry& v : entries) { + for (const CTxDSIn& s : v.sev) { + if (!s.fHasSig) return false; + } + } + return true; +} + +void CObfuscationPool::NewBlock() { - CMutableTransaction txNew; - txNew.vin.clear(); - txNew.vout.clear(); + LogPrint("obfuscation", "CObfuscationPool::NewBlock \n"); - int found = -1; - CScript sigPubKey = CScript(); - unsigned int i = 0; + //we we're processing lots of blocks, we'll just leave + if (GetTime() - lastNewBlock < 10) return; + lastNewBlock = GetTime(); - BOOST_FOREACH (CObfuScationEntry& e, entries) { - BOOST_FOREACH (const CTxOut& out, e.vout) - txNew.vout.push_back(out); + obfuScationPool.CheckTimeout(); +} - BOOST_FOREACH (const CTxDSIn& s, e.sev) { - txNew.vin.push_back(s); +bool CObfuScationSigner::IsVinAssociatedWithPubkey(CTxIn& vin, CPubKey& pubkey) +{ + CScript payee2; + payee2 = GetScriptForDestination(pubkey.GetID()); - if (s == newVin) { - found = i; - sigPubKey = s.prevPubKey; + CTransaction txVin; + uint256 hash; + if (GetTransaction(vin.prevout.hash, txVin, hash, true)) { + for (CTxOut out : txVin.vout) { + if (out.nValue == MASTERNODE_COLLATERAL_AMOUNT * COIN) { + if (out.scriptPubKey == payee2) return true; } - i++; } } - if (found >= 0) { //might have to do this one input at a time? - int n = found; - txNew.vin[n].scriptSig = newSig; - LogPrint("obfuscation", "CObfuscationPool::SignatureValid() - Sign with sig %s\n", newSig.ToString().substr(0, 24)); - if (!VerifyScript(txNew.vin[n].scriptSig, sigPubKey, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, MutableTransactionSignatureChecker(&txNew, n))) { - LogPrint("obfuscation", "CObfuscationPool::SignatureValid() - Signing - Error signing input %u\n", n); - return false; - } + return false; +} + +bool CObfuScationSigner::SetKey(std::string strSecret, std::string& errorMessage, CKey& key, CPubKey& pubkey) +{ + CBitcoinSecret vchSecret; + bool fGood = vchSecret.SetString(strSecret); + + if (!fGood) { + errorMessage = _("Invalid private key."); + return false; } - LogPrint("obfuscation", "CObfuscationPool::SignatureValid() - Signing - Successfully validated input\n"); + key = vchSecret.GetKey(); + pubkey = key.GetPubKey(); + return true; } -// check to make sure the collateral provided by the client is valid -bool CObfuscationPool::IsCollateralValid(const CTransaction& txCollateral) +bool CObfuScationSigner::GetKeysFromSecret(std::string strSecret, CKey& keyRet, CPubKey& pubkeyRet) { - if (txCollateral.vout.size() < 1) return false; - if (txCollateral.nLockTime != 0) return false; + CBitcoinSecret vchSecret; - int64_t nValueIn = 0; - int64_t nValueOut = 0; - bool missingTx = false; + if (!vchSecret.SetString(strSecret)) return false; - BOOST_FOREACH (const CTxOut o, txCollateral.vout) { - nValueOut += o.nValue; + keyRet = vchSecret.GetKey(); + pubkeyRet = keyRet.GetPubKey(); - if (!o.scriptPubKey.IsNormalPaymentScript()) { - LogPrintf("CObfuscationPool::IsCollateralValid - Invalid Script %s\n", txCollateral.ToString()); - return false; - } - } + return true; +} - BOOST_FOREACH (const CTxIn i, txCollateral.vin) { - CTransaction tx2; - uint256 hash; - if (GetTransaction(i.prevout.hash, tx2, hash, true)) { - if (tx2.vout.size() > i.prevout.n) { - nValueIn += tx2.vout[i.prevout.n].nValue; - } - } else { - missingTx = true; - } - } +bool CObfuScationSigner::SignMessage(std::string strMessage, std::string& errorMessage, vector& vchSig, CKey key) +{ + CHashWriter ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strMessage; - if (missingTx) { - LogPrint("obfuscation", "CObfuscationPool::IsCollateralValid - Unknown inputs in collateral transaction - %s\n", txCollateral.ToString()); + if (!key.SignCompact(ss.GetHash(), vchSig)) { + errorMessage = _("Signing failed."); return false; } - //collateral transactions are required to pay out OBFUSCATION_COLLATERAL as a fee to the miners - if (nValueIn - nValueOut < OBFUSCATION_COLLATERAL) { - LogPrint("obfuscation", "CObfuscationPool::IsCollateralValid - did not include enough fees in transaction %d\n%s\n", nValueOut - nValueIn, txCollateral.ToString()); - return false; - } + return true; +} - LogPrint("obfuscation", "CObfuscationPool::IsCollateralValid %s\n", txCollateral.ToString()); +bool CObfuScationSigner::VerifyMessage(CPubKey pubkey, vector& vchSig, std::string strMessage, std::string& errorMessage) +{ + CHashWriter ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << strMessage; - { - LOCK(cs_main); - CValidationState state; - if (!AcceptableInputs(mempool, state, txCollateral, true, NULL)) { - if (fDebug) LogPrintf("CObfuscationPool::IsCollateralValid - didn't pass IsAcceptable\n"); - return false; - } + CPubKey pubkey2; + if (!pubkey2.RecoverCompact(ss.GetHash(), vchSig)) { + errorMessage = _("Error recovering public key."); + return false; } - return true; -} + if (fDebug && pubkey2.GetID() != pubkey.GetID()) + LogPrintf("CObfuScationSigner::VerifyMessage -- keys don't match: %s %s\n", pubkey2.GetID().ToString(), pubkey.GetID().ToString()); + return (pubkey2.GetID() == pubkey.GetID()); +} -// -// Add a clients transaction to the pool -// -bool CObfuscationPool::AddEntry(const std::vector& newInput, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector& newOutput, int& errorID) +bool CObfuscationQueue::Sign() { if (!fMasterNode) return false; - BOOST_FOREACH (CTxIn in, newInput) { - if (in.prevout.IsNull() || nAmount < 0) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - input not valid!\n"); - errorID = ERR_INVALID_INPUT; - sessionUsers--; - return false; - } - } + std::string strMessage = vin.ToString() + std::to_string(nDenom) + std::to_string(time) + std::to_string(ready); + + CKey key2; + CPubKey pubkey2; + std::string errorMessage = ""; - if (!IsCollateralValid(txCollateral)) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - collateral not valid!\n"); - errorID = ERR_INVALID_COLLATERAL; - sessionUsers--; + if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2)) { + LogPrintf("CObfuscationQueue():Relay - ERROR: Invalid Masternodeprivkey: '%s'\n", errorMessage); return false; } - if ((int)entries.size() >= GetMaxPoolTransactions()) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - entries is full!\n"); - errorID = ERR_ENTRIES_FULL; - sessionUsers--; + if (!obfuScationSigner.SignMessage(strMessage, errorMessage, vchSig, key2)) { + LogPrintf("CObfuscationQueue():Relay - Sign message failed"); return false; } - BOOST_FOREACH (CTxIn in, newInput) { - LogPrint("obfuscation", "looking for vin -- %s\n", in.ToString()); - BOOST_FOREACH (const CObfuScationEntry& v, entries) { - BOOST_FOREACH (const CTxDSIn& s, v.sev) { - if ((CTxIn)s == in) { - LogPrint("obfuscation", "CObfuscationPool::AddEntry - found in vin\n"); - errorID = ERR_ALREADY_HAVE; - sessionUsers--; - return false; - } - } - } + if (!obfuScationSigner.VerifyMessage(pubkey2, vchSig, strMessage, errorMessage)) { + LogPrintf("CObfuscationQueue():Relay - Verify message failed"); + return false; } - CObfuScationEntry v; - v.Add(newInput, nAmount, txCollateral, newOutput); - entries.push_back(v); - - LogPrint("obfuscation", "CObfuscationPool::AddEntry -- adding %s\n", newInput[0].ToString()); - errorID = MSG_ENTRIES_ADDED; - return true; } -bool CObfuscationPool::AddScriptSig(const CTxIn& newVin) +bool CObfuscationQueue::Relay() { - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig -- new sig %s\n", newVin.scriptSig.ToString().substr(0, 24)); - - - BOOST_FOREACH (const CObfuScationEntry& v, entries) { - BOOST_FOREACH (const CTxDSIn& s, v.sev) { - if (s.scriptSig == newVin.scriptSig) { - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig - already exists\n"); - return false; - } - } - } - - if (!SignatureValid(newVin.scriptSig, newVin)) { - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig - Invalid Sig\n"); - return false; - } - - LogPrint("obfuscation", "CObfuscationPool::AddScriptSig -- sig %s\n", newVin.ToString()); - - BOOST_FOREACH (CTxIn& vin, finalTransaction.vin) { - if (newVin.prevout == vin.prevout && vin.nSequence == newVin.nSequence) { - vin.scriptSig = newVin.scriptSig; - vin.prevPubKey = newVin.prevPubKey; - LogPrint("obfuscation", "CObfuScationPool::AddScriptSig -- adding to finalTransaction %s\n", newVin.scriptSig.ToString().substr(0, 24)); - } - } - for (unsigned int i = 0; i < entries.size(); i++) { - if (entries[i].AddSig(newVin)) { - LogPrint("obfuscation", "CObfuScationPool::AddScriptSig -- adding %s\n", newVin.scriptSig.ToString().substr(0, 24)); - return true; - } - } - - LogPrintf("CObfuscationPool::AddScriptSig -- Couldn't set sig!\n"); - return false; -} - -// Check to make sure everything is signed -bool CObfuscationPool::SignaturesComplete() -{ - BOOST_FOREACH (const CObfuScationEntry& v, entries) { - BOOST_FOREACH (const CTxDSIn& s, v.sev) { - if (!s.fHasSig) return false; - } - } - return true; -} - -// -// Execute a Obfuscation denomination via a Masternode. -// This is only ran from clients -// -void CObfuscationPool::SendObfuscationDenominate(std::vector& vin, std::vector& vout, CAmount amount) -{ - if (fMasterNode) { - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - Obfuscation from a Masternode is not supported currently.\n"); - return; - } - - if (txCollateral == CMutableTransaction()) { - LogPrintf("CObfuscationPool:SendObfuscationDenominate() - Obfuscation collateral not set"); - return; - } - - // lock the funds we're going to use - BOOST_FOREACH (CTxIn in, txCollateral.vin) - lockedCoins.push_back(in); - - BOOST_FOREACH (CTxIn in, vin) - lockedCoins.push_back(in); - - //BOOST_FOREACH(CTxOut o, vout) - // LogPrintf(" vout - %s\n", o.ToString()); - - - // we should already be connected to a Masternode - if (!sessionFoundMasternode) { - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - No Masternode has been selected yet.\n"); - UnlockCoins(); - SetNull(); - return; - } - - if (!CheckDiskSpace()) { - UnlockCoins(); - SetNull(); - fEnableZeromint = false; - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - Not enough disk space, disabling Obfuscation.\n"); - return; - } - - UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); - - LogPrintf("CObfuscationPool::SendObfuscationDenominate() - Added transaction to pool.\n"); - - ClearLastMessage(); - - //check it against the memory pool to make sure it's valid - { - CAmount nValueOut = 0; - - CValidationState state; - CMutableTransaction tx; - - BOOST_FOREACH (const CTxOut& o, vout) { - nValueOut += o.nValue; - tx.vout.push_back(o); - } - - BOOST_FOREACH (const CTxIn& i, vin) { - tx.vin.push_back(i); - - LogPrint("obfuscation", "dsi -- tx in %s\n", i.ToString()); - } - - LogPrintf("Submitting tx %s\n", tx.ToString()); - - while (true) { - TRY_LOCK(cs_main, lockMain); - if (!lockMain) { - MilliSleep(50); - continue; - } - if (!AcceptableInputs(mempool, state, CTransaction(tx), false, NULL, false, true)) { - LogPrintf("dsi -- transaction not valid! %s \n", tx.ToString()); - UnlockCoins(); - SetNull(); - return; - } - break; - } - } - - // store our entry for later use - CObfuScationEntry e; - e.Add(vin, amount, txCollateral, vout); - entries.push_back(e); - - RelayIn(entries[0].sev, entries[0].amount, txCollateral, entries[0].vout); - Check(); -} - -// Incoming message from Masternode updating the progress of Obfuscation -// newAccepted: -1 mean's it'n not a "transaction accepted/not accepted" message, just a standard update -// 0 means transaction was not accepted -// 1 means transaction was accepted - -bool CObfuscationPool::StatusUpdate(int newState, int newEntriesCount, int newAccepted, int& errorID, int newSessionID) -{ - if (fMasterNode) return false; - if (state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false; - - UpdateState(newState); - entriesCount = newEntriesCount; - - if (errorID != MSG_NOERR) strAutoDenomResult = _("Masternode:") + " " + GetMessageByID(errorID); - - if (newAccepted != -1) { - lastEntryAccepted = newAccepted; - countEntriesAccepted += newAccepted; - if (newAccepted == 0) { - UpdateState(POOL_STATUS_ERROR); - lastMessage = GetMessageByID(errorID); - } - - if (newAccepted == 1 && newSessionID != 0) { - sessionID = newSessionID; - LogPrintf("CObfuscationPool::StatusUpdate - set sessionID to %d\n", sessionID); - sessionFoundMasternode = true; - } - } - - if (newState == POOL_STATUS_ACCEPTING_ENTRIES) { - if (newAccepted == 1) { - LogPrintf("CObfuscationPool::StatusUpdate - entry accepted! \n"); - sessionFoundMasternode = true; - //wait for other users. Masternode will report when ready - UpdateState(POOL_STATUS_QUEUE); - } else if (newAccepted == 0 && sessionID == 0 && !sessionFoundMasternode) { - LogPrintf("CObfuscationPool::StatusUpdate - entry not accepted by Masternode \n"); - UnlockCoins(); - UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); - DoAutomaticDenominating(); //try another Masternode - } - if (sessionFoundMasternode) return true; - } - - return true; -} - -// -// After we receive the finalized transaction from the Masternode, we must -// check it to make sure it's what we want, then sign it if we agree. -// If we refuse to sign, it's possible we'll be charged collateral -// -bool CObfuscationPool::SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node) -{ - if (fMasterNode) return false; - - finalTransaction = finalTransactionNew; - LogPrintf("CObfuscationPool::SignFinalTransaction %s", finalTransaction.ToString()); - - vector sigs; - - //make sure my inputs/outputs are present, otherwise refuse to sign - BOOST_FOREACH (const CObfuScationEntry e, entries) { - BOOST_FOREACH (const CTxDSIn s, e.sev) { - /* Sign my transaction and all outputs */ - int mine = -1; - CScript prevPubKey = CScript(); - CTxIn vin = CTxIn(); - - for (unsigned int i = 0; i < finalTransaction.vin.size(); i++) { - if (finalTransaction.vin[i] == s) { - mine = i; - prevPubKey = s.prevPubKey; - vin = s; - } - } - - if (mine >= 0) { //might have to do this one input at a time? - int foundOutputs = 0; - CAmount nValue1 = 0; - CAmount nValue2 = 0; - - for (unsigned int i = 0; i < finalTransaction.vout.size(); i++) { - BOOST_FOREACH (const CTxOut& o, e.vout) { - if (finalTransaction.vout[i] == o) { - foundOutputs++; - nValue1 += finalTransaction.vout[i].nValue; - } - } - } - - BOOST_FOREACH (const CTxOut o, e.vout) - nValue2 += o.nValue; - - int targetOuputs = e.vout.size(); - if (foundOutputs < targetOuputs || nValue1 != nValue2) { - // in this case, something went wrong and we'll refuse to sign. It's possible we'll be charged collateral. But that's - // better then signing if the transaction doesn't look like what we wanted. - LogPrintf("CObfuscationPool::Sign - My entries are not correct! Refusing to sign. %d entries %d target. \n", foundOutputs, targetOuputs); - UnlockCoins(); - SetNull(); - - return false; - } - - const CKeyStore& keystore = *pwalletMain; - - LogPrint("obfuscation", "CObfuscationPool::Sign - Signing my input %i\n", mine); - if (!SignSignature(keystore, prevPubKey, finalTransaction, mine, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig - LogPrint("obfuscation", "CObfuscationPool::Sign - Unable to sign my own transaction! \n"); - // not sure what to do here, it will timeout...? - } - - sigs.push_back(finalTransaction.vin[mine]); - LogPrint("obfuscation", " -- dss %d %d %s\n", mine, (int)sigs.size(), finalTransaction.vin[mine].scriptSig.ToString()); - } - } - - LogPrint("obfuscation", "CObfuscationPool::Sign - txNew:\n%s", finalTransaction.ToString()); - } - - // push all of our signatures to the Masternode - if (sigs.size() > 0 && node != NULL) - node->PushMessage("dss", sigs); - - - return true; -} - -void CObfuscationPool::NewBlock() -{ - LogPrint("obfuscation", "CObfuscationPool::NewBlock \n"); - - //we we're processing lots of blocks, we'll just leave - if (GetTime() - lastNewBlock < 10) return; - lastNewBlock = GetTime(); - - obfuScationPool.CheckTimeout(); -} - -// Obfuscation transaction was completed (failed or successful) -void CObfuscationPool::CompletedTransaction(bool error, int errorID) -{ - if (fMasterNode) return; - - if (error) { - LogPrintf("CompletedTransaction -- error \n"); - UpdateState(POOL_STATUS_ERROR); - - Check(); - UnlockCoins(); - SetNull(); - } else { - LogPrintf("CompletedTransaction -- success \n"); - UpdateState(POOL_STATUS_SUCCESS); - - UnlockCoins(); - SetNull(); - - // To avoid race conditions, we'll only let DS run once per block - cachedLastSuccess = chainActive.Tip()->nHeight; - } - lastMessage = GetMessageByID(errorID); -} - -void CObfuscationPool::ClearLastMessage() -{ - lastMessage = ""; -} - -// -// Passively run Obfuscation in the background to anonymize funds based on the given configuration. -// -// This does NOT run by default for daemons, only for QT. -// -bool CObfuscationPool::DoAutomaticDenominating(bool fDryRun) -{ - return false; // Disabled until Obfuscation is completely removed - - if (!fEnableZeromint) return false; - if (fMasterNode) return false; - if (state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false; - if (GetEntriesCount() > 0) { - strAutoDenomResult = _("Mixing in progress..."); - return false; - } - - TRY_LOCK(cs_obfuscation, lockDS); - if (!lockDS) { - strAutoDenomResult = _("Lock is already in place."); - return false; - } - - if (!masternodeSync.IsBlockchainSynced()) { - strAutoDenomResult = _("Can't mix while sync in progress."); - return false; - } - - if (!fDryRun && pwalletMain->IsLocked()) { - strAutoDenomResult = _("Wallet is locked."); - return false; - } - - if (chainActive.Tip()->nHeight - cachedLastSuccess < minBlockSpacing) { - LogPrintf("CObfuscationPool::DoAutomaticDenominating - Last successful Obfuscation action was too recent\n"); - strAutoDenomResult = _("Last successful Obfuscation action was too recent."); - return false; - } - - if (mnodeman.size() == 0) { - LogPrint("obfuscation", "CObfuscationPool::DoAutomaticDenominating - No Masternodes detected\n"); - strAutoDenomResult = _("No Masternodes detected."); - return false; - } - - // ** find the coins we'll use - std::vector vCoins; - CAmount nValueMin = CENT; - CAmount nValueIn = 0; - - CAmount nOnlyDenominatedBalance; - CAmount nBalanceNeedsDenominated; - - // should not be less than fees in OBFUSCATION_COLLATERAL + few (lets say 5) smallest denoms - CAmount nLowestDenom = OBFUSCATION_COLLATERAL + obfuScationDenominations[obfuScationDenominations.size() - 1] * 5; - - // if there are no OBF collateral inputs yet - if (!pwalletMain->HasCollateralInputs()) - // should have some additional amount for them - nLowestDenom += OBFUSCATION_COLLATERAL * 4; - - CAmount nBalanceNeedsAnonymized = nAnonymizeIonAmount * COIN - pwalletMain->GetAnonymizedBalance(); - - // if balanceNeedsAnonymized is more than pool max, take the pool max - if (nBalanceNeedsAnonymized > OBFUSCATION_POOL_MAX) nBalanceNeedsAnonymized = OBFUSCATION_POOL_MAX; - - // if balanceNeedsAnonymized is more than non-anonymized, take non-anonymized - CAmount nAnonymizableBalance = pwalletMain->GetAnonymizableBalance(); - if (nBalanceNeedsAnonymized > nAnonymizableBalance) nBalanceNeedsAnonymized = nAnonymizableBalance; - - if (nBalanceNeedsAnonymized < nLowestDenom) { - LogPrintf("DoAutomaticDenominating : No funds detected in need of denominating \n"); - strAutoDenomResult = _("No funds detected in need of denominating."); - return false; - } - - LogPrint("obfuscation", "DoAutomaticDenominating : nLowestDenom=%d, nBalanceNeedsAnonymized=%d\n", nLowestDenom, nBalanceNeedsAnonymized); - - // select coins that should be given to the pool - if (!pwalletMain->SelectCoinsDark(nValueMin, nBalanceNeedsAnonymized, vCoins, nValueIn, 0, nZeromintPercentage)) { - nValueIn = 0; - vCoins.clear(); - - if (pwalletMain->SelectCoinsDark(nValueMin, 9999999 * COIN, vCoins, nValueIn, -2, 0)) { - nOnlyDenominatedBalance = pwalletMain->GetDenominatedBalance(true) + pwalletMain->GetDenominatedBalance() - pwalletMain->GetAnonymizedBalance(); - nBalanceNeedsDenominated = nBalanceNeedsAnonymized - nOnlyDenominatedBalance; - - if (nBalanceNeedsDenominated > nValueIn) nBalanceNeedsDenominated = nValueIn; - - if (nBalanceNeedsDenominated < nLowestDenom) return false; // most likely we just waiting for denoms to confirm - if (!fDryRun) return CreateDenominated(nBalanceNeedsDenominated); - - return true; - } else { - LogPrintf("DoAutomaticDenominating : Can't denominate - no compatible inputs left\n"); - strAutoDenomResult = _("Can't denominate: no compatible inputs left."); - return false; - } - } - - if (fDryRun) return true; - - nOnlyDenominatedBalance = pwalletMain->GetDenominatedBalance(true) + pwalletMain->GetDenominatedBalance() - pwalletMain->GetAnonymizedBalance(); - nBalanceNeedsDenominated = nBalanceNeedsAnonymized - nOnlyDenominatedBalance; - - //check if we have should create more denominated inputs - if (nBalanceNeedsDenominated > nOnlyDenominatedBalance) return CreateDenominated(nBalanceNeedsDenominated); - - //check if we have the collateral sized inputs - if (!pwalletMain->HasCollateralInputs()) return !pwalletMain->HasCollateralInputs(false) && MakeCollateralAmounts(); - - std::vector vOut; - - // initial phase, find a Masternode - if (!sessionFoundMasternode) { - // Clean if there is anything left from previous session - UnlockCoins(); - SetNull(); - - int nUseQueue = rand() % 100; - UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); - - if (pwalletMain->GetDenominatedBalance(true) > 0) { //get denominated unconfirmed inputs - LogPrintf("DoAutomaticDenominating -- Found unconfirmed denominated outputs, will wait till they confirm to continue.\n"); - strAutoDenomResult = _("Found unconfirmed denominated outputs, will wait till they confirm to continue."); - return false; - } - - //check our collateral nad create new if needed - std::string strReason; - CValidationState state; - if (txCollateral == CMutableTransaction()) { - if (!pwalletMain->CreateCollateralTransaction(txCollateral, strReason)) { - LogPrintf("% -- create collateral error:%s\n", __func__, strReason); - return false; - } - } else { - if (!IsCollateralValid(txCollateral)) { - LogPrintf("%s -- invalid collateral, recreating...\n", __func__); - if (!pwalletMain->CreateCollateralTransaction(txCollateral, strReason)) { - LogPrintf("%s -- create collateral error: %s\n", __func__, strReason); - return false; - } - } - } - - //if we've used 90% of the Masternode list then drop all the oldest first - int nThreshold = (int)(mnodeman.CountEnabled(ActiveProtocol()) * 0.9); - LogPrint("obfuscation", "Checking vecMasternodesUsed size %d threshold %d\n", (int)vecMasternodesUsed.size(), nThreshold); - while ((int)vecMasternodesUsed.size() > nThreshold) { - vecMasternodesUsed.erase(vecMasternodesUsed.begin()); - LogPrint("obfuscation", " vecMasternodesUsed size %d threshold %d\n", (int)vecMasternodesUsed.size(), nThreshold); - } - - //don't use the queues all of the time for mixing - if (nUseQueue > 33) { - // Look through the queues and see if anything matches - BOOST_FOREACH (CObfuscationQueue& dsq, vecObfuscationQueue) { - CService addr; - if (dsq.time == 0) continue; - - if (!dsq.GetAddress(addr)) continue; - if (dsq.IsExpired()) continue; - - int protocolVersion; - if (!dsq.GetProtocolVersion(protocolVersion)) continue; - if (protocolVersion < ActiveProtocol()) continue; - - //non-denom's are incompatible - if ((dsq.nDenom & (1 << 4))) continue; - - bool fUsed = false; - //don't reuse Masternodes - BOOST_FOREACH (CTxIn usedVin, vecMasternodesUsed) { - if (dsq.vin == usedVin) { - fUsed = true; - break; - } - } - if (fUsed) continue; - - std::vector vTempCoins; - std::vector vTempCoins2; - // Try to match their denominations if possible - if (!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nValueMin, nBalanceNeedsAnonymized, vTempCoins, vTempCoins2, nValueIn, 0, nZeromintPercentage)) { - LogPrintf("DoAutomaticDenominating --- Couldn't match denominations %d\n", dsq.nDenom); - continue; - } - - CMasternode* pmn = mnodeman.Find(dsq.vin); - if (pmn == NULL) { - LogPrintf("DoAutomaticDenominating --- dsq vin %s is not in masternode list!", dsq.vin.ToString()); - continue; - } - - LogPrintf("DoAutomaticDenominating --- attempt to connect to masternode from queue %s\n", pmn->addr.ToString()); - lastTimeChanged = GetTimeMillis(); - - // connect to Masternode and submit the queue request - CNode* pnode = ConnectNode((CAddress)addr, NULL, true); - if (pnode != NULL) { - pSubmittedToMasternode = pmn; - vecMasternodesUsed.push_back(dsq.vin); - sessionDenom = dsq.nDenom; - - pnode->PushMessage("dsa", sessionDenom, txCollateral); - LogPrintf("DoAutomaticDenominating --- connected (from queue), sending dsa for %d - %s\n", sessionDenom, pnode->addr.ToString()); - strAutoDenomResult = _("Mixing in progress..."); - dsq.time = 0; //remove node - return true; - } else { - LogPrintf("DoAutomaticDenominating --- error connecting \n"); - strAutoDenomResult = _("Error connecting to Masternode."); - dsq.time = 0; //remove node - continue; - } - } - } - - // do not initiate queue if we are a liquidity proveder to avoid useless inter-mixing - if (nLiquidityProvider) return false; - - int i = 0; - - // otherwise, try one randomly - while (i < 10) { - CMasternode* pmn = mnodeman.FindRandomNotInVec(vecMasternodesUsed, ActiveProtocol()); - if (pmn == NULL) { - LogPrintf("DoAutomaticDenominating --- Can't find random masternode!\n"); - strAutoDenomResult = _("Can't find random Masternode."); - return false; - } - - if (pmn->nLastDsq != 0 && - pmn->nLastDsq + mnodeman.CountEnabled(ActiveProtocol()) / 5 > mnodeman.nDsqCount) { - i++; - continue; - } - - lastTimeChanged = GetTimeMillis(); - LogPrintf("DoAutomaticDenominating --- attempt %d connection to Masternode %s\n", i, pmn->addr.ToString()); - CNode* pnode = ConnectNode((CAddress)pmn->addr, NULL, true); - if (pnode != NULL) { - pSubmittedToMasternode = pmn; - vecMasternodesUsed.push_back(pmn->vin); - - std::vector vecAmounts; - pwalletMain->ConvertList(vCoins, vecAmounts); - // try to get a single random denom out of vecAmounts - while (sessionDenom == 0) - sessionDenom = GetDenominationsByAmounts(vecAmounts); - - pnode->PushMessage("dsa", sessionDenom, txCollateral); - LogPrintf("DoAutomaticDenominating --- connected, sending dsa for %d\n", sessionDenom); - strAutoDenomResult = _("Mixing in progress..."); - return true; - } else { - vecMasternodesUsed.push_back(pmn->vin); // postpone MN we wasn't able to connect to - i++; - continue; - } - } - - strAutoDenomResult = _("No compatible Masternode found."); - return false; - } - - strAutoDenomResult = _("Mixing in progress..."); - return false; -} - - -bool CObfuscationPool::PrepareObfuscationDenominate() -{ - std::string strError = ""; - // Submit transaction to the pool if we get here - // Try to use only inputs with the same number of rounds starting from lowest number of rounds possible - for (int i = 0; i < nZeromintPercentage; i++) { - strError = pwalletMain->PrepareObfuscationDenominate(i, i + 1); - LogPrintf("DoAutomaticDenominating : Running Obfuscation denominate for %d rounds. Return '%s'\n", i, strError); - if (strError == "") return true; - } - - // We failed? That's strange but let's just make final attempt and try to mix everything - strError = pwalletMain->PrepareObfuscationDenominate(0, nZeromintPercentage); - LogPrintf("DoAutomaticDenominating : Running Obfuscation denominate for all rounds. Return '%s'\n", strError); - if (strError == "") return true; - - // Should never actually get here but just in case - strAutoDenomResult = strError; - LogPrintf("DoAutomaticDenominating : Error running denominate, %s\n", strError); - return false; -} - -bool CObfuscationPool::SendRandomPaymentToSelf() -{ - int64_t nBalance = pwalletMain->GetBalance(); - int64_t nPayment = (nBalance * 0.35) + (rand() % nBalance); - - if (nPayment > nBalance) nPayment = nBalance - (0.1 * COIN); - - // make our change address - CReserveKey reservekey(pwalletMain); - - CScript scriptChange; - CPubKey vchPubKey; - assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptChange = GetScriptForDestination(vchPubKey.GetID()); - - CWalletTx wtx; - CAmount nFeeRet = 0; - std::string strFail = ""; - std::vector vecSend; - int nChangePosRet = -1; - - // ****** Add fees ************ / - CRecipient recipient = {scriptChange, nPayment, false}; - vecSend.push_back(recipient); - - CCoinControl* coinControl = NULL; - bool success = pwalletMain->CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosRet, strFail, coinControl, ONLY_DENOMINATED); - if (!success) { - LogPrintf("SendRandomPaymentToSelf: Error - %s\n", strFail); - return false; - } - - pwalletMain->CommitTransaction(wtx, reservekey); - - LogPrintf("SendRandomPaymentToSelf Success: tx %s\n", wtx.GetHash().GetHex()); - - return true; -} - -// Split up large inputs or create fee sized inputs -bool CObfuscationPool::MakeCollateralAmounts() -{ - CWalletTx wtx; - CAmount nFeeRet = 0; - std::string strFail = ""; - std::vector vecSend; - int nChangePosRet = -1; - CCoinControl coinControl; - coinControl.fAllowOtherInputs = false; - coinControl.fAllowWatchOnly = false; - // make our collateral address - CReserveKey reservekeyCollateral(pwalletMain); - // make our change address - CReserveKey reservekeyChange(pwalletMain); - - CScript scriptCollateral; - CPubKey vchPubKey; - assert(reservekeyCollateral.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptCollateral = GetScriptForDestination(vchPubKey.GetID()); - - CRecipient recipient = {scriptCollateral, OBFUSCATION_COLLATERAL * 4, false}; - vecSend.push_back(recipient); - - // try to use non-denominated and not mn-like funds - bool success = pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, - nFeeRet, nChangePosRet, strFail, &coinControl, ONLY_NONDENOMINATED_NOT20000IFMN); - if (!success) { - // if we failed (most likeky not enough funds), try to use all coins instead - - // MN-like funds should not be touched in any case and we can't mix denominated without collaterals anyway - CCoinControl* coinControlNull = NULL; - LogPrintf("MakeCollateralAmounts: ONLY_NONDENOMINATED_NOT20000IFMN Error - %s\n", strFail); - success = pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, - nFeeRet, nChangePosRet, strFail, coinControlNull, ONLY_NOT20000IFMN); - if (!success) { - LogPrintf("MakeCollateralAmounts: ONLY_NOT20000IFMN Error - %s\n", strFail); - reservekeyCollateral.ReturnKey(); - return false; - } - } - - reservekeyCollateral.KeepKey(); - - LogPrintf("MakeCollateralAmounts: tx %s\n", wtx.GetHash().GetHex()); - - // use the same cachedLastSuccess as for DS mixinx to prevent race - if (!pwalletMain->CommitTransaction(wtx, reservekeyChange)) { - LogPrintf("MakeCollateralAmounts: CommitTransaction failed!\n"); - return false; - } - - cachedLastSuccess = chainActive.Tip()->nHeight; - - return true; -} - -// Create denominations -bool CObfuscationPool::CreateDenominated(CAmount nTotalValue) -{ - CWalletTx wtx; - CAmount nFeeRet = 0; - std::string strFail = ""; - std::vector vecSend; - int nChangePosRet = -1; - CAmount nValueLeft = nTotalValue; - - // make our collateral address - CReserveKey reservekeyCollateral(pwalletMain); - // make our change address - CReserveKey reservekeyChange(pwalletMain); - // make our denom addresses - CReserveKey reservekeyDenom(pwalletMain); - - CScript scriptCollateral; - CPubKey vchPubKey; - assert(reservekeyCollateral.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptCollateral = GetScriptForDestination(vchPubKey.GetID()); - - // ****** Add collateral outputs ************ / - if (!pwalletMain->HasCollateralInputs()) { - CRecipient recipient = {scriptCollateral, OBFUSCATION_COLLATERAL * 4, false}; - vecSend.push_back(recipient); - nValueLeft -= OBFUSCATION_COLLATERAL * 4; - } - - // ****** Add denoms ************ / - BOOST_REVERSE_FOREACH (CAmount v, obfuScationDenominations) { - int nOutputs = 0; - - // add each output up to 10 times until it can't be added again - while (nValueLeft - v >= OBFUSCATION_COLLATERAL && nOutputs <= 10) { - CScript scriptDenom; - CPubKey vchPubKey; - //use a unique change address - assert(reservekeyDenom.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptDenom = GetScriptForDestination(vchPubKey.GetID()); - // TODO: do not keep reservekeyDenom here - reservekeyDenom.KeepKey(); - - CRecipient recipient = {scriptDenom, v, false}; - vecSend.push_back(recipient); - - //increment outputs and subtract denomination amount - nOutputs++; - nValueLeft -= v; - LogPrintf("CreateDenominated1 %d\n", nValueLeft); - } - - if (nValueLeft == 0) break; - } - LogPrintf("CreateDenominated2 %d\n", nValueLeft); - - // if we have anything left over, it will be automatically send back as change - there is no need to send it manually - - CCoinControl* coinControl = NULL; - bool success = pwalletMain->CreateTransaction(vecSend, wtx, reservekeyChange, - nFeeRet, nChangePosRet, strFail, coinControl, ONLY_NONDENOMINATED_NOT20000IFMN); - if (!success) { - LogPrintf("CreateDenominated: Error - %s\n", strFail); - // TODO: return reservekeyDenom here - reservekeyCollateral.ReturnKey(); - return false; - } - - // TODO: keep reservekeyDenom here - reservekeyCollateral.KeepKey(); - - // use the same cachedLastSuccess as for DS mixinx to prevent race - if (pwalletMain->CommitTransaction(wtx, reservekeyChange)) - cachedLastSuccess = chainActive.Tip()->nHeight; - else - LogPrintf("CreateDenominated: CommitTransaction failed!\n"); - - LogPrintf("CreateDenominated: tx %s\n", wtx.GetHash().GetHex()); - - return true; -} - -bool CObfuscationPool::IsCompatibleWithEntries(std::vector& vout) -{ - if (GetDenominations(vout) == 0) return false; - - BOOST_FOREACH (const CObfuScationEntry v, entries) { - LogPrintf(" IsCompatibleWithEntries %d %d\n", GetDenominations(vout), GetDenominations(v.vout)); - /* - BOOST_FOREACH(CTxOut o1, vout) - LogPrintf(" vout 1 - %s\n", o1.ToString()); - - BOOST_FOREACH(CTxOut o2, v.vout) - LogPrintf(" vout 2 - %s\n", o2.ToString()); -*/ - if (GetDenominations(vout) != GetDenominations(v.vout)) return false; - } - - return true; -} - -bool CObfuscationPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txCollateral, int& errorID) -{ - if (nDenom == 0) return false; - - LogPrintf("CObfuscationPool::IsCompatibleWithSession - sessionDenom %d sessionUsers %d\n", sessionDenom, sessionUsers); - - if (!unitTest && !IsCollateralValid(txCollateral)) { - LogPrint("obfuscation", "CObfuscationPool::IsCompatibleWithSession - collateral not valid!\n"); - errorID = ERR_INVALID_COLLATERAL; - return false; - } - - if (sessionUsers < 0) sessionUsers = 0; - - if (sessionUsers == 0) { - sessionID = 1 + (rand() % 999999); - sessionDenom = nDenom; - sessionUsers++; - lastTimeChanged = GetTimeMillis(); - - if (!unitTest) { - //broadcast that I'm accepting entries, only if it's the first entry through - CObfuscationQueue dsq; - dsq.nDenom = nDenom; - dsq.vin = activeMasternode.vin; - dsq.time = GetTime(); - dsq.Sign(); - dsq.Relay(); - } - - UpdateState(POOL_STATUS_QUEUE); - vecSessionCollateral.push_back(txCollateral); - return true; - } - - if ((state != POOL_STATUS_ACCEPTING_ENTRIES && state != POOL_STATUS_QUEUE) || sessionUsers >= GetMaxPoolTransactions()) { - if ((state != POOL_STATUS_ACCEPTING_ENTRIES && state != POOL_STATUS_QUEUE)) errorID = ERR_MODE; - if (sessionUsers >= GetMaxPoolTransactions()) errorID = ERR_QUEUE_FULL; - LogPrintf("CObfuscationPool::IsCompatibleWithSession - incompatible mode, return false %d %d\n", state != POOL_STATUS_ACCEPTING_ENTRIES, sessionUsers >= GetMaxPoolTransactions()); - return false; - } - - if (nDenom != sessionDenom) { - errorID = ERR_DENOM; - return false; - } - - LogPrintf("CObfuScationPool::IsCompatibleWithSession - compatible\n"); - - sessionUsers++; - lastTimeChanged = GetTimeMillis(); - vecSessionCollateral.push_back(txCollateral); - - return true; -} - -//create a nice string to show the denominations -void CObfuscationPool::GetDenominationsToString(int nDenom, std::string& strDenom) -{ - // Function returns as follows: - // - // bit 0 - 100ION+1 ( bit on if present ) - // bit 1 - 10ION+1 - // bit 2 - 1ION+1 - // bit 3 - .1ION+1 - // bit 3 - non-denom - - - strDenom = ""; - - if (nDenom & (1 << 0)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "100"; - } - - if (nDenom & (1 << 1)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "10"; - } - - if (nDenom & (1 << 2)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "1"; - } - - if (nDenom & (1 << 3)) { - if (strDenom.size() > 0) strDenom += "+"; - strDenom += "0.1"; - } -} - -int CObfuscationPool::GetDenominations(const std::vector& vout) -{ - std::vector vout2; - - BOOST_FOREACH (CTxDSOut out, vout) - vout2.push_back(out); - - return GetDenominations(vout2); -} - -// return a bitshifted integer representing the denominations in this list -int CObfuscationPool::GetDenominations(const std::vector& vout, bool fSingleRandomDenom) -{ - std::vector > denomUsed; - - // make a list of denominations, with zero uses - BOOST_FOREACH (int64_t d, obfuScationDenominations) - denomUsed.push_back(make_pair(d, 0)); - - // look for denominations and update uses to 1 - BOOST_FOREACH (CTxOut out, vout) { - bool found = false; - BOOST_FOREACH (PAIRTYPE(int64_t, int) & s, denomUsed) { - if (out.nValue == s.first) { - s.second = 1; - found = true; - } - } - if (!found) return 0; - } - - int denom = 0; - int c = 0; - // if the denomination is used, shift the bit on. - // then move to the next - BOOST_FOREACH (PAIRTYPE(int64_t, int) & s, denomUsed) { - int bit = (fSingleRandomDenom ? rand() % 2 : 1) * s.second; - denom |= bit << c++; - if (fSingleRandomDenom && bit) break; // use just one random denomination - } - - // Function returns as follows: - // - // bit 0 - 100ION+1 ( bit on if present ) - // bit 1 - 10ION+1 - // bit 2 - 1ION+1 - // bit 3 - .1ION+1 - - return denom; -} - - -int CObfuscationPool::GetDenominationsByAmounts(std::vector& vecAmount) -{ - CScript e = CScript(); - std::vector vout1; - - // Make outputs by looping through denominations, from small to large - BOOST_REVERSE_FOREACH (CAmount v, vecAmount) { - CTxOut o(v, e); - vout1.push_back(o); - } - - return GetDenominations(vout1, true); -} - -int CObfuscationPool::GetDenominationsByAmount(CAmount nAmount, int nDenomTarget) -{ - CScript e = CScript(); - CAmount nValueLeft = nAmount; - - std::vector vout1; - - // Make outputs by looping through denominations, from small to large - BOOST_REVERSE_FOREACH (CAmount v, obfuScationDenominations) { - if (nDenomTarget != 0) { - bool fAccepted = false; - if ((nDenomTarget & (1 << 0)) && v == ((100 * COIN) + 100000)) { - fAccepted = true; - } else if ((nDenomTarget & (1 << 1)) && v == ((10 * COIN) + 10000)) { - fAccepted = true; - } else if ((nDenomTarget & (1 << 2)) && v == ((1 * COIN) + 1000)) { - fAccepted = true; - } else if ((nDenomTarget & (1 << 3)) && v == ((.1 * COIN) + 100)) { - fAccepted = true; - } - if (!fAccepted) continue; - } - - int nOutputs = 0; - - // add each output up to 10 times until it can't be added again - while (nValueLeft - v >= 0 && nOutputs <= 10) { - CTxOut o(v, e); - vout1.push_back(o); - nValueLeft -= v; - nOutputs++; - } - LogPrintf("GetDenominationsByAmount --- %d nOutputs %d\n", v, nOutputs); - } - - return GetDenominations(vout1); -} - -std::string CObfuscationPool::GetMessageByID(int messageID) -{ - switch (messageID) { - case ERR_ALREADY_HAVE: - return _("Already have that input."); - case ERR_DENOM: - return _("No matching denominations found for mixing."); - case ERR_ENTRIES_FULL: - return _("Entries are full."); - case ERR_EXISTING_TX: - return _("Not compatible with existing transactions."); - case ERR_FEES: - return _("Transaction fees are too high."); - case ERR_INVALID_COLLATERAL: - return _("Collateral not valid."); - case ERR_INVALID_INPUT: - return _("Input is not valid."); - case ERR_INVALID_SCRIPT: - return _("Invalid script detected."); - case ERR_INVALID_TX: - return _("Transaction not valid."); - case ERR_MAXIMUM: - return _("Value more than Obfuscation pool maximum allows."); - case ERR_MN_LIST: - return _("Not in the Masternode list."); - case ERR_MODE: - return _("Incompatible mode."); - case ERR_NON_STANDARD_PUBKEY: - return _("Non-standard public key detected."); - case ERR_NOT_A_MN: - return _("This is not a Masternode."); - case ERR_QUEUE_FULL: - return _("Masternode queue is full."); - case ERR_RECENT: - return _("Last Obfuscation was too recent."); - case ERR_SESSION: - return _("Session not complete!"); - case ERR_MISSING_TX: - return _("Missing input transaction information."); - case ERR_VERSION: - return _("Incompatible version."); - case MSG_SUCCESS: - return _("Transaction created successfully."); - case MSG_ENTRIES_ADDED: - return _("Your entries added successfully."); - case MSG_NOERR: - default: - return ""; - } -} - -bool CObfuScationSigner::IsVinAssociatedWithPubkey(CTxIn& vin, CPubKey& pubkey) -{ - CScript payee2; - payee2 = GetScriptForDestination(pubkey.GetID()); - - CTransaction txVin; - uint256 hash; - if (GetTransaction(vin.prevout.hash, txVin, hash, true)) { - BOOST_FOREACH (CTxOut out, txVin.vout) { - if (out.nValue == MASTERNODE_COLLATERAL_AMOUNT * COIN) { - if (out.scriptPubKey == payee2) return true; - } - } - } - - return false; -} - -bool CObfuScationSigner::SetKey(std::string strSecret, std::string& errorMessage, CKey& key, CPubKey& pubkey) -{ - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(strSecret); - - if (!fGood) { - errorMessage = _("Invalid private key."); - return false; - } - - key = vchSecret.GetKey(); - pubkey = key.GetPubKey(); - - return true; -} - -bool CObfuScationSigner::GetKeysFromSecret(std::string strSecret, CKey& keyRet, CPubKey& pubkeyRet) -{ - CBitcoinSecret vchSecret; - - if (!vchSecret.SetString(strSecret)) return false; - - keyRet = vchSecret.GetKey(); - pubkeyRet = keyRet.GetPubKey(); - - return true; -} - -bool CObfuScationSigner::SignMessage(std::string strMessage, std::string& errorMessage, vector& vchSig, CKey key) -{ - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; - - if (!key.SignCompact(ss.GetHash(), vchSig)) { - errorMessage = _("Signing failed."); - return false; - } - - return true; -} - -bool CObfuScationSigner::VerifyMessage(CPubKey pubkey, vector& vchSig, std::string strMessage, std::string& errorMessage) -{ - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; - - CPubKey pubkey2; - if (!pubkey2.RecoverCompact(ss.GetHash(), vchSig)) { - errorMessage = _("Error recovering public key."); - return false; - } - - if (fDebug && pubkey2.GetID() != pubkey.GetID()) - LogPrintf("CObfuScationSigner::VerifyMessage -- keys don't match: %s %s\n", pubkey2.GetID().ToString(), pubkey.GetID().ToString()); - - return (pubkey2.GetID() == pubkey.GetID()); -} - -bool CObfuscationQueue::Sign() -{ - if (!fMasterNode) return false; - - std::string strMessage = vin.ToString() + std::to_string(nDenom) + std::to_string(time) + std::to_string(ready); - - CKey key2; - CPubKey pubkey2; - std::string errorMessage = ""; - - if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, key2, pubkey2)) { - LogPrintf("CObfuscationQueue():Relay - ERROR: Invalid Masternodeprivkey: '%s'\n", errorMessage); - return false; - } - - if (!obfuScationSigner.SignMessage(strMessage, errorMessage, vchSig, key2)) { - LogPrintf("CObfuscationQueue():Relay - Sign message failed"); - return false; - } - - if (!obfuScationSigner.VerifyMessage(pubkey2, vchSig, strMessage, errorMessage)) { - LogPrintf("CObfuscationQueue():Relay - Verify message failed"); - return false; - } - - return true; -} - -bool CObfuscationQueue::Relay() -{ - LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { - // always relay to everyone - pnode->PushMessage("dsq", (*this)); - } - - return true; -} - -bool CObfuscationQueue::CheckSignature() -{ - CMasternode* pmn = mnodeman.Find(vin); - - if (pmn != NULL) { - std::string strMessage = vin.ToString() + std::to_string(nDenom) + std::to_string(time) + std::to_string(ready); - - std::string errorMessage = ""; - if (!obfuScationSigner.VerifyMessage(pmn->pubKeyMasternode, vchSig, strMessage, errorMessage)) { - return error("CObfuscationQueue::CheckSignature() - Got bad Masternode address signature %s \n", vin.ToString().c_str()); - } - - return true; - } - - return false; -} + LOCK(cs_vNodes); + for (CNode* pnode : vNodes) { + // always relay to everyone + pnode->PushMessage("dsq", (*this)); + } + return true; +} void CObfuscationPool::RelayFinalTransaction(const int sessionID, const CTransaction& txNew) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { pnode->PushMessage("dsf", sessionID, txNew); } } -void CObfuscationPool::RelayIn(const std::vector& vin, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& vout) -{ - if (!pSubmittedToMasternode) return; - - std::vector vin2; - std::vector vout2; - - BOOST_FOREACH (CTxDSIn in, vin) - vin2.push_back(in); - - BOOST_FOREACH (CTxDSOut out, vout) - vout2.push_back(out); - - CNode* pnode = FindNode(pSubmittedToMasternode->addr); - if (pnode != NULL) { - LogPrintf("RelayIn - found master, relaying message - %s \n", pnode->addr.ToString()); - pnode->PushMessage("dsi", vin2, nAmount, txCollateral, vout2); - } -} - void CObfuscationPool::RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const int errorID) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) pnode->PushMessage("dssu", sessionID, newState, newEntriesCount, newAccepted, errorID); } void CObfuscationPool::RelayCompletedTransaction(const int sessionID, const bool error, const int errorID) { LOCK(cs_vNodes); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) pnode->PushMessage("dsc", sessionID, error, errorID); } @@ -2325,10 +701,6 @@ void ThreadCheckObfuScationPool() obfuScationPool.CheckTimeout(); obfuScationPool.CheckForCompleteQueue(); - - if (obfuScationPool.GetState() == POOL_STATUS_IDLE && c % 15 == 0) { - obfuScationPool.DoAutomaticDenominating(); - } } } } diff --git a/src/obfuscation.h b/src/obfuscation.h index b2372bec91dce..9a9cacfb065be 100644 --- a/src/obfuscation.h +++ b/src/obfuscation.h @@ -62,7 +62,6 @@ class CTxDSIn : public CTxIn { public: bool fHasSig; // flag to indicate if signed - int nSentTimes; //times we've sent this anonymously CTxDSIn(const CTxIn& in) { @@ -70,7 +69,6 @@ class CTxDSIn : public CTxIn scriptSig = in.scriptSig; prevPubKey = in.prevPubKey; nSequence = in.nSequence; - nSentTimes = 0; fHasSig = false; } }; @@ -100,7 +98,6 @@ class CObfuScationEntry std::vector vout; CAmount amount; CTransaction collateral; - CTransaction txSupporting; int64_t addedTime; // time in UTC milliseconds CObfuScationEntry() @@ -117,10 +114,10 @@ class CObfuScationEntry return false; } - BOOST_FOREACH (const CTxIn& in, vinIn) + for (const CTxIn& in : vinIn) sev.push_back(in); - BOOST_FOREACH (const CTxOut& out, voutIn) + for (const CTxOut& out : voutIn) vout.push_back(out); amount = amountIn; @@ -131,24 +128,6 @@ class CObfuScationEntry return true; } - bool AddSig(const CTxIn& vin) - { - BOOST_FOREACH (CTxDSIn& s, sev) { - if (s.prevout == vin.prevout && s.nSequence == vin.nSequence) { - if (s.fHasSig) { - return false; - } - s.scriptSig = vin.scriptSig; - s.prevPubKey = vin.prevPubKey; - s.fHasSig = true; - - return true; - } - } - - return false; - } - bool IsExpired() { return (GetTime() - addedTime) > OBFUSCATION_QUEUE_TIMEOUT; // 120 seconds @@ -189,27 +168,6 @@ class CObfuscationQueue READWRITE(vchSig); } - bool GetAddress(CService& addr) - { - CMasternode* pmn = mnodeman.Find(vin); - if (pmn != NULL) { - addr = pmn->addr; - return true; - } - return false; - } - - /// Get the protocol version - bool GetProtocolVersion(int& protocolVersion) - { - CMasternode* pmn = mnodeman.Find(vin); - if (pmn != NULL) { - protocolVersion = pmn->protocolVersion; - return true; - } - return false; - } - /** Sign this Obfuscation transaction * \return true if all conditions are met: * 1) we have an active Masternode, @@ -227,8 +185,6 @@ class CObfuscationQueue return (GetTime() - time) > OBFUSCATION_QUEUE_TIMEOUT; // 120 seconds } - /// Check if we have a valid Masternode address - bool CheckSignature(); }; /** Helper class to store Obfuscation transaction (tx) information. @@ -264,7 +220,6 @@ class CObfuScationSigner class CObfuscationPool { private: - mutable CCriticalSection cs_obfuscation; std::vector entries; // Masternode/clients entries CMutableTransaction finalTransaction; // the finalized transaction ready for signing @@ -279,18 +234,15 @@ class CObfuscationPool std::vector lockedCoins; std::string lastMessage; - bool unitTest; int sessionID; int sessionUsers; //N Users have said they'll join - bool sessionFoundMasternode; //If we've found a compatible Masternode std::vector vecSessionCollateral; int cachedLastSuccess; int minBlockSpacing; //required blocks between mixes - CMutableTransaction txCollateral; int64_t lastNewBlock; @@ -328,7 +280,6 @@ class CObfuscationPool CMasternode* pSubmittedToMasternode; int sessionDenom; //Users must submit an denom matching this - int cachedNumBlocks; //used for the overview screen CObfuscationPool() { @@ -336,42 +287,17 @@ class CObfuscationPool to behave themselves. If they don't it takes their money. */ cachedLastSuccess = 0; - cachedNumBlocks = std::numeric_limits::max(); - unitTest = false; - txCollateral = CMutableTransaction(); minBlockSpacing = 0; lastNewBlock = 0; SetNull(); } - /** Process a Obfuscation message using the Obfuscation protocol - * \param pfrom - * \param strCommand lower case command string; valid values are: - * Command | Description - * -------- | ----------------- - * dsa | Obfuscation Acceptable - * dsc | Obfuscation Complete - * dsf | Obfuscation Final tx - * dsi | Obfuscation vIn - * dsq | Obfuscation Queue - * dss | Obfuscation Signal Final Tx - * dssu | Obfuscation status update - * dssub | Obfuscation Subscribe To - * \param vRecv - */ - void ProcessMessageObfuscation(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); - void InitCollateralAddress() { SetCollateralAddress(Params().ObfuscationPoolDummyAddress()); } - void SetMinBlockSpacing(int minBlockSpacingIn) - { - minBlockSpacing = minBlockSpacingIn; - } - bool SetCollateralAddress(std::string strAddress); void Reset(); void SetNull(); @@ -388,19 +314,11 @@ class CObfuscationPool return state; } - std::string GetStatus(); - int GetEntriesCount() const { return entries.size(); } - /// Get the time the last entry was accepted (time in UTC milliseconds) - int GetLastEntryAccepted() const - { - return lastEntryAccepted; - } - /// Get the count of the accepted entries int GetCountEntriesAccepted() const { @@ -431,22 +349,6 @@ class CObfuscationPool return Params().PoolMaxTransactions(); } - /// Do we have enough users to take entries? - bool IsSessionReady() - { - return sessionUsers >= GetMaxPoolTransactions(); - } - - /// Are these outputs compatible with other client in the pool? - bool IsCompatibleWithEntries(std::vector& vout); - - /// Is this amount compatible with other client in the pool? - bool IsCompatibleWithSession(CAmount nAmount, CTransaction txCollateral, int& errorID); - - /// Passively run Obfuscation in the background according to the configuration in settings (only for QT) - bool DoAutomaticDenominating(bool fDryRun = false); - bool PrepareObfuscationDenominate(); - /// Check for process in Obfuscation void Check(); void CheckFinalTransaction(); @@ -456,57 +358,15 @@ class CObfuscationPool void ChargeRandomFees(); void CheckTimeout(); void CheckForCompleteQueue(); - /// Check to make sure a signature matches an input in the pool - bool SignatureValid(const CScript& newSig, const CTxIn& newVin); - /// If the collateral is valid given by a client - bool IsCollateralValid(const CTransaction& txCollateral); - /// Add a clients entry to the pool - bool AddEntry(const std::vector& newInput, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector& newOutput, int& errorID); - /// Add signature to a vin - bool AddScriptSig(const CTxIn& newVin); /// Check that all inputs are signed. (Are all inputs signed?) bool SignaturesComplete(); - /// As a client, send a transaction to a Masternode to start the denomination process - void SendObfuscationDenominate(std::vector& vin, std::vector& vout, CAmount amount); - /// Get Masternode updates about the progress of Obfuscation - bool StatusUpdate(int newState, int newEntriesCount, int newAccepted, int& errorID, int newSessionID = 0); - - /// As a client, check and sign the final transaction - bool SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node); - - /// Get the last valid block hash for a given modulus - bool GetLastValidBlockHash(uint256& hash, int mod = 1, int nBlockHeight = 0); /// Process a new block void NewBlock(); - void CompletedTransaction(bool error, int errorID); - void ClearLastMessage(); - /// Used for liquidity providers - bool SendRandomPaymentToSelf(); - - /// Split up large inputs or make fee sized inputs - bool MakeCollateralAmounts(); - bool CreateDenominated(CAmount nTotalValue); - - /// Get the denominations for a list of outputs (returns a bitshifted integer) - int GetDenominations(const std::vector& vout, bool fSingleRandomDenom = false); - int GetDenominations(const std::vector& vout); - - void GetDenominationsToString(int nDenom, std::string& strDenom); - - /// Get the denominations for a specific amount of ion. - int GetDenominationsByAmount(CAmount nAmount, int nDenomTarget = 0); // is not used anymore? - int GetDenominationsByAmounts(std::vector& vecAmount); - - std::string GetMessageByID(int messageID); // // Relay Obfuscation Messages // - void RelayFinalTransaction(const int sessionID, const CTransaction& txNew); - void RelaySignaturesAnon(std::vector& vin); - void RelayInAnon(std::vector& vin, std::vector& vout); - void RelayIn(const std::vector& vin, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector& vout); void RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const int errorID = MSG_NOERR); void RelayCompletedTransaction(const int sessionID, const bool error, const int errorID); }; diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index f32dadb8b9566..59ae59d4b5ee7 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -144,5 +144,5 @@ void CBlock::print() const bool CBlock::IsZerocoinStake() const { - return IsProofOfStake() && vtx[1].IsZerocoinSpend(); -} \ No newline at end of file + return IsProofOfStake() && vtx[1].HasZerocoinSpendInputs(); +} diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index d7f1552506b36..8dab347141231 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -14,7 +14,6 @@ #include "utilstrencodings.h" #include "transaction.h" -#include extern bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow); @@ -60,13 +59,23 @@ CTxIn::CTxIn(const libzerocoin::CoinSpend& spend, libzerocoin::CoinDenomination nSequence = denom; } +bool CTxIn::IsZerocoinSpend() const +{ + return prevout.hash == 0 && scriptSig.IsZerocoinSpend(); +} + +bool CTxIn::IsZerocoinPublicSpend() const +{ + return scriptSig.IsZerocoinPublicSpend(); +} + std::string CTxIn::ToString() const { std::string str; str += "CTxIn("; str += prevout.ToString(); if (prevout.IsNull()) - if(scriptSig.IsZerocoinSpend()) + if(IsZerocoinSpend()) str += strprintf(", zerocoinspend %s...", HexStr(scriptSig).substr(0, 25)); else str += strprintf(", coinbase %s", HexStr(scriptSig)); @@ -98,6 +107,19 @@ uint256 CTxOut::GetHash() const return SerializeHash(*this); } +bool CTxOut::IsZerocoinMint() const +{ + return scriptPubKey.IsZerocoinMint(); +} + +CAmount CTxOut::GetZerocoinMinted() const +{ + if (!IsZerocoinMint()) + return CAmount(0); + + return nValue; +} + std::string CTxOut::ToString() const { return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30)); @@ -149,17 +171,45 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) { return *this; } +bool CTransaction::HasZerocoinSpendInputs() const +{ + for (const CTxIn& txin: vin) { + if (txin.IsZerocoinSpend() || txin.IsZerocoinPublicSpend()) + return true; + } + return false; +} + +bool CTransaction::HasZerocoinMintOutputs() const +{ + for(const CTxOut& txout : vout) { + if (txout.IsZerocoinMint()) + return true; + } + return false; +} + +bool CTransaction::HasZerocoinPublicSpendInputs() const +{ + // The wallet only allows publicSpend inputs in the same tx and not a combination between piv and xion + for(const CTxIn& txin : vin) { + if (txin.IsZerocoinPublicSpend()) + return true; + } + return false; +} + bool CTransaction::IsCoinStake() const { if (vin.empty()) return false; // ppcoin: the coin stake transaction is marked with the first output empty - bool fAllowNull = vin[0].scriptSig.IsZerocoinSpend(); + bool fAllowNull = vin[0].IsZerocoinSpend(); if (vin[0].prevout.IsNull() && !fAllowNull) return false; - return (vin.size() > 0 && vout.size() >= 2 && vout[0].IsEmpty()); + return (vout.size() >= 2 && vout[0].IsEmpty()); } CAmount CTransaction::GetValueOut() const @@ -181,14 +231,12 @@ CAmount CTransaction::GetValueOut() const CAmount CTransaction::GetZerocoinMinted() const { + CAmount nValueOut = 0; for (const CTxOut& txOut : vout) { - if(!txOut.scriptPubKey.IsZerocoinMint()) - continue; - - return txOut.nValue; + nValueOut += txOut.GetZerocoinMinted(); } - return CAmount(0); + return nValueOut; } bool CTransaction::UsesUTXO(const COutPoint out) @@ -212,12 +260,9 @@ std::list CTransaction::GetOutPoints() const CAmount CTransaction::GetZerocoinSpent() const { - if(!IsZerocoinSpend()) - return 0; - CAmount nValueOut = 0; for (const CTxIn& txin : vin) { - if(!txin.scriptSig.IsZerocoinSpend()) + if(!txin.IsZerocoinSpend()) continue; nValueOut += txin.nSequence * COIN; @@ -230,7 +275,7 @@ int CTransaction::GetZerocoinMintCount() const { int nCount = 0; for (const CTxOut& out : vout) { - if (out.scriptPubKey.IsZerocoinMint()) + if (out.IsZerocoinMint()) nCount++; } return nCount; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 18943c3372a1e..395a7836e6f21 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -95,6 +95,9 @@ class CTxIn return (nSequence == std::numeric_limits::max()); } + bool IsZerocoinSpend() const; + bool IsZerocoinPublicSpend() const; + friend bool operator==(const CTxIn& a, const CTxIn& b) { return (a.prevout == b.prevout && @@ -178,10 +181,8 @@ class CTxOut return (nValue < GetDustThreshold(minRelayTxFee)); } - bool IsZerocoinMint() const - { - return !scriptPubKey.empty() && scriptPubKey.IsZerocoinMint(); - } + bool IsZerocoinMint() const; + CAmount GetZerocoinMinted() const; friend bool operator==(const CTxOut& a, const CTxOut& b) { @@ -266,23 +267,14 @@ class CTransaction // Compute modified tx size for priority calculation (optionally given tx size) unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const; - bool IsZerocoinSpend() const - { - return (vin.size() > 0 && vin[0].prevout.hash == 0 && vin[0].scriptSig[0] == OP_ZEROCOINSPEND); - } + bool HasZerocoinSpendInputs() const; + bool HasZerocoinPublicSpendInputs() const; - bool IsZerocoinMint() const - { - for(const CTxOut& txout : vout) { - if (txout.scriptPubKey.IsZerocoinMint()) - return true; - } - return false; - } + bool HasZerocoinMintOutputs() const; bool ContainsZerocoins() const { - return IsZerocoinSpend() || IsZerocoinMint(); + return HasZerocoinSpendInputs() || HasZerocoinPublicSpendInputs() || HasZerocoinMintOutputs(); } CAmount GetZerocoinMinted() const; diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt new file mode 100644 index 0000000000000..18d4eb94c5571 --- /dev/null +++ b/src/qt/CMakeLists.txt @@ -0,0 +1,199 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.10) + +set(CMAKE_INCLUDE_CURRENT_DIR OFF) +set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/forms) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(CMAKE_POSITION_INDEPENDENT_CODE ON) +endif () + +find_package(Qrcode) +if (QRCODE_FOUND) + include_directories ( ${QRCODE_INCLUDE_DIR} ) + link_directories ( ${QRCODE_LIBRARY_DIRS} ) +endif() + +if($ENV{target} MATCHES "Windows") + find_package(Qt5) +else() + unset(Qt5Enables) + foreach(comp Widgets Core Gui Network LinguistTools DBus) + find_package(Qt5${comp}) + set(Qt5Enables "${Qt5Enables};Qt5${comp}_FOUND") + if(Qt5${comp}_FOUND) + MESSAGE(STATUS "FOUND QT5${comp}") + include_directories(${include_directories} ${Qt5${comp}_INCLUDE_DIRS} ${QT_USE_FILE}) + add_definitions(${Qt5${comp}_DEFINITIONS}) + list(APPEND Qt5_LIBRARIES ${Qt5${comp}_LIBRARIES}) + else() + MESSAGE(WARNING "Cant find Qt5${comp}") + endif() + endforeach(comp) + + find_package(Qt5DBus) + if (Qt5DBus_FOUND) + include_directories(${include_directories} "/usr/local/opt/qt5/include/QtDBus/") + add_compile_options("-DUSE_DBUS") + endif() +endif() + +# Why isn't this done automatically?? +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(CMAKE_AUTOMOC_MOC_OPTIONS "-DQ_OS_MAC") +endif() + +file(GLOB LOCAL_QT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) +source_group("QtHeaders" FILES ${LOCAL_QT_HEADERS}) + +find_package(Protobuf REQUIRED) +include_directories(${PROTOBUF_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${CMAKE_CURRENT_SOURCE_DIR}/paymentrequest.proto) + +set(GUI_FORMS + ${CMAKE_CURRENT_SOURCE_DIR}/forms/addressbookpage.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/askpassphrasedialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/bip38tooldialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/coincontroldialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/governancepage.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/xioncontroldialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/blockexplorer.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/editaddressdialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/helpmessagedialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/intro.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/masternodelist.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/multisenddialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/obfuscationconfig.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/privacydialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/openuridialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/optionsdialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/overviewpage.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/receivecoinsdialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/receiverequestdialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/rpcconsole.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/sendcoinsdialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/sendcoinsentry.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/signverifymessagedialog.ui + ${CMAKE_CURRENT_SOURCE_DIR}/forms/transactiondescdialog.ui + ) + +SET(QT_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/multisenddialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bantablemodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bip38tooldialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/blockexplorer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinaddressvalidator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinamountfield.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bitcoingui.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinunits.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/clientmodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/csvmodelwriter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/governancepage.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/guiutil.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/intro.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/multisigdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/masternodelist.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/networkstyle.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/notificator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/optionsdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/optionsmodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/peertablemodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/platformstyle.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qvalidatedlineedit.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qvaluecombobox.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rpcconsole.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/splashscreen.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/trafficgraphwidget.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utilitydialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/addressbookpage.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/addresstablemodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/askpassphrasedialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/coincontroldialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/xioncontroldialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/coincontroltreewidget.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/privacydialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/proposalframe.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/editaddressdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/masternodelist.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/openuridialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/overviewpage.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/paymentrequestplus.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/paymentserver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/receivecoinsdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/receiverequestdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/recentrequeststablemodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sendcoinsdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sendcoinsentry.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/signverifymessagedialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactiondesc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactiondescdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactionfilterproxy.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactionrecord.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactiontablemodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/transactionview.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/walletframe.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/walletmodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/walletmodeltransaction.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/walletview.cpp + ) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + list(APPEND QT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/macdockiconhandler.mm) + list(APPEND QT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/macnotificationhandler.mm) +endif() + +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + list(APPEND QT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/winshutdownmonitor.cpp) +endif () + +add_library(qt_stuff STATIC ${BitcoinHeaders} ${QtHeaders} ${QT_SOURCES} ${PROTO_SRCS} ${PROTO_HDRS}) +target_include_directories(qt_stuff PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +set_property(TARGET qt_stuff PROPERTY CXX_STANDARD 11) + +file(GLOB QT_TRANSLATIONS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/locale/*.ts) + +get_filename_component(QM_FILES_BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/locale" ABSOLUTE) +set_source_files_properties(${QT_TRANSLATIONS_FILES} PROPERTIES OUTPUT_LOCATION "${QM_FILES_BINARY_DIR}") + +QT5_ADD_TRANSLATION(QM ${QT_TRANSLATIONS_FILES}) +add_custom_target(translations_target ALL DEPENDS ${QM}) + +QT5_ADD_RESOURCES(QRC_RESOURCE ion.qrc) +QT5_ADD_RESOURCES(QRC_LOCALE_RESOURCE ion_locale.qrc) + +add_executable(ion-qt ion.cpp ${QM} ${QRC_RESOURCE} ${QRC_LOCALE_RESOURCE}) +add_dependencies(ion-qt translations_target libunivalue libsecp256k1 leveldb leveldb_sse42 memenv) +target_link_libraries(ion-qt + qt_stuff + univalue + SERVER_A UTIL_A WALLET_A CLI_A COMMON_A BITCOIN_CRYPTO_A ZEROCOIN_A + leveldb leveldb_sse42 memenv miniupnpc secp256k1 + ${BerkeleyDB_LIBRARIES} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${PROTOBUF_LIBRARIES} ${LIBEVENT_LIB} + pthread + ) +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + target_link_libraries(ion-qt "-framework Cocoa") +endif() +if(GMP_FOUND) + target_link_libraries(ion-qt ${GMP_LIBRARY}) +endif() +if(ZMQ_FOUND) + target_link_libraries(ion-qt ZMQ_A ${ZMQ_LIB}) +endif() +if (QRCODE_FOUND) + target_link_libraries(ion-qt ${QRCODE_LIB}) +endif() + +QT5_USE_Modules(ion-qt Gui) +QT5_USE_Modules(ion-qt Core) +QT5_USE_Modules(ion-qt Widgets) +QT5_USE_Modules(ion-qt Test) +QT5_USE_Modules(ion-qt PrintSupport) +QT5_USE_Modules(ion-qt Network) +if (Qt5DBus_FOUND) + QT5_USE_Modules(ion-qt DBus) +endif() diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index e16de322646d9..8af81015a873a 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -82,7 +82,7 @@ class AddressTablePriv cachedAddressTable.clear(); { LOCK(wallet->cs_wallet); - BOOST_FOREACH (const PAIRTYPE(CTxDestination, CAddressBookData) & item, wallet->mapAddressBook) { + for (const PAIRTYPE(CTxDestination, CAddressBookData) & item : wallet->mapAddressBook) { const CBitcoinAddress& address = item.first; bool fMine = IsMine(*wallet, address.Get()); AddressTableEntry::Type addressType = translateTransactionType( diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index cd27ef8bb8390..58c73dd0c7897 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -31,7 +31,7 @@ #include "init.h" #include "masternodelist.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include diff --git a/src/qt/blockexplorer.cpp b/src/qt/blockexplorer.cpp index 14428f411d5fc..37020a2147326 100644 --- a/src/qt/blockexplorer.cpp +++ b/src/qt/blockexplorer.cpp @@ -12,7 +12,7 @@ #include "net.h" #include "txdb.h" #include "ui_blockexplorer.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "utilstrencodings.h" #include @@ -405,7 +405,7 @@ std::string AddressToString(const CBitcoinAddress& Address) { std::vector Txs; paddressmap->GetTxs(Txs, AddressScript.GetID()); - BOOST_FOREACH (const CDiskTxPos& pos, Txs) + for (const CDiskTxPos& pos : Txs) { CTransaction tx; CBlock block; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index a7c0426d9caba..0015be0967f5e 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -8,6 +8,7 @@ #include "bantablemodel.h" #include "guiconstants.h" +#include "guiutil.h" #include "peertablemodel.h" #include "alert.h" @@ -19,7 +20,7 @@ #include "masternodeman.h" #include "net.h" #include "netbase.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include @@ -65,7 +66,7 @@ int ClientModel::getNumConnections(unsigned int flags) const return vNodes.size(); int nNum = 0; - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) nNum++; @@ -112,6 +113,15 @@ QDateTime ClientModel::getLastBlockDate() const return QDateTime::fromTime_t(Params().GenesisBlock().GetBlockTime()); // Genesis block's time of current network } +QString ClientModel::getLastBlockHash() const +{ + LOCK(cs_main); + if (chainActive.Tip()) + return QString::fromStdString(chainActive.Tip()->GetBlockHash().ToString()); + else + return QString::fromStdString(Params().GenesisBlock().GetHash().ToString()); // Genesis block's hash of current network +} + double ClientModel::getVerificationProgress() const { LOCK(cs_main); @@ -248,6 +258,11 @@ QString ClientModel::formatClientStartupTime() const return QDateTime::fromTime_t(nClientStartupTime).toString(); } +QString ClientModel::dataDir() const +{ + return GUIUtil::boostPathToQString(GetDataDir()); +} + void ClientModel::updateBanlist() { banTableModel->refresh(); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 0841f3a3001f4..c1ff982cfa55d 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -7,6 +7,7 @@ #ifndef BITCOIN_QT_CLIENTMODEL_H #define BITCOIN_QT_CLIENTMODEL_H +#include "uint256.h" #include #include @@ -62,6 +63,8 @@ class ClientModel : public QObject double getVerificationProgress() const; QDateTime getLastBlockDate() const; + QString getLastBlockHash() const; + //! Return true if core is doing initial block download bool inInitialBlockDownload() const; //! Return true if core is importing blocks @@ -74,6 +77,7 @@ class ClientModel : public QObject bool isReleaseVersion() const; QString clientName() const; QString formatClientStartupTime() const; + QString dataDir() const; bool getTorInfo(std::string& ip_port) const; diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 9e6d2b59f13ce..e7696a9c72515 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -560,7 +560,7 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) coinControl->ListSelected(vCoinControl); model->getOutputs(vCoinControl, vOutputs); - BOOST_FOREACH (const COutput& out, vOutputs) { + for (const COutput& out : vOutputs) { // unselect already spent, very unlikely scenario, this could happen // when selected are spent elsewhere, like rpc or another computer uint256 txhash = out.tx->GetHash(); @@ -751,7 +751,7 @@ void CoinControlDialog::updateView() map> mapCoins; model->listCoins(mapCoins); - BOOST_FOREACH (PAIRTYPE(QString, vector) coins, mapCoins) { + for (PAIRTYPE(QString, vector) coins : mapCoins) { CCoinControlWidgetItem* itemWalletAddress = new CCoinControlWidgetItem(); itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); QString sWalletAddress = coins.first; diff --git a/src/qt/forms/governancepage.ui b/src/qt/forms/governancepage.ui index c6a8b4b2f492c..a19d8c2487970 100644 --- a/src/qt/forms/governancepage.ui +++ b/src/qt/forms/governancepage.ui @@ -14,16 +14,7 @@ Form - - 9 - - - 9 - - - 9 - - + 9 @@ -34,16 +25,7 @@ - - 0 - - - 0 - - - 0 - - + 0 @@ -122,16 +104,7 @@ - - 6 - - - 6 - - - 6 - - + 6 @@ -140,16 +113,7 @@ 0 - - 0 - - - 0 - - - 0 - - + 0 @@ -204,16 +168,7 @@ QLayout::SetDefaultConstraint - - 0 - - - 0 - - - 0 - - + 0 diff --git a/src/qt/forms/masternodelist.ui b/src/qt/forms/masternodelist.ui index b3c7cac47f240..a727069ce1dfc 100644 --- a/src/qt/forms/masternodelist.ui +++ b/src/qt/forms/masternodelist.ui @@ -14,16 +14,7 @@ Form - - 9 - - - 9 - - - 9 - - + 9 @@ -34,16 +25,7 @@ - - 0 - - - 0 - - - 0 - - + 0 @@ -122,16 +104,7 @@ - - 6 - - - 6 - - - 6 - - + 6 @@ -140,16 +113,7 @@ 0 - - 0 - - - 0 - - - 0 - - + 0 diff --git a/src/qt/forms/multisenddialog.ui b/src/qt/forms/multisenddialog.ui index 4d70dc33e48e0..8900f79638562 100644 --- a/src/qt/forms/multisenddialog.ui +++ b/src/qt/forms/multisenddialog.ui @@ -17,16 +17,7 @@ MultiSend - - 6 - - - 6 - - - 6 - - + 6 diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 45538bf83002c..f45ced3a4843a 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -20,7 +20,7 @@ - 4 + 0 @@ -131,100 +131,109 @@ - - - - - Enable automatic minting of ION units to xION - - - Qt::LeftToRight - - - Enable xION Automint - - - - - - - Enable automatic xION minting from specific addresses - - - Qt::LeftToRight - - - Enable Automint Addresses - - - - - - - - - - - Percentage of incoming ION which get automatically converted to xION via Zerocoin Protocol (min: 10%) - - - Percentage of autominted xION - - - - - - - 1 - - - 100 - - - - - - - - - QLayout::SetFixedSize - - - - - - 16777215 - 16777215 - - - - Wait with automatic conversion to Zerocoin until enough ION for this denomination is available - - - Preferred Automint xION Denomination - - - - - - - - 16777215 - 27 - - - - Wait with automatic conversion to Zerocoin until enough ION for this denomination is available - - - 9 - - - 9 - - - - + + + + 0 + + + + + + + Enable automatic minting of ION units to xION + + + Qt::LeftToRight + + + Enable xION Automint + + + + + + + Enable automatic xION minting from specific addresses + + + Qt::LeftToRight + + + Enable Automint Addresses + + + + + + + + + + + Percentage of incoming ION which get automatically converted to xION via Zerocoin Protocol (min: 10%) + + + Percentage of autominted xION + + + + + + + 1 + + + 100 + + + + + + + + + QLayout::SetFixedSize + + + + + + 16777215 + 16777215 + + + + Wait with automatic conversion to Zerocoin until enough ION for this denomination is available + + + Preferred Automint xION Denomination + + + + + + + + 16777215 + 27 + + + + Wait with automatic conversion to Zerocoin until enough ION for this denomination is available + + + 9 + + + 9 + + + + + + + @@ -552,114 +561,117 @@ https://www.transifex.com/ioncoincore/ioncore - - - Qt::Horizontal - + + + + 0 + + + + + Qt::Horizontal + + + + + + + + + Unit to show amounts in: + + + Qt::PlainText + + + + + + + Choose the default subdivision unit to show in the interface and when sending coins. + + + + + + + + + + + Decimal digits + + + + + + + + + + + + + + Hide empty balances + + + Qt::LeftToRight + + + Hide empty balances + + + + + + + Hide orphan stakes in transaction lists + + + Hide orphan stakes + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + + + Third party transaction URLs + + + + + + + Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + + + + + + - - - - - - &Unit to show amounts in: - - - Qt::PlainText - - - unit - - - - - - - Choose the default subdivision unit to show in the interface and when sending coins. - - - - - - - - - - - Decimal digits - - - - - - - - - - - - - - Hide empty balances - - - Qt::LeftToRight - - - Hide empty balances - - - - - - - Hide orphan stakes in transaction lists - - - Hide orphan stakes - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - - - Third party transaction URLs - - - thirdPartyTxUrls - - - - - - - Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - - - - - diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 729b82fd96b1d..567da4569d8e8 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -58,31 +58,13 @@ - - 0 - - - 0 - - - 0 - - + 0 - - 0 - - - 0 - - - 0 - - + 0 @@ -201,16 +183,7 @@ QFrame::Raised - - 0 - - - 0 - - - 0 - - + 0 diff --git a/src/qt/forms/privacydialog.ui b/src/qt/forms/privacydialog.ui index 5f2ec476d8c74..2285a3ccfdec1 100644 --- a/src/qt/forms/privacydialog.ui +++ b/src/qt/forms/privacydialog.ui @@ -34,16 +34,7 @@ - - 0 - - - 0 - - - 0 - - + 0 @@ -122,16 +113,7 @@ - - 6 - - - 6 - - - 6 - - + 6 @@ -140,16 +122,7 @@ 0 - - 0 - - - 0 - - - 0 - - + 0 @@ -370,78 +343,31 @@ - - - - 131 - 0 - - - - Enter an amount of Ion to convert to xION - - - Mint Zerocoin + + + Qt::Horizontal - - - - - + - 60 - 0 + 40 + 20 - - 0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - xION - - - - - - - Available for minting are coins which are confirmed and not locked or Masternode collaterals. - - - Available for Minting: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + - - - - 75 - true - - - - Enter an amount of Ion to convert to xION + + + color: red; +font-weight: bold; - 0.000 000 00 ION - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + xION minting is DISABLED - + Qt::Horizontal @@ -454,7 +380,7 @@ - + 80 @@ -462,177 +388,15 @@ - Reset Zerocoin Wallet DB. Deletes transactions that did not make it into the blockchain. - - - Reset - - - - - - - - - - - - 131 - 27 - - - - - 131 - 16777215 - - - - + Rescan the complete blockchain for Zerocoin mints and their meta-data. - Coin Control... - - - false + ReScan - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - 75 - true - - - - Quantity: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 0 - - - - - - - true - - - - 75 - true - - - - Amount: - - - 0 - - - - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0 - - - 0 - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - true - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0.00 ION - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - + 80 @@ -640,28 +404,15 @@ - Rescan the complete blockchain for Zerocoin mints and their meta-data. + Reset Zerocoin Wallet DB. Deletes transactions that did not make it into the blockchain. - ReScan + Reset - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -720,6 +471,47 @@ + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + color: red; +font-weight: bold; + + + xION spending is NOT private (links back to the mint transaction) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + @@ -2091,16 +1883,7 @@ To change the percentage (no restart required): 0 - - 0 - - - 0 - - - 0 - - + 0 @@ -2522,16 +2305,7 @@ To change the percentage (no restart required): 0 - - 0 - - - 0 - - - 0 - - + 0 @@ -2595,16 +2369,7 @@ To change the percentage (no restart required): - - 0 - - - 0 - - - 0 - - + 0 diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index 006b0089aa350..9ce68ef091530 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -19,16 +19,7 @@ - - 0 - - - 0 - - - 0 - - + 0 @@ -107,16 +98,7 @@ - - 6 - - - 6 - - - 6 - - + 6 @@ -199,7 +181,7 @@ - + An optional amount to request. Leave this empty or zero to not request a specific amount. diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index 3907b4b93714b..0af1b4809da10 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -7,7 +7,7 @@ 0 0 769 - 485 + 516 @@ -27,6 +27,13 @@ 12 + + + + N/A + + + @@ -184,7 +191,7 @@ - + @@ -197,14 +204,14 @@ - + Name - + IBeamCursor @@ -220,14 +227,14 @@ - + Number of connections - + IBeamCursor @@ -243,14 +250,14 @@ - + Number of Masternodes - + IBeamCursor @@ -266,7 +273,7 @@ - + @@ -279,14 +286,14 @@ - + Current number of blocks - + IBeamCursor @@ -302,14 +309,14 @@ - + Last block time - + IBeamCursor @@ -325,7 +332,7 @@ - + Qt::Vertical @@ -338,7 +345,7 @@ - + @@ -351,7 +358,7 @@ - + Open the ION debug log file from the current data directory. This can take a few seconds for large log files. @@ -364,6 +371,27 @@ + + + + Data Directory + + + + + + + Last block hash + + + + + + + N/A + + + @@ -1298,12 +1326,12 @@ - - Custom Backup Path: - false + + Custom Backup Path: + @@ -1311,6 +1339,9 @@ IBeamCursor + + false + N/A @@ -1320,19 +1351,16 @@ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - false - - - Custom xION Backup Path: - false + + Custom xION Backup Path: + @@ -1340,6 +1368,9 @@ IBeamCursor + + false + N/A @@ -1349,19 +1380,16 @@ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - false - - - Custom Backups Threshold: - false + + Custom Backups Threshold: + @@ -1369,6 +1397,9 @@ IBeamCursor + + false + N/A @@ -1378,9 +1409,6 @@ Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - false - diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 96694342141f9..be26b2031c5c9 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -25,31 +25,13 @@ 0 - - 0 - - - 0 - - - 0 - - + 0 - - 0 - - - 0 - - - 0 - - + 0 @@ -176,16 +158,7 @@ 0 - - 0 - - - 0 - - - 0 - - + 0 @@ -345,16 +318,7 @@ - - 0 - - - 0 - - - 0 - - + 0 @@ -902,16 +866,7 @@ - - 0 - - - 0 - - - 0 - - + 0 @@ -962,16 +917,7 @@ 0 - - 0 - - - 0 - - - 0 - - + 0 @@ -1258,16 +1204,7 @@ 0 - - 0 - - - 0 - - - 0 - - + 0 diff --git a/src/qt/forms/xioncontroldialog.ui b/src/qt/forms/xioncontroldialog.ui index a167739a63c9d..78cb9ec84712d 100644 --- a/src/qt/forms/xioncontroldialog.ui +++ b/src/qt/forms/xioncontroldialog.ui @@ -118,7 +118,7 @@ - + diff --git a/src/qt/governancepage.cpp b/src/qt/governancepage.cpp index 6a531639d7efc..af6f6b5f3a875 100644 --- a/src/qt/governancepage.cpp +++ b/src/qt/governancepage.cpp @@ -84,6 +84,17 @@ void GovernancePage::updateProposalList() std::vector proposalsList = budget.GetAllProposals(); std::sort (proposalsList.begin(), proposalsList.end(), sortProposalsByVotes()); int nRow = 0; + CBlockIndex* pindexPrev; + { + LOCK(cs_main); + pindexPrev = chainActive.Tip(); + } + if (!pindexPrev) return; + int nBlockStart = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); + int nBlocksLeft = nBlockStart - pindexPrev->nHeight; + int nBlockEnd = nBlockStart + Params().GetBudgetCycleBlocks() - 1; + int mnCount = mnodeman.CountEnabled(ActiveProtocol()); + for (CBudgetProposal* pbudgetProposal : proposalsList) { if (!pbudgetProposal->fValid) continue; if (pbudgetProposal->GetRemainingPaymentCount() < 1) continue; @@ -96,8 +107,13 @@ void GovernancePage::updateProposalList() if (std::find(allotedProposals.begin(), allotedProposals.end(), pbudgetProposal) != allotedProposals.end()) { nTotalAllotted += pbudgetProposal->GetAllotted(); proposalFrame->setObjectName(QStringLiteral("proposalFramePassing")); - } else + } else if (!pbudgetProposal->IsEstablished()) { + proposalFrame->setObjectName(QStringLiteral("proposalFrameNotEstablished")); + } else if (pbudgetProposal->IsPassing(pindexPrev, nBlockStart, nBlockEnd, mnCount)) { + proposalFrame->setObjectName(QStringLiteral("proposalFramePassingUnfunded")); + } else { proposalFrame->setObjectName(QStringLiteral("proposalFrame")); + } proposalFrame->setFrameShape(QFrame::StyledPanel); if (extendedProposal == pbudgetProposal) @@ -108,23 +124,12 @@ void GovernancePage::updateProposalList() ++nRow; } - CBlockIndex* pindexPrev = chainActive.Tip(); - int nNext, nLeft; - if (!pindexPrev) { - nNext = 0; - nLeft = 0; - } - else { - nNext = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks(); - nLeft = nNext - pindexPrev->nHeight; - } - - ui->next_superblock_value->setText(QString::number(nNext)); - ui->blocks_before_super_value->setText(QString::number(nLeft)); - ui->time_before_super_value->setText(QString::number(nLeft/60/24)); + ui->next_superblock_value->setText(QString::number(nBlockStart)); + ui->blocks_before_super_value->setText(QString::number(nBlocksLeft)); + ui->time_before_super_value->setText(QString::number(nBlocksLeft/60/24)); ui->alloted_budget_value->setText(QString::number(nTotalAllotted/COIN)); ui->unallocated_budget_value->setText(QString::number((budget.GetTotalBudget(pindexPrev->nHeight) - nTotalAllotted)/COIN)); - ui->masternode_count_value->setText(QString::number(mnodeman.stable_size())); + ui->masternode_count_value->setText(QString::number(mnodeman.CountEnabled(ActiveProtocol()))); } void GovernancePage::setExtendedProposal(CBudgetProposal* proposal) diff --git a/src/qt/ion.cpp b/src/qt/ion.cpp index 7cdb2a3a1309c..36773d5caf63d 100644 --- a/src/qt/ion.cpp +++ b/src/qt/ion.cpp @@ -30,7 +30,7 @@ #include "init.h" #include "main.h" #include "rpc/server.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #ifdef ENABLE_WALLET diff --git a/src/qt/ionstrings.cpp b/src/qt/ionstrings.cpp index 70fe6667d1182..53adac7a89aa8 100644 --- a/src/qt/ionstrings.cpp +++ b/src/qt/ionstrings.cpp @@ -111,9 +111,6 @@ QT_TRANSLATE_NOOP("ion-core", "" "Flush database activity from memory pool to disk log every megabytes " "(default: %u)"), QT_TRANSLATE_NOOP("ion-core", "" -"Found unconfirmed denominated outputs, will wait till they confirm to " -"continue."), -QT_TRANSLATE_NOOP("ion-core", "" "If paytxfee is not set, include enough fee so transactions begin " "confirmation on average within n blocks (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "" @@ -264,7 +261,6 @@ QT_TRANSLATE_NOOP("ion-core", "Accept public REST requests (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Add a node to connect to and attempt to keep the connection open"), QT_TRANSLATE_NOOP("ion-core", "Adding Wrapped Serials supply..."), QT_TRANSLATE_NOOP("ion-core", "Allow DNS lookups for -addnode, -seednode and -connect"), -QT_TRANSLATE_NOOP("ion-core", "Already have that input."), QT_TRANSLATE_NOOP("ion-core", "Always query for peer addresses via DNS lookup (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Append comment to the user agent string"), QT_TRANSLATE_NOOP("ion-core", "Attempt to force blockchain corruption recovery"), @@ -272,9 +268,7 @@ QT_TRANSLATE_NOOP("ion-core", "Attempt to recover private keys from a corrupt wa QT_TRANSLATE_NOOP("ion-core", "Automatically create Tor hidden service (default: %d)"), QT_TRANSLATE_NOOP("ion-core", "Block creation options:"), QT_TRANSLATE_NOOP("ion-core", "Calculating missing accumulators..."), -QT_TRANSLATE_NOOP("ion-core", "Can't denominate: no compatible inputs left."), -QT_TRANSLATE_NOOP("ion-core", "Can't find random Masternode."), -QT_TRANSLATE_NOOP("ion-core", "Can't mix while sync in progress."), +QT_TRANSLATE_NOOP("ion-core", "Cannot create public spend input"), QT_TRANSLATE_NOOP("ion-core", "Cannot downgrade wallet"), QT_TRANSLATE_NOOP("ion-core", "Cannot resolve -bind address: '%s'"), QT_TRANSLATE_NOOP("ion-core", "Cannot resolve -externalip address: '%s'"), @@ -282,7 +276,6 @@ QT_TRANSLATE_NOOP("ion-core", "Cannot resolve -whitebind address: '%s'"), QT_TRANSLATE_NOOP("ion-core", "Cannot write default address"), QT_TRANSLATE_NOOP("ion-core", "CoinSpend: Accumulator witness does not verify"), QT_TRANSLATE_NOOP("ion-core", "CoinSpend: failed check"), -QT_TRANSLATE_NOOP("ion-core", "Collateral not valid."), QT_TRANSLATE_NOOP("ion-core", "Connect only to the specified node(s)"), QT_TRANSLATE_NOOP("ion-core", "Connect through SOCKS5 proxy"), QT_TRANSLATE_NOOP("ion-core", "Connect to a node to retrieve peer addresses, and disconnect"), @@ -314,8 +307,6 @@ QT_TRANSLATE_NOOP("ion-core", "Enable publish raw transaction (locked via SwiftX QT_TRANSLATE_NOOP("ion-core", "Enable publish raw transaction in
"), QT_TRANSLATE_NOOP("ion-core", "Enable staking functionality (0-1, default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Enable the client to act as a masternode (0-1, default: %u)"), -QT_TRANSLATE_NOOP("ion-core", "Entries are full."), -QT_TRANSLATE_NOOP("ion-core", "Error connecting to Masternode."), QT_TRANSLATE_NOOP("ion-core", "Error initializing block database"), QT_TRANSLATE_NOOP("ion-core", "Error initializing wallet database environment %s!"), QT_TRANSLATE_NOOP("ion-core", "Error loading block database"), @@ -329,38 +320,31 @@ QT_TRANSLATE_NOOP("ion-core", "Error writing zerocoinDB to disk"), QT_TRANSLATE_NOOP("ion-core", "Error"), QT_TRANSLATE_NOOP("ion-core", "Error: A fatal internal error occured, see debug.log for details"), QT_TRANSLATE_NOOP("ion-core", "Error: A fatal internal error occurred, see debug.log for details"), -QT_TRANSLATE_NOOP("ion-core", "Error: Can't select current denominated inputs"), QT_TRANSLATE_NOOP("ion-core", "Error: Disk space is low!"), QT_TRANSLATE_NOOP("ion-core", "Error: No valid utxo!"), QT_TRANSLATE_NOOP("ion-core", "Error: Unsupported argument -tor found, use -onion."), QT_TRANSLATE_NOOP("ion-core", "Error: Wallet locked, unable to create transaction!"), -QT_TRANSLATE_NOOP("ion-core", "Error: You already have pending entries in the Obfuscation pool"), QT_TRANSLATE_NOOP("ion-core", "Failed to calculate accumulator checkpoint"), QT_TRANSLATE_NOOP("ion-core", "Failed to create mint"), QT_TRANSLATE_NOOP("ion-core", "Failed to find Zerocoins in wallet.dat"), QT_TRANSLATE_NOOP("ion-core", "Failed to listen on any port. Use -listen=0 if you want this."), QT_TRANSLATE_NOOP("ion-core", "Failed to parse host:port string"), +QT_TRANSLATE_NOOP("ion-core", "Failed to parse public spend"), QT_TRANSLATE_NOOP("ion-core", "Failed to read block"), QT_TRANSLATE_NOOP("ion-core", "Failed to select a zerocoin"), QT_TRANSLATE_NOOP("ion-core", "Failed to wipe zerocoinDB"), QT_TRANSLATE_NOOP("ion-core", "Failed to write coin serial number into wallet"), QT_TRANSLATE_NOOP("ion-core", "Fee (in ION/kB) to add to transactions you send (default: %s)"), -QT_TRANSLATE_NOOP("ion-core", "Finalizing transaction."), QT_TRANSLATE_NOOP("ion-core", "Force safe mode (default: %u)"), -QT_TRANSLATE_NOOP("ion-core", "Found enough users, signing ( waiting %s )"), -QT_TRANSLATE_NOOP("ion-core", "Found enough users, signing ..."), QT_TRANSLATE_NOOP("ion-core", "Generate coins (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "How many blocks to check at startup (default: %u, 0 = all)"), QT_TRANSLATE_NOOP("ion-core", "If is not supplied, output all debugging information."), QT_TRANSLATE_NOOP("ion-core", "Importing..."), QT_TRANSLATE_NOOP("ion-core", "Imports blocks from external blk000??.dat file"), QT_TRANSLATE_NOOP("ion-core", "Include IP addresses in debug output (default: %u)"), -QT_TRANSLATE_NOOP("ion-core", "Incompatible mode."), -QT_TRANSLATE_NOOP("ion-core", "Incompatible version."), QT_TRANSLATE_NOOP("ion-core", "Incorrect or no genesis block found. Wrong datadir for network?"), QT_TRANSLATE_NOOP("ion-core", "Information"), QT_TRANSLATE_NOOP("ion-core", "Initialization sanity check failed. ION Core is shutting down."), -QT_TRANSLATE_NOOP("ion-core", "Input is not valid."), QT_TRANSLATE_NOOP("ion-core", "Insufficient funds"), QT_TRANSLATE_NOOP("ion-core", "Insufficient funds."), QT_TRANSLATE_NOOP("ion-core", "Invalid -onion address or hostname: '%s'"), @@ -375,10 +359,7 @@ QT_TRANSLATE_NOOP("ion-core", "Invalid masternodeprivkey. Please see documenatio QT_TRANSLATE_NOOP("ion-core", "Invalid netmask specified in -whitelist: '%s'"), QT_TRANSLATE_NOOP("ion-core", "Invalid port detected in masternode.conf"), QT_TRANSLATE_NOOP("ion-core", "Invalid private key."), -QT_TRANSLATE_NOOP("ion-core", "Invalid script detected."), QT_TRANSLATE_NOOP("ion-core", "Keep at most unconnectable transactions in memory (default: %u)"), -QT_TRANSLATE_NOOP("ion-core", "Last Obfuscation was too recent."), -QT_TRANSLATE_NOOP("ion-core", "Last successful Obfuscation action was too recent."), QT_TRANSLATE_NOOP("ion-core", "Limit size of signature cache to entries (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Line: %d"), QT_TRANSLATE_NOOP("ion-core", "Listen for JSON-RPC connections on (default: %u or testnet: %u)"), @@ -392,34 +373,19 @@ QT_TRANSLATE_NOOP("ion-core", "Loading sporks..."), QT_TRANSLATE_NOOP("ion-core", "Loading wallet... (%3.2f %%)"), QT_TRANSLATE_NOOP("ion-core", "Loading wallet..."), QT_TRANSLATE_NOOP("ion-core", "Location of the auth cookie (default: data dir)"), -QT_TRANSLATE_NOOP("ion-core", "Lock is already in place."), QT_TRANSLATE_NOOP("ion-core", "Lock masternodes from masternode configuration file (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Lookup(): Invalid -proxy address or hostname: '%s'"), QT_TRANSLATE_NOOP("ion-core", "Maintain at most connections to peers (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Masternode options:"), -QT_TRANSLATE_NOOP("ion-core", "Masternode queue is full."), -QT_TRANSLATE_NOOP("ion-core", "Masternode:"), QT_TRANSLATE_NOOP("ion-core", "Maximum per-connection receive buffer, *1000 bytes (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Maximum per-connection send buffer, *1000 bytes (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Mint did not make it into blockchain"), -QT_TRANSLATE_NOOP("ion-core", "Missing input transaction information."), -QT_TRANSLATE_NOOP("ion-core", "Mixing in progress..."), QT_TRANSLATE_NOOP("ion-core", "Need address because change is not exact"), QT_TRANSLATE_NOOP("ion-core", "Need to specify a port with -whitebind: '%s'"), -QT_TRANSLATE_NOOP("ion-core", "No Masternodes detected."), -QT_TRANSLATE_NOOP("ion-core", "No compatible Masternode found."), -QT_TRANSLATE_NOOP("ion-core", "No funds detected in need of denominating."), -QT_TRANSLATE_NOOP("ion-core", "No matching denominations found for mixing."), QT_TRANSLATE_NOOP("ion-core", "Node relay options:"), -QT_TRANSLATE_NOOP("ion-core", "Non-standard public key detected."), -QT_TRANSLATE_NOOP("ion-core", "Not compatible with existing transactions."), QT_TRANSLATE_NOOP("ion-core", "Not enough file descriptors available."), -QT_TRANSLATE_NOOP("ion-core", "Not in the Masternode list."), QT_TRANSLATE_NOOP("ion-core", "Number of automatic wallet backups (default: 10)"), QT_TRANSLATE_NOOP("ion-core", "Number of custom location backups to retain (default: %d)"), -QT_TRANSLATE_NOOP("ion-core", "Obfuscation is idle."), -QT_TRANSLATE_NOOP("ion-core", "Obfuscation request complete:"), -QT_TRANSLATE_NOOP("ion-core", "Obfuscation request incomplete:"), QT_TRANSLATE_NOOP("ion-core", "Only accept block chain matching built-in checkpoints (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Only connect to nodes in network (ipv4, ipv6 or onion)"), QT_TRANSLATE_NOOP("ion-core", "Options:"), @@ -428,6 +394,7 @@ QT_TRANSLATE_NOOP("ion-core", "Percentage of automatically minted Zerocoin (1-1 QT_TRANSLATE_NOOP("ion-core", "Preparing for resync..."), QT_TRANSLATE_NOOP("ion-core", "Prepend debug output with timestamp (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Print version and exit"), +QT_TRANSLATE_NOOP("ion-core", "Pubcoin not found in mint tx"), QT_TRANSLATE_NOOP("ion-core", "RPC server options:"), QT_TRANSLATE_NOOP("ion-core", "Randomly drop 1 of every network messages"), QT_TRANSLATE_NOOP("ion-core", "Randomly fuzz 1 of every network messages"), @@ -450,7 +417,6 @@ QT_TRANSLATE_NOOP("ion-core", "Run a thread to flush wallet periodically (defaul QT_TRANSLATE_NOOP("ion-core", "Run in the background as a daemon and accept commands"), QT_TRANSLATE_NOOP("ion-core", "Selected coins value is less than payment target"), QT_TRANSLATE_NOOP("ion-core", "Send transactions as zero-fee transactions if possible (default: %u)"), -QT_TRANSLATE_NOOP("ion-core", "Session not complete!"), QT_TRANSLATE_NOOP("ion-core", "Session timed out."), QT_TRANSLATE_NOOP("ion-core", "Set database cache size in megabytes (%d to %d, default: %d)"), QT_TRANSLATE_NOOP("ion-core", "Set external address:port to get to this masternode (example: %s)"), @@ -477,9 +443,6 @@ QT_TRANSLATE_NOOP("ion-core", "Spend Valid"), QT_TRANSLATE_NOOP("ion-core", "Spend unconfirmed change when sending transactions (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Staking options:"), QT_TRANSLATE_NOOP("ion-core", "Stop running after importing blocks from disk (default: %u)"), -QT_TRANSLATE_NOOP("ion-core", "Submitted following entries to masternode: %u / %d"), -QT_TRANSLATE_NOOP("ion-core", "Submitted to masternode, waiting for more entries ( %u / %d ) %s"), -QT_TRANSLATE_NOOP("ion-core", "Submitted to masternode, waiting in queue %s"), QT_TRANSLATE_NOOP("ion-core", "Support the zerocoin light node protocol (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "SwiftX options:"), QT_TRANSLATE_NOOP("ion-core", "Synchronization failed"), @@ -495,7 +458,6 @@ QT_TRANSLATE_NOOP("ion-core", "The transaction did not verify"), QT_TRANSLATE_NOOP("ion-core", "This help message"), QT_TRANSLATE_NOOP("ion-core", "This is experimental software."), QT_TRANSLATE_NOOP("ion-core", "This is intended for regression testing tools and app development."), -QT_TRANSLATE_NOOP("ion-core", "This is not a Masternode."), QT_TRANSLATE_NOOP("ion-core", "Threshold for disconnecting misbehaving peers (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Too many spends needed"), QT_TRANSLATE_NOOP("ion-core", "Tor control port password (default: empty)"), @@ -504,19 +466,15 @@ QT_TRANSLATE_NOOP("ion-core", "Transaction Created"), QT_TRANSLATE_NOOP("ion-core", "Transaction Mint Started"), QT_TRANSLATE_NOOP("ion-core", "Transaction amount too small"), QT_TRANSLATE_NOOP("ion-core", "Transaction amounts must be positive"), -QT_TRANSLATE_NOOP("ion-core", "Transaction created successfully."), -QT_TRANSLATE_NOOP("ion-core", "Transaction fees are too high."), -QT_TRANSLATE_NOOP("ion-core", "Transaction not valid."), QT_TRANSLATE_NOOP("ion-core", "Transaction too large for fee policy"), QT_TRANSLATE_NOOP("ion-core", "Transaction too large"), -QT_TRANSLATE_NOOP("ion-core", "Transmitting final transaction."), QT_TRANSLATE_NOOP("ion-core", "Trying to spend an already spent serial #, try again."), QT_TRANSLATE_NOOP("ion-core", "Unable to bind to %s on this computer (bind returned error %s)"), -QT_TRANSLATE_NOOP("ion-core", "Unable to find transaction containing mint"), +QT_TRANSLATE_NOOP("ion-core", "Unable to find transaction containing mint %s"), +QT_TRANSLATE_NOOP("ion-core", "Unable to find transaction containing mint, txHash: %s"), QT_TRANSLATE_NOOP("ion-core", "Unable to sign spork message, wrong key?"), QT_TRANSLATE_NOOP("ion-core", "Unable to start HTTP server. See debug log for details."), QT_TRANSLATE_NOOP("ion-core", "Unknown network specified in -onlynet: '%s'"), -QT_TRANSLATE_NOOP("ion-core", "Unknown state: id = %u"), QT_TRANSLATE_NOOP("ion-core", "Upgrade wallet to latest format"), QT_TRANSLATE_NOOP("ion-core", "Use UPnP to map the listening port (default: %u)"), QT_TRANSLATE_NOOP("ion-core", "Use UPnP to map the listening port (default: 1 when listening)"), @@ -526,11 +484,9 @@ QT_TRANSLATE_NOOP("ion-core", "Use the test network"), QT_TRANSLATE_NOOP("ion-core", "User Agent comment (%s) contains unsafe characters."), QT_TRANSLATE_NOOP("ion-core", "Username for JSON-RPC connections"), QT_TRANSLATE_NOOP("ion-core", "Value is below the smallest available denomination (= 1) of xION"), -QT_TRANSLATE_NOOP("ion-core", "Value more than Obfuscation pool maximum allows."), QT_TRANSLATE_NOOP("ion-core", "Verifying blocks..."), QT_TRANSLATE_NOOP("ion-core", "Verifying wallet..."), QT_TRANSLATE_NOOP("ion-core", "Wallet %s resides outside data directory %s"), -QT_TRANSLATE_NOOP("ion-core", "Wallet is locked."), QT_TRANSLATE_NOOP("ion-core", "Wallet needed to be rewritten: restart ION Core to complete"), QT_TRANSLATE_NOOP("ion-core", "Wallet options:"), QT_TRANSLATE_NOOP("ion-core", "Wallet window title"), @@ -538,11 +494,8 @@ QT_TRANSLATE_NOOP("ion-core", "Warning"), QT_TRANSLATE_NOOP("ion-core", "Warning: This version is obsolete, upgrade required!"), QT_TRANSLATE_NOOP("ion-core", "Warning: Unsupported argument -benchmark ignored, use -debug=bench."), QT_TRANSLATE_NOOP("ion-core", "Warning: Unsupported argument -debugnet ignored, use -debug=net."), -QT_TRANSLATE_NOOP("ion-core", "Will retry..."), QT_TRANSLATE_NOOP("ion-core", "You don't have enough Zerocoins in your wallet"), QT_TRANSLATE_NOOP("ion-core", "You need to rebuild the database using -reindex to change -txindex"), -QT_TRANSLATE_NOOP("ion-core", "Your entries added successfully."), -QT_TRANSLATE_NOOP("ion-core", "Your transaction was accepted into the pool!"), QT_TRANSLATE_NOOP("ion-core", "Zapping all transactions from wallet..."), QT_TRANSLATE_NOOP("ion-core", "ZeroMQ notification options:"), QT_TRANSLATE_NOOP("ion-core", "Zerocoin options:"), diff --git a/src/qt/locale/ion_en.ts b/src/qt/locale/ion_en.ts index 1e2c438f7c288..7aff4d1058d97 100644 --- a/src/qt/locale/ion_en.ts +++ b/src/qt/locale/ion_en.ts @@ -1591,12 +1591,12 @@ Address: %4 Form - + GOVERNANCE - + Update Proposals @@ -1776,12 +1776,12 @@ Address: %4 Form - + MASTERNODES - + Note: Status of your masternodes in local wallet can potentially be slightly incorrect.<br />Always wait for wallet to sync additional data and then double check from another node<br />if your node should be running but you still see "MISSING" in "Status" field. @@ -1904,7 +1904,7 @@ Address: %4 - + Enter whole numbers 1 - 100 @@ -2336,91 +2336,6 @@ Please be patient after clicking import. - - ObfuscationConfig - - - Configure Obfuscation - - - - - Basic Privacy - Basic Privacy - - - - High Privacy - High Privacy - - - - Maximum Privacy - Maximum Privacy - - - - Please select a privacy level. - Please select a privacy level. - - - - Use 2 separate masternodes to mix funds up to 20000 ION - - - - - Use 8 separate masternodes to mix funds up to 20000 ION - - - - - Use 16 separate masternodes - Use 16 separate masternodes - - - - This option is the quickest and will cost about ~0.025 ION to anonymize 20000 ION - - - - - This option is moderately fast and will cost about 0.05 ION to anonymize 20000 ION - - - - - This is the slowest and most secure option. Using maximum anonymity will cost - This is the slowest and most secure option. Using maximum anonymity will cost - - - - 0.1 ION per 20000 ION you anonymize. - - - - - - - Obfuscation Configuration - - - - - Obfuscation was successfully set to basic (%1 and 2 rounds). You can change this at any time by opening ION's configuration screen. - - - - - Obfuscation was successfully set to high (%1 and 8 rounds). You can change this at any time by opening ION's configuration screen. - - - - - Obfuscation was successfully set to maximum (%1 and 16 rounds). You can change this at any time by opening ION's configuration screen. - - - OpenURIDialog @@ -2482,7 +2397,7 @@ Please be patient after clicking import. (0 = auto, <0 = leave that many cores free) - + W&allet W&allet @@ -2517,7 +2432,7 @@ Please be patient after clicking import. Expert - + Automatically start ION after logging in to the system. @@ -2527,7 +2442,7 @@ Please be patient after clicking import. - + Whether to show coin control features or not. Whether to show coin control features or not. @@ -2573,7 +2488,7 @@ https://www.transifex.com/ioncoincore/ioncore Map port using &UPnP - + Enable automatic minting of ION units to xION @@ -2614,7 +2529,7 @@ https://www.transifex.com/ioncoincore/ioncore - + Stake split threshold: @@ -2684,12 +2599,12 @@ https://www.transifex.com/ioncoincore/ioncore User Interface Theme: - - &Unit to show amounts in: - &Unit to show amounts in: + + Unit to show amounts in: + - + Choose the default subdivision unit to show in the interface and when sending coins. Choose the default subdivision unit to show in the interface and when sending coins. @@ -2716,12 +2631,12 @@ https://www.transifex.com/ioncoincore/ioncore - + Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. - + Third party transaction URLs Third party transaction URLs @@ -2751,7 +2666,7 @@ https://www.transifex.com/ioncoincore/ioncore &Cancel - + Any @@ -2772,17 +2687,17 @@ https://www.transifex.com/ioncoincore/ioncore - + Client restart required to activate changes. Client restart required to activate changes. - + Client will be shutdown, do you want to proceed? Client will be shutdown, do you want to proceed? - + This change would require a client restart. This change would require a client restart. @@ -2810,7 +2725,7 @@ https://www.transifex.com/ioncoincore/ioncore Form - + Available: @@ -2892,12 +2807,12 @@ Immature: confirmed, but less than 1 mint of the same denomination after it was - + OVERVIEW - + Combined Balance (including unconfirmed and immature coins) @@ -2971,7 +2886,7 @@ Immature: confirmed, but less than 1 mint of the same denomination after it was Recent transactions - + out of sync out of sync @@ -3143,7 +3058,7 @@ To enable AutoMint change 'enablezeromint=0' to 'enablezeromint=1 PrivacyDialog - + Zerocoin Actions: @@ -3153,42 +3068,23 @@ To enable AutoMint change 'enablezeromint=0' to 'enablezeromint=1 - - - + Mint Zerocoin - - + 0 - - + xION - - Available for minting are coins which are confirmed and not locked or Masternode collaterals. - - - - - Available for Minting: - - - - - 0.000 000 00 ION - - - - + Reset Zerocoin Wallet DB. Deletes transactions that did not make it into the blockchain. @@ -3198,22 +3094,7 @@ To enable AutoMint change 'enablezeromint=0' to 'enablezeromint=1 Reset - - Coin Control... - - - - - Quantity: - Quantity: - - - - Amount: - Amount: - - - + Rescan the complete blockchain for Zerocoin mints and their meta-data. @@ -3223,23 +3104,17 @@ To enable AutoMint change 'enablezeromint=0' to 'enablezeromint=1 - + Status and/or Mesages from the last Mint Action. - + PRIVACY - - - Enter an amount of Ion to convert to xION - - - - + xION Control @@ -3255,17 +3130,16 @@ To enable AutoMint change 'enablezeromint=0' to 'enablezeromint=1 - + Spend Zerocoin. Without 'Pay To:' address creates payments to yourself. - + - - + Spend Zerocoin @@ -3287,9 +3161,9 @@ xION are mature when they have more than 20 confirmations AND more than 2 mints - + - + @@ -3374,16 +3248,16 @@ xION are mature when they have more than 20 confirmations AND more than 2 mints - + - + Total Balance including unconfirmed and immature xION - - + + Total Zerocoin Balance: @@ -3430,8 +3304,8 @@ To change the percentage (no restart required): - - + + Global Supply: @@ -3488,7 +3362,7 @@ To change the percentage (no restart required): - + Show xION denominations list @@ -3498,7 +3372,17 @@ To change the percentage (no restart required): - + + xION minting is DISABLED + + + + + xION spending is NOT private (links back to the mint transaction) + + + + Denominations with value 5: @@ -3573,7 +3457,7 @@ To change the percentage (no restart required): - + Priority: Priority: @@ -3609,10 +3493,6 @@ To change the percentage (no restart required): - - - - Coins automatically selected @@ -3622,12 +3502,12 @@ To change the percentage (no restart required): medium - + Coin Control Features Coin Control Features - + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. @@ -3647,40 +3527,23 @@ To change the percentage (no restart required): Change: - + out of sync out of sync - Mint Status: Okay - - Copy quantity - Copy quantity - - - - Copy amount - Copy amount - - - + Starting ResetMintZerocoin: rescanning complete blockchain, this will need up to 30 minutes depending on your hardware. Please be patient... - - ) needed. -Maximum allowed: - - - - + xION Spend #: @@ -3690,7 +3553,7 @@ Maximum allowed: - + <b>enabled</b>. @@ -3705,19 +3568,17 @@ Maximum allowed: - - + xION is currently disabled due to maintenance. - - + xION is currently undergoing maintenance. - + Denom. with value <b>1</b>: @@ -3758,12 +3619,12 @@ Maximum allowed: - + AutoMint Status: - + Denom. <b>1</b>: @@ -3803,53 +3664,22 @@ Maximum allowed: - - Error: Your wallet is locked. Please enter the wallet passphrase first. - - - - - Message: Enter an amount > 0. - - - - - Minting - - - - - Successfully minted - - - - - xION in - - - - - sec. Used denominations: - - - - - + - + Duration: - + - + sec. - + Starting ResetSpentZerocoin: @@ -3899,45 +3729,24 @@ Maximum allowed: - - Too much inputs ( - - - - - -Either mint higher denominations (so fewer inputs are needed) or reduce the amount to spend. - - - - - + Spend Zerocoin failed with status = - - - PrivacyDialog - Enter an amount of ION to convert to xION - - - - - - + denomination: - + Spending Zerocoin. Computationally expensive, might need several minutes depending on your hardware. Please be patient... - + serial: @@ -4725,7 +4534,7 @@ Please be patient... ReceiveCoinsDialog - + Reuse one of the previously used receiving addresses.<br>Reusing addresses has security and privacy issues.<br>Do not use this unless re-generating a payment request made before. Reuse one of the previously used receiving addresses.<br>Reusing addresses has security and privacy issues.<br>Do not use this unless re-generating a payment request made before. @@ -4767,12 +4576,12 @@ Please be patient... - + RECEIVE - + An optional message to attach to the payment request, which will be displayed when the request is opened.<br>Note: The message will not be sent with the payment over the ION network. @@ -4929,7 +4738,7 @@ Please be patient... RecentRequestsTableModel - + Date Date @@ -4980,12 +4789,12 @@ Please be patient... Send Coins - + SEND - + Coin Control Features Coin Control Features @@ -4995,7 +4804,7 @@ Please be patient... Insufficient funds! - + Quantity: Quantity: @@ -5075,7 +4884,7 @@ Please be patient... - + SwiftX technology allows for near instant transactions - A flat fee of 0.01 ION applies @@ -5100,7 +4909,7 @@ Please be patient... Minimize - + per kilobyte per kilobyte @@ -5120,7 +4929,7 @@ Please be patient... Custom: - + (Smart fee not initialized yet. This usually takes a few blocks...) (Smart fee not initialized yet. This usually takes a few blocks...) @@ -5135,7 +4944,7 @@ Please be patient... Confirmation time: - + Open Coin Control... @@ -5145,7 +4954,7 @@ Please be patient... - + If the custom fee is set to 1000 uIONs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 uIONs in fee,<br />while "at least" pays 1000 uIONs. For transactions bigger than a kilobyte both pay by kilobyte. @@ -5161,7 +4970,7 @@ Please be patient... - + normal normal @@ -5171,7 +4980,7 @@ Please be patient... fast - + Recommended @@ -6691,11 +6500,6 @@ Please be patient... Flush database activity from memory pool to disk log every <n> megabytes (default: %u) Flush database activity from memory pool to disk log every <n> megabytes (default: %u) - - - Found unconfirmed denominated outputs, will wait till they confirm to continue. - Found unconfirmed denominated outputs, will wait till they confirm to continue. - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -6956,11 +6760,6 @@ Please be patient... Allow DNS lookups for -addnode, -seednode and -connect Allow DNS lookups for -addnode, -seednode and -connect - - - Already have that input. - Already have that input. - Always query for peer addresses via DNS lookup (default: %u) @@ -6992,22 +6791,7 @@ Please be patient... - - Can't denominate: no compatible inputs left. - Can't denominate: no compatible inputs left. - - - - Can't find random Masternode. - Can't find random Masternode. - - - - Can't mix while sync in progress. - Can't mix while sync in progress. - - - + Cannot downgrade wallet Cannot downgrade wallet @@ -7036,11 +6820,6 @@ Please be patient... CoinSpend: failed check - - - Collateral not valid. - Collateral not valid. - Connect only to the specified node(s) @@ -7161,16 +6940,6 @@ Please be patient... Enable the client to act as a masternode (0-1, default: %u) Enable the client to act as a masternode (0-1, default: %u) - - - Entries are full. - Entries are full. - - - - Error connecting to Masternode. - Error connecting to Masternode. - Error initializing block database @@ -7233,11 +7002,6 @@ Please be patient... - Error: Can't select current denominated inputs - Error: Can't select current denominated inputs - - - Error: Disk space is low! Error: Disk space is low! @@ -7251,11 +7015,6 @@ Please be patient... Error: Wallet locked, unable to create transaction! Error: Wallet locked, unable to create transaction! - - - Error: You already have pending entries in the Obfuscation pool - - Failed to calculate accumulator checkpoint @@ -7272,7 +7031,7 @@ Please be patient... - + Failed to read block Failed to read block @@ -7281,26 +7040,11 @@ Please be patient... Fee (in ION/kB) to add to transactions you send (default: %s) - - - Finalizing transaction. - Finalizing transaction. - Force safe mode (default: %u) Force safe mode (default: %u) - - - Found enough users, signing ( waiting %s ) - Found enough users, signing ( waiting %s ) - - - - Found enough users, signing ... - Found enough users, signing ... - Generate coins (default: %u) @@ -7331,16 +7075,6 @@ Please be patient... Include IP addresses in debug output (default: %u) Include IP addresses in debug output (default: %u) - - - Incompatible mode. - Incompatible mode. - - - - Incompatible version. - Incompatible version. - Incorrect or no genesis block found. Wrong datadir for network? @@ -7356,11 +7090,6 @@ Please be patient... Initialization sanity check failed. ION Core is shutting down. - - - Input is not valid. - Input is not valid. - Insufficient funds @@ -7432,17 +7161,12 @@ Please be patient... Invalid private key. - - Invalid script detected. - Invalid script detected. - - - + Percentage of automatically minted Zerocoin (1-100, default: %u) - + Recalculating ION supply... @@ -7477,7 +7201,7 @@ Please be patient... - + Support the zerocoin light node protocol (default: %u) @@ -7487,12 +7211,12 @@ Please be patient... - + This is a pre-release test build - use at your own risk - do not use for staking or merchant applications! - + mints deleted @@ -7544,7 +7268,7 @@ Please be patient... - + In rare cases, a spend with 7 coins exceeds our maximum allowable transaction size, please retry spend using 6 or less coins @@ -7574,17 +7298,22 @@ Please be patient... - + Attempt to force blockchain corruption recovery - + + Cannot create public spend input + + + + CoinSpend: Accumulator witness does not verify - + Display the stake modifier calculations in the debug.log file. @@ -7619,17 +7348,17 @@ Please be patient... - + Error: A fatal internal error occurred, see debug.log for details - + Error: No valid utxo! - + Failed to create mint @@ -7639,7 +7368,12 @@ Please be patient... - + + Failed to parse public spend + + + + Failed to select a zerocoin @@ -7654,20 +7388,10 @@ Please be patient... - + Keep at most <n> unconnectable transactions in memory (default: %u) Keep at most <n> unconnectable transactions in memory (default: %u) - - - Last Obfuscation was too recent. - - - - - Last successful Obfuscation action was too recent. - - Limit size of signature cache to <n> entries (default: %u) @@ -7733,11 +7457,6 @@ Please be patient... Location of the auth cookie (default: data dir) - - - Lock is already in place. - Lock is already in place. - Lock masternodes from masternode configuration file (default: %u) @@ -7758,16 +7477,6 @@ Please be patient... Masternode options: Masternode options: - - - Masternode queue is full. - Masternode queue is full. - - - - Masternode: - Masternode: - Maximum per-connection receive buffer, <n>*1000 bytes (default: %u) @@ -7783,16 +7492,6 @@ Please be patient... Mint did not make it into blockchain - - - Missing input transaction information. - Missing input transaction information. - - - - Mixing in progress... - Mixing in progress... - Need address because change is not exact @@ -7803,51 +7502,16 @@ Please be patient... Need to specify a port with -whitebind: '%s' Need to specify a port with -whitebind: '%s' - - - No Masternodes detected. - No Masternodes detected. - - - - No compatible Masternode found. - No compatible Masternode found. - - - - No funds detected in need of denominating. - No funds detected in need of denominating. - - - - No matching denominations found for mixing. - No matching denominations found for mixing. - Node relay options: Node relay options: - - - Non-standard public key detected. - Non-standard public key detected. - - - - Not compatible with existing transactions. - Not compatible with existing transactions. - Not enough file descriptors available. Not enough file descriptors available. - - - Not in the Masternode list. - Not in the Masternode list. - Number of automatic wallet backups (default: 10) @@ -7858,21 +7522,6 @@ Please be patient... Number of custom location backups to retain (default: %d) - - - Obfuscation is idle. - - - - - Obfuscation request complete: - - - - - Obfuscation request incomplete: - - Only accept block chain matching built-in checkpoints (default: %u) @@ -7894,12 +7543,22 @@ Please be patient... Password for JSON-RPC connections - + + Unable to find transaction containing mint %s + + + + + Unable to find transaction containing mint, txHash: %s + + + + Use block spam filter (default: %u) - + could not get lock on cs_spendcache @@ -7909,7 +7568,7 @@ Please be patient... - + Preparing for resync... @@ -7923,6 +7582,11 @@ Please be patient... Print version and exit + + + Pubcoin not found in mint tx + + RPC server options: @@ -7998,11 +7662,6 @@ Please be patient... Send transactions as zero-fee transactions if possible (default: %u) Send transactions as zero-fee transactions if possible (default: %u) - - - Session not complete! - Session not complete! - Session timed out. @@ -8133,21 +7792,6 @@ Please be patient... Stop running after importing blocks from disk (default: %u) Stop running after importing blocks from disk (default: %u) - - - Submitted following entries to masternode: %u / %d - Submitted following entries to masternode: %u / %d - - - - Submitted to masternode, waiting for more entries ( %u / %d ) %s - Submitted to masternode, waiting for more entries ( %u / %d ) %s - - - - Submitted to masternode, waiting in queue %s - Submitted to masternode, waiting in queue %s - Synchronization failed @@ -8213,11 +7857,6 @@ Please be patient... This is intended for regression testing tools and app development. This is intended for regression testing tools and app development. - - - This is not a Masternode. - This is not a Masternode. - Threshold for disconnecting misbehaving peers (default: %u) @@ -8258,21 +7897,6 @@ Please be patient... Transaction amounts must be positive Transaction amounts must be positive - - - Transaction created successfully. - Transaction created successfully. - - - - Transaction fees are too high. - Transaction fees are too high. - - - - Transaction not valid. - Transaction not valid. - Transaction too large for fee policy @@ -8283,11 +7907,6 @@ Please be patient... Transaction too large Transaction too large - - - Transmitting final transaction. - Transmitting final transaction. - Trying to spend an already spent serial #, try again. @@ -8299,12 +7918,7 @@ Please be patient... Unable to bind to %s on this computer (bind returned error %s) - - Unable to find transaction containing mint - - - - + Unable to sign spork message, wrong key? Unable to sign spork message, wrong key? @@ -8318,11 +7932,6 @@ Please be patient... Unknown network specified in -onlynet: '%s' Unknown network specified in -onlynet: '%s' - - - Unknown state: id = %u - Unknown state: id = %u - Upgrade wallet to latest format @@ -8363,11 +7972,6 @@ Please be patient... Value is below the smallest available denomination (= 1) of xION - - - Value more than Obfuscation pool maximum allows. - - Verifying blocks... @@ -8383,11 +7987,6 @@ Please be patient... Wallet %s resides outside data directory %s Wallet %s resides outside data directory %s - - - Wallet is locked. - Wallet is locked. - Wallet needed to be rewritten: restart ION Core to complete @@ -8423,11 +8022,6 @@ Please be patient... Warning: Unsupported argument -debugnet ignored, use -debug=net. Warning: Unsupported argument -debugnet ignored, use -debug=net. - - - Will retry... - Will retry... - You don't have enough Zerocoins in your wallet @@ -8438,16 +8032,6 @@ Please be patient... You need to rebuild the database using -reindex to change -txindex You need to rebuild the database using -reindex to change -txindex - - - Your entries added successfully. - Your entries added successfully. - - - - Your transaction was accepted into the pool! - Your transaction was accepted into the pool! - Zapping all transactions from wallet... diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index c870d5608274b..62be6e43f7d73 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -90,7 +90,7 @@ void MasternodeList::StartAlias(std::string strAlias) std::string strStatusHtml; strStatusHtml += "
Alias: " + strAlias; - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { if (mne.getAlias() == strAlias) { std::string strError; CMasternodeBroadcast mnb; @@ -122,7 +122,7 @@ void MasternodeList::StartAll(std::string strCommand) int nCountFailed = 0; std::string strFailedHtml; - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { std::string strError; CMasternodeBroadcast mnb; @@ -210,7 +210,7 @@ void MasternodeList::updateMyNodeList(bool fForce) nTimeMyListUpdated = GetTime(); ui->tableWidgetMyMasternodes->setSortingEnabled(false); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { int nIndex; if(!mne.castOutputIndex(nIndex)) continue; diff --git a/src/qt/obfuscationconfig.cpp b/src/qt/obfuscationconfig.cpp deleted file mode 100644 index 6c6d023b2ce3f..0000000000000 --- a/src/qt/obfuscationconfig.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2014-2016 The Dash Developers -// Copyright (c) 2016-2017 The PIVX developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "obfuscationconfig.h" -#include "ui_obfuscationconfig.h" - -#include "bitcoinunits.h" -#include "guiconstants.h" -#include "init.h" -#include "optionsmodel.h" -#include "walletmodel.h" - -#include -#include -#include -#include - -ObfuscationConfig::ObfuscationConfig(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint), - ui(new Ui::ObfuscationConfig), - model(0) -{ - ui->setupUi(this); - - connect(ui->buttonBasic, SIGNAL(clicked()), this, SLOT(clickBasic())); - connect(ui->buttonHigh, SIGNAL(clicked()), this, SLOT(clickHigh())); - connect(ui->buttonMax, SIGNAL(clicked()), this, SLOT(clickMax())); -} - -ObfuscationConfig::~ObfuscationConfig() -{ - delete ui; -} - -void ObfuscationConfig::setModel(WalletModel* model) -{ - this->model = model; -} - -void ObfuscationConfig::clickBasic() -{ - configure(true, 1000, 2); - - QString strAmount(BitcoinUnits::formatWithUnit( - model->getOptionsModel()->getDisplayUnit(), 1000 * COIN)); - QMessageBox::information(this, tr("Obfuscation Configuration"), - tr( - "Obfuscation was successfully set to basic (%1 and 2 rounds). You can change this at any time by opening ION's configuration screen.") - .arg(strAmount)); - - close(); -} - -void ObfuscationConfig::clickHigh() -{ - configure(true, 1000, 8); - - QString strAmount(BitcoinUnits::formatWithUnit( - model->getOptionsModel()->getDisplayUnit(), 1000 * COIN)); - QMessageBox::information(this, tr("Obfuscation Configuration"), - tr( - "Obfuscation was successfully set to high (%1 and 8 rounds). You can change this at any time by opening ION's configuration screen.") - .arg(strAmount)); - - close(); -} - -void ObfuscationConfig::clickMax() -{ - configure(true, 1000, 16); - - QString strAmount(BitcoinUnits::formatWithUnit( - model->getOptionsModel()->getDisplayUnit(), 1000 * COIN)); - QMessageBox::information(this, tr("Obfuscation Configuration"), - tr( - "Obfuscation was successfully set to maximum (%1 and 16 rounds). You can change this at any time by opening ION's configuration screen.") - .arg(strAmount)); - - close(); -} - -void ObfuscationConfig::configure(bool enabled, int coins, int rounds) -{ - QSettings settings; - - settings.setValue("nObfuscationRounds", rounds); - settings.setValue("nAnonymizeIonAmount", coins); - - nZeromintPercentage = rounds; - nAnonymizeIonAmount = coins; -} diff --git a/src/qt/obfuscationconfig.h b/src/qt/obfuscationconfig.h deleted file mode 100644 index 598bb8ddfdbeb..0000000000000 --- a/src/qt/obfuscationconfig.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2014-2016 The Dash Developers -// Copyright (c) 2016-2017 The PIVX developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef OBFUSCATIONCONFIG_H -#define OBFUSCATIONCONFIG_H - -#include - -namespace Ui -{ -class ObfuscationConfig; -} -class WalletModel; - -/** Multifunctional dialog to ask for passphrases. Used for encryption, unlocking, and changing the passphrase. - */ -class ObfuscationConfig : public QDialog -{ - Q_OBJECT - -public: - ObfuscationConfig(QWidget* parent = 0); - ~ObfuscationConfig(); - - void setModel(WalletModel* model); - - -private: - Ui::ObfuscationConfig* ui; - WalletModel* model; - void configure(bool enabled, int coins, int rounds); - -private slots: - - void clickBasic(); - void clickHigh(); - void clickMax(); -}; - -#endif // OBFUSCATIONCONFIG_H diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 7ab22cd280d4a..704652eabb51a 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -68,9 +68,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(paren ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWindow)); #endif - /* remove Wallet tab in case of -disablewallet */ + /* remove Wallet tab and xIon options in case of -disablewallet */ if (!enableWallet) { ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWallet)); + + ui->verticalXionOptionsWidget->hide(); + ui->verticalXionDisplayWidget->hide(); } /* Display elements init */ @@ -269,7 +272,6 @@ void OptionsDialog::on_resetButton_clicked() void OptionsDialog::on_okButton_clicked() { mapper->submit(); - obfuScationPool.cachedNumBlocks = std::numeric_limits::max(); pwalletMain->MarkDirty(); accept(); } diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 5883fe2f1a8f3..35b1c354e806d 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -97,11 +97,6 @@ void OptionsModel::Init() settings.setValue("nPreferredDenom", 0); nPreferredDenom = settings.value("nPreferredDenom", "0").toLongLong(); - if (!settings.contains("nAnonymizeIonAmount")) - settings.setValue("nAnonymizeIonAmount", 1000); - - nAnonymizeIonAmount = settings.value("nAnonymizeIonAmount").toLongLong(); - if (!settings.contains("fShowMasternodesTab")) settings.setValue("fShowMasternodesTab", masternodeConfig.getCount()); @@ -272,8 +267,6 @@ QVariant OptionsModel::data(const QModelIndex& index, int role) const return QVariant(nZeromintPercentage); case ZeromintPrefDenom: return QVariant(nPreferredDenom); - case AnonymizeIonAmount: - return QVariant(nAnonymizeIonAmount); case Listen: return settings.value("fListen"); default: @@ -410,11 +403,6 @@ bool OptionsModel::setData(const QModelIndex& index, const QVariant& value, int settings.setValue("fHideOrphans", fHideOrphans); emit hideOrphansChanged(fHideOrphans); break; - case AnonymizeIonAmount: - nAnonymizeIonAmount = value.toInt(); - settings.setValue("nAnonymizeIonAmount", nAnonymizeIonAmount); - emit anonymizeIonAmountChanged(nAnonymizeIonAmount); - break; case CoinControlFeatures: fCoinControlFeatures = value.toBool(); settings.setValue("fCoinControlFeatures", fCoinControlFeatures); diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index a7f7b6b925c77..0dfc484c5cab6 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -13,7 +13,6 @@ #include "guiutil.h" #include "init.h" #include "obfuscation.h" -#include "obfuscationconfig.h" #include "optionsmodel.h" #include "transactionfilterproxy.h" #include "transactionrecord.h" diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 4c796ec0f3331..8129941275723 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -12,7 +12,7 @@ #include "base58.h" #include "chainparams.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "wallet/wallet.h" diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 0a6f38b93f85f..38e35c908e21a 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -76,7 +76,7 @@ class PeerTablePriv { TRY_LOCK(cs_main, lockMain); if (lockMain) { - BOOST_FOREACH (CNodeCombinedStats& stats, cachedNodeStats) + for (CNodeCombinedStats& stats : cachedNodeStats) stats.fNodeStateStatsAvailable = GetNodeStateStats(stats.nodeStats.nodeid, stats.nodeStateStats); } } diff --git a/src/qt/privacydialog.cpp b/src/qt/privacydialog.cpp index fd18c40f9a4f1..53fdc109c74a6 100644 --- a/src/qt/privacydialog.cpp +++ b/src/qt/privacydialog.cpp @@ -36,11 +36,11 @@ PrivacyDialog::PrivacyDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystem // "Spending 999999 xION ought to be enough for anybody." - Bill Gates, 2017 ui->xIONpayAmount->setValidator( new QDoubleValidator(0.0, 21000000.0, 20, this) ); - ui->labelMintAmountValue->setValidator( new QIntValidator(0, 999999, this) ); + //ui->labelMintAmountValue->setValidator( new QIntValidator(0, 999999, this) ); // disable MINT // Default texts for (mini-) coincontrol - ui->labelCoinControlQuantity->setText (tr("Coins automatically selected")); - ui->labelCoinControlAmount->setText (tr("Coins automatically selected")); + //ui->labelCoinControlQuantity->setText (tr("Coins automatically selected")); // disable MINT + //ui->labelCoinControlAmount->setText (tr("Coins automatically selected")); // disable MINT ui->labelxIONSyncStatus->setText("(" + tr("out of sync") + ")"); // Sunken frame for minting messages @@ -50,6 +50,7 @@ PrivacyDialog::PrivacyDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystem ui->TEMintStatus->setPlainText(tr("Mint Status: Okay")); // Coin Control signals + /* [disable MINT and coinControl] connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked())); // Coin Control: clipboard actions @@ -59,6 +60,7 @@ PrivacyDialog::PrivacyDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystem connect(clipboardAmountAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardAmount())); ui->labelCoinControlQuantity->addAction(clipboardQuantityAction); ui->labelCoinControlAmount->addAction(clipboardAmountAction); + */ // Denomination labels ui->labelzDenom1Text->setText(tr("Denom. with value 1:")); @@ -109,6 +111,8 @@ PrivacyDialog::PrivacyDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystem if(!settings.contains("fDenomsSectionMinimized")) settings.setValue("fDenomsSectionMinimized", true); minimizeDenomsSection(settings.value("fDenomsSectionMinimized").toBool()); + + ui->checkBoxMintChange->setVisible(false); } PrivacyDialog::~PrivacyDialog() @@ -153,7 +157,8 @@ void PrivacyDialog::on_addressBookButton_clicked() ui->xIONpayAmount->setFocus(); } } - +/* disable MINT + * void PrivacyDialog::on_pushButtonMintxION_clicked() { if (!walletModel || !walletModel->getOptionsModel()) @@ -234,7 +239,7 @@ void PrivacyDialog::on_pushButtonMintxION_clicked() return; } - +*/ void PrivacyDialog::on_pushButtonMintReset_clicked() { ui->TEMintStatus->setPlainText(tr("Starting ResetMintZerocoin: rescanning complete blockchain, this will need up to 30 minutes depending on your hardware.\nPlease be patient...")); @@ -343,7 +348,7 @@ void PrivacyDialog::sendxION() } // Convert change to xION - bool fMintChange = ui->checkBoxMintChange->isChecked(); + bool fMintChange = false;// ui->checkBoxMintChange->isChecked(); // Persist minimize change setting fMinimizeChange = ui->checkBoxMinimizeChange->isChecked(); @@ -438,6 +443,7 @@ void PrivacyDialog::sendxION() // Display errors during spend if (!fSuccess) { + /* int nNeededSpends = receipt.GetNeededSpends(); // Number of spends we would need for this transaction const int nMaxSpends = Params().Zerocoin_MaxSpendsPerTransaction(); // Maximum possible spends for one xION transaction if (nNeededSpends > nMaxSpends) { @@ -447,9 +453,10 @@ void PrivacyDialog::sendxION() ui->TEMintStatus->setPlainText(tr("Spend Zerocoin failed with status = ") +QString::number(receipt.GetStatus(), 10) + "\n" + "Message: " + QString::fromStdString(strStatusMessage.toStdString())); } else { - QMessageBox::warning(this, tr("Spend Zerocoin"), receipt.GetStatusMessage().c_str(), QMessageBox::Ok, QMessageBox::Ok); - ui->TEMintStatus->setPlainText(tr("Spend Zerocoin failed with status = ") +QString::number(receipt.GetStatus(), 10) + "\n" + "Message: " + QString::fromStdString(receipt.GetStatusMessage())); - } + */ + QMessageBox::warning(this, tr("Spend Zerocoin"), receipt.GetStatusMessage().c_str(), QMessageBox::Ok, QMessageBox::Ok); + ui->TEMintStatus->setPlainText(tr("Spend Zerocoin failed with status = ") +QString::number(receipt.GetStatus(), 10) + "\n" + "Message: " + QString::fromStdString(receipt.GetStatusMessage())); + //} ui->xIONpayAmount->setFocus(); ui->TEMintStatus->repaint(); ui->TEMintStatus->verticalScrollBar()->setValue(ui->TEMintStatus->verticalScrollBar()->maximum()); // Automatically scroll to end of text @@ -490,7 +497,7 @@ void PrivacyDialog::sendxION() strStats += tr("address: "); CTxDestination dest; - if(txout.scriptPubKey.IsZerocoinMint()) + if(txout.IsZerocoinMint()) strStats += tr("xION Mint"); else if(ExtractDestination(txout.scriptPubKey, dest)) strStats += tr(CBitcoinAddress(dest).ToString().c_str()); @@ -518,6 +525,8 @@ void PrivacyDialog::on_payTo_textChanged(const QString& address) updateLabel(address); } +/* DISABLE MINTs: no need for coinCointrol + // Coin Control: copy label "Quantity" to clipboard void PrivacyDialog::coinControlClipboardQuantity() { @@ -559,7 +568,7 @@ void PrivacyDialog::coinControlUpdateLabels() ui->labelCoinControlAmount->setText (tr("Coins automatically selected")); } } - +*/ void PrivacyDialog::on_pushButtonShowDenoms_clicked() { @@ -705,7 +714,6 @@ void PrivacyDialog::setBalance(const CAmount& balance, const CAmount& unconfirme ui->labelzAvailableAmount->setText(QString::number(zerocoinBalance/COIN) + QString(" xION ")); ui->labelzAvailableAmount_2->setText(QString::number(matureZerocoinBalance/COIN) + QString(" xION ")); ui->labelzAvailableAmount_4->setText(QString::number(zerocoinBalance/COIN) + QString(" xION ")); - ui->labelxIONAmountValue->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, balance - immatureBalance - nLockedBalance, false, BitcoinUnits::separatorAlways)); // Display AutoMint status updateAutomintStatus(); @@ -797,20 +805,21 @@ void PrivacyDialog::updateAutomintStatus() void PrivacyDialog::updateSPORK16Status() { // Update/enable labels, buttons and tooltips depending on the current SPORK_16 status - bool fButtonsEnabled = ui->pushButtonMintxION->isEnabled(); + //bool fButtonsEnabled = ui->pushButtonMintxION->isEnabled(); + bool fButtonsEnabled = false; bool fMaintenanceMode = GetAdjustedTime() > GetSporkValue(SPORK_9_ZEROCOIN_MAINTENANCE_MODE); if (fMaintenanceMode && fButtonsEnabled) { // Mint xION - ui->pushButtonMintxION->setEnabled(false); - ui->pushButtonMintxION->setToolTip(tr("xION is currently disabled due to maintenance.")); + //ui->pushButtonMintxION->setEnabled(false); + //ui->pushButtonMintxION->setToolTip(tr("xION is currently disabled due to maintenance.")); // Spend xION ui->pushButtonSpendxION->setEnabled(false); ui->pushButtonSpendxION->setToolTip(tr("xION is currently disabled due to maintenance.")); } else if (!fMaintenanceMode && !fButtonsEnabled) { // Mint xION - ui->pushButtonMintxION->setEnabled(true); - ui->pushButtonMintxION->setToolTip(tr("PrivacyDialog", "Enter an amount of ION to convert to xION", 0)); + //ui->pushButtonMintxION->setEnabled(true); + //ui->pushButtonMintxION->setToolTip(tr("PrivacyDialog", "Enter an amount of ION to convert to xION", 0)); // Spend xION ui->pushButtonSpendxION->setEnabled(true); diff --git a/src/qt/privacydialog.h b/src/qt/privacydialog.h index 32b01cf7bb1c8..d7d27e642ed98 100644 --- a/src/qt/privacydialog.h +++ b/src/qt/privacydialog.h @@ -82,13 +82,13 @@ private slots: void on_payTo_textChanged(const QString& address); void on_addressBookButton_clicked(); // void coinControlFeatureChanged(bool); - void coinControlButtonClicked(); +// MINT disabled void coinControlButtonClicked(); // void coinControlChangeChecked(int); // void coinControlChangeEdited(const QString&); - void coinControlUpdateLabels(); +// MINT disabled void coinControlUpdateLabels(); - void coinControlClipboardQuantity(); - void coinControlClipboardAmount(); +// MINT disabled void coinControlClipboardQuantity(); +// MINT disabled void coinControlClipboardAmount(); // void coinControlClipboardFee(); // void coinControlClipboardAfterFee(); // void coinControlClipboardBytes(); @@ -96,7 +96,7 @@ private slots: // void coinControlClipboardLowOutput(); // void coinControlClipboardChange(); - void on_pushButtonMintxION_clicked(); +// MINT disabled void on_pushButtonMintxION_clicked(); void on_pushButtonMintReset_clicked(); void on_pushButtonSpentReset_clicked(); void on_pushButtonSpendxION_clicked(); diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 881e5b335f285..312e8471aa6e7 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -11,7 +11,6 @@ #include "optionsmodel.h" #include "streams.h" -#include RecentRequestsTableModel::RecentRequestsTableModel(CWallet* wallet, WalletModel* parent) : walletModel(parent) { @@ -21,7 +20,7 @@ RecentRequestsTableModel::RecentRequestsTableModel(CWallet* wallet, WalletModel* // Load entries from wallet std::vector vReceiveRequests; parent->loadReceiveRequests(vReceiveRequests); - BOOST_FOREACH (const std::string& request, vReceiveRequests) + for (const std::string& request : vReceiveRequests) addNewRequest(request); /* These columns must match the indices in the ColumnIndex enumeration */ diff --git a/src/qt/res/css/default.css b/src/qt/res/css/default.css index 840aa62f42de2..d8765bd4465b5 100755 --- a/src/qt/res/css/default.css +++ b/src/qt/res/css/default.css @@ -1724,6 +1724,16 @@ QWidget#GovernancePage .ProposalFrame#proposalFramePassing { border:1px solid #00ef00; } +QWidget#GovernancePage .ProposalFrame#proposalFrameNotEstablished { + background-color:qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #0080ff, stop: 1 #00a3ff); + border:1px solid #00a3ff; +} + +QWidget#GovernancePage .ProposalFrame#proposalFramePassingUnfunded { + background-color:qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #cccc00, stop: 1 #efef00); + border:1px solid #efef00; +} + QWidget#GovernancePage .ProposalFrame > QLabel#strProposalName, QLabel#strMonthlyPayout, QLabel#strRemainingPaymentCount { font-size:18pt; } diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index a3a9b0c5795a8..00a1e6dc6c5c1 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -491,6 +491,7 @@ void RPCConsole::setClientModel(ClientModel* model) ui->clientVersion->setText(model->formatFullVersion()); ui->clientName->setText(model->clientName()); ui->buildDate->setText(model->formatBuildDate()); + ui->dataDir->setText(model->dataDir()); ui->startupTime->setText(model->formatClientStartupTime()); ui->networkName->setText(QString::fromStdString(Params().NetworkIDString())); @@ -686,8 +687,10 @@ void RPCConsole::setNumConnections(int count) void RPCConsole::setNumBlocks(int count) { ui->numberOfBlocks->setText(QString::number(count)); - if (clientModel) + if (clientModel) { ui->lastBlockTime->setText(clientModel->getLastBlockDate().toString()); + ui->lastBlockHash->setText(clientModel->getLastBlockHash()); + } } void RPCConsole::setMasternodeCount(const QString& strMasternodes) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 3626eebbe00aa..f89dcda6c381c 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -19,7 +19,7 @@ #include "base58.h" #include "coincontrol.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "utilmoneystr.h" #include "wallet/wallet.h" diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index df2bc2147088f..658b3dd13cee0 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -9,7 +9,7 @@ #include "clientversion.h" #include "init.h" #include "networkstyle.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "version.h" diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index b311646c61006..66a52f917b20c 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -16,7 +16,7 @@ #include "main.h" #include "script/script.h" #include "timedata.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "wallet/wallet.h" @@ -156,7 +156,7 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco // Coinbase // CAmount nUnmatured = 0; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) + for (const CTxOut& txout : wtx.vout) nUnmatured += wallet->GetCredit(txout, ISMINE_ALL); strHTML += "" + tr("Credit") + ": "; if (wtx.IsInMainChain()) @@ -171,13 +171,13 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, nNet) + "
"; } else { isminetype fAllFromMe = ISMINE_SPENDABLE; - BOOST_FOREACH (const CTxIn& txin, wtx.vin) { + for (const CTxIn& txin : wtx.vin) { isminetype mine = wallet->IsMine(txin); if (fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { isminetype mine = wallet->IsMine(txout); if (fAllToMe > mine) fAllToMe = mine; } @@ -189,7 +189,7 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco // // Debit // - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { // Ignore change isminetype toSelf = wallet->IsMine(txout); if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE)) @@ -231,10 +231,10 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco // // Mixed debit transaction // - BOOST_FOREACH (const CTxIn& txin, wtx.vin) + for (const CTxIn& txin : wtx.vin) if (wallet->IsMine(txin)) strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
"; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) + for (const CTxOut& txout : wtx.vout) if (wallet->IsMine(txout)) strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "
"; } @@ -281,10 +281,10 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco // if (fDebug) { strHTML += "

" + tr("Debug information") + "

"; - BOOST_FOREACH (const CTxIn& txin, wtx.vin) + for (const CTxIn& txin : wtx.vin) if (wallet->IsMine(txin)) strHTML += "" + tr("Debit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet->GetDebit(txin, ISMINE_ALL)) + "
"; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) + for (const CTxOut& txout : wtx.vout) if (wallet->IsMine(txout)) strHTML += "" + tr("Credit") + ": " + BitcoinUnits::formatHtmlWithUnit(unit, wallet->GetCredit(txout, ISMINE_ALL)) + "
"; @@ -294,7 +294,7 @@ QString TransactionDesc::toHTML(CWallet* wallet, CWalletTx& wtx, TransactionReco strHTML += "
" + tr("Inputs") + ":"; strHTML += "
    "; - BOOST_FOREACH (const CTxIn& txin, wtx.vin) { + for (const CTxIn& txin : wtx.vin) { COutPoint prevout = txin.prevout; CCoins prev; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index cf0d0fd676fc9..d84c8431394eb 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -12,7 +12,9 @@ #include "timedata.h" #include "wallet/wallet.h" #include "xionchain.h" +#include "main.h" +#include #include /* Return positive answer if transaction should be shown in list. @@ -42,19 +44,29 @@ QList TransactionRecord::decomposeTransaction(const CWallet* std::map mapValue = wtx.mapValue; bool fZSpendFromMe = false; - if (wtx.IsZerocoinSpend()) { + if (wtx.HasZerocoinSpendInputs()) { // a zerocoin spend that was created by this wallet - libzerocoin::CoinSpend zcspend = TxInToZerocoinSpend(wtx.vin[0]); - fZSpendFromMe = wallet->IsMyZerocoinSpend(zcspend.getCoinSerialNumber()); + if (wtx.HasZerocoinPublicSpendInputs()) { + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + CValidationState state; + if (!XIONModule::ParseZerocoinPublicSpend(wtx.vin[0], wtx, state, publicSpend)){ + throw std::runtime_error("Error parsing zc public spend"); + } + fZSpendFromMe = wallet->IsMyZerocoinSpend(publicSpend.getCoinSerialNumber()); + } else { + libzerocoin::CoinSpend zcspend = TxInToZerocoinSpend(wtx.vin[0]); + fZSpendFromMe = wallet->IsMyZerocoinSpend(zcspend.getCoinSerialNumber()); + } } if (wtx.IsCoinStake()) { TransactionRecord sub(hash, nTime); CTxDestination address; - if (!wtx.IsZerocoinSpend() && !ExtractDestination(wtx.vout[1].scriptPubKey, address)) + if (!wtx.HasZerocoinSpendInputs() && !ExtractDestination(wtx.vout[1].scriptPubKey, address)) return parts; - if (wtx.IsZerocoinSpend() && (fZSpendFromMe || wallet->xionTracker->HasMintTx(hash))) { + if (wtx.HasZerocoinSpendInputs() && (fZSpendFromMe || wallet->xionTracker->HasMintTx(hash))) { //xION stake reward sub.involvesWatchAddress = false; sub.type = TransactionRecord::StakeXION; @@ -85,7 +97,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* } parts.append(sub); - } else if (wtx.IsZerocoinSpend()) { + } else if (wtx.HasZerocoinSpendInputs()) { //zerocoin spend outputs bool fFeeAssigned = false; for (const CTxOut& txout : wtx.vout) { @@ -152,7 +164,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* // // Credit // - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { isminetype mine = wallet->IsMine(txout); if (mine) { TransactionRecord sub(hash, nTime); @@ -182,7 +194,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* int nFromMe = 0; bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; - BOOST_FOREACH (const CTxIn& txin, wtx.vin) { + for (const CTxIn& txin : wtx.vin) { if (wallet->IsMine(txin)) { fAllFromMeDenom = fAllFromMeDenom && wallet->IsDenominated(txin); nFromMe++; @@ -195,7 +207,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* isminetype fAllToMe = ISMINE_SPENDABLE; bool fAllToMeDenom = true; int nToMe = 0; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { if (wallet->IsMine(txout)) { fAllToMeDenom = fAllToMeDenom && wallet->IsDenominatedAmount(txout.nValue); nToMe++; @@ -245,7 +257,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* sub.credit = nCredit - nChange; parts.append(sub); parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument - } else if (fAllFromMe || wtx.IsZerocoinMint()) { + } else if (fAllFromMe || wtx.HasZerocoinMintOutputs()) { // // Debit // @@ -267,7 +279,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* if (ExtractDestination(txout.scriptPubKey, address)) { //This is most likely only going to happen when resyncing deterministic wallet without the knowledge of the //private keys that the change was sent to. Do not display a "sent to" here. - if (wtx.IsZerocoinMint()) + if (wtx.HasZerocoinMintOutputs()) continue; // Sent to ION Address sub.type = TransactionRecord::SendToAddress; diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index f48b89dcc8d6c..f114ded33a93d 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -17,7 +17,7 @@ #include "transactiontablemodel.h" #include "walletmodel.h" -#include "ui_interface.h" +#include "guiinterface.h" #include #include diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 2c5db1ebbaff6..8481bf6b28a5d 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -42,7 +42,7 @@ bool WalletFrame::addWallet(const QString& name, WalletModel* walletModel) if (!gui || !clientModel || !walletModel || mapWalletViews.count(name) > 0) return false; - WalletView* walletView = new WalletView(this); + WalletView* walletView = new WalletView(walletStack); walletView->setBitcoinGUI(gui); walletView->setClientModel(clientModel); walletView->setWalletModel(walletModel); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index a16458111cd20..b789f377fad4e 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -18,7 +18,7 @@ #include "main.h" #include "spork.h" #include "sync.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "wallet/wallet.h" #include "wallet/walletdb.h" // for BackupWallet #include @@ -64,7 +64,7 @@ CAmount WalletModel::getBalance(const CCoinControl* coinControl) const CAmount nBalance = 0; std::vector vCoins; wallet->AvailableCoins(vCoins, true, coinControl); - BOOST_FOREACH (const COutput& out, vCoins) + for (const COutput& out : vCoins) if (out.fSpendable) nBalance += out.tx->vout[out.i].nValue; @@ -697,7 +697,7 @@ bool WalletModel::getPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const void WalletModel::getOutputs(const std::vector& vOutpoints, std::vector& vOutputs) { LOCK2(cs_main, wallet->cs_wallet); - BOOST_FOREACH (const COutPoint& outpoint, vOutpoints) { + for (const COutPoint& outpoint : vOutpoints) { if (!wallet->mapWallet.count(outpoint.hash)) continue; int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); if (nDepth < 0) continue; @@ -723,7 +723,7 @@ void WalletModel::listCoins(std::map >& mapCoins) wallet->ListLockedCoins(vLockedCoins); // add locked coins - BOOST_FOREACH (const COutPoint& outpoint, vLockedCoins) { + for (const COutPoint& outpoint : vLockedCoins) { if (!wallet->mapWallet.count(outpoint.hash)) continue; int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); if (nDepth < 0) continue; @@ -732,7 +732,7 @@ void WalletModel::listCoins(std::map >& mapCoins) vCoins.push_back(out); } - BOOST_FOREACH (const COutput& out, vCoins) { + for (const COutput& out : vCoins) { COutput cout = out; while (wallet->IsChange(cout.tx->vout[cout.i]) && cout.tx->vin.size() > 0 && wallet->IsMine(cout.tx->vin[0])) { @@ -781,8 +781,8 @@ void WalletModel::listZerocoinMints(std::set& setMints, bool fUnusedO void WalletModel::loadReceiveRequests(std::vector& vReceiveRequests) { LOCK(wallet->cs_wallet); - BOOST_FOREACH (const PAIRTYPE(CTxDestination, CAddressBookData) & item, wallet->mapAddressBook) - BOOST_FOREACH (const PAIRTYPE(std::string, std::string) & item2, item.second.destdata) + for (const PAIRTYPE(CTxDestination, CAddressBookData) & item : wallet->mapAddressBook) + for (const PAIRTYPE(std::string, std::string) & item2 : item.second.destdata) if (item2.first.size() > 2 && item2.first.substr(0, 2) == "rr") // receive request vReceiveRequests.push_back(item2.second); } diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 2d0e1368793e4..c418fde746b43 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -25,7 +25,7 @@ #include "transactionview.h" #include "walletmodel.h" -#include "ui_interface.h" +#include "guiinterface.h" #include #include diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 8f95d0d8178e7..fe86dca8a7391 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -11,7 +11,7 @@ #include "masternodelist.h" #include -#include +#include class BitcoinGUI; class ClientModel; diff --git a/src/qt/xioncontroldialog.cpp b/src/qt/xioncontroldialog.cpp index 03dd84a9424e1..a2380529c6306 100644 --- a/src/qt/xioncontroldialog.cpp +++ b/src/qt/xioncontroldialog.cpp @@ -80,7 +80,7 @@ void XIonControlDialog::updateList() //populate rows with mint info int nBestHeight = chainActive.Height(); - map mapMaturityHeight = GetMintMaturityHeight(); + //map mapMaturityHeight = GetMintMaturityHeight(); for (const CMintMeta& mint : setMints) { // assign this mint to the correct denomination in the tree view libzerocoin::CoinDenomination denom = mint.denom; @@ -123,9 +123,10 @@ void XIonControlDialog::updateList() } // check for maturity - bool isMature = false; - if (mapMaturityHeight.count(mint.denom)) - isMature = mint.nHeight < mapMaturityHeight.at(denom); + // Always mature, public spends doesn't require any new accumulation. + bool isMature = true; + //if (mapMaturityHeight.count(mint.denom)) + // isMature = mint.nHeight < mapMaturityHeight.at(denom); // disable selecting this mint if it is not spendable - also display a reason why bool fSpendable = isMature && nConfirmations >= Params().Zerocoin_MintRequiredConfirmations() && mint.isSeedCorrect; diff --git a/src/rest.cpp b/src/rest.cpp index 7d9d9cf8b2697..db72ec10fcf3e 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -155,7 +155,7 @@ static bool rest_headers(HTTPRequest* req, } CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION); - BOOST_FOREACH(const CBlockIndex *pindex, headers) { + for (const CBlockIndex *pindex : headers) { ssHeader << pindex->GetBlockHeader(); } @@ -175,7 +175,7 @@ static bool rest_headers(HTTPRequest* req, } case RF_JSON: { UniValue jsonHeaders(UniValue::VARR); - BOOST_FOREACH(const CBlockIndex *pindex, headers) { + for (const CBlockIndex *pindex : headers) { jsonHeaders.push_back(blockheaderToJSON(pindex)); } string strJSON = jsonHeaders.write() + "\n"; @@ -561,7 +561,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) objGetUTXOResponse.push_back(Pair("bitmap", bitmapStringRepresentation)); UniValue utxos(UniValue::VARR); - BOOST_FOREACH (const CCoin& coin, outs) { + for (const CCoin& coin : outs) { UniValue utxo(UniValue::VOBJ); utxo.push_back(Pair("txvers", (int32_t)coin.nTxVer)); utxo.push_back(Pair("height", (int32_t)coin.nHeight)); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index dbc08a7d215fc..09a32a57f49c7 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -19,12 +19,15 @@ #include "xion/accumulatormap.h" #include "xion/accumulators.h" #include "wallet/wallet.h" +#include "xion/xionmodule.h" #include "xionchain.h" + #include #include #include #include #include +#include #include #include // boost::thread::interrupt @@ -114,7 +117,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("acc_checkpoint", block.nAccumulatorCheckpoint.GetHex())); UniValue txs(UniValue::VARR); - BOOST_FOREACH (const CTransaction& tx, block.vtx) { + for (const CTransaction& tx : block.vtx) { if (txDetails) { UniValue objTx(UniValue::VOBJ); TxToJSON(tx, uint256(0), objTx); @@ -435,7 +438,7 @@ UniValue mempoolToJSON(bool fVerbose = false) if (fVerbose) { LOCK(mempool.cs); UniValue o(UniValue::VOBJ); - BOOST_FOREACH (const PAIRTYPE(uint256, CTxMemPoolEntry) & entry, mempool.mapTx) { + for (const PAIRTYPE(uint256, CTxMemPoolEntry) & entry : mempool.mapTx) { const uint256& hash = entry.first; const CTxMemPoolEntry& e = entry.second; UniValue info(UniValue::VOBJ); @@ -447,13 +450,13 @@ UniValue mempoolToJSON(bool fVerbose = false) info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height()))); const CTransaction& tx = e.GetTx(); set setDepends; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { if (mempool.exists(txin.prevout.hash)) setDepends.insert(txin.prevout.hash.ToString()); } UniValue depends(UniValue::VARR); - BOOST_FOREACH(const string& dep, setDepends) { + for (const string& dep : setDepends) { depends.push_back(dep); } @@ -466,7 +469,7 @@ UniValue mempoolToJSON(bool fVerbose = false) mempool.queryHashes(vtxid); UniValue a(UniValue::VARR); - BOOST_FOREACH (const uint256& hash, vtxid) + for (const uint256& hash : vtxid) a.push_back(hash.ToString()); return a; @@ -1012,9 +1015,9 @@ UniValue getchaintips(const UniValue& params, bool fHelp) known blocks, and successively remove blocks that appear as pprev of another block. */ std::set setTips; - BOOST_FOREACH (const PAIRTYPE(const uint256, CBlockIndex*) & item, mapBlockIndex) + for (const PAIRTYPE(const uint256, CBlockIndex*) & item : mapBlockIndex) setTips.insert(item.second); - BOOST_FOREACH (const PAIRTYPE(const uint256, CBlockIndex*) & item, mapBlockIndex) { + for (const PAIRTYPE(const uint256, CBlockIndex*) & item : mapBlockIndex) { const CBlockIndex* pprev = item.second->pprev; if (pprev) setTips.erase(pprev); @@ -1025,7 +1028,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp) /* Construct the output array. */ UniValue res(UniValue::VARR); - BOOST_FOREACH (const CBlockIndex* block, setTips) { + for (const CBlockIndex* block : setTips) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("height", block->nHeight)); obj.push_back(Pair("hash", block->phashBlock->GetHex())); @@ -1083,66 +1086,22 @@ UniValue getfeeinfo(const UniValue& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getfeeinfo", "5") + HelpExampleRpc("getfeeinfo", "5")); - LOCK(cs_main); - int nBlocks = params[0].get_int(); - int nBestHeight = chainActive.Height(); + int nBestHeight; + { + LOCK(cs_main); + nBestHeight = chainActive.Height(); + } int nStartHeight = nBestHeight - nBlocks; if (nBlocks < 0 || nStartHeight <= 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid start height"); - CAmount nFees = 0; - int64_t nBytes = 0; - int64_t nTotal = 0; - for (int i = nStartHeight; i <= nBestHeight; i++) { - CBlockIndex* pindex = chainActive[i]; - CBlock block; - if (!ReadBlockFromDisk(block, pindex)) - throw JSONRPCError(RPC_DATABASE_ERROR, "failed to read block from disk"); + UniValue newParams(UniValue::VARR); + newParams.push_back(UniValue(nStartHeight)); + newParams.push_back(UniValue(nBlocks)); + newParams.push_back(UniValue(true)); // fFeeOnly - CAmount nValueIn = 0; - CAmount nValueOut = 0; - for (const CTransaction& tx : block.vtx) { - if (tx.IsCoinBase() || tx.IsCoinStake()) - continue; - - for (unsigned int j = 0; j < tx.vin.size(); j++) { - if (tx.vin[j].scriptSig.IsZerocoinSpend()) { - nValueIn += tx.vin[j].nSequence * COIN; - continue; - } - - COutPoint prevout = tx.vin[j].prevout; - CTransaction txPrev; - uint256 hashBlock; - if(!GetTransaction(prevout.hash, txPrev, hashBlock, true)) - throw JSONRPCError(RPC_DATABASE_ERROR, "failed to read tx from disk"); - nValueIn += txPrev.vout[prevout.n].nValue; - } - - for (unsigned int j = 0; j < tx.vout.size(); j++) { - nValueOut += tx.vout[j].nValue; - } - - nFees += nValueIn - nValueOut; - nBytes += tx.GetSerializeSize(SER_NETWORK, CLIENT_VERSION); - nTotal++; - } - - pindex = chainActive.Next(pindex); - if (!pindex) - break; - } - - UniValue ret(UniValue::VOBJ); - CFeeRate nFeeRate = CFeeRate(nFees, nBytes); - ret.push_back(Pair("txcount", (int64_t)nTotal)); - ret.push_back(Pair("txbytes", (int64_t)nBytes)); - ret.push_back(Pair("ttlfee", FormatMoney(nFees))); - ret.push_back(Pair("feeperkb", FormatMoney(nFeeRate.GetFeePerK()))); - ret.push_back(Pair("rec_highpriorityfee_perkb", FormatMoney(nFeeRate.GetFeePerK() + 1000))); - - return ret; + return getblockindexstats(newParams, false); } UniValue mempoolInfoToJSON() @@ -1371,17 +1330,50 @@ UniValue getaccumulatorwitness(const UniValue& params, bool fHelp) return obj; } +void validaterange(const UniValue& params, int& heightStart, int& heightEnd, int minHeightStart) +{ + if (params.size() < 2) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Not enough parameters in validaterange"); + } + + int nBestHeight; + { + LOCK(cs_main); + nBestHeight = chainActive.Height(); + } + + heightStart = params[0].get_int(); + if (heightStart > nBestHeight) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid starting block (%d). Out of range.", heightStart)); + } + + const int range = params[1].get_int(); + if (range < 1) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block range. Must be strictly positive."); + } + + heightEnd = heightStart + range - 1; + + if (heightStart < minHeightStart && heightEnd >= minHeightStart) { + heightStart = minHeightStart; + } + + if (heightEnd > nBestHeight) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid ending block (%d). Out of range.", heightEnd)); + } +} + UniValue getmintsinblocks(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) throw runtime_error( - "getmintsinblocks \"height\" \"range\" \"coinDenomination\"\n" + "getmintsinblocks height range coinDenomination\n" "\nReturns the number of mints of a certain denomination" "\noccurred in blocks [height, height+1, height+2, ..., height+range-1]\n" "\nArguments:\n" "1. height (numeric, required) block height where the search starts.\n" "2. range (numeric, required) number of blocks to include.\n" - "2. coinDenomination (numeric, required) coin denomination.\n" + "3. coinDenomination (numeric, required) coin denomination.\n" "\nResult:\n" "{\n" @@ -1394,19 +1386,8 @@ UniValue getmintsinblocks(const UniValue& params, bool fHelp) { HelpExampleCli("getmintsinblocks", "1200000 1000 5") + HelpExampleRpc("getmintsinblocks", "1200000, 1000, 5")); - int nBestHeight = chainActive.Height(); - - int heightStart = params[0].get_int(); - if (heightStart < Params().Zerocoin_StartHeight()) - heightStart = Params().Zerocoin_StartHeight(); - - int range = params[1].get_int(); - if (range < 1) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block range. Must be strictly positive."); - - int heightEnd = heightStart + range - 1; - if (heightEnd > nBestHeight) - heightEnd = nBestHeight; + int heightStart, heightEnd; + validaterange(params, heightStart, heightEnd, Params().Zerocoin_StartHeight()); int d = params[2].get_int(); libzerocoin::CoinDenomination denom = libzerocoin::IntToZerocoinDenomination(d); @@ -1414,19 +1395,23 @@ UniValue getmintsinblocks(const UniValue& params, bool fHelp) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid denomination. Must be in {1, 5, 10, 50, 100, 500, 1000, 5000}"); int num_of_mints = 0; - CBlockIndex* pindex = chainActive[heightStart]; - - while (true) { - num_of_mints += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), denom); - if (pindex->nHeight < heightEnd) - pindex = chainActive.Next(pindex); - else - break; + { + LOCK(cs_main); + CBlockIndex* pindex = chainActive[heightStart]; + + while (true) { + num_of_mints += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), denom); + if (pindex->nHeight < heightEnd) { + pindex = chainActive.Next(pindex); + } else { + break; + } + } } UniValue obj(UniValue::VOBJ); obj.push_back(Pair("Starting block", heightStart)); - obj.push_back(Pair("Ending block", pindex->nHeight)); + obj.push_back(Pair("Ending block", heightEnd-1)); obj.push_back(Pair("Number of "+ std::to_string(d) +"-denom mints", num_of_mints)); return obj; @@ -1436,7 +1421,7 @@ UniValue getmintsinblocks(const UniValue& params, bool fHelp) { UniValue getserials(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( - "getserials \"hash\"\n" + "getserials height range ( fVerbose )\n" "\nLook the inputs of any tx in a range of blocks and returns the serial numbers for any coinspend.\n" "\nArguments:\n" @@ -1448,28 +1433,22 @@ UniValue getserials(const UniValue& params, bool fHelp) { HelpExampleCli("getserials", "1254000 1000") + HelpExampleRpc("getserials", "1254000, 1000")); - LOCK(cs_main); - - int nBestHeight = chainActive.Height(); - - int heightStart = params[0].get_int(); - if (heightStart < Params().Zerocoin_StartHeight()) - heightStart = Params().Zerocoin_StartHeight(); - - int range = params[1].get_int(); - if (range < 1) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block range. Must be strictly positive."); - - int heightEnd = heightStart + range - 1; - if (heightEnd > nBestHeight) - heightEnd = nBestHeight; + int heightStart, heightEnd; + validaterange(params, heightStart, heightEnd, Params().Zerocoin_StartHeight()); bool fVerbose = false; if (params.size() > 2) { fVerbose = params[2].get_bool(); } - CBlockIndex* pblockindex = chainActive[heightStart]; + CBlockIndex* pblockindex = nullptr; + { + LOCK(cs_main); + pblockindex = chainActive[heightStart]; + } + + if (!pblockindex) + throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid block height"); UniValue serialsObj(UniValue::VOBJ); // for fVerbose UniValue serialsArr(UniValue::VARR); @@ -1502,13 +1481,31 @@ UniValue getserials(const UniValue& params, bool fHelp) { } // loop through each input for (const CTxIn& txin : tx.vin) { - if (txin.scriptSig.IsZerocoinSpend()) { - libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txin); - std::string serial_str = spend.getCoinSerialNumber().ToString(16); + bool isPublicSpend = txin.IsZerocoinPublicSpend(); + if (txin.IsZerocoinSpend() || isPublicSpend) { + std::string serial_str; + int denom; + if (isPublicSpend) { + CTxOut prevOut; + CValidationState state; + if(!GetOutput(txin.prevout.hash, txin.prevout.n, state, prevOut)){ + throw JSONRPCError(RPC_INTERNAL_ERROR, "public zerocoin spend prev output not found"); + } + libzerocoin::ZerocoinParams *params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + if (!XIONModule::parseCoinSpend(txin, tx, prevOut, publicSpend)) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "public zerocoin spend parse failed"); + } + serial_str = publicSpend.getCoinSerialNumber().ToString(16); + denom = libzerocoin::ZerocoinDenominationToInt(publicSpend.getDenomination()); + } else { + libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txin); + serial_str = spend.getCoinSerialNumber().ToString(16); + denom = libzerocoin::ZerocoinDenominationToInt(spend.getDenomination()); + } if (!fVerbose) { serialsArr.push_back(serial_str); } else { - int denom = libzerocoin::ZerocoinDenominationToInt(spend.getDenomination()); UniValue s(UniValue::VOBJ); s.push_back(Pair("serial", serial_str)); s.push_back(Pair("denom", denom)); @@ -1519,14 +1516,17 @@ UniValue getserials(const UniValue& params, bool fHelp) { s.push_back(Pair("blocktime", block.GetBlockTime())); serialsArr.push_back(s); } - } } // end for vin in tx } // end for tx in block - if (pblockindex->nHeight < heightEnd) pblockindex = chainActive.Next(pblockindex); - else break; + if (pblockindex->nHeight < heightEnd) { + LOCK(cs_main); + pblockindex = chainActive.Next(pblockindex); + } else { + break; + } } // end for blocks @@ -1849,3 +1849,180 @@ UniValue scantxoutset(const UniValue& params, bool fHelp) } return result; } +UniValue getblockindexstats(const UniValue& params, bool fHelp) { + if (fHelp || params.size() < 2 || params.size() > 3) + throw runtime_error( + "getblockindexstats height range ( fFeeOnly )\n" + "\nReturns aggregated BlockIndex data for blocks " + "\n[height, height+1, height+2, ..., height+range-1]\n" + + "\nArguments:\n" + "1. height (numeric, required) block height where the search starts.\n" + "2. range (numeric, required) number of blocks to include.\n" + "3. fFeeOnly (boolean, optional, default=False) return only fee info.\n" + + "\nResult:\n" + "{\n" + " \"first_block\": \"x\" (integer) First counted block\n" + " \"last_block\": \"x\" (integer) Last counted block\n" + " \"txcount\": xxxxx (numeric) tx count (excluding coinbase/coinstake)\n" + " \"txcount_all\": xxxxx (numeric) tx count (including coinbase/coinstake)\n" + " \"mintcount\": { [if fFeeOnly=False]\n" + " \"denom_1\": xxxx (numeric) number of mints of denom_1 occurred over the block range\n" + " \"denom_5\": xxxx (numeric) number of mints of denom_5 occurred over the block range\n" + " ... ... number of mints of other denominations: ..., 10, 50, 100, 500, 1000, 5000\n" + " }\n" + " \"spendcount\": { [if fFeeOnly=False]\n" + " \"denom_1\": xxxx (numeric) number of spends of denom_1 occurred over the block range\n" + " \"denom_5\": xxxx (numeric) number of spends of denom_5 occurred over the block range\n" + " ... ... number of spends of other denominations: ..., 10, 50, 100, 500, 1000, 5000\n" + " }\n" + " \"pubspendcount\": { [if fFeeOnly=False]\n" + " \"denom_1\": xxxx (numeric) number of PUBLIC spends of denom_1 occurred over the block range\n" + " \"denom_5\": xxxx (numeric) number of PUBLIC spends of denom_5 occurred over the block range\n" + " ... ... number of PUBLIC spends of other denominations: ..., 10, 50, 100, 500, 1000, 5000\n" + " }\n" + " \"txbytes\": xxxxx (numeric) Sum of the size of all txes (xION excluded) over block range\n" + " \"ttlfee\": xxxxx (numeric) Sum of the fee amount of all txes (xION mints excluded) over block range\n" + " \"ttlfee_all\": xxxxx (numeric) Sum of the fee amount of all txes (xION mints included) over block range\n" + " \"feeperkb\": xxxxx (numeric) Average fee per kb (excluding zc txes)\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("getblockindexstats", "1200000 1000") + + HelpExampleRpc("getblockindexstats", "1200000, 1000")); + + int heightStart, heightEnd; + validaterange(params, heightStart, heightEnd); + // return object + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("Starting block", heightStart)); + ret.push_back(Pair("Ending block", heightEnd)); + + bool fFeeOnly = false; + if (params.size() > 2) { + fFeeOnly = params[2].get_bool(); + } + + CAmount nFees = 0; + CAmount nFees_all = 0; + int64_t nBytes = 0; + int64_t nTxCount = 0; + int64_t nTxCount_all = 0; + + std::map mapMintCount; + std::map mapSpendCount; + std::map mapPublicSpendCount; + for (auto& denom : libzerocoin::zerocoinDenomList) { + mapMintCount.insert(make_pair(denom, 0)); + mapSpendCount.insert(make_pair(denom, 0)); + mapPublicSpendCount.insert(make_pair(denom, 0)); + } + + CBlockIndex* pindex = nullptr; + { + LOCK(cs_main); + pindex = chainActive[heightStart]; + } + + if (!pindex) + throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid block height"); + + while (true) { + CBlock block; + if (!ReadBlockFromDisk(block, pindex)) { + throw JSONRPCError(RPC_DATABASE_ERROR, "failed to read block from disk"); + } + + CAmount nValueIn = 0; + CAmount nValueOut = 0; + const int ntx = block.vtx.size(); + nTxCount_all += ntx; + nTxCount = block.IsProofOfStake() ? nTxCount + ntx - 2 : nTxCount + ntx - 1; + + // loop through each tx in block and save size and fee + for (const CTransaction& tx : block.vtx) { + if (tx.IsCoinBase() || (tx.IsCoinStake() && !tx.HasZerocoinSpendInputs())) + continue; + + // fetch input value from prevouts and count spends + for (unsigned int j = 0; j < tx.vin.size(); j++) { + if (tx.vin[j].IsZerocoinSpend()) { + if (!fFeeOnly) + mapSpendCount[libzerocoin::IntToZerocoinDenomination(tx.vin[j].nSequence)]++; + continue; + } + if (tx.vin[j].IsZerocoinPublicSpend()) { + if (!fFeeOnly) + mapPublicSpendCount[libzerocoin::IntToZerocoinDenomination(tx.vin[j].nSequence)]++; + continue; + } + + COutPoint prevout = tx.vin[j].prevout; + CTransaction txPrev; + uint256 hashBlock; + if(!GetTransaction(prevout.hash, txPrev, hashBlock, true)) + throw JSONRPCError(RPC_DATABASE_ERROR, "failed to read tx from disk"); + nValueIn += txPrev.vout[prevout.n].nValue; + } + + // zc spends have no fee + if (tx.HasZerocoinSpendInputs()) + continue; + + // sum output values in nValueOut + for (unsigned int j = 0; j < tx.vout.size(); j++) { + nValueOut += tx.vout[j].nValue; + } + + // update sums + nFees_all += nValueIn - nValueOut; + if (!tx.HasZerocoinMintOutputs()) { + nFees += nValueIn - nValueOut; + nBytes += tx.GetSerializeSize(SER_NETWORK, CLIENT_VERSION); + } + } + + // add mints to map + if (!fFeeOnly) { + for (auto& denom : libzerocoin::zerocoinDenomList) { + mapMintCount[denom] += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), denom); + } + } + + if (pindex->nHeight < heightEnd) { + LOCK(cs_main); + pindex = chainActive.Next(pindex); + } else { + break; + } + } + + // get fee rate + CFeeRate nFeeRate = CFeeRate(nFees, nBytes); + + // return UniValue object + ret.push_back(Pair("txcount", (int64_t)nTxCount)); + ret.push_back(Pair("txcount_all", (int64_t)nTxCount_all)); + if (!fFeeOnly) { + UniValue mint_obj(UniValue::VOBJ); + UniValue spend_obj(UniValue::VOBJ); + UniValue pubspend_obj(UniValue::VOBJ); + for (auto& denom : libzerocoin::zerocoinDenomList) { + mint_obj.push_back(Pair(strprintf("denom_%d", ZerocoinDenominationToInt(denom)), mapMintCount[denom])); + spend_obj.push_back(Pair(strprintf("denom_%d", ZerocoinDenominationToInt(denom)), mapSpendCount[denom])); + pubspend_obj.push_back(Pair(strprintf("denom_%d", ZerocoinDenominationToInt(denom)), mapPublicSpendCount[denom])); + } + ret.push_back(Pair("mintcount", mint_obj)); + ret.push_back(Pair("spendcount", spend_obj)); + ret.push_back(Pair("publicspendcount", pubspend_obj)); + + } + ret.push_back(Pair("txbytes", (int64_t)nBytes)); + ret.push_back(Pair("ttlfee", FormatMoney(nFees))); + ret.push_back(Pair("ttlfee_all", FormatMoney(nFees_all))); + ret.push_back(Pair("feeperkb", FormatMoney(nFeeRate.GetFeePerK()))); + + return ret; + +} diff --git a/src/rpc/budget.cpp b/src/rpc/budget.cpp index 668cc9ec09b6c..aba05233c07e2 100644 --- a/src/rpc/budget.cpp +++ b/src/rpc/budget.cpp @@ -49,109 +49,6 @@ void budgetToJSON(CBudgetProposal* pbudgetProposal, UniValue& bObj) bObj.push_back(Pair("fValid", pbudgetProposal->fValid)); } -// This command is retained for backwards compatibility, but is depreciated. -// Future removal of this command is planned to keep things clean. -UniValue mnbudget(const UniValue& params, bool fHelp) -{ - string strCommand; - if (params.size() >= 1) - strCommand = params[0].get_str(); - - if (fHelp || - (strCommand != "vote-alias" && strCommand != "vote-many" && strCommand != "prepare" && strCommand != "submit" && strCommand != "vote" && strCommand != "getvotes" && strCommand != "getinfo" && strCommand != "show" && strCommand != "projection" && strCommand != "check" && strCommand != "nextblock")) - throw runtime_error( - "mnbudget \"command\"... ( \"passphrase\" )\n" - "\nVote or show current budgets\n" - "This command is depreciated, please see individual command documentation for future reference\n\n" - - "\nAvailable commands:\n" - " prepare - Prepare proposal for network by signing and creating tx\n" - " submit - Submit proposal for network\n" - " vote-many - Vote on a ION initiative\n" - " vote-alias - Vote on a ION initiative\n" - " vote - Vote on a ION initiative/budget\n" - " getvotes - Show current masternode budgets\n" - " getinfo - Show current masternode budgets\n" - " show - Show all budgets\n" - " projection - Show the projection of which proposals will be paid the next cycle\n" - " check - Scan proposals and remove invalid\n" - " nextblock - Get next superblock for budget system\n"); - - if (strCommand == "nextblock") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getnextsuperblock(newParams, fHelp); - } - - if (strCommand == "prepare") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return preparebudget(newParams, fHelp); - } - - if (strCommand == "submit") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return submitbudget(newParams, fHelp); - } - - if (strCommand == "vote" || strCommand == "vote-many" || strCommand == "vote-alias") { - if (strCommand == "vote-alias") - throw runtime_error( - "vote-alias is not supported with this command\n" - "Please use mnbudgetvote instead.\n" - ); - return mnbudgetvote(params, fHelp); - } - - if (strCommand == "projection") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getbudgetprojection(newParams, fHelp); - } - - if (strCommand == "show" || strCommand == "getinfo") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getbudgetinfo(newParams, fHelp); - } - - if (strCommand == "getvotes") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getbudgetvotes(newParams, fHelp); - } - - if (strCommand == "check") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return checkbudgets(newParams, fHelp); - } - - return NullUniValue; -} - UniValue preparebudget(const UniValue& params, bool fHelp) { int nBlockMin = 0; @@ -456,7 +353,7 @@ UniValue mnbudgetvote(const UniValue& params, bool fHelp) } if (strCommand == "many") { - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { std::string errorMessage; std::vector vchMasterNodeSignature; std::string strMasterNodeSignMessage; @@ -527,7 +424,7 @@ UniValue mnbudgetvote(const UniValue& params, bool fHelp) std::vector mnEntries; mnEntries = masternodeConfig.getEntries(); - BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { if( strAlias != mne.getAlias()) continue; @@ -713,7 +610,7 @@ UniValue getbudgetprojection(const UniValue& params, bool fHelp) CAmount nTotalAllotted = 0; std::vector winningProps = budget.GetBudget(); - BOOST_FOREACH (CBudgetProposal* pbudgetProposal, winningProps) { + for (CBudgetProposal* pbudgetProposal : winningProps) { nTotalAllotted += pbudgetProposal->GetAllotted(); CTxDestination address1; @@ -784,7 +681,7 @@ UniValue getbudgetinfo(const UniValue& params, bool fHelp) } std::vector winningProps = budget.GetAllProposals(); - BOOST_FOREACH (CBudgetProposal* pbudgetProposal, winningProps) { + for (CBudgetProposal* pbudgetProposal : winningProps) { if (strShow == "valid" && !pbudgetProposal->fValid) continue; UniValue bObj(UniValue::VOBJ); @@ -890,7 +787,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) UniValue resultsObj(UniValue::VOBJ); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { std::string errorMessage; std::vector vchMasterNodeSignature; std::string strMasterNodeSignMessage; @@ -988,7 +885,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) UniValue resultObj(UniValue::VOBJ); std::vector winningFbs = budget.GetFinalizedBudgets(); - BOOST_FOREACH (CFinalizedBudget* finalizedBudget, winningFbs) { + for (CFinalizedBudget* finalizedBudget : winningFbs) { UniValue bObj(UniValue::VOBJ); bObj.push_back(Pair("FeeTX", finalizedBudget->nFeeTXHash.ToString())); bObj.push_back(Pair("Hash", finalizedBudget->GetHash().ToString())); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index c46e55e2f4022..96719c9519eac 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -8,7 +8,7 @@ #include "rpc/client.h" #include "rpc/protocol.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include @@ -111,10 +111,6 @@ static const CRPCConvertParam vRPCConvertParams[] = {"setban", 2}, {"setban", 3}, {"spork", 1}, - {"mnbudget", 3}, - {"mnbudget", 4}, - {"mnbudget", 6}, - {"mnbudget", 8}, {"preparebudget", 2}, {"preparebudget", 3}, {"preparebudget", 5}, @@ -157,6 +153,9 @@ static const CRPCConvertParam vRPCConvertParams[] = {"getaccumulatorwitness",2}, {"getmintsvalues", 2}, {"getaccumulatorcheckpoints", 0}, + {"getblockindexstats", 0}, + {"getblockindexstats", 1}, + {"getblockindexstats", 2}, {"getmintsinblocks", 0}, {"getmintsinblocks", 1}, {"getmintsinblocks", 2}, diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 9c606124ebcbb..922e0c9ceed90 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -45,147 +45,6 @@ UniValue getpoolinfo(const UniValue& params, bool fHelp) return obj; } -// This command is retained for backwards compatibility, but is depreciated. -// Future removal of this command is planned to keep things clean. -UniValue masternode(const UniValue& params, bool fHelp) -{ - string strCommand; - if (params.size() >= 1) - strCommand = params[0].get_str(); - - if (fHelp || - (strCommand != "start" && strCommand != "start-alias" && strCommand != "start-many" && strCommand != "start-all" && strCommand != "start-missing" && - strCommand != "start-disabled" && strCommand != "list" && strCommand != "list-conf" && strCommand != "count" && strCommand != "enforce" && - strCommand != "debug" && strCommand != "current" && strCommand != "winners" && strCommand != "genkey" && strCommand != "connect" && - strCommand != "outputs" && strCommand != "status" && strCommand != "calcscore")) - throw runtime_error( - "masternode \"command\"...\n" - "\nSet of commands to execute masternode related actions\n" - "This command is depreciated, please see individual command documentation for future reference\n\n" - - "\nArguments:\n" - "1. \"command\" (string or set of strings, required) The command to execute\n" - - "\nAvailable commands:\n" - " count - Print count information of all known masternodes\n" - " current - Print info on current masternode winner\n" - " debug - Print masternode status\n" - " genkey - Generate new masternodeprivkey\n" - " outputs - Print masternode compatible outputs\n" - " start - Start masternode configured in ioncoin.conf\n" - " start-alias - Start single masternode by assigned alias configured in masternode.conf\n" - " start- - Start masternodes configured in masternode.conf (: 'all', 'missing', 'disabled')\n" - " status - Print masternode status information\n" - " list - Print list of all known masternodes (see masternodelist for more info)\n" - " list-conf - Print masternode.conf in JSON format\n" - " winners - Print list of masternode winners\n"); - - if (strCommand == "list") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return listmasternodes(newParams, fHelp); - } - - if (strCommand == "connect") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return masternodeconnect(newParams, fHelp); - } - - if (strCommand == "count") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodecount(newParams, fHelp); - } - - if (strCommand == "current") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return masternodecurrent(newParams, fHelp); - } - - if (strCommand == "debug") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return masternodedebug(newParams, fHelp); - } - - if (strCommand == "start" || strCommand == "start-alias" || strCommand == "start-many" || strCommand == "start-all" || strCommand == "start-missing" || strCommand == "start-disabled") { - return startmasternode(params, fHelp); - } - - if (strCommand == "genkey") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return createmasternodekey(newParams, fHelp); - } - - if (strCommand == "list-conf") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return listmasternodeconf(newParams, fHelp); - } - - if (strCommand == "outputs") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodeoutputs(newParams, fHelp); - } - - if (strCommand == "status") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodestatus(newParams, fHelp); - } - - if (strCommand == "winners") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodewinners(newParams, fHelp); - } - - if (strCommand == "calcscore") { - UniValue newParams(UniValue::VARR); - // forward params but skip command - for (unsigned int i = 1; i < params.size(); i++) { - newParams.push_back(params[i]); - } - return getmasternodescores(newParams, fHelp); - } - - return NullUniValue; -} - UniValue listmasternodes(const UniValue& params, bool fHelp) { std::string strFilter = ""; @@ -229,7 +88,7 @@ UniValue listmasternodes(const UniValue& params, bool fHelp) nHeight = pindex->nHeight; } std::vector > vMasternodeRanks = mnodeman.GetMasternodeRanks(nHeight); - BOOST_FOREACH (PAIRTYPE(int, CMasternode) & s, vMasternodeRanks) { + for (PAIRTYPE(int, CMasternode) & s : vMasternodeRanks) { UniValue obj(UniValue::VOBJ); std::string strVin = s.second.vin.prevout.ToStringShort(); std::string strTxHash = s.second.vin.prevout.hash.ToString(); @@ -471,7 +330,7 @@ UniValue startmasternode (const UniValue& params, bool fHelp) UniValue resultsObj(UniValue::VARR); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { std::string errorMessage; int nIndex; if(!mne.castOutputIndex(nIndex)) @@ -522,7 +381,7 @@ UniValue startmasternode (const UniValue& params, bool fHelp) UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", alias)); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { if (mne.getAlias() == alias) { found = true; std::string errorMessage; @@ -606,7 +465,7 @@ UniValue getmasternodeoutputs (const UniValue& params, bool fHelp) vector possibleCoins = activeMasternode.SelectCoinsMasternode(); UniValue ret(UniValue::VARR); - BOOST_FOREACH (COutput& out, possibleCoins) { + for (COutput& out : possibleCoins) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txhash", out.tx->GetHash().ToString())); obj.push_back(Pair("outputidx", out.i)); @@ -651,7 +510,7 @@ UniValue listmasternodeconf (const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); - BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { int nIndex; if(!mne.castOutputIndex(nIndex)) continue; @@ -787,7 +646,7 @@ UniValue getmasternodewinners (const UniValue& params, bool fHelp) UniValue winner(UniValue::VARR); boost::char_separator sep(","); boost::tokenizer< boost::char_separator > tokens(strPayment, sep); - BOOST_FOREACH (const string& t, tokens) { + for (const string& t : tokens) { UniValue addr(UniValue::VOBJ); std::size_t pos = t.find(":"); std::string strAddress = t.substr(0,pos); @@ -852,7 +711,7 @@ UniValue getmasternodescores (const UniValue& params, bool fHelp) for (int nHeight = chainActive.Tip()->nHeight - nLast; nHeight < chainActive.Tip()->nHeight + 20; nHeight++) { uint256 nHigh = 0; CMasternode* pBestMasternode = NULL; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { + for (CMasternode& mn : vMasternodes) { uint256 n = mn.CalculateScore(1, nHeight - 100); if (n > nHigh) { nHigh = n; @@ -936,7 +795,7 @@ UniValue createmasternodebroadcast(const UniValue& params, bool fHelp) UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", alias)); - BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { if(mne.getAlias() == alias) { found = true; std::string errorMessage; @@ -979,7 +838,7 @@ UniValue createmasternodebroadcast(const UniValue& params, bool fHelp) UniValue resultsObj(UniValue::VARR); - BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { std::string errorMessage; CTxIn vin = CTxIn(uint256S(mne.getTxHash()), uint32_t(atoi(mne.getOutputIndex().c_str()))); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 024509d8456ac..ce73395b8ad62 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -17,6 +17,7 @@ #include "pow.h" #include "rpc/server.h" #include "util.h" +#include "validationinterface.h" #ifdef ENABLE_WALLET #include "wallet/db.h" #include "wallet/wallet.h" @@ -546,7 +547,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) UniValue transactions(UniValue::VARR); map setTxIndex; int i = 0; - BOOST_FOREACH (CTransaction& tx, pblock->vtx) { + for (CTransaction& tx : pblock->vtx) { uint256 txHash = tx.GetHash(); setTxIndex[txHash] = i++; @@ -560,7 +561,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) entry.push_back(Pair("hash", txHash.GetHex())); UniValue deps(UniValue::VARR); - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (setTxIndex.count(in.prevout.hash)) deps.push_back(setTxIndex[in.prevout.hash]); } diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 1ae65b333ee03..ca51f2446a464 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -277,7 +277,7 @@ class DescribeAddressVisitor : public boost::static_visitor obj.push_back(Pair("script", GetTxnOutputType(whichType))); obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); UniValue a(UniValue::VARR); - BOOST_FOREACH (const CTxDestination& addr, addresses) + for (const CTxDestination& addr : addresses) a.push_back(CBitcoinAddress(addr).ToString()); obj.push_back(Pair("addresses", a)); if (whichType == TX_MULTISIG) diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 7680bc8174c73..578dbcd4731e6 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -13,11 +13,10 @@ #include "protocol.h" #include "sync.h" #include "timedata.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "version.h" -#include #include @@ -56,7 +55,7 @@ UniValue ping(const UniValue& params, bool fHelp) // Request that each node send a ping during next message processing pass LOCK2(cs_main, cs_vNodes); - BOOST_FOREACH (CNode* pNode, vNodes) { + for (CNode* pNode : vNodes) { pNode->fPingQueued = true; } @@ -69,7 +68,7 @@ static void CopyNodeStats(std::vector& vstats) LOCK(cs_vNodes); vstats.reserve(vNodes.size()); - BOOST_FOREACH (CNode* pnode, vNodes) { + for (CNode* pnode : vNodes) { CNodeStats stats; pnode->copyStats(stats); vstats.push_back(stats); @@ -123,7 +122,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); - BOOST_FOREACH (const CNodeStats& stats, vstats) { + for (const CNodeStats& stats : vstats) { UniValue obj(UniValue::VOBJ); CNodeStateStats statestats; bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); @@ -153,7 +152,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("synced_headers", statestats.nSyncHeight)); obj.push_back(Pair("synced_blocks", statestats.nCommonHeight)); UniValue heights(UniValue::VARR); - BOOST_FOREACH (int height, statestats.vHeightInFlight) { + for (int height : statestats.vHeightInFlight) { heights.push_back(height); } obj.push_back(Pair("inflight", heights)); @@ -274,12 +273,12 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) list laddedNodes(0); if (params.size() == 1) { LOCK(cs_vAddedNodes); - BOOST_FOREACH (string& strAddNode, vAddedNodes) + for (string& strAddNode : vAddedNodes) laddedNodes.push_back(strAddNode); } else { string strNode = params[1].get_str(); LOCK(cs_vAddedNodes); - BOOST_FOREACH (string& strAddNode, vAddedNodes) + for (string& strAddNode : vAddedNodes) if (strAddNode == strNode) { laddedNodes.push_back(strAddNode); break; @@ -290,7 +289,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); if (!fDns) { - BOOST_FOREACH (string& strAddNode, laddedNodes) { + for (string& strAddNode : laddedNodes) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", strAddNode)); ret.push_back(obj); @@ -299,7 +298,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) } list > > laddedAddreses(0); - BOOST_FOREACH (string& strAddNode, laddedNodes) { + for (string& strAddNode : laddedNodes) { vector vservNode(0); if (Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) laddedAddreses.push_back(make_pair(strAddNode, vservNode)); @@ -319,11 +318,11 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) UniValue addresses(UniValue::VARR); bool fConnected = false; - BOOST_FOREACH (CService& addrNode, it->second) { + for (CService& addrNode : it->second) { bool fFound = false; UniValue node(UniValue::VOBJ); node.push_back(Pair("address", addrNode.ToString())); - BOOST_FOREACH (CNode* pnode, vNodes) + for (CNode* pnode : vNodes) if (pnode->addr == addrNode) { fFound = true; fConnected = true; @@ -439,7 +438,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp) UniValue localAddresses(UniValue::VARR); { LOCK(cs_mapLocalHost); - BOOST_FOREACH (const PAIRTYPE(CNetAddr, LocalServiceInfo) & item, mapLocalHost) { + for (const std::pair &item : mapLocalHost) { UniValue rec(UniValue::VOBJ); rec.push_back(Pair("address", item.first.ToString())); rec.push_back(Pair("port", item.second.nPort)); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 817ee7b47bc1e..984882aa853a0 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -56,7 +56,7 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud out.push_back(Pair("type", GetTxnOutputType(type))); UniValue a(UniValue::VARR); - BOOST_FOREACH (const CTxDestination& addr, addresses) + for (const CTxDestination& addr : addresses) a.push_back(CBitcoinAddress(addr).ToString()); out.push_back(Pair("addresses", a)); } @@ -212,12 +212,12 @@ UniValue listunspent(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 4) throw runtime_error( - "listunspent ( minconf maxconf [\"address\",...] )\n" + "listunspent ( minconf maxconf [\"address\",...] watchonlyconfig )\n" "\nReturns array of unspent transaction outputs\n" "with between minconf and maxconf (inclusive) confirmations.\n" "Optionally filter to only include txouts paid to specified addresses.\n" "Results are an array of Objects, each of which has:\n" - "{txid, vout, scriptPubKey, amount, confirmations}\n" + "{txid, vout, scriptPubKey, amount, confirmations, spendable}\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n" @@ -227,18 +227,20 @@ UniValue listunspent(const UniValue& params, bool fHelp) " \"address\" (string) ion address\n" " ,...\n" " ]\n" - "4. watchonlyconfig (numberic, optional, default=1) 1 = list regular unspent transactions, 2 = list only watchonly transactions, 3 = list all unspent transactions (including watchonly)\n" + "4. watchonlyconfig (numeric, optional, default=1) 1 = list regular unspent transactions, 2 = list only watchonly transactions, 3 = list all unspent transactions (including watchonly)\n" "\nResult\n" "[ (array of json object)\n" " {\n" - " \"txid\" : \"txid\", (string) the transaction id \n" + " \"txid\" : \"txid\", (string) the transaction id\n" " \"vout\" : n, (numeric) the vout value\n" " \"address\" : \"address\", (string) the ion address\n" " \"account\" : \"account\", (string) The associated account, or \"\" for the default account\n" " \"scriptPubKey\" : \"key\", (string) the script key\n" + " \"redeemScript\" : \"key\", (string) the redeemscript key\n" " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n" - " \"confirmations\" : n (numeric) The number of confirmations\n" + " \"confirmations\" : n, (numeric) The number of confirmations\n" + " \"spendable\" : true|false (boolean) Whether we have the private keys to spend this output\n" " }\n" " ,...\n" "]\n" @@ -282,7 +284,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, false, ALL_COINS, false, nWatchonlyConfig); - BOOST_FOREACH (const COutput& out, vecOutputs) { + for (const COutput& out : vecOutputs) { if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) continue; @@ -408,7 +410,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) set setAddress; vector addrList = sendTo.getKeys(); - BOOST_FOREACH(const string& name_, addrList) { + for (const string& name_ : addrList) { CBitcoinAddress address(name_); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid ION address: ")+name_); @@ -652,7 +654,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) CCoinsViewMemPool viewMempool(&viewChain, mempool); view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view - BOOST_FOREACH (const CTxIn& txin, mergedTx.vin) { + for (const CTxIn& txin : mergedTx.vin) { const uint256& prevHash = txin.prevout.hash; CCoins coins; view.AccessCoins(prevHash); // this is certainly allowed to fail @@ -778,7 +780,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); // ... and merge in other signatures: - BOOST_FOREACH (const CMutableTransaction& txv, txVariants) { + for (const CMutableTransaction& txv : txVariants) { txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); } ScriptError serror = SCRIPT_ERR_OK; @@ -902,7 +904,7 @@ UniValue getspentzerocoinamount(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter for transaction input"); const CTxIn& input = tx.vin[inputIndex]; - if (!input.scriptSig.IsZerocoinSpend()) + if (!input.IsZerocoinSpend()) return -1; libzerocoin::CoinSpend spend = TxInToZerocoinSpend(input); @@ -992,4 +994,68 @@ UniValue createrawzerocoinstake(const UniValue& params, bool fHelp) return ret; } + +UniValue createrawzerocoinpublicspend(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "createrawzerocoinpublicspend mint_input \n" + "\nCreates raw xION public spend.\n" + + HelpRequiringPassphrase() + "\n" + + "\nArguments:\n" + "1. mint_input (hex string, required) serial hash of the mint used as input\n" + "2. \"address\" (string, optional, default=change) Send to specified address or to a new change address.\n" + + + "\nResult:\n" + "{\n" + " \"hex\": \"xxx\", (hex string) raw public spend signed transaction\n" + "}\n" + "\nExamples\n" + + HelpExampleCli("createrawzerocoinpublicspend", "0d8c16eee7737e3cc1e4e70dc006634182b175e039700931283b202715a0818f") + + HelpExampleRpc("createrawzerocoinpublicspend", "0d8c16eee7737e3cc1e4e70dc006634182b175e039700931283b202715a0818f")); + + + assert(pwalletMain != NULL); + LOCK2(cs_main, pwalletMain->cs_wallet); + + std::string serial_hash = params[0].get_str(); + if (!IsHex(serial_hash)) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex serial hash"); + + std::string address_str = ""; + CBitcoinAddress address; + CBitcoinAddress* addr_ptr = nullptr; + if (params.size() > 1) { + address_str = params[1].get_str(); + address = CBitcoinAddress(address_str); + if(!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid ION address"); + addr_ptr = &address; + } + + EnsureWalletIsUnlocked(); + + uint256 hashSerial(serial_hash); + CZerocoinMint input_mint; + if (!pwalletMain->GetMint(hashSerial, input_mint)) { + std::string strErr = "Failed to fetch mint associated with serial hash " + serial_hash; + throw JSONRPCError(RPC_WALLET_ERROR, strErr); + } + CAmount nAmount = input_mint.GetDenominationAsAmount(); + vector vMintsSelected = vector(1,input_mint); + + // create the spend + CWalletTx rawTx; + CZerocoinSpendReceipt receipt; + CReserveKey reserveKey(pwalletMain); + vector vNewMints; + if (!pwalletMain->CreateZerocoinSpendTransaction(nAmount, rawTx, reserveKey, receipt, vMintsSelected, vNewMints, false, true, addr_ptr, true)) + throw JSONRPCError(RPC_WALLET_ERROR, receipt.GetStatusMessage()); + + // output the raw transaction + return EncodeHexTx(rawTx); +} #endif + diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 91843a23d761a..2002e87d1204a 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -12,13 +12,12 @@ #include "main.h" #include "random.h" #include "sync.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "utilstrencodings.h" #include #include -#include #include #include #include @@ -75,7 +74,7 @@ void RPCTypeCheck(const UniValue& params, bool fAllowNull) { unsigned int i = 0; - BOOST_FOREACH(UniValue::VType t, typesExpected) { + for (UniValue::VType t : typesExpected) { if (params.size() <= i) break; @@ -93,7 +92,7 @@ void RPCTypeCheckObj(const UniValue& o, const map& typesExpected, bool fAllowNull) { - BOOST_FOREACH(const PAIRTYPE(string, UniValue::VType)& t, typesExpected) { + for (const PAIRTYPE(string, UniValue::VType)& t : typesExpected) { const UniValue& v = find_value(o, t.first); if (!fAllowNull && v.isNull()) throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first)); @@ -200,7 +199,7 @@ string CRPCTable::help(string strCommand) const vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second)); sort(vCommands.begin(), vCommands.end()); - BOOST_FOREACH (const PAIRTYPE(string, const CRPCCommand*) & command, vCommands) { + for (const PAIRTYPE(string, const CRPCCommand*) & command : vCommands) { const CRPCCommand* pcmd = command.second; string strMethod = pcmd->name; // We already filter duplicates, but these deprecated screw up the sort order @@ -306,6 +305,7 @@ static const CRPCCommand vRPCCommands[] = {"blockchain", "getaccumulatorvalues", &getaccumulatorvalues, true, false, false}, {"blockchain", "getaccumulatorcheckpoints", &getaccumulatorcheckpoints, true, false, false}, {"blockchain", "getaccumulatorwitness", &getaccumulatorwitness, true, false, false}, + {"blockchain", "getblockindexstats", &getblockindexstats, true, false, false}, {"blockchain", "getmintsinblocks", &getmintsinblocks, true, false, false}, {"blockchain", "getserials", &getserials, true, false, false}, {"blockchain", "getblockchaininfo", &getblockchaininfo, true, false, false}, @@ -367,7 +367,6 @@ static const CRPCCommand vRPCCommands[] = { "hidden", "waitforblockheight", &waitforblockheight, true, true, false }, /* ION features */ - {"ion", "masternode", &masternode, true, true, false}, {"ion", "listmasternodes", &listmasternodes, true, true, false}, {"ion", "getmasternodecount", &getmasternodecount, true, true, false}, {"ion", "masternodeconnect", &masternodeconnect, true, true, false}, @@ -383,7 +382,6 @@ static const CRPCCommand vRPCCommands[] = {"ion", "getmasternodestatus", &getmasternodestatus, true, true, false}, {"ion", "getmasternodewinners", &getmasternodewinners, true, true, false}, {"ion", "getmasternodescores", &getmasternodescores, true, true, false}, - {"ion", "mnbudget", &mnbudget, true, true, false}, {"ion", "preparebudget", &preparebudget, true, true, false}, {"ion", "submitbudget", &submitbudget, true, true, false}, {"ion", "mnbudgetvote", &mnbudgetvote, true, true, false}, @@ -451,6 +449,7 @@ static const CRPCCommand vRPCCommands[] = {"wallet", "walletpassphrase", &walletpassphrase, true, false, true}, {"zerocoin", "createrawzerocoinstake", &createrawzerocoinstake, false, false, true}, + {"zerocoin", "createrawzerocoinpublicspend", &createrawzerocoinpublicspend, false, false, true}, {"zerocoin", "getzerocoinbalance", &getzerocoinbalance, false, false, true}, {"zerocoin", "listmintedzerocoins", &listmintedzerocoins, false, false, true}, {"zerocoin", "listspentzerocoins", &listspentzerocoins, false, false, true}, diff --git a/src/rpc/server.h b/src/rpc/server.h index de63b50e56b39..1a94a1bc2f0c7 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -179,7 +179,7 @@ extern std::string HelpExampleCli(std::string methodname, std::string args); extern std::string HelpExampleRpc(std::string methodname, std::string args); extern void EnsureWalletIsUnlocked(bool fAllowAnonOnly = false); -extern UniValue DoXionSpend(const CAmount nAmount, bool fMintChange, bool fMinimizeChange, vector& vMintsSelected, std::string address_str); +extern UniValue DoXionSpend(const CAmount nAmount, bool fMintChange, bool fMinimizeChange, vector& vMintsSelected, std::string address_str, bool isPublicSpend = true); extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpc/net.cpp extern UniValue getpeerinfo(const UniValue& params, bool fHelp); @@ -284,6 +284,7 @@ extern UniValue decodescript(const UniValue& params, bool fHelp); extern UniValue signrawtransaction(const UniValue& params, bool fHelp); extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); extern UniValue createrawzerocoinstake(const UniValue& params, bool fHelp); +extern UniValue createrawzerocoinpublicspend(const UniValue& params, bool fHelp); extern UniValue findserial(const UniValue& params, bool fHelp); // in rpc/blockchain.cpp extern UniValue getblockcount(const UniValue& params, bool fHelp); @@ -308,13 +309,14 @@ extern UniValue reconsiderblock(const UniValue& params, bool fHelp); extern UniValue getaccumulatorvalues(const UniValue& params, bool fHelp); extern UniValue getaccumulatorcheckpoints(const UniValue& params, bool fHelp); extern UniValue getaccumulatorwitness(const UniValue& params, bool fHelp); +extern UniValue getblockindexstats(const UniValue& params, bool fHelp); extern UniValue getmintsinblocks(const UniValue& params, bool fHelp); extern UniValue getserials(const UniValue& params, bool fHelp); extern UniValue getchecksumblock(const UniValue& params, bool fHelp); +extern void validaterange(const UniValue& params, int& heightStart, int& heightEnd, int minHeightStart=1); extern UniValue scantxoutset(const UniValue& params, bool fHelp); extern UniValue getpoolinfo(const UniValue& params, bool fHelp); // in rpc/masternode.cpp -extern UniValue masternode(const UniValue& params, bool fHelp); extern UniValue listmasternodes(const UniValue& params, bool fHelp); extern UniValue getmasternodecount(const UniValue& params, bool fHelp); extern UniValue createmasternodebroadcast(const UniValue& params, bool fHelp); @@ -331,8 +333,7 @@ extern UniValue getmasternodestatus(const UniValue& params, bool fHelp); extern UniValue getmasternodewinners(const UniValue& params, bool fHelp); extern UniValue getmasternodescores(const UniValue& params, bool fHelp); -extern UniValue mnbudget(const UniValue& params, bool fHelp); // in rpc/budget.cpp -extern UniValue preparebudget(const UniValue& params, bool fHelp); +extern UniValue preparebudget(const UniValue& params, bool fHelp); // in rpc/budget.cpp extern UniValue submitbudget(const UniValue& params, bool fHelp); extern UniValue mnbudgetvote(const UniValue& params, bool fHelp); extern UniValue getbudgetvotes(const UniValue& params, bool fHelp); diff --git a/src/script/script.cpp b/src/script/script.cpp index 468a0c1d46b01..d314b43917908 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -154,6 +154,7 @@ const char* GetOpName(opcodetype opcode) // zerocoin case OP_ZEROCOINMINT : return "OP_ZEROCOINMINT"; case OP_ZEROCOINSPEND : return "OP_ZEROCOINSPEND"; + case OP_ZEROCOINPUBLICSPEND : return "OP_ZEROCOINPUBLICSPEND"; case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; @@ -248,19 +249,24 @@ bool CScript::IsPayToScriptHash() const this->at(22) == OP_EQUAL); } +bool CScript::StartsWithOpcode(const opcodetype opcode) const +{ + return (!this->empty() && this->at(0) == opcode); +} + bool CScript::IsZerocoinMint() const { - //fast test for Zerocoin Mint CScripts - return (this->size() > 0 && - this->at(0) == OP_ZEROCOINMINT); + return StartsWithOpcode(OP_ZEROCOINMINT); } bool CScript::IsZerocoinSpend() const { - if (this->empty()) - return false; + return StartsWithOpcode(OP_ZEROCOINSPEND); +} - return (this->at(0) == OP_ZEROCOINSPEND); +bool CScript::IsZerocoinPublicSpend() const +{ + return StartsWithOpcode(OP_ZEROCOINPUBLICSPEND); } bool CScript::IsPushOnly(const_iterator pc) const diff --git a/src/script/script.h b/src/script/script.h index d276df42f42ad..a86502e381660 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -171,6 +171,7 @@ enum opcodetype // zerocoin OP_ZEROCOINMINT = 0xc1, OP_ZEROCOINSPEND = 0xc2, + OP_ZEROCOINPUBLICSPEND = 0xc3, // template matching params OP_SMALLINTEGER = 0xfa, @@ -598,8 +599,10 @@ class CScript : public std::vector bool IsNormalPaymentScript() const; bool IsPayToScriptHash() const; + bool StartsWithOpcode(const opcodetype opcode) const; bool IsZerocoinMint() const; bool IsZerocoinSpend() const; + bool IsZerocoinPublicSpend() const; /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly(const_iterator pc) const; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 0e71ff2ea90d2..07e7731c8eaf7 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -13,7 +13,6 @@ #include "uint256.h" #include "util.h" -#include using namespace std; @@ -158,7 +157,7 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutab static CScript PushAll(const vector& values) { CScript result; - BOOST_FOREACH(const valtype& v, values) + for (const valtype& v : values) result << v; return result; } @@ -169,12 +168,12 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& { // Combine all the signatures we've got: set allsigs; - BOOST_FOREACH(const valtype& v, sigs1) + for (const valtype& v : sigs1) { if (!v.empty()) allsigs.insert(v); } - BOOST_FOREACH(const valtype& v, sigs2) + for (const valtype& v : sigs2) { if (!v.empty()) allsigs.insert(v); @@ -185,7 +184,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& unsigned int nSigsRequired = vSolutions.front()[0]; unsigned int nPubKeys = vSolutions.size()-2; map sigs; - BOOST_FOREACH(const valtype& sig, allsigs) + for (const valtype& sig : allsigs) { for (unsigned int i = 0; i < nPubKeys; i++) { diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 64d8af90fe4b9..3d6275f01b22e 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -11,7 +11,6 @@ #include "util.h" #include "utilstrencodings.h" -#include using namespace std; @@ -66,7 +65,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector 150) return false; vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.end()); @@ -86,7 +85,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector& keys) CScript script; script << CScript::EncodeOP_N(nRequired); - BOOST_FOREACH(const CPubKey& key, keys) + for (const CPubKey& key : keys) script << ToByteVector(key); script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG; return script; diff --git a/src/swifttx.cpp b/src/swifttx.cpp index 4789d95505b3a..1dd76b64fcd5a 100644 --- a/src/swifttx.cpp +++ b/src/swifttx.cpp @@ -18,6 +18,7 @@ #include "sync.h" #include "util.h" #include "validationinterface.h" +#include using namespace std; using namespace boost; @@ -61,7 +62,7 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v return; } - BOOST_FOREACH (const CTxOut o, tx.vout) { + for (const CTxOut &o : tx.vout) { // IX supports normal scripts and unspendable scripts (used in DS collateral and Budget collateral). // TODO: Look into other script types that are normal and can be included if (!o.scriptPubKey.IsNormalPaymentScript() && !o.scriptPubKey.IsUnspendable()) { @@ -106,7 +107,7 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str(), tx.GetHash().ToString().c_str()); - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (!mapLockedInputs.count(in.prevout)) { mapLockedInputs.insert(make_pair(in.prevout, tx.GetHash())); } @@ -185,10 +186,10 @@ bool IsIXTXValid(const CTransaction& txCollateral) CAmount nValueOut = 0; bool missingTx = false; - BOOST_FOREACH (const CTxOut o, txCollateral.vout) + for (const CTxOut &o : txCollateral.vout) nValueOut += o.nValue; - BOOST_FOREACH (const CTxIn i, txCollateral.vin) { + for (const CTxIn &i : txCollateral.vin) { CTransaction tx2; uint256 hash; if (GetTransaction(i.prevout.hash, tx2, hash, true)) { @@ -370,7 +371,7 @@ bool ProcessConsensusVote(CNode* pnode, CConsensusVote& ctx) #endif if (mapTxLockReq.count(ctx.txHash)) { - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (!mapLockedInputs.count(in.prevout)) { mapLockedInputs.insert(make_pair(in.prevout, ctx.txHash)); } @@ -402,7 +403,7 @@ bool CheckForConflictingLocks(CTransaction& tx) Blocks could have been rejected during this time, which is OK. After they cancel out, the client will rescan the blocks and find they're acceptable and then take the chain with the most work. */ - BOOST_FOREACH (const CTxIn& in, tx.vin) { + for (const CTxIn& in : tx.vin) { if (mapLockedInputs.count(in.prevout)) { if (mapLockedInputs[in.prevout] != tx.GetHash()) { LogPrintf("SwiftX::CheckForConflictingLocks - found two complete conflicting locks - removing both. %s %s", tx.GetHash().ToString().c_str(), mapLockedInputs[in.prevout].ToString().c_str()); @@ -444,13 +445,13 @@ void CleanTransactionLocksList() if (mapTxLockReq.count(it->second.txHash)) { CTransaction& tx = mapTxLockReq[it->second.txHash]; - BOOST_FOREACH (const CTxIn& in, tx.vin) + for (const CTxIn& in : tx.vin) mapLockedInputs.erase(in.prevout); mapTxLockReq.erase(it->second.txHash); mapTxLockReqRejected.erase(it->second.txHash); - BOOST_FOREACH (CConsensusVote& v, it->second.vecConsensusVotes) + for (CConsensusVote& v : it->second.vecConsensusVotes) mapTxLockVote.erase(v.GetHash()); } @@ -530,7 +531,7 @@ bool CConsensusVote::Sign() bool CTransactionLock::SignaturesValid() { - BOOST_FOREACH (CConsensusVote vote, vecConsensusVotes) { + for (CConsensusVote vote : vecConsensusVotes) { int n = mnodeman.GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight, MIN_SWIFTTX_PROTO_VERSION); if (n == -1) { @@ -567,7 +568,7 @@ int CTransactionLock::CountSignatures() if (nBlockHeight == 0) return -1; int n = 0; - BOOST_FOREACH (CConsensusVote v, vecConsensusVotes) { + for (CConsensusVote v : vecConsensusVotes) { if (v.nBlockHeight == nBlockHeight) { n++; } diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp index 5683a2181d36a..01a91f5198d3c 100644 --- a/src/test/Checkpoints_tests.cpp +++ b/src/test/Checkpoints_tests.cpp @@ -10,12 +10,13 @@ #include "checkpoints.h" #include "uint256.h" +#include "test_ion.h" #include using namespace std; -BOOST_AUTO_TEST_SUITE(Checkpoints_tests) +BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sanity) { diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index f9746fdaa5c65..8b1001603ea5a 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -16,11 +16,12 @@ #include "serialize.h" #include "util.h" +#include "test/test_ion.h" + #include #include // for 'map_list_of()' #include -#include #include // Tests this internal-to-main.cpp method: @@ -41,7 +42,7 @@ CService ip(uint32_t i) return CService(CNetAddr(s), Params().GetDefaultPort()); } -BOOST_AUTO_TEST_SUITE(DoS_tests) +BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) BOOST_AUTO_TEST_CASE(DoS_banning) { diff --git a/src/test/README.md b/src/test/README.md index c5129d2ce86cd..ff0cd97a6cdb2 100644 --- a/src/test/README.md +++ b/src/test/README.md @@ -1,21 +1,57 @@ -# Notes +### Compiling/running unit tests + +Unit tests will be automatically compiled if dependencies were met in `./configure` +and tests weren't explicitly disabled. + +After configuring, they can be run with `make check`. + +To run the iond tests manually, launch `src/test/test_ion`. To recompile +after a test file was modified, run `make` and then run the test again. If you +modify a non-test file, use `make -C src/test` to recompile only what's needed +to run the iond tests. + +To add more iond tests, add `BOOST_AUTO_TEST_CASE` functions to the existing +.cpp files in the `test/` directory or add new .cpp files that +implement new BOOST_FIXTURE_TEST_SUITE sections. + +To run the ion-qt tests manually, launch `src/qt/test/test_ion-qt` + +To add more ion-qt tests, add them to the `src/qt/test/` directory and +the `src/qt/test/test_main.cpp` file. + +### Running individual tests + +test_ion has some built-in command-line arguments; for +example, to run just the getarg_tests verbosely: + + test_ion --log_level=all --run_test=getarg_tests + +... or to run just the doubledash test: + + test_ion --run_test=getarg_tests/doubledash + +Run `test_ion --help` for the full list. + +### Note on adding test cases + The sources in this directory are unit test cases. Boost includes a -unit testing framework, and since bitcoin already uses boost, it makes +unit testing framework, and since ion already uses boost, it makes sense to simply use this framework rather than require developers to configure some other framework (we want as few impediments to creating unit tests as possible). -The build system is setup to compile an executable called "test_ion" +The build system is setup to compile an executable called `test_ion` that runs all of the unit tests. The main source file is called test_ion.cpp, which simply includes other files that contain the actual unit tests (outside of a couple required preprocessor -directives). The pattern is to create one test file for each class or -source file for which you want to create unit tests. The file naming -convention is "_tests.cpp" and such files should wrap -their tests in a test suite called "_tests". For an -examples of this pattern, examine uint160_tests.cpp and -uint256_tests.cpp. +directives). To add a new unit test file to our test suite you need +to add the file to `src/Makefile.test.include`. The pattern is to +create one test file for each class or source file for which you want +to create unit tests. The file naming convention is +`_tests.cpp` and such files should wrap their tests +in a test suite called `_tests`. For an example of +this pattern, examine `uint160_tests.cpp` and `uint256_tests.cpp`. For further reading, I found the following website to be helpful in explaining how the boost unit test framework works: -[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/). \ No newline at end of file +[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://archive.is/dRBGf). diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp index 579da3c1b6287..d0623c0be5de5 100644 --- a/src/test/accounting_tests.cpp +++ b/src/test/accounting_tests.cpp @@ -6,14 +6,15 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" +#include "test/test_ion.h" + #include -#include #include extern CWallet* pwalletMain; -BOOST_AUTO_TEST_SUITE(accounting_tests) +BOOST_FIXTURE_TEST_SUITE(accounting_tests, TestingSetup) static void GetResults(CWalletDB& walletdb, std::map& results) @@ -23,7 +24,7 @@ GetResults(CWalletDB& walletdb, std::map& results) results.clear(); BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK); walletdb.ListAccountCreditDebit("", aes); - BOOST_FOREACH(CAccountingEntry& ae, aes) + for (CAccountingEntry& ae : aes) { results[ae.nOrderPos] = ae; } diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp new file mode 100644 index 0000000000000..2cef8df4b7db8 --- /dev/null +++ b/src/test/addrman_tests.cpp @@ -0,0 +1,520 @@ +// Copyright (c) 2012-2013 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "addrman.h" +#include "test/test_ion.h" +#include +#include +#include // for ReadLE64 + +#include "hash.h" +#include "random.h" + +class CAddrManTest : public CAddrMan +{ + uint64_t state; + +public: + CAddrManTest() + { + state = 1; + } + + //! Ensure that bucket placement is always the same for testing purposes. + void MakeDeterministic() + { + nKey.SetNull(); + seed_insecure_rand(true); + } + + int RandomInt(int nMax) + { + state = ReadLE64((CHashWriter(SER_GETHASH, 0) << state).GetHash().begin()); + return (unsigned int)(state % nMax); + } + + CAddrInfo* Find(const CNetAddr& addr, int* pnId = NULL) + { + return CAddrMan::Find(addr, pnId); + } + + CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = NULL) + { + return CAddrMan::Create(addr, addrSource, pnId); + } + + void Delete(int nId) + { + CAddrMan::Delete(nId); + } +}; + +BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(addrman_simple) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + // Test 1: Does Addrman respond correctly when empty. + BOOST_CHECK(addrman.size() == 0); + CAddrInfo addr_null = addrman.Select(); + BOOST_CHECK(addr_null.ToString() == "[::]:0"); + + // Test 2: Does Addrman::Add work as expected. + CService addr1 = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 1); + CAddrInfo addr_ret1 = addrman.Select(); + BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333"); + + // Test 3: Does IP address deduplication work correctly. + // Expected dup IP should not be added. + CService addr1_dup = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1_dup), source); + BOOST_CHECK(addrman.size() == 1); + + + // Test 5: New table has one addr and we add a diff addr we should + // have two addrs. + CService addr2 = CService("250.1.1.2", 8333); + addrman.Add(CAddress(addr2), source); + BOOST_CHECK(addrman.size() == 2); + + // Test 6: AddrMan::Clear() should empty the new table. + addrman.Clear(); + BOOST_CHECK(addrman.size() == 0); + CAddrInfo addr_null2 = addrman.Select(); + BOOST_CHECK(addr_null2.ToString() == "[::]:0"); +} + +BOOST_AUTO_TEST_CASE(addrman_ports) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + BOOST_CHECK(addrman.size() == 0); + + // Test 7; Addr with same IP but diff port does not replace existing addr. + CService addr1 = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 1); + + CService addr1_port = CService("250.1.1.1", 8334); + addrman.Add(CAddress(addr1_port), source); + BOOST_CHECK(addrman.size() == 1); + CAddrInfo addr_ret2 = addrman.Select(); + BOOST_CHECK(addr_ret2.ToString() == "250.1.1.1:8333"); + + // Test 8: Add same IP but diff port to tried table, it doesn't get added. + // Perhaps this is not ideal behavior but it is the current behavior. + addrman.Good(CAddress(addr1_port)); + BOOST_CHECK(addrman.size() == 1); + bool newOnly = true; + CAddrInfo addr_ret3 = addrman.Select(newOnly); + BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333"); +} + + +BOOST_AUTO_TEST_CASE(addrman_select) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + // Test 9: Select from new with 1 addr in new. + CService addr1 = CService("250.1.1.1", 8333); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 1); + + bool newOnly = true; + CAddrInfo addr_ret1 = addrman.Select(newOnly); + BOOST_CHECK(addr_ret1.ToString() == "250.1.1.1:8333"); + + // Test 10: move addr to tried, select from new expected nothing returned. + addrman.Good(CAddress(addr1)); + BOOST_CHECK(addrman.size() == 1); + CAddrInfo addr_ret2 = addrman.Select(newOnly); + BOOST_CHECK(addr_ret2.ToString() == "[::]:0"); + + CAddrInfo addr_ret3 = addrman.Select(); + BOOST_CHECK(addr_ret3.ToString() == "250.1.1.1:8333"); + + BOOST_CHECK(addrman.size() == 1); + + + // Add three addresses to new table. + CService addr2 = CService("250.3.1.1", 8333); + CService addr3 = CService("250.3.2.2", 9999); + CService addr4 = CService("250.3.3.3", 9999); + + addrman.Add(CAddress(addr2), CService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr3), CService("250.3.1.1", 8333)); + addrman.Add(CAddress(addr4), CService("250.4.1.1", 8333)); + + // Add three addresses to tried table. + CService addr5 = CService("250.4.4.4", 8333); + CService addr6 = CService("250.4.5.5", 7777); + CService addr7 = CService("250.4.6.6", 8333); + + addrman.Add(CAddress(addr5), CService("250.3.1.1", 8333)); + addrman.Good(CAddress(addr5)); + addrman.Add(CAddress(addr6), CService("250.3.1.1", 8333)); + addrman.Good(CAddress(addr6)); + addrman.Add(CAddress(addr7), CService("250.1.1.3", 8333)); + addrman.Good(CAddress(addr7)); + + // Test 11: 6 addrs + 1 addr from last test = 7. + BOOST_CHECK(addrman.size() == 7); + + // Test 12: Select pulls from new and tried regardless of port number. + BOOST_CHECK(addrman.Select().ToString() == "250.4.6.6:8333"); + BOOST_CHECK(addrman.Select().ToString() == "250.3.2.2:9999"); + BOOST_CHECK(addrman.Select().ToString() == "250.3.3.3:9999"); + BOOST_CHECK(addrman.Select().ToString() == "250.4.4.4:8333"); +} + +BOOST_AUTO_TEST_CASE(addrman_new_collisions) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + BOOST_CHECK(addrman.size() == 0); + + for (int i = 1; i < 18; i++) { + CService addr = CService("250.1.1." + boost::to_string(i)); + addrman.Add(CAddress(addr), source); + + //Test 13: No collision in new table yet. + BOOST_CHECK(addrman.size() == i); + } + + //Test 14: new table collision! + CService addr1 = CService("250.1.1.18"); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 17); + + CService addr2 = CService("250.1.1.19"); + addrman.Add(CAddress(addr2), source); + BOOST_CHECK(addrman.size() == 18); +} + +BOOST_AUTO_TEST_CASE(addrman_tried_collisions) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CNetAddr source = CNetAddr("252.2.2.2"); + + BOOST_CHECK(addrman.size() == 0); + + for (int i = 1; i < 80; i++) { + CService addr = CService("250.1.1." + boost::to_string(i)); + addrman.Add(CAddress(addr), source); + addrman.Good(CAddress(addr)); + + //Test 15: No collision in tried table yet. + BOOST_TEST_MESSAGE(addrman.size()); + BOOST_CHECK(addrman.size() == i); + } + + //Test 16: tried table collision! + CService addr1 = CService("250.1.1.80"); + addrman.Add(CAddress(addr1), source); + BOOST_CHECK(addrman.size() == 79); + + CService addr2 = CService("250.1.1.81"); + addrman.Add(CAddress(addr2), source); + BOOST_CHECK(addrman.size() == 80); +} + +BOOST_AUTO_TEST_CASE(addrman_find) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.2.1", 9999)); + CAddress addr3 = CAddress(CService("251.255.2.1", 8333)); + + CNetAddr source1 = CNetAddr("250.1.2.1"); + CNetAddr source2 = CNetAddr("250.1.2.2"); + + addrman.Add(addr1, source1); + addrman.Add(addr2, source2); + addrman.Add(addr3, source1); + + // Test 17: ensure Find returns an IP matching what we searched on. + CAddrInfo* info1 = addrman.Find(addr1); + BOOST_CHECK(info1); + if (info1) + BOOST_CHECK(info1->ToString() == "250.1.2.1:8333"); + + // Test 18; Find does not discriminate by port number. + CAddrInfo* info2 = addrman.Find(addr2); + BOOST_CHECK(info2); + if (info2) + BOOST_CHECK(info2->ToString() == info1->ToString()); + + // Test 19: Find returns another IP matching what we searched on. + CAddrInfo* info3 = addrman.Find(addr3); + BOOST_CHECK(info3); + if (info3) + BOOST_CHECK(info3->ToString() == "251.255.2.1:8333"); +} + +BOOST_AUTO_TEST_CASE(addrman_create) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CNetAddr source1 = CNetAddr("250.1.2.1"); + + int nId; + CAddrInfo* pinfo = addrman.Create(addr1, source1, &nId); + + // Test 20: The result should be the same as the input addr. + BOOST_CHECK(pinfo->ToString() == "250.1.2.1:8333"); + + CAddrInfo* info2 = addrman.Find(addr1); + BOOST_CHECK(info2->ToString() == "250.1.2.1:8333"); +} + + +BOOST_AUTO_TEST_CASE(addrman_delete) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + BOOST_CHECK(addrman.size() == 0); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CNetAddr source1 = CNetAddr("250.1.2.1"); + + int nId; + addrman.Create(addr1, source1, &nId); + + // Test 21: Delete should actually delete the addr. + BOOST_CHECK(addrman.size() == 1); + addrman.Delete(nId); + BOOST_CHECK(addrman.size() == 0); + CAddrInfo* info2 = addrman.Find(addr1); + BOOST_CHECK(info2 == NULL); +} + +BOOST_AUTO_TEST_CASE(addrman_getaddr) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + // Test 22: Sanity check, GetAddr should never return anything if addrman + // is empty. + BOOST_CHECK(addrman.size() == 0); + vector vAddr1 = addrman.GetAddr(); + BOOST_CHECK(vAddr1.size() == 0); + + CAddress addr1 = CAddress(CService("250.250.2.1", 8333)); + addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false + CAddress addr2 = CAddress(CService("250.251.2.2", 9999)); + addr2.nTime = GetAdjustedTime(); + CAddress addr3 = CAddress(CService("251.252.2.3", 8333)); + addr3.nTime = GetAdjustedTime(); + CAddress addr4 = CAddress(CService("252.253.3.4", 8333)); + addr4.nTime = GetAdjustedTime(); + CAddress addr5 = CAddress(CService("252.254.4.5", 8333)); + addr5.nTime = GetAdjustedTime(); + CNetAddr source1 = CNetAddr("250.1.2.1"); + CNetAddr source2 = CNetAddr("250.2.3.3"); + + // Test 23: Ensure GetAddr works with new addresses. + addrman.Add(addr1, source1); + addrman.Add(addr2, source2); + addrman.Add(addr3, source1); + addrman.Add(addr4, source2); + addrman.Add(addr5, source1); + + // GetAddr returns 23% of addresses, 23% of 5 is 1 rounded down. + BOOST_CHECK(addrman.GetAddr().size() == 1); + + // Test 24: Ensure GetAddr works with new and tried addresses. + addrman.Good(CAddress(addr1)); + addrman.Good(CAddress(addr2)); + BOOST_CHECK(addrman.GetAddr().size() == 1); + + // Test 25: Ensure GetAddr still returns 23% when addrman has many addrs. + for (unsigned int i = 1; i < (8 * 256); i++) { + int octet1 = i % 256; + int octet2 = (i / 256) % 256; + int octet3 = (i / (256 * 2)) % 256; + std::string strAddr = boost::to_string(octet1) + "." + boost::to_string(octet2) + "." + boost::to_string(octet3) + ".23"; + CAddress addr = CAddress(CService(strAddr)); + + // Ensure that for all addrs in addrman, isTerrible == false. + addr.nTime = GetAdjustedTime(); + addrman.Add(addr, CNetAddr(strAddr)); + if (i % 8 == 0) + addrman.Good(addr); + } + std::vector vAddr = addrman.GetAddr(); + + size_t percent23 = (addrman.size() * 23) / 100; + BOOST_CHECK(vAddr.size() == percent23); + BOOST_CHECK(vAddr.size() == 461); + // (Addrman.size() < number of addresses added) due to address collisons. + BOOST_CHECK(addrman.size() == 2007); +} + + +BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CAddress addr1 = CAddress(CService("250.1.1.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.1.1", 9999)); + + CNetAddr source1 = CNetAddr("250.1.1.1"); + + + CAddrInfo info1 = CAddrInfo(addr1, source1); + + uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); + uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); + + + BOOST_CHECK(info1.GetTriedBucket(nKey1) == 40); + + // Test 26: Make sure key actually randomizes bucket placement. A fail on + // this test could be a security issue. + BOOST_CHECK(info1.GetTriedBucket(nKey1) != info1.GetTriedBucket(nKey2)); + + // Test 27: Two addresses with same IP but different ports can map to + // different buckets because they have different keys. + CAddrInfo info2 = CAddrInfo(addr2, source1); + + BOOST_CHECK(info1.GetKey() != info2.GetKey()); + BOOST_CHECK(info1.GetTriedBucket(nKey1) != info2.GetTriedBucket(nKey1)); + + std::set buckets; + for (int i = 0; i < 255; i++) { + CAddrInfo infoi = CAddrInfo( + CAddress(CService("250.1.1." + boost::to_string(i))), + CNetAddr("250.1.1." + boost::to_string(i))); + int bucket = infoi.GetTriedBucket(nKey1); + buckets.insert(bucket); + } + // Test 28: IP addresses in the same group (\16 prefix for IPv4) should + // never get more than 8 buckets + BOOST_CHECK(buckets.size() == 8); + + buckets.clear(); + for (int j = 0; j < 255; j++) { + CAddrInfo infoj = CAddrInfo( + CAddress(CService("250." + boost::to_string(j) + ".1.1")), + CNetAddr("250." + boost::to_string(j) + ".1.1")); + int bucket = infoj.GetTriedBucket(nKey1); + buckets.insert(bucket); + } + // Test 29: IP addresses in the different groups should map to more than + // 8 buckets. + BOOST_CHECK(buckets.size() == 160); +} + +BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) +{ + CAddrManTest addrman; + + // Set addrman addr placement to be deterministic. + addrman.MakeDeterministic(); + + CAddress addr1 = CAddress(CService("250.1.2.1", 8333)); + CAddress addr2 = CAddress(CService("250.1.2.1", 9999)); + + CNetAddr source1 = CNetAddr("250.1.2.1"); + + CAddrInfo info1 = CAddrInfo(addr1, source1); + + uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); + uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); + + BOOST_CHECK(info1.GetNewBucket(nKey1) == 786); + + // Test 30: Make sure key actually randomizes bucket placement. A fail on + // this test could be a security issue. + BOOST_CHECK(info1.GetNewBucket(nKey1) != info1.GetNewBucket(nKey2)); + + // Test 31: Ports should not effect bucket placement in the addr + CAddrInfo info2 = CAddrInfo(addr2, source1); + BOOST_CHECK(info1.GetKey() != info2.GetKey()); + BOOST_CHECK(info1.GetNewBucket(nKey1) == info2.GetNewBucket(nKey1)); + + std::set buckets; + for (int i = 0; i < 255; i++) { + CAddrInfo infoi = CAddrInfo( + CAddress(CService("250.1.1." + boost::to_string(i))), + CNetAddr("250.1.1." + boost::to_string(i))); + int bucket = infoi.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 32: IP addresses in the same group (\16 prefix for IPv4) should + // always map to the same bucket. + BOOST_CHECK(buckets.size() == 1); + + buckets.clear(); + for (int j = 0; j < 4 * 255; j++) { + CAddrInfo infoj = CAddrInfo(CAddress( + CService( + boost::to_string(250 + (j / 255)) + "." + boost::to_string(j % 256) + ".1.1")), + CNetAddr("251.4.1.1")); + int bucket = infoj.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 33: IP addresses in the same source groups should map to no more + // than 64 buckets. + BOOST_CHECK(buckets.size() <= 64); + + buckets.clear(); + for (int p = 0; p < 255; p++) { + CAddrInfo infoj = CAddrInfo( + CAddress(CService("250.1.1.1")), + CNetAddr("250." + boost::to_string(p) + ".1.1")); + int bucket = infoj.GetNewBucket(nKey1); + buckets.insert(bucket); + } + // Test 34: IP addresses in the different source groups should map to more + // than 64 buckets. + BOOST_CHECK(buckets.size() > 64); +} +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 4869ba52acceb..c7dd4d3594e30 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -15,10 +15,11 @@ #include "util.h" #include "utilstrencodings.h" +#include "test/test_bitcoin.h" + #include #include -#include #include #if 0 @@ -78,7 +79,7 @@ } #endif -struct ReadAlerts +struct ReadAlerts : public TestingSetup { ReadAlerts() { @@ -118,7 +119,7 @@ BOOST_AUTO_TEST_CASE(AlertApplies) { SetMockTime(11); - BOOST_FOREACH(const CAlert& alert, alerts) + for (const CAlert& alert : alerts) { BOOST_CHECK(alert.CheckSignature()); } @@ -163,7 +164,7 @@ BOOST_AUTO_TEST_CASE(AlertNotify) mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string(); - BOOST_FOREACH(CAlert alert, alerts) + for (CAlert alert : alerts) alert.ProcessAlert(false); std::vector r = read_lines(temp); diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 69888da3dfa01..00c20a869b44a 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -5,10 +5,11 @@ #include "util.h" #include "allocators.h" +#include "test/test_ion.h" #include -BOOST_AUTO_TEST_SUITE(allocator_tests) +BOOST_FIXTURE_TEST_SUITE(allocator_tests, BasicTestingSetup) // Dummy memory page locker for platform independent tests static const void *last_lock_addr, *last_unlock_addr; diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp index 5e97dd335a81d..e297e704a5703 100644 --- a/src/test/arith_uint256_tests.cpp +++ b/src/test/arith_uint256_tests.cpp @@ -13,9 +13,9 @@ #include "arith_uint256.h" #include #include "version.h" +#include "test/test_ion.h" -BOOST_AUTO_TEST_SUITE(arith_uint256_tests) -///BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup) /// Convert vector to arith_uint256, via uint256 blob inline arith_uint256 arith_uint256V(const std::vector& vch) diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index 68617abbdd5f8..4bbc9f103d59e 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -3,10 +3,11 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "utilstrencodings.h" +#include "test/test_ion.h" #include -BOOST_AUTO_TEST_SUITE(base32_tests) +BOOST_FIXTURE_TEST_SUITE(base32_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(base32_testvectors) { diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index ce503187fd795..a1745453f746e 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -14,15 +14,15 @@ #include "uint256.h" #include "util.h" #include "utilstrencodings.h" +#include "test/test_ion.h" -#include #include #include extern UniValue read_json(const std::string& jsondata); -BOOST_AUTO_TEST_SUITE(base58_tests) +BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup) // Goal: test low-level base58 encoding functionality BOOST_AUTO_TEST_CASE(base58_EncodeBase58) diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index f2bf3326ad8d8..e31b19d34950e 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -3,10 +3,11 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "utilstrencodings.h" +#include "test/test_ion.h" #include -BOOST_AUTO_TEST_SUITE(base64_tests) +BOOST_FIXTURE_TEST_SUITE(base64_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(base64_testvectors) { diff --git a/src/test/benchmark_zerocoin.cpp b/src/test/benchmark_zerocoin.cpp index c3aee3e0786ee..2e468778c2788 100644 --- a/src/test/benchmark_zerocoin.cpp +++ b/src/test/benchmark_zerocoin.cpp @@ -25,6 +25,7 @@ #include "libzerocoin/Coin.h" #include "libzerocoin/CoinSpend.h" #include "libzerocoin/Accumulator.h" +#include "test_ion.h" using namespace std; using namespace libzerocoin; @@ -402,7 +403,8 @@ Testb_RunAllTests() cout << ggSuccessfulTests << " out of " << ggNumTests << " tests passed." << endl << endl; delete gg_Params; } -BOOST_AUTO_TEST_SUITE(benchmark_zerocoin) + +BOOST_FIXTURE_TEST_SUITE(benchmark_zerocoin, TestingSetup) BOOST_AUTO_TEST_CASE(benchmark_test) { diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 9cf07fc38cc76..c558ff99f1c79 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -8,6 +8,7 @@ #include "key.h" #include "uint256.h" #include "util.h" +#include "test/test_bitcoin.h" #include #include @@ -82,7 +83,7 @@ void RunTest(const TestVector &test) { CExtPubKey pubkey; key.SetMaster(&seed[0], seed.size()); pubkey = key.Neuter(); - BOOST_FOREACH(const TestDerivation &derive, test.vDerive) { + for (const TestDerivation &derive : test.vDerive) { unsigned char data[74]; key.Encode(data); pubkey.Encode(data); @@ -107,7 +108,7 @@ void RunTest(const TestVector &test) { } } -BOOST_AUTO_TEST_SUITE(bip32_tests) +BOOST_FIXTURE_TEST_SUITE(bip32_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(bip32_test1) { RunTest(test1); diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 3ac5cf1bc8ebb..8c0dc0c04ebb6 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -14,6 +14,7 @@ #include "uint256.h" #include "util.h" #include "utilstrencodings.h" +#include "test/test_ion.h" #include @@ -23,7 +24,7 @@ using namespace std; using namespace boost::tuples; -BOOST_AUTO_TEST_SUITE(bloom_tests) +BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) { diff --git a/src/test/budget_tests.cpp b/src/test/budget_tests.cpp index 14ef683532edb..41c238b1c3a4e 100644 --- a/src/test/budget_tests.cpp +++ b/src/test/budget_tests.cpp @@ -5,10 +5,11 @@ #include "masternode-budget.h" #include "tinyformat.h" #include "utilmoneystr.h" +#include "test_ion.h" #include -BOOST_AUTO_TEST_SUITE(budget_tests) +BOOST_FIXTURE_TEST_SUITE(budget_tests, TestingSetup) void CheckBudgetValue(int nHeight, std::string strNetwork, CAmount nExpectedValue) { diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index 0703414e620e0..13d8a9fe33e28 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -12,6 +12,7 @@ #include "consensus/validation.h" #include "main.h" #include "utiltime.h" +#include "test/test_ion.h" #include @@ -20,7 +21,7 @@ #include -BOOST_AUTO_TEST_SUITE(CheckBlock_tests) +BOOST_FIXTURE_TEST_SUITE(CheckBlock_tests, BasicTestingSetup) bool read_block(const std::string& filename, CBlock& block) { diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 48ea3bd9fa22c..0eb3e7ecef268 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -5,6 +5,7 @@ #include "coins.h" #include "random.h" #include "uint256.h" +#include "test/test_ion.h" #include #include @@ -58,7 +59,7 @@ class CCoinsViewTest : public CCoinsView }; } -BOOST_AUTO_TEST_SUITE(coins_tests) +BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) static const unsigned int NUM_SIMULATION_ITERATIONS = 40000; diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp index bf404cf0cfa82..5f0ad991dd7bf 100644 --- a/src/test/compress_tests.cpp +++ b/src/test/compress_tests.cpp @@ -4,6 +4,7 @@ #include "compressor.h" #include "util.h" +#include "test/test_ion.h" #include @@ -21,7 +22,7 @@ // amounts 50 .. 21000000 #define NUM_MULTIPLES_50BTC 420000 -BOOST_AUTO_TEST_SUITE(compress_tests) +BOOST_FIXTURE_TEST_SUITE(compress_tests, BasicTestingSetup) bool static TestEncode(uint64_t in) { return in == CTxOutCompressor::DecompressAmount(CTxOutCompressor::CompressAmount(in)); diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 26708f5071a37..db144e1936a12 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -11,13 +11,14 @@ #include "crypto/hmac_sha512.h" #include "random.h" #include "utilstrencodings.h" +#include "test/test_ion.h" #include #include #include -BOOST_AUTO_TEST_SUITE(crypto_tests) +BOOST_FIXTURE_TEST_SUITE(crypto_tests, BasicTestingSetup) template void TestVector(const Hasher &h, const In &in, const Out &out) { diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 560404284af44..57b324f6540d7 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -4,15 +4,15 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "util.h" +#include "test/test_ion.h" #include #include #include -#include #include -BOOST_AUTO_TEST_SUITE(getarg_tests) +BOOST_FIXTURE_TEST_SUITE(getarg_tests, BasicTestingSetup) static void ResetArgs(const std::string& strArg) { @@ -25,7 +25,7 @@ static void ResetArgs(const std::string& strArg) // Convert to char*: std::vector vecChar; - BOOST_FOREACH(std::string& s, vecArg) + for (std::string& s : vecArg) vecChar.push_back(s.c_str()); ParseParameters(vecChar.size(), &vecChar[0]); diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index b8e290f071fda..a46be7372998b 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -4,6 +4,7 @@ #include "hash.h" #include "utilstrencodings.h" +#include "test/test_ion.h" #include @@ -11,7 +12,7 @@ using namespace std; -BOOST_AUTO_TEST_SUITE(hash_tests) +BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(murmurhash3) { diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 8764d31c66570..38eec4838bb66 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -12,6 +12,7 @@ #include "uint256.h" #include "util.h" #include "utilstrencodings.h" +#include "test_ion.h" #include #include @@ -60,8 +61,7 @@ void dumpKeyInfo(uint256 privkey) } #endif - -BOOST_AUTO_TEST_SUITE(key_tests) +BOOST_FIXTURE_TEST_SUITE(key_tests, TestingSetup) BOOST_AUTO_TEST_CASE(key_test1) { diff --git a/src/test/libzerocoin_tests.cpp b/src/test/libzerocoin_tests.cpp index 77bde281209b3..6d0ec60d6f9b9 100644 --- a/src/test/libzerocoin_tests.cpp +++ b/src/test/libzerocoin_tests.cpp @@ -24,6 +24,7 @@ #include "libzerocoin/Coin.h" #include "libzerocoin/CoinSpend.h" #include "libzerocoin/Accumulator.h" +#include "test_ion.h" using namespace std; using namespace libzerocoin; @@ -33,16 +34,16 @@ using namespace libzerocoin; #define COLOR_STR_RED "\033[31m" #define TESTS_COINS_TO_ACCUMULATE 10 -#define NON_PRIME_TESTS 100 +#define NON_PRIME_TESTS 100 // Global test counters uint32_t gNumTests = 0; uint32_t gSuccessfulTests = 0; // Proof size -uint32_t gProofSize = 0; -uint32_t gCoinSize = 0; -uint32_t gSerialNumberSize = 0; +uint32_t gProofSize = 0; +uint32_t gCoinSize = 0; +uint32_t gSerialNumberSize = 0; // Global coin array PrivateCoin *gCoins[TESTS_COINS_TO_ACCUMULATE]; @@ -57,42 +58,42 @@ ZerocoinParams *g_Params; void LogTestResult(string testName, bool (*testPtr)()) { - string colorGreen(COLOR_STR_GREEN); - string colorNormal(COLOR_STR_NORMAL); - string colorRed(COLOR_STR_RED); + string colorGreen(COLOR_STR_GREEN); + string colorNormal(COLOR_STR_NORMAL); + string colorRed(COLOR_STR_RED); - cout << "Testing if " << testName << "..." << endl; + cout << "Testing if " << testName << "..." << endl; - bool testResult = testPtr(); + bool testResult = testPtr(); - if (testResult == true) { - cout << "\t" << colorGreen << "[PASS]" << colorNormal << endl; - gSuccessfulTests++; - } else { - cout << colorRed << "\t[FAIL]" << colorNormal << endl; - } + if (testResult == true) { + cout << "\t" << colorGreen << "[PASS]" << colorNormal << endl; + gSuccessfulTests++; + } else { + cout << colorRed << "\t[FAIL]" << colorNormal << endl; + } - gNumTests++; + gNumTests++; } CBigNum GetTestModulus() { - static CBigNum testModulus(0); + static CBigNum testModulus(0); - // TODO: should use a hard-coded RSA modulus for testing - if (!testModulus) { - CBigNum p, q; + // TODO: should use a hard-coded RSA modulus for testing + if (!testModulus) { + CBigNum p, q; - // Note: we are NOT using safe primes for testing because - // they take too long to generate. Don't do this in real - // usage. See the paramgen utility for better code. - p = CBigNum::generatePrime(1024, false); - q = CBigNum::generatePrime(1024, false); - testModulus = p * q; - } + // Note: we are NOT using safe primes for testing because + // they take too long to generate. Don't do this in real + // usage. See the paramgen utility for better code. + p = CBigNum::generatePrime(1024, false); + q = CBigNum::generatePrime(1024, false); + testModulus = p * q; + } - return testModulus; + return testModulus; } ////////// @@ -102,393 +103,393 @@ GetTestModulus() bool Test_GenRSAModulus() { - CBigNum result = GetTestModulus(); - - if (!result) { - return false; - } - else { - return true; - } + CBigNum result = GetTestModulus(); + + if (!result) { + return false; + } + else { + return true; + } } bool Test_CalcParamSizes() { - bool result = true; + bool result = true; #if 0 - uint32_t pLen, qLen; - - try { - calculateGroupParamLengths(4000, 80, &pLen, &qLen); - if (pLen < 1024 || qLen < 256) { - result = false; - } - calculateGroupParamLengths(4000, 96, &pLen, &qLen); - if (pLen < 2048 || qLen < 256) { - result = false; - } - calculateGroupParamLengths(4000, 112, &pLen, &qLen); - if (pLen < 3072 || qLen < 320) { - result = false; - } - calculateGroupParamLengths(4000, 120, &pLen, &qLen); - if (pLen < 3072 || qLen < 320) { - result = false; - } - calculateGroupParamLengths(4000, 128, &pLen, &qLen); - if (pLen < 3072 || qLen < 320) { - result = false; - } - } catch (exception &e) { - result = false; - } + uint32_t pLen, qLen; + + try { + calculateGroupParamLengths(4000, 80, &pLen, &qLen); + if (pLen < 1024 || qLen < 256) { + result = false; + } + calculateGroupParamLengths(4000, 96, &pLen, &qLen); + if (pLen < 2048 || qLen < 256) { + result = false; + } + calculateGroupParamLengths(4000, 112, &pLen, &qLen); + if (pLen < 3072 || qLen < 320) { + result = false; + } + calculateGroupParamLengths(4000, 120, &pLen, &qLen); + if (pLen < 3072 || qLen < 320) { + result = false; + } + calculateGroupParamLengths(4000, 128, &pLen, &qLen); + if (pLen < 3072 || qLen < 320) { + result = false; + } + } catch (exception &e) { + result = false; + } #endif - return result; + return result; } bool Test_GenerateGroupParams() { - uint32_t pLen = 1024, qLen = 256, count; - IntegerGroupParams group; + uint32_t pLen = 1024, qLen = 256, count; + IntegerGroupParams group; - for (count = 0; count < 1; count++) { + for (count = 0; count < 1; count++) { - try { - group = deriveIntegerGroupParams(calculateSeed(GetTestModulus(), "test", ZEROCOIN_DEFAULT_SECURITYLEVEL, "TEST GROUP"), pLen, qLen); - } catch (std::runtime_error e) { - cout << "Caught exception " << e.what() << endl; - return false; - } + try { + group = deriveIntegerGroupParams(calculateSeed(GetTestModulus(), "test", ZEROCOIN_DEFAULT_SECURITYLEVEL, "TEST GROUP"), pLen, qLen); + } catch (std::runtime_error e) { + cout << "Caught exception " << e.what() << endl; + return false; + } - // Now perform some simple tests on the resulting parameters - if ((uint32_t)group.groupOrder.bitSize() < qLen || (uint32_t)group.modulus.bitSize() < pLen) { - return false; - } + // Now perform some simple tests on the resulting parameters + if ((uint32_t)group.groupOrder.bitSize() < qLen || (uint32_t)group.modulus.bitSize() < pLen) { + return false; + } - CBigNum c = group.g.pow_mod(group.groupOrder, group.modulus); - //cout << "g^q mod p = " << c << endl; - if (!(c.isOne())) return false; + CBigNum c = group.g.pow_mod(group.groupOrder, group.modulus); + //cout << "g^q mod p = " << c << endl; + if (!(c.isOne())) return false; - // Try at multiple parameter sizes - pLen = pLen * 1.5; - qLen = qLen * 1.5; - } + // Try at multiple parameter sizes + pLen = pLen * 1.5; + qLen = qLen * 1.5; + } - return true; + return true; } bool Test_ParamGen() { - bool result = true; + bool result = true; - try { - // Instantiating testParams runs the parameter generation code - ZerocoinParams testParams(GetTestModulus(),ZEROCOIN_DEFAULT_SECURITYLEVEL); - } catch (runtime_error e) { - cout << e.what() << endl; - result = false; - } + try { + // Instantiating testParams runs the parameter generation code + ZerocoinParams testParams(GetTestModulus(),ZEROCOIN_DEFAULT_SECURITYLEVEL); + } catch (runtime_error e) { + cout << e.what() << endl; + result = false; + } - return result; + return result; } bool Test_Accumulator() { - // This test assumes a list of coins were generated during - // the Test_MintCoin() test. - if (gCoins[0] == NULL) { - return false; - } - try { - // Accumulate the coin list from first to last into one accumulator + // This test assumes a list of coins were generated during + // the Test_MintCoin() test. + if (gCoins[0] == NULL) { + return false; + } + try { + // Accumulate the coin list from first to last into one accumulator Accumulator accOne(&g_Params->accumulatorParams, CoinDenomination::ZQ_ONE); Accumulator accTwo(&g_Params->accumulatorParams,CoinDenomination::ZQ_ONE); Accumulator accThree(&g_Params->accumulatorParams,CoinDenomination::ZQ_ONE); Accumulator accFour(&g_Params->accumulatorParams,CoinDenomination::ZQ_ONE); - AccumulatorWitness wThree(g_Params, accThree, gCoins[0]->getPublicCoin()); - - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - accOne += gCoins[i]->getPublicCoin(); - accTwo += gCoins[TESTS_COINS_TO_ACCUMULATE - (i+1)]->getPublicCoin(); - accThree += gCoins[i]->getPublicCoin(); - wThree += gCoins[i]->getPublicCoin(); - if(i != 0) { - accFour += gCoins[i]->getPublicCoin(); - } - } - - // Compare the accumulated results - if (accOne.getValue() != accTwo.getValue() || accOne.getValue() != accThree.getValue()) { - cout << "Accumulators don't match" << endl; - return false; - } - - if(accFour.getValue() != wThree.getValue()) { - cout << "Witness math not working," << endl; - return false; - } - - // Verify that the witness is correct - if (!wThree.VerifyWitness(accThree, gCoins[0]->getPublicCoin()) ) { - cout << "Witness not valid" << endl; - return false; - } - - // Serialization test: see if we can serialize the accumulator - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << accOne; - - // Deserialize it into a new object - Accumulator newAcc(g_Params, ss); - - // Compare the results - if (accOne.getValue() != newAcc.getValue()) { - return false; - } - - } catch (runtime_error e) { - return false; - } - - return true; + AccumulatorWitness wThree(g_Params, accThree, gCoins[0]->getPublicCoin()); + + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + accOne += gCoins[i]->getPublicCoin(); + accTwo += gCoins[TESTS_COINS_TO_ACCUMULATE - (i+1)]->getPublicCoin(); + accThree += gCoins[i]->getPublicCoin(); + wThree += gCoins[i]->getPublicCoin(); + if(i != 0) { + accFour += gCoins[i]->getPublicCoin(); + } + } + + // Compare the accumulated results + if (accOne.getValue() != accTwo.getValue() || accOne.getValue() != accThree.getValue()) { + cout << "Accumulators don't match" << endl; + return false; + } + + if(accFour.getValue() != wThree.getValue()) { + cout << "Witness math not working," << endl; + return false; + } + + // Verify that the witness is correct + if (!wThree.VerifyWitness(accThree, gCoins[0]->getPublicCoin()) ) { + cout << "Witness not valid" << endl; + return false; + } + + // Serialization test: see if we can serialize the accumulator + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << accOne; + + // Deserialize it into a new object + Accumulator newAcc(g_Params, ss); + + // Compare the results + if (accOne.getValue() != newAcc.getValue()) { + return false; + } + + } catch (runtime_error e) { + return false; + } + + return true; } bool Test_EqualityPoK() { - // Run this test 10 times - for (uint32_t i = 0; i < 10; i++) { - try { - // Generate a random integer "val" - CBigNum val = CBigNum::randBignum(g_Params->coinCommitmentGroup.groupOrder); - - // Manufacture two commitments to "val", both - // under different sets of parameters - Commitment one(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, val); - - Commitment two(&g_Params->serialNumberSoKCommitmentGroup, val); - - // Now generate a proof of knowledge that "one" and "two" are - // both commitments to the same value - CommitmentProofOfKnowledge pok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, - &g_Params->serialNumberSoKCommitmentGroup, - one, two); - - // Serialize the proof into a stream - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << pok; - - // Deserialize back into a PoK object - CommitmentProofOfKnowledge newPok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, - &g_Params->serialNumberSoKCommitmentGroup, - ss); - - if (newPok.Verify(one.getCommitmentValue(), two.getCommitmentValue()) != true) { - return false; - } - - // Just for fun, deserialize the proof a second time - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << pok; - - // This time tamper with it, then deserialize it back into a PoK - ss2[15] = 0; - CommitmentProofOfKnowledge newPok2(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, - &g_Params->serialNumberSoKCommitmentGroup, - ss2); - - // If the tampered proof verifies, that's a failure! - if (newPok2.Verify(one.getCommitmentValue(), two.getCommitmentValue()) == true) { - return false; - } - - } catch (runtime_error &e) { - return false; - } - } - - return true; + // Run this test 10 times + for (uint32_t i = 0; i < 10; i++) { + try { + // Generate a random integer "val" + CBigNum val = CBigNum::randBignum(g_Params->coinCommitmentGroup.groupOrder); + + // Manufacture two commitments to "val", both + // under different sets of parameters + Commitment one(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, val); + + Commitment two(&g_Params->serialNumberSoKCommitmentGroup, val); + + // Now generate a proof of knowledge that "one" and "two" are + // both commitments to the same value + CommitmentProofOfKnowledge pok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, + &g_Params->serialNumberSoKCommitmentGroup, + one, two); + + // Serialize the proof into a stream + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << pok; + + // Deserialize back into a PoK object + CommitmentProofOfKnowledge newPok(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, + &g_Params->serialNumberSoKCommitmentGroup, + ss); + + if (newPok.Verify(one.getCommitmentValue(), two.getCommitmentValue()) != true) { + return false; + } + + // Just for fun, deserialize the proof a second time + CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); + ss2 << pok; + + // This time tamper with it, then deserialize it back into a PoK + ss2[15] = 0; + CommitmentProofOfKnowledge newPok2(&g_Params->accumulatorParams.accumulatorPoKCommitmentGroup, + &g_Params->serialNumberSoKCommitmentGroup, + ss2); + + // If the tampered proof verifies, that's a failure! + if (newPok2.Verify(one.getCommitmentValue(), two.getCommitmentValue()) == true) { + return false; + } + + } catch (runtime_error &e) { + return false; + } + } + + return true; } bool Test_MintCoin() { - gCoinSize = 0; + gCoinSize = 0; - try { - // Generate a list of coins - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + try { + // Generate a list of coins + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { gCoins[i] = new PrivateCoin(g_Params,libzerocoin::CoinDenomination::ZQ_ONE); - PublicCoin pc = gCoins[i]->getPublicCoin(); - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << pc; - gCoinSize += ss.size(); - } + PublicCoin pc = gCoins[i]->getPublicCoin(); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << pc; + gCoinSize += ss.size(); + } - gCoinSize /= TESTS_COINS_TO_ACCUMULATE; + gCoinSize /= TESTS_COINS_TO_ACCUMULATE; - } catch (exception &e) { - return false; - } + } catch (exception &e) { + return false; + } - return true; + return true; } bool Test_InvalidCoin() { - CBigNum coinValue; - - try { - // Pick a random non-prime CBigNum - for (uint32_t i = 0; i < NON_PRIME_TESTS; i++) { - coinValue = CBigNum::randBignum(g_Params->coinCommitmentGroup.modulus); - coinValue = coinValue * 2; - if (!coinValue.isPrime()) break; - } - - PublicCoin pubCoin(g_Params); - if (pubCoin.validate()) { - // A blank coin should not be valid! - return false; - } - - PublicCoin pubCoin2(g_Params, coinValue, ZQ_ONE); - if (pubCoin2.validate()) { - // A non-prime coin should not be valid! - return false; - } - - PublicCoin pubCoin3 = pubCoin2; - if (pubCoin2.validate()) { - // A copy of a non-prime coin should not be valid! - return false; - } - - // Serialize and deserialize the coin - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << pubCoin; - PublicCoin pubCoin4(g_Params, ss); - if (pubCoin4.validate()) { - // A deserialized copy of a non-prime coin should not be valid! - return false; - } - - } catch (runtime_error &e) { - cout << "Caught exception: " << e.what() << endl; - return false; - } - - return true; + CBigNum coinValue; + + try { + // Pick a random non-prime CBigNum + for (uint32_t i = 0; i < NON_PRIME_TESTS; i++) { + coinValue = CBigNum::randBignum(g_Params->coinCommitmentGroup.modulus); + coinValue = coinValue * 2; + if (!coinValue.isPrime()) break; + } + + PublicCoin pubCoin(g_Params); + if (pubCoin.validate()) { + // A blank coin should not be valid! + return false; + } + + PublicCoin pubCoin2(g_Params, coinValue, ZQ_ONE); + if (pubCoin2.validate()) { + // A non-prime coin should not be valid! + return false; + } + + PublicCoin pubCoin3 = pubCoin2; + if (pubCoin2.validate()) { + // A copy of a non-prime coin should not be valid! + return false; + } + + // Serialize and deserialize the coin + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << pubCoin; + PublicCoin pubCoin4(g_Params, ss); + if (pubCoin4.validate()) { + // A deserialized copy of a non-prime coin should not be valid! + return false; + } + + } catch (runtime_error &e) { + cout << "Caught exception: " << e.what() << endl; + return false; + } + + return true; } bool Test_MintAndSpend() { - try { - // This test assumes a list of coins were generated in Test_MintCoin() - if (gCoins[0] == NULL) - { - // No coins: mint some. - Test_MintCoin(); - if (gCoins[0] == NULL) { - return false; - } - } - - // Accumulate the list of generated coins into a fresh accumulator. - // The first one gets marked as accumulated for a witness, the - // others just get accumulated normally. + try { + // This test assumes a list of coins were generated in Test_MintCoin() + if (gCoins[0] == NULL) + { + // No coins: mint some. + Test_MintCoin(); + if (gCoins[0] == NULL) { + return false; + } + } + + // Accumulate the list of generated coins into a fresh accumulator. + // The first one gets marked as accumulated for a witness, the + // others just get accumulated normally. Accumulator acc(&g_Params->accumulatorParams,CoinDenomination::ZQ_ONE); - AccumulatorWitness wAcc(g_Params, acc, gCoins[0]->getPublicCoin()); + AccumulatorWitness wAcc(g_Params, acc, gCoins[0]->getPublicCoin()); - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - acc += gCoins[i]->getPublicCoin(); - wAcc +=gCoins[i]->getPublicCoin(); - } + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + acc += gCoins[i]->getPublicCoin(); + wAcc +=gCoins[i]->getPublicCoin(); + } - // Now spend the coin - //SpendMetaData m(1,1); - CDataStream cc(SER_NETWORK, PROTOCOL_VERSION); - cc << *gCoins[0]; - PrivateCoin myCoin(g_Params,cc); + // Now spend the coin + //SpendMetaData m(1,1); + CDataStream cc(SER_NETWORK, PROTOCOL_VERSION); + cc << *gCoins[0]; + PrivateCoin myCoin(g_Params,cc); - CoinSpend spend(g_Params, g_Params, myCoin, acc, 0, wAcc, 0, SpendType::SPEND); + CoinSpend spend(g_Params, g_Params, myCoin, acc, 0, wAcc, 0, SpendType::SPEND); spend.Verify(acc); - // Serialize the proof and deserialize into newSpend - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << spend; - gProofSize = ss.size(); - CoinSpend newSpend(g_Params, g_Params, ss); - - // See if we can verify the deserialized proof (return our result) - bool ret = newSpend.Verify(acc); - - // Extract the serial number - CBigNum serialNumber = newSpend.getCoinSerialNumber(); - gSerialNumberSize = ceil((double)serialNumber.bitSize() / 8.0); - - return ret; - } catch (runtime_error &e) { - cout << e.what() << endl; - return false; - } - - return false; + // Serialize the proof and deserialize into newSpend + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << spend; + gProofSize = ss.size(); + CoinSpend newSpend(g_Params, g_Params, ss); + + // See if we can verify the deserialized proof (return our result) + bool ret = newSpend.Verify(acc); + + // Extract the serial number + CBigNum serialNumber = newSpend.getCoinSerialNumber(); + gSerialNumberSize = ceil((double)serialNumber.bitSize() / 8.0); + + return ret; + } catch (runtime_error &e) { + cout << e.what() << endl; + return false; + } + + return false; } void Test_RunAllTests() { - // Make a new set of parameters from a random RSA modulus - g_Params = new ZerocoinParams(GetTestModulus()); - - gNumTests = gSuccessfulTests = gProofSize = 0; - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - gCoins[i] = NULL; - } - - // Run through all of the Zerocoin tests - LogTestResult("an RSA modulus can be generated", Test_GenRSAModulus); - LogTestResult("parameter sizes are correct", Test_CalcParamSizes); - LogTestResult("group/field parameters can be generated", Test_GenerateGroupParams); - LogTestResult("parameter generation is correct", Test_ParamGen); - LogTestResult("coins can be minted", Test_MintCoin); - LogTestResult("invalid coins will be rejected", Test_InvalidCoin); - LogTestResult("the accumulator works", Test_Accumulator); - LogTestResult("the commitment equality PoK works", Test_EqualityPoK); - LogTestResult("a minted coin can be spent", Test_MintAndSpend); - - cout << endl << "Average coin size is " << gCoinSize << " bytes." << endl; - cout << "Serial number size is " << gSerialNumberSize << " bytes." << endl; - cout << "Spend proof size is " << gProofSize << " bytes." << endl; - - // Summarize test results - if (gSuccessfulTests < gNumTests) { - cout << endl << "ERROR: SOME TESTS FAILED" << endl; - } - - // Clear any generated coins - for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { - delete gCoins[i]; - } - - cout << endl << gSuccessfulTests << " out of " << gNumTests << " tests passed." << endl << endl; - delete g_Params; + // Make a new set of parameters from a random RSA modulus + g_Params = new ZerocoinParams(GetTestModulus()); + + gNumTests = gSuccessfulTests = gProofSize = 0; + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + gCoins[i] = NULL; + } + + // Run through all of the Zerocoin tests + LogTestResult("an RSA modulus can be generated", Test_GenRSAModulus); + LogTestResult("parameter sizes are correct", Test_CalcParamSizes); + LogTestResult("group/field parameters can be generated", Test_GenerateGroupParams); + LogTestResult("parameter generation is correct", Test_ParamGen); + LogTestResult("coins can be minted", Test_MintCoin); + LogTestResult("invalid coins will be rejected", Test_InvalidCoin); + LogTestResult("the accumulator works", Test_Accumulator); + LogTestResult("the commitment equality PoK works", Test_EqualityPoK); + LogTestResult("a minted coin can be spent", Test_MintAndSpend); + + cout << endl << "Average coin size is " << gCoinSize << " bytes." << endl; + cout << "Serial number size is " << gSerialNumberSize << " bytes." << endl; + cout << "Spend proof size is " << gProofSize << " bytes." << endl; + + // Summarize test results + if (gSuccessfulTests < gNumTests) { + cout << endl << "ERROR: SOME TESTS FAILED" << endl; + } + + // Clear any generated coins + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + delete gCoins[i]; + } + + cout << endl << gSuccessfulTests << " out of " << gNumTests << " tests passed." << endl << endl; + delete g_Params; } -BOOST_AUTO_TEST_SUITE(libzerocoin) +BOOST_FIXTURE_TEST_SUITE(libzerocoin, TestingSetup) BOOST_AUTO_TEST_CASE(libzerocoin_tests) { - cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " test utility." << endl << endl; - - Test_RunAllTests(); + cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " test utility." << endl << endl; + + Test_RunAllTests(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index 6397bc04fc51a..770d1240c8d6d 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -7,10 +7,11 @@ #include "primitives/transaction.h" #include "main.h" +#include "test_ion.h" #include -BOOST_AUTO_TEST_SUITE(main_tests) +BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup) CAmount nMoneySupplyPoWEnd = 16629951 * COIN; diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index c7f60b68514ee..5657aee510b14 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -11,9 +11,11 @@ #include "uint256.h" #include "util.h" +#include "test/test_bitcoin.h" + #include -BOOST_AUTO_TEST_SUITE(miner_tests) +BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup) static struct { @@ -260,7 +262,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) SetMockTime(0); mempool.clear(); - BOOST_FOREACH(CTransaction *tx, txFirst) + for (CTransaction *tx : txFirst) delete tx; Checkpoints::fEnabled = true; diff --git a/src/test/mruset_tests.cpp b/src/test/mruset_tests.cpp index 547cd1090c581..346772a8d3af3 100644 --- a/src/test/mruset_tests.cpp +++ b/src/test/mruset_tests.cpp @@ -6,6 +6,7 @@ #include "random.h" #include "util.h" +#include "test/test_ion.h" #include @@ -34,7 +35,7 @@ class mrutester } }; -BOOST_AUTO_TEST_SUITE(mruset_tests) +BOOST_FIXTURE_TEST_SUITE(mruset_tests, BasicTestingSetup) // Test that an mruset behaves like a set, as long as no more than MAX_SIZE elements are in it BOOST_AUTO_TEST_CASE(mruset_like_set) diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 9caab9ddd9f16..b5e1e28cb3be0 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -10,13 +10,13 @@ #include "script/interpreter.h" #include "script/sign.h" #include "uint256.h" +#include "test_ion.h" #ifdef ENABLE_WALLET #include "wallet/wallet_ismine.h" #endif #include -#include #include using namespace std; @@ -24,7 +24,7 @@ using namespace boost::assign; typedef vector valtype; -BOOST_AUTO_TEST_SUITE(multisig_tests) +BOOST_FIXTURE_TEST_SUITE(multisig_tests, TestingSetup) CScript sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, int whichIn) @@ -33,7 +33,7 @@ sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, CScript result; result << OP_0; // CHECKMULTISIG bug workaround - BOOST_FOREACH(const CKey &key, keys) + for (const CKey &key : keys) { vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 49e7a341f5e7f..5b6ef48b3e0ff 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -5,6 +5,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "netbase.h" +#include "test/test_ion.h" #include @@ -12,7 +13,7 @@ using namespace std; -BOOST_AUTO_TEST_SUITE(netbase_tests) +BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(netbase_networks) { diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index f2ff5dea6a4e5..7b40eff7c7d8f 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -8,6 +8,8 @@ #include "streams.h" #include "uint256.h" #include "version.h" +#include "random.h" +#include "test/test_ion.h" #include @@ -27,7 +29,7 @@ class CPartialMerkleTreeTester : public CPartialMerkleTree } }; -BOOST_AUTO_TEST_SUITE(pmt_tests) +BOOST_FIXTURE_TEST_SUITE(pmt_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(pmt_test1) { diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 0ac142dab4b18..1e7b0c04a0675 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -10,6 +10,8 @@ #include "netbase.h" #include "util.h" +#include "test/test_ion.h" + #include #include @@ -47,7 +49,7 @@ UniValue CallRPC(string args) } } -BOOST_AUTO_TEST_SUITE(rpc_tests) +BOOST_FIXTURE_TEST_SUITE(rpc_tests, TestingSetup) BOOST_AUTO_TEST_CASE(rpc_rawparams) { diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 861641c4de50f..6dfa5ac9079f1 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -9,6 +9,8 @@ #include "base58.h" #include "wallet/wallet.h" +#include "test/test_ion.h" + #include #include @@ -21,7 +23,7 @@ extern UniValue CallRPC(string args); extern CWallet* pwalletMain; -BOOST_AUTO_TEST_SUITE(rpc_wallet_tests) +BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, TestingSetup) BOOST_AUTO_TEST_CASE(rpc_addmultisig) { diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp index 464a8fbb8cfb7..c358b635f277c 100644 --- a/src/test/sanity_tests.cpp +++ b/src/test/sanity_tests.cpp @@ -4,9 +4,11 @@ #include "compat/sanity.h" #include "key.h" +#include "test_ion.h" #include -BOOST_AUTO_TEST_SUITE(sanity_tests) + +BOOST_FIXTURE_TEST_SUITE(sanity_tests, TestingSetup) BOOST_AUTO_TEST_CASE(basic_sanity) { diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 369093a12b46d..7ac29949fa410 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -8,6 +8,7 @@ #include "script/script.h" #include "script/script_error.h" #include "script/sign.h" +#include "test_ion.h" #ifdef ENABLE_WALLET #include "wallet/wallet_ismine.h" @@ -46,8 +47,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err); } - -BOOST_AUTO_TEST_SUITE(script_P2SH_tests) +BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, TestingSetup) BOOST_AUTO_TEST_CASE(sign) { diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index a344dcddac97e..1a108f39e57f3 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -15,6 +15,7 @@ #include "script/script_error.h" #include "script/sign.h" #include "util.h" +#include "test_ion.h" #if defined(HAVE_CONSENSUS_LIB) #include "script/bitcoinconsensus.h" @@ -31,7 +32,6 @@ #include #include #include -#include #include #include @@ -60,7 +60,7 @@ read_json(const std::string& jsondata) return v.get_array(); } -BOOST_AUTO_TEST_SUITE(script_tests) +BOOST_FIXTURE_TEST_SUITE(script_tests, TestingSetup) CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey) { @@ -587,7 +587,7 @@ BOOST_AUTO_TEST_CASE(script_build) std::string strGood; std::string strBad; - BOOST_FOREACH(TestBuilder& test, good) { + for (TestBuilder& test : good) { test.Test(true); std::string str = test.GetJSON().write(); #ifndef UPDATE_JSON_TESTS @@ -597,7 +597,7 @@ BOOST_AUTO_TEST_CASE(script_build) #endif strGood += str + ",\n"; } - BOOST_FOREACH(TestBuilder& test, bad) { + for (TestBuilder& test : bad) { test.Test(false); std::string str = test.GetJSON().write(); #ifndef UPDATE_JSON_TESTS @@ -717,7 +717,7 @@ sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transac // and vice-versa) // result << OP_0; - BOOST_FOREACH(const CKey &key, keys) + for (const CKey &key : keys) { vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); @@ -831,7 +831,7 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); -} +} BOOST_AUTO_TEST_CASE(script_combineSigs) { diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp index 0e0c778262d13..d8c82d029eccd 100644 --- a/src/test/scriptnum_tests.cpp +++ b/src/test/scriptnum_tests.cpp @@ -5,10 +5,13 @@ #include "libzerocoin/bignum.h" #include "script/script.h" +#include "test/test_ion.h" + #include #include #include -BOOST_AUTO_TEST_SUITE(scriptnum_tests) + +BOOST_FIXTURE_TEST_SUITE(scriptnum_tests, BasicTestingSetup) static const long values[] = \ { 0, 1, CHAR_MIN, CHAR_MAX, UCHAR_MAX, SHRT_MIN, USHRT_MAX, INT_MIN, INT_MAX, static_castUINT_MAX, LONG_MIN, LONG_MAX }; diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 59e95f2fd1235..1e14d0e856d52 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -4,6 +4,8 @@ #include "serialize.h" #include "streams.h" +#include "hash.h" +#include "test/test_ion.h" #include @@ -11,7 +13,7 @@ using namespace std; -BOOST_AUTO_TEST_SUITE(serialize_tests) +BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(varints) { @@ -70,8 +72,8 @@ static bool isCanonicalException(const std::ios_base::failure& ex) // The string returned by what() can be different for different platforms. // Instead of directly comparing the ex.what() with an expected string, - // create an instance of exception to see if ex.what() matches - // the expected explanatory string returned by the exception instance. + // create an instance of exception to see if ex.what() matches + // the expected explanatory string returned by the exception instance. return strcmp(expectedException.what(), ex.what()) == 0; } diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 7feb77ff9b41a..7fc5032915229 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -12,6 +12,7 @@ #include "serialize.h" #include "util.h" #include "version.h" +#include "test_ion.h" #include @@ -114,7 +115,7 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) { } } -BOOST_AUTO_TEST_SUITE(sighash_tests) +BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sighash_test) { diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index f56008d9af3ae..21ded6762fa63 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -8,10 +8,10 @@ #include "script/script.h" #include "script/standard.h" #include "uint256.h" +#include "test_ion.h" #include -#include #include using namespace std; @@ -24,7 +24,7 @@ Serialize(const CScript& s) return sSerialized; } -BOOST_AUTO_TEST_SUITE(sigopcount_tests) +BOOST_FIXTURE_TEST_SUITE(sigopcount_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(GetSigOpCount) { diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index 6644722bf0c1b..65c2319b57d1f 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -6,6 +6,7 @@ #include "main.h" #include "random.h" #include "util.h" +#include "test/test_ion.h" #include @@ -13,7 +14,7 @@ #define SKIPLIST_LENGTH 300000 -BOOST_AUTO_TEST_SUITE(skiplist_tests) +BOOST_FIXTURE_TEST_SUITE(skiplist_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(skiplist_test) { diff --git a/src/test/test_ion.cpp b/src/test/test_ion.cpp index 7609d36eb7a8f..8c04c3270a0be 100644 --- a/src/test/test_ion.cpp +++ b/src/test/test_ion.cpp @@ -5,19 +5,19 @@ #define BOOST_TEST_MODULE Ion Test Suite +#include "test_ion.h" + #include "main.h" #include "random.h" #include "txdb.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #ifdef ENABLE_WALLET #include "wallet/db.h" #include "wallet/wallet.h" #endif -#include #include -#include CClientUIInterface uiInterface; CWallet* pwalletMain; @@ -25,21 +25,25 @@ CWallet* pwalletMain; extern bool fPrintToConsole; extern void noui_connect(); -struct TestingSetup { - boost::filesystem::path pathTemp; - boost::thread_group threadGroup; - ECCVerifyHandle globalVerifyHandle; - - TestingSetup() { +BasicTestingSetup::BasicTestingSetup() +{ ECC_Start(); SetupEnvironment(); fPrintToDebugLog = false; // don't want to write to debug.log file fCheckBlockIndex = true; SelectParams(CBaseChainParams::UNITTEST); - noui_connect(); +} +BasicTestingSetup::~BasicTestingSetup() +{ + ECC_Stop(); +} + +TestingSetup::TestingSetup() +{ #ifdef ENABLE_WALLET bitdb.MakeMock(); #endif + ClearDatadirCache(); pathTemp = GetTempPath() / strprintf("test_ion_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); boost::filesystem::create_directories(pathTemp); mapArgs["-datadir"] = pathTemp.string(); @@ -57,28 +61,28 @@ struct TestingSetup { for (int i=0; i < nScriptCheckThreads-1; i++) threadGroup.create_thread(&ThreadScriptCheck); RegisterNodeSignals(GetNodeSignals()); - } - ~TestingSetup() - { +} + +TestingSetup::~TestingSetup() +{ + UnregisterNodeSignals(GetNodeSignals()); threadGroup.interrupt_all(); threadGroup.join_all(); - UnregisterNodeSignals(GetNodeSignals()); #ifdef ENABLE_WALLET + UnregisterValidationInterface(pwalletMain); delete pwalletMain; pwalletMain = NULL; #endif + UnloadBlockIndex(); pcoinsTip.reset(); pcoinsdbview.reset(); pblocktree.reset(); #ifdef ENABLE_WALLET bitdb.Flush(true); + bitdb.Reset(); #endif boost::filesystem::remove_all(pathTemp); - ECC_Stop(); - } -}; - -BOOST_GLOBAL_FIXTURE(TestingSetup); +} void Shutdown(void* parg) { diff --git a/src/test/test_ion.h b/src/test/test_ion.h new file mode 100644 index 0000000000000..a254f98cb8017 --- /dev/null +++ b/src/test/test_ion.h @@ -0,0 +1,30 @@ +#ifndef ION_TEST_TEST_ION_H +#define ION_TEST_TEST_ION_H + +#include "txdb.h" + +#include +#include + +/** Basic testing setup. + * This just configures logging and chain parameters. + */ +struct BasicTestingSetup { + BasicTestingSetup(); + ~BasicTestingSetup(); +}; + +/** Testing setup that configures a complete environment. + * Included are data directory, coins database, script check threads + * and wallet (if enabled) setup. + */ +struct TestingSetup: public BasicTestingSetup { + boost::filesystem::path pathTemp; + boost::thread_group threadGroup; + ECCVerifyHandle globalVerifyHandle; + + TestingSetup(); + ~TestingSetup(); +}; + +#endif diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp index 0327006f5f2b6..3171d71cf2d3b 100644 --- a/src/test/timedata_tests.cpp +++ b/src/test/timedata_tests.cpp @@ -3,12 +3,13 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "timedata.h" +#include "test/test_ion.h" #include using namespace std; -BOOST_AUTO_TEST_SUITE(timedata_tests) +BOOST_FIXTURE_TEST_SUITE(timedata_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(util_MedianFilter) { diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index a0e7f618da5e1..a56396df77c90 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -15,6 +15,7 @@ #include "script/script.h" #include "script/script_error.h" #include "core_io.h" +#include "test_ion.h" #include #include @@ -55,7 +56,7 @@ unsigned int ParseScriptFlags(string strFlags) vector words; split(words, strFlags, is_any_of(",")); - BOOST_FOREACH(string word, words) + for (string word : words) { if (!mapFlagNames.count(word)) BOOST_ERROR("Bad test: unknown verification flag '" << word << "'"); @@ -81,7 +82,7 @@ string FormatScriptFlags(unsigned int flags) return ret.substr(0, ret.size() - 1); } -BOOST_AUTO_TEST_SUITE(transaction_tests) +BOOST_FIXTURE_TEST_SUITE(transaction_tests, TestingSetup) /* DISABLE AS NOT WORKING - **TODO** - fix it BOOST_AUTO_TEST_CASE(tx_valid) diff --git a/src/test/tutorial_zerocoin.cpp b/src/test/tutorial_zerocoin.cpp index 5e86340ffbbd9..0801aa4fd0e2b 100644 --- a/src/test/tutorial_zerocoin.cpp +++ b/src/test/tutorial_zerocoin.cpp @@ -24,6 +24,7 @@ #include "libzerocoin/Coin.h" #include "libzerocoin/CoinSpend.h" #include "libzerocoin/Accumulator.h" +#include "test_ion.h" using namespace std; @@ -128,7 +129,7 @@ ZerocoinTutorial() // accepted as a valid transaction in the block chain. cout << "Error: coin is not valid!"; } - + cout << "Deserialized and verified the coin." << endl; /********************************************************************/ @@ -217,11 +218,11 @@ ZerocoinTutorial() cout << "ERROR: Our new CoinSpend transaction did not verify!" << endl; return false; } - + // Serialize the CoinSpend object into a buffer. CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION); serializedCoinSpend << spend; - + cout << "Successfully generated a coin spend transaction." << endl; /********************************************************************/ @@ -241,7 +242,7 @@ ZerocoinTutorial() // Create a new metadata object to contain the hash of the received // ZEROCOIN_SPEND transaction. If we were a real client we'd actually // compute the hash of the received transaction here. - + // If we were a real client we would now re-compute the Accumulator // from the information given in the ZEROCOIN_SPEND transaction. // For our purposes we'll just use the one we calculated above. @@ -273,7 +274,7 @@ ZerocoinTutorial() return false; } -BOOST_AUTO_TEST_SUITE(tutorial_libzerocoin) +BOOST_FIXTURE_TEST_SUITE(tutorial_libzerocoin, TestingSetup) BOOST_AUTO_TEST_CASE(tutorial_libzerocoin_tests) { cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " tutorial." << endl << endl; diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index d5f73fedcc479..7148aa5a4e974 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -1,7 +1,6 @@ // Copyright (c) 2011-2013 The Bitcoin Core developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - #include #include #include @@ -11,20 +10,21 @@ #include "uint256.h" #include #include "version.h" +#include "test/test_ion.h" + +BOOST_FIXTURE_TEST_SUITE(uint256_tests, BasicTestingSetup) -BOOST_AUTO_TEST_SUITE(uint256_tests) - -const unsigned char R1Array[] = +const unsigned char R1Array[] = "\x9c\x52\x4a\xdb\xcf\x56\x11\x12\x2b\x29\x12\x5e\x5d\x35\xd2\xd2" "\x22\x81\xaa\xb5\x33\xf0\x08\x32\xd5\x56\xb1\xf9\xea\xe5\x1d\x7d"; const char R1ArrayHex[] = "7D1DE5EAF9B156D53208F033B5AA8122D2d2355d5e12292b121156cfdb4a529c"; const double R1Ldouble = 0.4887374590559308955; // R1L equals roughly R1Ldouble * 2^256 -const double R1Sdouble = 0.7096329412477836074; +const double R1Sdouble = 0.7096329412477836074; const uint256 R1L = uint256(std::vector(R1Array,R1Array+32)); const uint160 R1S = uint160(std::vector(R1Array,R1Array+20)); const uint64_t R1LLow64 = 0x121156cfdb4a529cULL; -const unsigned char R2Array[] = +const unsigned char R2Array[] = "\x70\x32\x1d\x7c\x47\xa5\x6b\x40\x26\x7e\x0a\xc3\xa6\x9c\xb6\xbf" "\x13\x30\x47\xa3\x19\x2d\xda\x71\x49\x13\x72\xf0\xb4\xca\x81\xd7"; const uint256 R2L = uint256(std::vector(R2Array,R2Array+32)); @@ -32,19 +32,19 @@ const uint160 R2S = uint160(std::vector(R2Array,R2Array+20)); const char R1LplusR2L[] = "549FB09FEA236A1EA3E31D4D58F1B1369288D204211CA751527CFC175767850C"; -const unsigned char ZeroArray[] = +const unsigned char ZeroArray[] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; const uint256 ZeroL = uint256(std::vector(ZeroArray,ZeroArray+32)); const uint160 ZeroS = uint160(std::vector(ZeroArray,ZeroArray+20)); - -const unsigned char OneArray[] = + +const unsigned char OneArray[] = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; const uint256 OneL = uint256(std::vector(OneArray,OneArray+32)); const uint160 OneS = uint160(std::vector(OneArray,OneArray+20)); -const unsigned char MaxArray[] = +const unsigned char MaxArray[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; const uint256 MaxL = uint256(std::vector(MaxArray,MaxArray+32)); @@ -56,10 +56,10 @@ std::string ArrayToString(const unsigned char A[], unsigned int width) { std::stringstream Stream; Stream << std::hex; - for (unsigned int i = 0; i < width; ++i) + for (unsigned int i = 0; i < width; ++i) { Stream<(OneArray,OneArray+19)), uint_error); } -void shiftArrayRight(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) +void shiftArrayRight(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) { - for (unsigned int T=0; T < arrayLength; ++T) + for (unsigned int T=0; T < arrayLength; ++T) { unsigned int F = (T+bitsToShift/8); - if (F < arrayLength) + if (F < arrayLength) to[T] = from[F] >> (bitsToShift%8); else to[T] = 0; - if (F + 1 < arrayLength) + if (F + 1 < arrayLength) to[T] |= from[(F+1)] << (8-bitsToShift%8); } } -void shiftArrayLeft(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) +void shiftArrayLeft(unsigned char* to, const unsigned char* from, unsigned int arrayLength, unsigned int bitsToShift) { - for (unsigned int T=0; T < arrayLength; ++T) + for (unsigned int T=0; T < arrayLength; ++T) { - if (T >= bitsToShift/8) + if (T >= bitsToShift/8) { unsigned int F = T-bitsToShift/8; to[T] = from[F] << (bitsToShift%8); @@ -210,14 +210,14 @@ BOOST_AUTO_TEST_CASE( shifts ) { // "<<" ">>" "<<=" ">>=" BOOST_CHECK((HalfL >> (255-i)) == (OneL << i)); TmpL = HalfL; TmpL >>= (255-i); BOOST_CHECK(TmpL == (OneL << i)); - + shiftArrayLeft(TmpArray, R1Array, 32, i); BOOST_CHECK(uint256(std::vector(TmpArray,TmpArray+32)) == (R1L << i)); TmpL = R1L; TmpL <<= i; BOOST_CHECK(TmpL == (R1L << i)); shiftArrayRight(TmpArray, R1Array, 32, i); - BOOST_CHECK(uint256(std::vector(TmpArray,TmpArray+32)) == (R1L >> i)); + BOOST_CHECK(uint256(std::vector(TmpArray,TmpArray+32)) == (R1L >> i)); TmpL = R1L; TmpL >>= i; BOOST_CHECK(TmpL == (R1L >> i)); @@ -250,14 +250,14 @@ BOOST_AUTO_TEST_CASE( shifts ) { // "<<" ">>" "<<=" ">>=" BOOST_CHECK((HalfS >> (159-i)) == (OneS << i)); TmpS = HalfS; TmpS >>= (159-i); BOOST_CHECK(TmpS == (OneS << i)); - + shiftArrayLeft(TmpArray, R1Array, 20, i); BOOST_CHECK(uint160(std::vector(TmpArray,TmpArray+20)) == (R1S << i)); TmpS = R1S; TmpS <<= i; BOOST_CHECK(TmpS == (R1S << i)); shiftArrayRight(TmpArray, R1Array, 20, i); - BOOST_CHECK(uint160(std::vector(TmpArray,TmpArray+20)) == (R1S >> i)); + BOOST_CHECK(uint160(std::vector(TmpArray,TmpArray+20)) == (R1S >> i)); TmpS = R1S; TmpS >>= i; BOOST_CHECK(TmpS == (R1S >> i)); @@ -285,27 +285,27 @@ BOOST_AUTO_TEST_CASE( unaryOperators ) // ! ~ - { BOOST_CHECK(!ZeroL); BOOST_CHECK(!ZeroS); BOOST_CHECK(!(!OneL));BOOST_CHECK(!(!OneS)); - for (unsigned int i = 0; i < 256; ++i) + for (unsigned int i = 0; i < 256; ++i) BOOST_CHECK(!(!(OneL<(TmpArray,TmpArray+32)) == (~R1L)); BOOST_CHECK(uint160(std::vector(TmpArray,TmpArray+20)) == (~R1S)); BOOST_CHECK(-ZeroL == ZeroL); BOOST_CHECK(-ZeroS == ZeroS); BOOST_CHECK(-R1L == (~R1L)+1); BOOST_CHECK(-R1S == (~R1S)+1); - for (unsigned int i = 0; i < 256; ++i) + for (unsigned int i = 0; i < 256; ++i) BOOST_CHECK(-(OneL<= < > } } -BOOST_AUTO_TEST_CASE( plusMinus ) +BOOST_AUTO_TEST_CASE( plusMinus ) { uint256 TmpL = 0; BOOST_CHECK(R1L+R2L == uint256(R1LplusR2L)); @@ -412,7 +412,7 @@ BOOST_AUTO_TEST_CASE( plusMinus ) BOOST_CHECK( TmpL == (HalfL >> (i-1)) ); TmpL = (MaxL>>i); TmpL += 1; BOOST_CHECK( TmpL == (HalfL >> (i-1)) ); - TmpL = (MaxL>>i); + TmpL = (MaxL>>i); BOOST_CHECK( TmpL++ == (MaxL>>i) ); BOOST_CHECK( TmpL == (HalfL >> (i-1))); } @@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE( plusMinus ) BOOST_CHECK( TmpS == (HalfS >> (i-1)) ); TmpS = (MaxS>>i); TmpS += 1; BOOST_CHECK( TmpS == (HalfS >> (i-1)) ); - TmpS = (MaxS>>i); + TmpS = (MaxS>>i); BOOST_CHECK( TmpS++ == (MaxS>>i) ); BOOST_CHECK( TmpS == (HalfS >> (i-1))); } @@ -553,7 +553,7 @@ BOOST_AUTO_TEST_CASE( divide ) } -bool almostEqual(double d1, double d2) +bool almostEqual(double d1, double d2) { return fabs(d1-d2) <= 4*fabs(d1)*std::numeric_limits::epsilon(); } @@ -634,7 +634,7 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G BOOST_CHECK(MaxS.begin() + 20 == MaxS.end()); BOOST_CHECK(TmpS.begin() + 20 == TmpS.end()); BOOST_CHECK(R1S.GetLow64() == R1LLow64); - BOOST_CHECK(HalfS.GetLow64() ==0x0000000000000000ULL); + BOOST_CHECK(HalfS.GetLow64() ==0x0000000000000000ULL); BOOST_CHECK(OneS.GetLow64() ==0x0000000000000001ULL); BOOST_CHECK(R1S.GetSerializeSize(0,PROTOCOL_VERSION) == 20); BOOST_CHECK(ZeroS.GetSerializeSize(0,PROTOCOL_VERSION) == 20); @@ -654,17 +654,17 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G TmpS.Unserialize(ss,0,PROTOCOL_VERSION); BOOST_CHECK(MaxS == TmpS); ss.str(""); - - for (unsigned int i = 0; i < 255; ++i) + + for (unsigned int i = 0; i < 255; ++i) { BOOST_CHECK((OneL << i).getdouble() == ldexp(1.0,i)); if (i < 160) BOOST_CHECK((OneS << i).getdouble() == ldexp(1.0,i)); } BOOST_CHECK(ZeroL.getdouble() == 0.0); BOOST_CHECK(ZeroS.getdouble() == 0.0); - for (int i = 256; i > 53; --i) + for (int i = 256; i > 53; --i) BOOST_CHECK(almostEqual((R1L>>(256-i)).getdouble(), ldexp(R1Ldouble,i))); - for (int i = 160; i > 53; --i) + for (int i = 160; i > 53; --i) BOOST_CHECK(almostEqual((R1S>>(160-i)).getdouble(), ldexp(R1Sdouble,i))); uint64_t R1L64part = (R1L>>192).GetLow64(); uint64_t R1S64part = (R1S>>96).GetLow64(); @@ -809,21 +809,21 @@ BOOST_AUTO_TEST_CASE( getmaxcoverage ) // some more tests just to get 100% cover // ~R1L give a base_uint<256> BOOST_CHECK((~~R1L >> 10) == (R1L >> 10)); BOOST_CHECK((~~R1S >> 10) == (R1S >> 10)); BOOST_CHECK((~~R1L << 10) == (R1L << 10)); BOOST_CHECK((~~R1S << 10) == (R1S << 10)); - BOOST_CHECK(!(~~R1L < R1L)); BOOST_CHECK(!(~~R1S < R1S)); - BOOST_CHECK(~~R1L <= R1L); BOOST_CHECK(~~R1S <= R1S); - BOOST_CHECK(!(~~R1L > R1L)); BOOST_CHECK(!(~~R1S > R1S)); - BOOST_CHECK(~~R1L >= R1L); BOOST_CHECK(~~R1S >= R1S); - BOOST_CHECK(!(R1L < ~~R1L)); BOOST_CHECK(!(R1S < ~~R1S)); - BOOST_CHECK(R1L <= ~~R1L); BOOST_CHECK(R1S <= ~~R1S); - BOOST_CHECK(!(R1L > ~~R1L)); BOOST_CHECK(!(R1S > ~~R1S)); - BOOST_CHECK(R1L >= ~~R1L); BOOST_CHECK(R1S >= ~~R1S); - + BOOST_CHECK(!(~~R1L < R1L)); BOOST_CHECK(!(~~R1S < R1S)); + BOOST_CHECK(~~R1L <= R1L); BOOST_CHECK(~~R1S <= R1S); + BOOST_CHECK(!(~~R1L > R1L)); BOOST_CHECK(!(~~R1S > R1S)); + BOOST_CHECK(~~R1L >= R1L); BOOST_CHECK(~~R1S >= R1S); + BOOST_CHECK(!(R1L < ~~R1L)); BOOST_CHECK(!(R1S < ~~R1S)); + BOOST_CHECK(R1L <= ~~R1L); BOOST_CHECK(R1S <= ~~R1S); + BOOST_CHECK(!(R1L > ~~R1L)); BOOST_CHECK(!(R1S > ~~R1S)); + BOOST_CHECK(R1L >= ~~R1L); BOOST_CHECK(R1S >= ~~R1S); + BOOST_CHECK(~~R1L + R2L == R1L + ~~R2L); BOOST_CHECK(~~R1S + R2S == R1S + ~~R2S); BOOST_CHECK(~~R1L - R2L == R1L - ~~R2L); BOOST_CHECK(~~R1S - R2S == R1S - ~~R2S); - BOOST_CHECK(~R1L != R1L); BOOST_CHECK(R1L != ~R1L); - BOOST_CHECK(~R1S != R1S); BOOST_CHECK(R1S != ~R1S); + BOOST_CHECK(~R1L != R1L); BOOST_CHECK(R1L != ~R1L); + BOOST_CHECK(~R1S != R1S); BOOST_CHECK(R1S != ~R1S); unsigned char TmpArray[32]; CHECKBITWISEOPERATOR(~R1,R2,|) CHECKBITWISEOPERATOR(~R1,R2,^) diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp index d8a42c9513a9d..fb3500b0c2ff3 100644 --- a/src/test/univalue_tests.cpp +++ b/src/test/univalue_tests.cpp @@ -8,12 +8,13 @@ #include #include #include +#include "test/test_ion.h" #include using namespace std; -BOOST_AUTO_TEST_SUITE(univalue_tests) +BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(univalue_constructor) { diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index a32985c6e010c..b81cee7f1545f 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -11,6 +11,7 @@ #include "sync.h" #include "utilstrencodings.h" #include "utilmoneystr.h" +#include "test/test_ion.h" #include #include @@ -19,7 +20,7 @@ using namespace std; -BOOST_AUTO_TEST_SUITE(util_tests) +BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(util_criticalsection) { diff --git a/src/test/zerocoin_bignum_tests.cpp b/src/test/zerocoin_bignum_tests.cpp new file mode 100644 index 0000000000000..c61e60048e9f8 --- /dev/null +++ b/src/test/zerocoin_bignum_tests.cpp @@ -0,0 +1,90 @@ +// Copyright (c) 2017-2018 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include + +#include "libzerocoin/Commitment.h" +#include "libzerocoin/Denominations.h" +#include "libzerocoin/CoinSpend.h" +#include "libzerocoin/Accumulator.h" +#include "xion/zerocoin.h" + +using namespace libzerocoin; + +bool testRandKBitBignum(int k_bits) +{ + CBigNum x = CBigNum::randKBitBignum(k_bits); + return (x.bitSize() <= k_bits); +} + +bool testRandBignum(CBigNum limit) +{ + CBigNum x = CBigNum::randBignum(limit); + return 0 <= x && x < limit; +} + +BOOST_AUTO_TEST_SUITE(zerocoin_bignum_tests) + +std::string zerocoinModulus = "25195908475657893494027183240048398571429282126204032027777137836043662020707595556264018525880784" +"4069182906412495150821892985591491761845028084891200728449926873928072877767359714183472702618963750149718246911" +"6507761337985909570009733045974880842840179742910064245869181719511874612151517265463228221686998754918242243363" +"7259085141865462043576798423387184774447920739934236584823824281198163815010674810451660377306056201619676256133" +"8441436038339044149526344321901146575444541784240209246165157233507787077498171257724679629263863563732899121548" +"31438167899885040445364023527381951378636564391212010397122822120720357"; + +std::string strHexModulus = "c7970ceedcc3b0754490201a7aa613cd73911081c790f5f1a8726f463550bb5b7ff0db8e1ea1189ec72f93d1650011bd721aeeacc2acde32a04107f0648c2813a31f5b0b7765ff8b44b4b6ffc93384b646eb09c7cf5e8592d40ea33c80039f35b4f14a04b51f7bfd781be4d1673164ba8eb991c2c4d730bbbe35f592bdef524af7e8daefd26c66fc02c479af89d64d373f442709439de66ceb955f3ea37d5159f6135809f85334b5cb1813addc80cd05609f10ac6a95ad65872c909525bdad32bc729592642920f24c61dc5b3c3b7923e56b16a4d9d373d8721f24a3fc0f1b3131f55615172866bccc30f95054c824e733a5eb6817f7bc16399d48c6361cc7e5"; + +BOOST_AUTO_TEST_CASE(bignum_setdecimal) +{ + CBigNum bnDec; + bnDec.SetDec(zerocoinModulus); + CBigNum bnHex; + bnHex.SetHex(strHexModulus); + BOOST_CHECK_MESSAGE(bnDec == bnHex, "CBigNum.SetDec() does not work correctly"); +} + +std::string negstrHexModulus = "-c7970ceedcc3b0754490201a7aa613cd73911081c790f5f1a8726f463550bb5b7ff0db8e1ea1189ec72f93d1650011bd721aeeacc2acde32a04107f0648c2813a31f5b0b7765ff8b44b4b6ffc93384b646eb09c7cf5e8592d40ea33c80039f35b4f14a04b51f7bfd781be4d1673164ba8eb991c2c4d730bbbe35f592bdef524af7e8daefd26c66fc02c479af89d64d373f442709439de66ceb955f3ea37d5159f6135809f85334b5cb1813addc80cd05609f10ac6a95ad65872c909525bdad32bc729592642920f24c61dc5b3c3b7923e56b16a4d9d373d8721f24a3fc0f1b3131f55615172866bccc30f95054c824e733a5eb6817f7bc16399d48c6361cc7e5"; +std::string str_a = "775897c5463939bf29a02816aba7b1741162e1f6b052cd32fec36c44dfee7d4b5162de78bb0b448cb305b0a9bd7e006aec62d7c1e94a31003c2decbdc6fd7c9b261cb88801c51e7cee71a215ff113ccbd02069cf29671e6302944ca5780a2f626eb9046fa6872968addc93c74d09cf6b2872bc4c6bd08e89324cc7e9fb921488"; +std::string str_b = "-775897c5463939bf29a02816aba7b1741162e1f6b052cd32fec36c44dfee7d4b5162de78bb0b448cb305b0a9bd7e006aec62d7c1e94a31003c2decbdc6fd7c9b261cb88801c51e7cee71a215ff113ccbd02069cf29671e6302944ca5780a2f626eb9046fa6872968addc93c74d09cf6b2872bc4c6bd08e89324cc7e9fb921488"; + +BOOST_AUTO_TEST_CASE(bignum_basic_tests) +{ + CBigNum bn, bn2; + std::vector vch; + + bn.SetHex(strHexModulus); + vch = bn.getvch(); + bn2.setvch(vch); + BOOST_CHECK_MESSAGE(bn2 == bn, "CBigNum.setvch() or CBigNum.getvch() does not work correctly"); + + bn.SetHex(negstrHexModulus); + vch = bn.getvch(); + bn2.setvch(vch); + BOOST_CHECK_MESSAGE(bn2 == bn, "CBigNum.setvch() or CBigNum.getvch() does not work correctly"); + + bn.SetHex(str_a); + vch = bn.getvch(); + bn2.setvch(vch); + BOOST_CHECK_MESSAGE(bn2 == bn, "CBigNum.setvch() or CBigNum.getvch() does not work correctly"); + + bn.SetHex(str_b); + vch = bn.getvch(); + bn2.setvch(vch); + BOOST_CHECK_MESSAGE(bn2 == bn, "CBigNum.setvch() or CBigNum.getvch() does not work correctly"); +} + + +BOOST_AUTO_TEST_CASE(bignum_random_generation_tests) +{ + for(int i=1; i<3000; i++) { + BOOST_CHECK_MESSAGE(testRandKBitBignum(i), strprintf("CBigNum::randKBitBignum(%d) failed", i)); + } + + for(int i=1; i<3000; i++) { + CBigNum x = 1 + CBigNum::randKBitBignum(i); + BOOST_CHECK_MESSAGE(testRandBignum(x), strprintf("CBigNum::randBignum(x) failed with x=%s", x.ToString())); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/zerocoin_coinspend_tests.cpp b/src/test/zerocoin_coinspend_tests.cpp index 10777bef00233..695223680bee0 100644 --- a/src/test/zerocoin_coinspend_tests.cpp +++ b/src/test/zerocoin_coinspend_tests.cpp @@ -16,6 +16,7 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" #include "txdb.h" +#include "test/test_ion.h" #include #include @@ -23,7 +24,7 @@ using namespace libzerocoin; class CDeterministicMint; -BOOST_AUTO_TEST_SUITE(zerocoin_coinspend_tests) +BOOST_FIXTURE_TEST_SUITE(zerocoin_coinspend_tests, TestingSetup) /** * Check that wrapped serials pass and not pass using the new validation. diff --git a/src/test/zerocoin_denomination_tests.cpp b/src/test/zerocoin_denomination_tests.cpp index 2d15227478bb1..2acc88e0b2d06 100644 --- a/src/test/zerocoin_denomination_tests.cpp +++ b/src/test/zerocoin_denomination_tests.cpp @@ -10,13 +10,13 @@ #include "txdb.h" #include "wallet/wallet.h" #include "wallet/walletdb.h" +#include "test/test_ion.h" #include #include using namespace libzerocoin; -BOOST_AUTO_TEST_SUITE(zerocoin_denom_tests) - +BOOST_FIXTURE_TEST_SUITE(zerocoin_denom_tests, BasicTestingSetup) //translation from ion quantity to zerocoin denomination BOOST_AUTO_TEST_CASE(amount_to_denomination_test) @@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test241) nTotalAmount += currentAmount; CBigNum value; CBigNum rand; - CBigNum serial = CBigNum::RandKBitBigum(256); + CBigNum serial = CBigNum::randKBitBignum(256); bool isUsed = false; CMintMeta meta; meta.denom = denom; @@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test115) nTotalAmount += currentAmount; CBigNum value; CBigNum rand; - CBigNum serial = CBigNum::RandKBitBigum(256); + CBigNum serial = CBigNum::randKBitBignum(256); bool isUsed = false; CMintMeta meta; meta.denom = denom; @@ -259,7 +259,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test_from_245) nTotalAmount += currentAmount; CBigNum value; CBigNum rand; - CBigNum serial = CBigNum::RandKBitBigum(256); + CBigNum serial = CBigNum::randKBitBignum(256); bool isUsed = false; CMintMeta meta; meta.denom = denom; @@ -361,7 +361,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test_from_145) nTotalAmount += currentAmount; CBigNum value; CBigNum rand; - CBigNum serial = CBigNum::RandKBitBigum(256); + CBigNum serial = CBigNum::randKBitBignum(256); bool isUsed = false; CMintMeta meta; meta.denom = denom; @@ -467,7 +467,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test99) nTotalAmount += currentAmount; CBigNum value; CBigNum rand; - CBigNum serial = CBigNum::RandKBitBigum(256); + CBigNum serial = CBigNum::randKBitBignum(256); bool isUsed = false; CMintMeta meta; meta.denom = denom; diff --git a/src/test/zerocoin_implementation_tests.cpp b/src/test/zerocoin_implementation_tests.cpp index 767c18f744d09..0d8be2fbcd53e 100644 --- a/src/test/zerocoin_implementation_tests.cpp +++ b/src/test/zerocoin_implementation_tests.cpp @@ -17,12 +17,13 @@ #include "wallet/wallet.h" #include "xion/xionwallet.h" #include "xionchain.h" +#include "test_ion.h" using namespace libzerocoin; extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); -BOOST_AUTO_TEST_SUITE(zerocoin_implementation_tests) +BOOST_FIXTURE_TEST_SUITE(zerocoin_implementation_tests, TestingSetup) BOOST_AUTO_TEST_CASE(zcparams_test) { @@ -47,46 +48,7 @@ std::string zerocoinModulus = "2519590847565789349402718324004839857142928212620 "8441436038339044149526344321901146575444541784240209246165157233507787077498171257724679629263863563732899121548" "31438167899885040445364023527381951378636564391212010397122822120720357"; -std::string strHexModulus = "c7970ceedcc3b0754490201a7aa613cd73911081c790f5f1a8726f463550bb5b7ff0db8e1ea1189ec72f93d1650011bd721aeeacc2acde32a04107f0648c2813a31f5b0b7765ff8b44b4b6ffc93384b646eb09c7cf5e8592d40ea33c80039f35b4f14a04b51f7bfd781be4d1673164ba8eb991c2c4d730bbbe35f592bdef524af7e8daefd26c66fc02c479af89d64d373f442709439de66ceb955f3ea37d5159f6135809f85334b5cb1813addc80cd05609f10ac6a95ad65872c909525bdad32bc729592642920f24c61dc5b3c3b7923e56b16a4d9d373d8721f24a3fc0f1b3131f55615172866bccc30f95054c824e733a5eb6817f7bc16399d48c6361cc7e5"; -BOOST_AUTO_TEST_CASE(bignum_setdecimal) -{ - CBigNum bnDec; - bnDec.SetDec(zerocoinModulus); - CBigNum bnHex; - bnHex.SetHex(strHexModulus); - BOOST_CHECK_MESSAGE(bnDec == bnHex, "CBigNum.SetDec() does not work correctly"); -} - -std::string negstrHexModulus = "-c7970ceedcc3b0754490201a7aa613cd73911081c790f5f1a8726f463550bb5b7ff0db8e1ea1189ec72f93d1650011bd721aeeacc2acde32a04107f0648c2813a31f5b0b7765ff8b44b4b6ffc93384b646eb09c7cf5e8592d40ea33c80039f35b4f14a04b51f7bfd781be4d1673164ba8eb991c2c4d730bbbe35f592bdef524af7e8daefd26c66fc02c479af89d64d373f442709439de66ceb955f3ea37d5159f6135809f85334b5cb1813addc80cd05609f10ac6a95ad65872c909525bdad32bc729592642920f24c61dc5b3c3b7923e56b16a4d9d373d8721f24a3fc0f1b3131f55615172866bccc30f95054c824e733a5eb6817f7bc16399d48c6361cc7e5"; -std::string str_a = "775897c5463939bf29a02816aba7b1741162e1f6b052cd32fec36c44dfee7d4b5162de78bb0b448cb305b0a9bd7e006aec62d7c1e94a31003c2decbdc6fd7c9b261cb88801c51e7cee71a215ff113ccbd02069cf29671e6302944ca5780a2f626eb9046fa6872968addc93c74d09cf6b2872bc4c6bd08e89324cc7e9fb921488"; -std::string str_b = "-775897c5463939bf29a02816aba7b1741162e1f6b052cd32fec36c44dfee7d4b5162de78bb0b448cb305b0a9bd7e006aec62d7c1e94a31003c2decbdc6fd7c9b261cb88801c51e7cee71a215ff113ccbd02069cf29671e6302944ca5780a2f626eb9046fa6872968addc93c74d09cf6b2872bc4c6bd08e89324cc7e9fb921488"; - -BOOST_AUTO_TEST_CASE(bignum_basic_tests) -{ - CBigNum bn, bn2; - std::vector vch; - - bn.SetHex(strHexModulus); - vch = bn.getvch(); - bn2.setvch(vch); - BOOST_CHECK_MESSAGE(bn2 == bn, "CBigNum.setvch() or CBigNum.getvch() does not work correctly"); - - bn.SetHex(negstrHexModulus); - vch = bn.getvch(); - bn2.setvch(vch); - BOOST_CHECK_MESSAGE(bn2 == bn, "CBigNum.setvch() or CBigNum.getvch() does not work correctly"); - - bn.SetHex(str_a); - vch = bn.getvch(); - bn2.setvch(vch); - BOOST_CHECK_MESSAGE(bn2 == bn, "CBigNum.setvch() or CBigNum.getvch() does not work correctly"); - - bn.SetHex(str_b); - vch = bn.getvch(); - bn2.setvch(vch); - BOOST_CHECK_MESSAGE(bn2 == bn, "CBigNum.setvch() or CBigNum.getvch() does not work correctly"); -} //ZQ_ONE mints std::string rawTx1 = "0100000001983d5fd91685bb726c0ebc3676f89101b16e663fd896fea53e19972b95054c49000000006a473044022010fbec3e78f9c46e58193d481caff715ceb984df44671d30a2c0bde95c54055f0220446a97d9340da690eaf2658e5b2bf6a0add06f1ae3f1b40f37614c7079ce450d012103cb666bd0f32b71cbf4f32e95fa58e05cd83869ac101435fcb8acee99123ccd1dffffffff0200e1f5050000000086c10280004c80c3a01f94e71662f2ae8bfcd88dfc5b5e717136facd6538829db0c7f01e5fd793cccae7aa1958564518e0223d6d9ce15b1e38e757583546e3b9a3f85bd14408120cd5192a901bb52152e8759fdd194df230d78477706d0e412a66398f330be38a23540d12ab147e9fb19224913f3fe552ae6a587fb30a68743e52577150ff73042c0f0d8f000000001976a914d6042025bd1fff4da5da5c432d85d82b3f26a01688ac00000000"; @@ -138,7 +100,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinmint_test) CValidationState state; bool fFoundMint = false; for(unsigned int i = 0; i < tx.vout.size(); i++){ - if(!tx.vout[i].scriptPubKey.empty() && tx.vout[i].scriptPubKey.IsZerocoinMint()) { + if(tx.vout[i].IsZerocoinMint()) { BOOST_CHECK(CheckZerocoinMint(tx.GetHash(), tx.vout[i], state, true)); fFoundMint = true; } @@ -176,10 +138,10 @@ bool CheckZerocoinSpendNoDB(const CTransaction tx, string& strError) set serials; list vSpends; CAmount nTotalRedeemed = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { //only check txin that is a zcspend - if (!txin.scriptSig.IsZerocoinSpend()) + if (!txin.IsZerocoinSpend()) continue; // extract the CoinSpend from the txin @@ -274,7 +236,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) BOOST_CHECK_MESSAGE(DecodeHexTx(tx, raw.first), "Failed to deserialize hex transaction"); for(const CTxOut& out : tx.vout){ - if(!out.scriptPubKey.empty() && out.scriptPubKey.IsZerocoinMint()) { + if(out.IsZerocoinMint()) { PublicCoin publicCoin(Params().Zerocoin_Params(true)); BOOST_CHECK_MESSAGE(TxOutToPublicCoin(out, publicCoin, state), "Failed to convert CTxOut " << out.ToString() << " to PublicCoin"); @@ -401,7 +363,7 @@ BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) //Get the checksum of the accumulator we use for the spend and also add it to our checksum map uint32_t nChecksum_v2 = GetChecksum(accumulator_v2.getValue()); //AddAccumulatorChecksum(nChecksum_v2, accumulator_v2.getValue(), true); - uint256 ptxHash = CBigNum::RandKBitBigum(256).getuint256(); + uint256 ptxHash = CBigNum::randKBitBignum(256).getuint256(); CoinSpend coinSpend_v2(Params().Zerocoin_Params(false), Params().Zerocoin_Params(false), privateCoin_v2, accumulator_v2, nChecksum_v2, witness_v2, ptxHash, SpendType::SPEND); BOOST_CHECK_MESSAGE(coinSpend_v2.HasValidSerial(Params().Zerocoin_Params(false)), "coinspend_v2 does not have a valid serial"); diff --git a/src/test/zerocoin_transactions_tests.cpp b/src/test/zerocoin_transactions_tests.cpp index f3b02ffad32fc..cbd40d3a5679c 100644 --- a/src/test/zerocoin_transactions_tests.cpp +++ b/src/test/zerocoin_transactions_tests.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "libzerocoin/Denominations.h" +#include "libzerocoin/Coin.h" #include "amount.h" #include "chainparams.h" #include "coincontrol.h" @@ -10,13 +11,15 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" #include "txdb.h" +#include "xion/xionmodule.h" +#include "test/test_ion.h" #include #include using namespace libzerocoin; -BOOST_AUTO_TEST_SUITE(zerocoin_transactions_tests) +BOOST_FIXTURE_TEST_SUITE(zerocoin_transactions_tests, TestingSetup) static CWallet cWallet("unlocked.dat"); @@ -40,7 +43,7 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test) CZerocoinSpendReceipt receipt; cWallet.SpendZerocoin(nAmount, *wtx, receipt, vMints, fMintChange, fMinimizeChange); - BOOST_CHECK_MESSAGE(receipt.GetStatus() == XION_TRX_FUNDS_PROBLEMS, "Failed Invalid Amount Check"); + BOOST_CHECK_MESSAGE(receipt.GetStatus() == XION_TRX_FUNDS_PROBLEMS, strprintf("Failed Invalid Amount Check: %s", receipt.GetStatusMessage())); nAmount = 1; CZerocoinSpendReceipt receipt2; @@ -49,7 +52,68 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test) // if using "wallet.dat", instead of "unlocked.dat" need this /// BOOST_CHECK_MESSAGE(vString == "Error: Wallet locked, unable to create transaction!"," Locked Wallet Check Failed"); - BOOST_CHECK_MESSAGE(receipt2.GetStatus() == XION_TRX_FUNDS_PROBLEMS, "Failed Invalid Amount Check"); + BOOST_CHECK_MESSAGE(receipt2.GetStatus() == XION_TRX_FUNDS_PROBLEMS, strprintf("Failed Invalid Amount Check: %s", receipt.GetStatusMessage())); + +} + +BOOST_AUTO_TEST_CASE(zerocoin_public_spend_test) +{ + SelectParams(CBaseChainParams::MAIN); + ZerocoinParams *ZCParams = Params().Zerocoin_Params(false); + (void)ZCParams; + + PrivateCoin privCoin(ZCParams, libzerocoin::CoinDenomination::ZQ_ONE, true); + const CPrivKey privKey = privCoin.getPrivKey(); + + CZerocoinMint mint = CZerocoinMint( + privCoin.getPublicCoin().getDenomination(), + privCoin.getPublicCoin().getValue(), + privCoin.getRandomness(), + privCoin.getSerialNumber(), + false, + privCoin.getVersion(), + nullptr); + mint.SetPrivKey(privKey); + + + // Mint tx + CTransaction prevTx; + + CScript scriptSerializedCoin = CScript() + << OP_ZEROCOINMINT << privCoin.getPublicCoin().getValue().getvch().size() << privCoin.getPublicCoin().getValue().getvch(); + CTxOut out = CTxOut(libzerocoin::ZerocoinDenominationToAmount(privCoin.getPublicCoin().getDenomination()), scriptSerializedCoin); + prevTx.vout.push_back(out); + + mint.SetOutputIndex(0); + mint.SetTxHash(prevTx.GetHash()); + + // Spend tx + CMutableTransaction tx; + tx.vout.resize(1); + tx.vout[0].nValue = 1*CENT; + tx.vout[0].scriptPubKey = GetScriptForDestination(CBitcoinAddress("D9Ti4LEhF1n6dR2hGd2SyNADD51AVgva6q").Get()); + + CTxIn in; + if (!XIONModule::createInput(in, mint, tx.GetHash())){ + BOOST_CHECK_MESSAGE(false, "Failed to create zc input"); + } + + PublicCoinSpend publicSpend(ZCParams); + if (!XIONModule::validateInput(in, out, tx, publicSpend)){ + BOOST_CHECK_MESSAGE(false, "Failed to validate zc input"); + } + + PublicCoinSpend publicSpendTest(ZCParams); + BOOST_CHECK_MESSAGE(XIONModule::parseCoinSpend(in, tx, out, publicSpendTest), "Failed to parse public spend"); + libzerocoin::CoinSpend *spend = &publicSpendTest; + + BOOST_CHECK_MESSAGE(publicSpendTest.HasValidSignature(), "Failed to validate public spend signature"); + BOOST_CHECK_MESSAGE(spend->HasValidSignature(), "Failed to validate spend signature"); + + // Verify that fails with a different denomination + in.nSequence = 500; + PublicCoinSpend publicSpend2(ZCParams); + BOOST_CHECK_MESSAGE(!XIONModule::validateInput(in, out, tx, publicSpend2), "Different denomination"); } diff --git a/src/timedata.cpp b/src/timedata.cpp index 983445fe046e4..34898cf0c7dc2 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -8,11 +8,10 @@ #include "netbase.h" #include "sync.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "utilstrencodings.h" -#include using namespace std; @@ -85,7 +84,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) if (!fDone) { // If nobody has a time different than ours but within 5 minutes of ours, give a warning bool fMatch = false; - BOOST_FOREACH (int64_t nOffset, vSorted) + for (int64_t nOffset : vSorted) if (nOffset != 0 && abs64(nOffset) < 5 * 60) fMatch = true; @@ -99,7 +98,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) } } if (fDebug) { - BOOST_FOREACH (int64_t n, vSorted) + for (int64_t n : vSorted) LogPrintf("%+d ", n); LogPrintf("| "); } diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 2751e496318ca..5ea627c20ca19 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -490,7 +489,7 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe { if (reply.code == 250) { LogPrint("tor", "tor: ADD_ONION successful\n"); - BOOST_FOREACH(const std::string &s, reply.lines) { + for (const std::string &s : reply.lines) { std::map m = ParseTorReplyMapping(s); std::map::iterator i; if ((i = m.find("ServiceID")) != m.end()) @@ -621,7 +620,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro * 250-AUTH METHODS=NULL * 250-AUTH METHODS=HASHEDPASSWORD */ - BOOST_FOREACH(const std::string &s, reply.lines) { + for (const std::string &s : reply.lines) { std::pair l = SplitTorReplyLine(s); if (l.first == "AUTH") { std::map m = ParseTorReplyMapping(l.second); @@ -638,7 +637,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro } } } - BOOST_FOREACH(const std::string &s, methods) { + for (const std::string &s : methods) { LogPrint("tor", "tor: Supported authentication method: %s\n", s); } // Prefer NULL, otherwise SAFECOOKIE. If a password is provided, use HASHEDPASSWORD diff --git a/src/txdb.cpp b/src/txdb.cpp index eb36c5e96e496..406038914d5f1 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -84,21 +84,11 @@ bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex) return Write(make_pair('b', blockindex.GetBlockHash()), blockindex); } -bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo& info) -{ - return Write(make_pair('f', nFile), info); -} - bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo& info) { return Read(make_pair('f', nFile), info); } -bool CBlockTreeDB::WriteLastBlockFile(int nFile) -{ - return Write('l', nFile); -} - bool CBlockTreeDB::WriteReindexing(bool fReindexing) { if (fReindexing) @@ -165,6 +155,18 @@ void CCoinsViewDBCursor::Next() } } +bool CBlockTreeDB::WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo) { + CLevelDBBatch batch; + for (std::vector >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) { + batch.Write(make_pair('f', it->first), *it->second); + } + batch.Write('l', nLastFile); + for (std::vector::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) { + batch.Write(make_pair('b', (*it)->GetBlockHash()), CDiskBlockIndex(*it)); + } + return WriteBatch(batch, true); +} + bool CBlockTreeDB::ReadTxIndex(const uint256& txid, CDiskTxPos& pos) { return Read(make_pair('t', txid), pos); @@ -250,9 +252,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts() if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits)) return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString()); } - // ppcoin: build setStakeSeen - if (pindexNew->IsProofOfStake()) - setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); //populate accumulator checksum map in memory if(pindexNew->nAccumulatorCheckpoint != 0 && pindexNew->nAccumulatorCheckpoint != nPreviousCheckpoint) { diff --git a/src/txdb.h b/src/txdb.h index 2730944675f62..faa215e1907fe 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -79,10 +79,9 @@ class CBlockTreeDB : public CLevelDBWrapper public: bool WriteBlockIndex(const CDiskBlockIndex& blockindex); + bool WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo); bool ReadBlockFileInfo(int nFile, CBlockFileInfo& fileinfo); - bool WriteBlockFileInfo(int nFile, const CBlockFileInfo& fileinfo); bool ReadLastBlockFile(int& nFile); - bool WriteLastBlockFile(int nFile); bool WriteReindexing(bool fReindex); bool ReadReindexing(bool& fReindex); bool ReadTxIndex(const uint256& txid, CDiskTxPos& pos); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 5cd6ed6c242d2..59b1e9bed868e 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -77,14 +77,14 @@ class CBlockAverage size_t FeeSamples() const { return feeSamples.size(); } size_t GetFeeSamples(std::vector& insertInto) const { - BOOST_FOREACH (const CFeeRate& f, feeSamples) + for (const CFeeRate& f : feeSamples) insertInto.push_back(f); return feeSamples.size(); } size_t PrioritySamples() const { return prioritySamples.size(); } size_t GetPrioritySamples(std::vector& insertInto) const { - BOOST_FOREACH (double d, prioritySamples) + for (double d : prioritySamples) insertInto.push_back(d); return prioritySamples.size(); } @@ -103,7 +103,7 @@ class CBlockAverage } static bool AreSane(const std::vector& vecFee, const CFeeRate& minRelayFee) { - BOOST_FOREACH (CFeeRate fee, vecFee) { + for (CFeeRate fee : vecFee) { if (!AreSane(fee, minRelayFee)) return false; } @@ -115,7 +115,7 @@ class CBlockAverage } static bool AreSane(const std::vector vecPriority) { - BOOST_FOREACH (double priority, vecPriority) { + for (double priority : vecPriority) { if (!AreSane(priority)) return false; } @@ -214,7 +214,7 @@ class CMinerPolicyEstimator // to confirm. std::vector > entriesByConfirmations; entriesByConfirmations.resize(history.size()); - BOOST_FOREACH (const CTxMemPoolEntry& entry, entries) { + for (const CTxMemPoolEntry& entry : entries) { // How many blocks did it take for miners to include this transaction? int delta = nBlockHeight - entry.GetHeight(); if (delta <= 0) { @@ -234,7 +234,7 @@ class CMinerPolicyEstimator std::random_shuffle(e.begin(), e.end()); e.resize(10); } - BOOST_FOREACH (const CTxMemPoolEntry* entry, e) { + for (const CTxMemPoolEntry* entry : e) { // Fees are stored and reported as BTC-per-kb: CFeeRate feeRate(entry->GetFee(), entry->GetTxSize()); double dPriority = entry->GetPriority(entry->GetHeight()); // Want priority when it went IN @@ -326,7 +326,7 @@ class CMinerPolicyEstimator { fileout << nBestSeenHeight; fileout << history.size(); - BOOST_FOREACH (const CBlockAverage& entry, history) { + for (const CBlockAverage& entry : history) { entry.Write(fileout); } } @@ -413,7 +413,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry) { mapTx[hash] = entry; const CTransaction& tx = mapTx[hash].GetTx(); - if(!tx.IsZerocoinSpend()) { + if(!tx.HasZerocoinSpendInputs()) { for (unsigned int i = 0; i < tx.vin.size(); i++) mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); } @@ -457,7 +457,7 @@ void CTxMemPool::remove(const CTransaction& origTx, std::list& rem txToRemove.push_back(it->second.ptx->GetHash()); } } - BOOST_FOREACH (const CTxIn& txin, tx.vin) + for (const CTxIn& txin : tx.vin) mapNextTx.erase(txin.prevout); removed.push_back(tx); @@ -475,7 +475,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache* pcoins, unsigned in list transactionsToRemove; for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { const CTransaction& tx = it->second.GetTx(); - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) continue; @@ -487,7 +487,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache* pcoins, unsigned in } } } - BOOST_FOREACH (const CTransaction& tx, transactionsToRemove) { + for (const CTransaction& tx : transactionsToRemove) { list removed; remove(tx, removed, true); } @@ -498,7 +498,7 @@ void CTxMemPool::removeConflicts(const CTransaction& tx, std::list // Remove transactions which depend on inputs of tx, recursively list result; LOCK(cs); - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { std::map::iterator it = mapNextTx.find(txin.prevout); if (it != mapNextTx.end()) { const CTransaction& txConflict = *it->second.ptx; @@ -516,13 +516,13 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned i { LOCK(cs); std::vector entries; - BOOST_FOREACH (const CTransaction& tx, vtx) { + for (const CTransaction& tx : vtx) { uint256 hash = tx.GetHash(); if (mapTx.count(hash)) entries.push_back(mapTx[hash]); } minerPolicyEstimator->seenBlock(entries, nBlockHeight, minRelayFee); - BOOST_FOREACH (const CTransaction& tx, vtx) { + for (const CTransaction& tx : vtx) { std::list dummy; remove(tx, dummy, false); removeConflicts(tx, conflicts); @@ -558,7 +558,7 @@ void CTxMemPool::check(const CCoinsViewCache* pcoins) const checkTotal += it->second.GetTxSize(); const CTransaction& tx = it->second.GetTx(); bool fDependsWait = false; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); if (it2 != mapTx.end()) { @@ -567,11 +567,11 @@ void CTxMemPool::check(const CCoinsViewCache* pcoins) const fDependsWait = true; } else { const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); - if(!txin.scriptSig.IsZerocoinSpend()) + if(!txin.IsZerocoinSpend() && !txin.IsZerocoinPublicSpend()) assert(coins && coins->IsAvailable(txin.prevout.n)); } // Check whether its inputs are marked in mapNextTx. - if(!txin.scriptSig.IsZerocoinSpend()) { + if(!txin.IsZerocoinSpend() && !txin.IsZerocoinPublicSpend()) { std::map::const_iterator it3 = mapNextTx.find(txin.prevout); assert(it3 != mapNextTx.end()); assert(it3->second.ptx == &tx); diff --git a/src/util.cpp b/src/util.cpp index a973b0f2f063a..7fcff815068c9 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -81,7 +81,6 @@ #include // for startswith() and endswith() #include #include -#include #include #include #include @@ -107,8 +106,6 @@ int nZeromintPercentage = 10; int nPreferredDenom = 0; const int64_t AUTOMINT_DELAY = (60 * 5); // Wait at least 5 minutes until Automint starts -int nAnonymizeIonAmount = 1000; -int nLiquidityProvider = 0; /** Spork enforcement enabled time */ int64_t enforceMasternodePaymentsTime = 4085657524; bool fSucessfullyLoaded = false; diff --git a/src/util.h b/src/util.h index a517b291a8dd0..ef396c213e0a3 100644 --- a/src/util.h +++ b/src/util.h @@ -40,8 +40,6 @@ extern int nSwiftTXDepth; extern int nZeromintPercentage; extern const int64_t AUTOMINT_DELAY; extern int nPreferredDenom; -extern int nAnonymizeIonAmount; -extern int nLiquidityProvider; extern bool fEnableZeromint; extern bool fEnableAutoConvert; extern int64_t enforceMasternodePaymentsTime; @@ -72,6 +70,9 @@ int LogPrintStr(const std::string& str); #define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) +/** Get format string from VA_ARGS for error reporting */ +template std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; } + /** * When we switch to C++11, this can be switched to variadic templates instead * of this macro-based construction (see tinyformat.h). @@ -82,13 +83,25 @@ int LogPrintStr(const std::string& str); static inline int LogPrint(const char* category, const char* format, TINYFORMAT_VARARGS(n)) \ { \ if (!LogAcceptCategory(category)) return 0; \ - return LogPrintStr(tfm::format(format, TINYFORMAT_PASSARGS(n))); \ + std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ + try { \ + _log_msg_ = tfm::format(format, TINYFORMAT_PASSARGS(n)); \ + } catch (std::runtime_error &e) { \ + _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(format, TINYFORMAT_PASSARGS(n));\ + } \ + return LogPrintStr(_log_msg_); \ } \ /** Log error and return false */ \ template \ static inline bool error(const char* format, TINYFORMAT_VARARGS(n)) \ { \ - LogPrintStr(std::string("ERROR: ") + tfm::format(format, TINYFORMAT_PASSARGS(n)) + "\n"); \ + std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ + try { \ + _log_msg_ = tfm::format(format, TINYFORMAT_PASSARGS(n)); \ + } catch (std::runtime_error &e) { \ + _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(format, TINYFORMAT_PASSARGS(n));\ + } \ + LogPrintStr(std::string("ERROR: ") + _log_msg_ + "\n"); \ return false; \ } @@ -120,7 +133,8 @@ void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length); bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest); bool TryCreateDirectory(const boost::filesystem::path& p); boost::filesystem::path GetDefaultDataDir(); -const boost::filesystem::path& GetDataDir(bool fNetSpecific = true); +const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); +void ClearDatadirCache(); boost::filesystem::path GetConfigFile(); boost::filesystem::path GetMasternodeConfigFile(); #ifndef WIN32 diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 4fc1afff78ca5..bbd5936e9b11a 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -40,22 +40,31 @@ void CDBEnv::EnvShutdown() return; fDbEnvInit = false; - int ret = dbenv.close(0); + int ret = dbenv->close(0); if (ret != 0) LogPrintf("CDBEnv::EnvShutdown : Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret)); if (!fMockDb) DbEnv(0).remove(strPath.c_str(), 0); } -CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS) +void CDBEnv::Reset() { + delete dbenv; + dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS); fDbEnvInit = false; fMockDb = false; } +CDBEnv::CDBEnv() : dbenv(NULL) +{ + Reset(); +} + CDBEnv::~CDBEnv() { EnvShutdown(); + delete dbenv; + dbenv = NULL; } void CDBEnv::Close() @@ -80,17 +89,17 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn) if (GetBoolArg("-privdb", true)) nEnvFlags |= DB_PRIVATE; - dbenv.set_lg_dir(pathLogDir.string().c_str()); - dbenv.set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet - dbenv.set_lg_bsize(0x10000); - dbenv.set_lg_max(1048576); - dbenv.set_lk_max_locks(40000); - dbenv.set_lk_max_objects(40000); - dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug - dbenv.set_flags(DB_AUTO_COMMIT, 1); - dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); - dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); - int ret = dbenv.open(strPath.c_str(), + dbenv->set_lg_dir(pathLogDir.string().c_str()); + dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet + dbenv->set_lg_bsize(0x10000); + dbenv->set_lg_max(1048576); + dbenv->set_lk_max_locks(40000); + dbenv->set_lk_max_objects(40000); + dbenv->set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug + dbenv->set_flags(DB_AUTO_COMMIT, 1); + dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1); + dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1); + int ret = dbenv->open(strPath.c_str(), DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -117,14 +126,14 @@ void CDBEnv::MakeMock() LogPrint("db", "CDBEnv::MakeMock\n"); - dbenv.set_cachesize(1, 0, 1); - dbenv.set_lg_bsize(10485760 * 4); - dbenv.set_lg_max(10485760); - dbenv.set_lk_max_locks(10000); - dbenv.set_lk_max_objects(10000); - dbenv.set_flags(DB_AUTO_COMMIT, 1); - dbenv.log_set_config(DB_LOG_IN_MEMORY, 1); - int ret = dbenv.open(NULL, + dbenv->set_cachesize(1, 0, 1); + dbenv->set_lg_bsize(10485760 * 4); + dbenv->set_lg_max(10485760); + dbenv->set_lk_max_locks(10000); + dbenv->set_lk_max_objects(10000); + dbenv->set_flags(DB_AUTO_COMMIT, 1); + dbenv->log_set_config(DB_LOG_IN_MEMORY, 1); + int ret = dbenv->open(NULL, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -145,7 +154,7 @@ CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDB LOCK(cs_db); assert(mapFileUseCount.count(strFile) == 0); - Db db(&dbenv, 0); + Db db(dbenv, 0); int result = db.verify(strFile.c_str(), NULL, NULL, 0); if (result == 0) return VERIFY_OK; @@ -168,7 +177,7 @@ bool CDBEnv::Salvage(std::string strFile, bool fAggressive, std::vectortxn_checkpoint(0, 0, 0); if (fMockDb) return; - dbenv.lsn_reset(strFile.c_str(), 0); + dbenv->lsn_reset(strFile.c_str(), 0); } @@ -237,7 +246,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode) : pdb(NULL), activ ++bitdb.mapFileUseCount[strFile]; pdb = bitdb.mapDb[strFile]; if (pdb == NULL) { - pdb = new Db(&bitdb.dbenv, 0); + pdb = new Db(bitdb.dbenv, 0); bool fMockDb = bitdb.IsMock(); if (fMockDb) { @@ -284,7 +293,7 @@ void CDB::Flush() if (fReadOnly) nMinutes = 1; - bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); + bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0); } void CDB::Close() @@ -323,7 +332,7 @@ bool CDBEnv::RemoveDb(const string& strFile) this->CloseDb(strFile); LOCK(cs_db); - int rc = dbenv.dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT); + int rc = dbenv->dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT); return (rc == 0); } @@ -343,7 +352,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} CDB db(strFile.c_str(), "r"); - Db* pdbCopy = new Db(&bitdb.dbenv, 0); + Db* pdbCopy = new Db(bitdb.dbenv, 0); int ret = pdbCopy->open(NULL, // Txn pointer strFileRes.c_str(), // Filename @@ -393,10 +402,10 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) } } if (fSuccess) { - Db dbA(&bitdb.dbenv, 0); + Db dbA(bitdb.dbenv, 0); if (dbA.remove(strFile.c_str(), NULL, 0)) fSuccess = false; - Db dbB(&bitdb.dbenv, 0); + Db dbB(bitdb.dbenv, 0); if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) fSuccess = false; } @@ -428,12 +437,12 @@ void CDBEnv::Flush(bool fShutdown) if (nRefCount == 0) { // Move log data to the dat file CloseDb(strFile); - LogPrint("db", "CDBEnv::Flush : %s checkpoint\n", strFile); - dbenv.txn_checkpoint(0, 0, 0); - LogPrint("db", "CDBEnv::Flush : %s detach\n", strFile); + LogPrint("db", "CDBEnv::Flush: %s checkpoint\n", strFile); + dbenv->txn_checkpoint(0, 0, 0); + LogPrint("db", "CDBEnv::Flush: %s detach\n", strFile); if (!fMockDb) - dbenv.lsn_reset(strFile.c_str(), 0); - LogPrint("db", "CDBEnv::Flush : %s closed\n", strFile); + dbenv->lsn_reset(strFile.c_str(), 0); + LogPrint("db", "CDBEnv::Flush: %s closed\n", strFile); mapFileUseCount.erase(mi++); } else mi++; @@ -442,7 +451,7 @@ void CDBEnv::Flush(bool fShutdown) if (fShutdown) { char** listp; if (mapFileUseCount.empty()) { - dbenv.log_archive(&listp, DB_ARCH_REMOVE); + dbenv->log_archive(&listp, DB_ARCH_REMOVE); Close(); if (!fMockDb) boost::filesystem::remove_all(boost::filesystem::path(strPath) / "database"); diff --git a/src/wallet/db.h b/src/wallet/db.h index 2128c04349c0c..756150513c631 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -43,12 +43,14 @@ class CDBEnv public: mutable CCriticalSection cs_db; - DbEnv dbenv; + DbEnv *dbenv; std::map mapFileUseCount; std::map mapDb; CDBEnv(); ~CDBEnv(); + void Reset(); + void MakeMock(); bool IsMock() { return fMockDb; } @@ -83,7 +85,7 @@ class CDBEnv DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) { DbTxn* ptxn = NULL; - int ret = dbenv.txn_begin(NULL, &ptxn, flags); + int ret = dbenv->txn_begin(NULL, &ptxn, flags); if (!ptxn || ret != 0) return NULL; return ptxn; diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 16f7d7c5cfdf8..e559772c77e29 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -51,7 +51,7 @@ int64_t static DecodeDumpTime(const std::string& str) std::string static EncodeDumpString(const std::string& str) { std::stringstream ret; - BOOST_FOREACH (unsigned char c, str) { + for (unsigned char c : str) { if (c <= 32 || c >= 128 || c == '%') { ret << '%' << HexStr(&c, &c + 1); } else { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a3f69573b60e9..233458c080055 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -63,12 +63,12 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) uint256 hash = wtx.GetHash(); entry.push_back(Pair("txid", hash.GetHex())); UniValue conflicts(UniValue::VARR); - BOOST_FOREACH (const uint256& conflict, wtx.GetConflicts()) + for (const uint256& conflict : wtx.GetConflicts()) conflicts.push_back(conflict.GetHex()); entry.push_back(Pair("walletconflicts", conflicts)); entry.push_back(Pair("time", wtx.GetTxTime())); entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived)); - BOOST_FOREACH (const PAIRTYPE(string, string) & item, wtx.mapValue) + for (const PAIRTYPE(string, string) & item : wtx.mapValue) entry.push_back(Pair(item.first, item.second)); } @@ -137,7 +137,7 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew = false) it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid(); ++it) { const CWalletTx& wtx = (*it).second; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) + for (const CTxOut& txout : wtx.vout) if (txout.scriptPubKey == scriptPubKey) bKeyUsed = true; } @@ -312,7 +312,7 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) // Find all addresses that have the given account UniValue ret(UniValue::VARR); - BOOST_FOREACH (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item, pwalletMain->mapAddressBook) { + for (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item : pwalletMain->mapAddressBook) { const CBitcoinAddress& address = item.first; const string& strName = item.second.name; if (strName == strAccount) @@ -487,9 +487,9 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp) UniValue jsonGroupings(UniValue::VARR); map balances = pwalletMain->GetAddressBalances(); - BOOST_FOREACH (set grouping, pwalletMain->GetAddressGroupings()) { + for (set grouping : pwalletMain->GetAddressGroupings()) { UniValue jsonGrouping(UniValue::VARR); - BOOST_FOREACH (CTxDestination address, grouping) { + for (CTxDestination address : grouping) { UniValue addressInfo(UniValue::VARR); addressInfo.push_back(CBitcoinAddress(address).ToString()); addressInfo.push_back(ValueFromAmount(balances[address])); @@ -605,7 +605,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) if (wtx.IsCoinBase() || !IsFinalTx(wtx)) continue; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) + for (const CTxOut& txout : wtx.vout) if (txout.scriptPubKey == scriptPubKey) if (wtx.GetDepthInMainChain() >= nMinDepth) nAmount += txout.nValue; @@ -657,7 +657,7 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) if (wtx.IsCoinBase() || !IsFinalTx(wtx)) continue; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) if (wtx.GetDepthInMainChain() >= nMinDepth) @@ -759,10 +759,10 @@ UniValue getbalance(const UniValue& params, bool fHelp) list listSent; wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); if (wtx.GetDepthInMainChain() >= nMinDepth) { - BOOST_FOREACH (const COutputEntry& r, listReceived) + for (const COutputEntry& r : listReceived) nBalance += r.amount; } - BOOST_FOREACH (const COutputEntry& s, listSent) + for (const COutputEntry& s : listSent) nBalance -= s.amount; nBalance -= allFee; } @@ -1027,7 +1027,7 @@ UniValue sendmany(const UniValue& params, bool fHelp) CAmount totalAmount = 0; vector keys = sendTo.getKeys(); - BOOST_FOREACH(const string& name_, keys) { + for (const string& name_ : keys) { CBitcoinAddress address(name_); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid ION address: ")+name_); @@ -1164,7 +1164,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) if (nDepth < nMinDepth) continue; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { CTxDestination address; if (!ExtractDestination(txout.scriptPubKey, address)) continue; @@ -1186,7 +1186,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) // Reply UniValue ret(UniValue::VARR); map mapAccountTally; - BOOST_FOREACH (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item, pwalletMain->mapAddressBook) { + for (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item : pwalletMain->mapAddressBook) { const CBitcoinAddress& address = item.first; const string& strAccount = item.second.name; map::iterator it = mapTally.find(address); @@ -1221,7 +1221,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) obj.push_back(Pair("bcconfirmations", (nBCConf == std::numeric_limits::max() ? 0 : nBCConf))); UniValue transactions(UniValue::VARR); if (it != mapTally.end()) { - BOOST_FOREACH (const uint256& item, (*it).second.txids) { + for (const uint256& item : (*it).second.txids) { transactions.push_back(item.GetHex()); } } @@ -1335,7 +1335,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe // Sent if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) { - BOOST_FOREACH (const COutputEntry& s, listSent) { + for (const COutputEntry& s : listSent) { UniValue entry(UniValue::VOBJ); if (involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY)) entry.push_back(Pair("involvesWatchonly", true)); @@ -1354,7 +1354,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe // Received if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) { - BOOST_FOREACH (const COutputEntry& r, listReceived) { + for (const COutputEntry& r : listReceived) { string account; if (pwalletMain->mapAddressBook.count(r.destination)) account = pwalletMain->mapAddressBook[r.destination].name; @@ -1560,7 +1560,7 @@ UniValue listaccounts(const UniValue& params, bool fHelp) includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY; map mapAccountBalances; - BOOST_FOREACH (const PAIRTYPE(CTxDestination, CAddressBookData) & entry, pwalletMain->mapAddressBook) { + for (const PAIRTYPE(CTxDestination, CAddressBookData) & entry : pwalletMain->mapAddressBook) { if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me mapAccountBalances[entry.second.name] = 0; } @@ -1576,10 +1576,10 @@ UniValue listaccounts(const UniValue& params, bool fHelp) continue; wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly); mapAccountBalances[strSentAccount] -= nFee; - BOOST_FOREACH (const COutputEntry& s, listSent) + for (const COutputEntry& s : listSent) mapAccountBalances[strSentAccount] -= s.amount; if (nDepth >= nMinDepth) { - BOOST_FOREACH (const COutputEntry& r, listReceived) + for (const COutputEntry& r : listReceived) if (pwalletMain->mapAddressBook.count(r.destination)) mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount; else @@ -1588,11 +1588,11 @@ UniValue listaccounts(const UniValue& params, bool fHelp) } const list & acentries = pwalletMain->laccentries; - BOOST_FOREACH (const CAccountingEntry& entry, acentries) + for (const CAccountingEntry& entry : acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; UniValue ret(UniValue::VOBJ); - BOOST_FOREACH (const PAIRTYPE(string, CAmount) & accountBalance, mapAccountBalances) { + for (const PAIRTYPE(string, CAmount) & accountBalance : mapAccountBalances) { ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); } return ret; @@ -2153,7 +2153,7 @@ UniValue listlockunspent(const UniValue& params, bool fHelp) UniValue ret(UniValue::VARR); - BOOST_FOREACH (COutPoint& outpt, vOutpts) { + for (COutPoint& outpt : vOutpts) { UniValue o(UniValue::VOBJ); o.push_back(Pair("txid", outpt.hash.GetHex())); @@ -2406,7 +2406,7 @@ UniValue printAddresses() std::vector vCoins; pwalletMain->AvailableCoins(vCoins); std::map mapAddresses; - BOOST_FOREACH (const COutput& out, vCoins) { + for (const COutput& out : vCoins) { CTxDestination utxoAddress; ExtractDestination(out.tx->vout[out.i].scriptPubKey, utxoAddress); std::string strAdd = CBitcoinAddress(utxoAddress).ToString(); @@ -2846,6 +2846,10 @@ UniValue mintzerocoin(const UniValue& params, bool fHelp) "\nAs a json rpc call\n" + HelpExampleRpc("mintzerocoin", "13, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")); + + if (Params().NetworkID() != CBaseChainParams::REGTEST) + throw JSONRPCError(RPC_WALLET_ERROR, "xION minting is DISABLED"); + LOCK2(cs_main, pwalletMain->cs_wallet); if (params.size() == 1) @@ -2930,6 +2934,7 @@ UniValue spendzerocoin(const UniValue& params, bool fHelp) "3. minimizechange (boolean, required) Try to minimize the returning change [false]\n" "4. \"address\" (string, optional, default=change) Send to specified address or to a new change address.\n" " If there is change then an address is required\n" + "5. ispublicspend (boolean, optional, default=true) create a public zc spend instead of use the old code (only for regression tests)" "\nResult:\n" "{\n" @@ -2967,12 +2972,19 @@ UniValue spendzerocoin(const UniValue& params, bool fHelp) CAmount nAmount = AmountFromValue(params[0]); // Spending amount bool fMintChange = params[1].get_bool(); // Mint change to xION + if (fMintChange && Params().NetworkID() != CBaseChainParams::REGTEST) + throw JSONRPCError(RPC_WALLET_ERROR, "xION minting is DISABLED, cannot mint change"); bool fMinimizeChange = params[2].get_bool(); // Minimize change std::string address_str = params.size() > 3 ? params[3].get_str() : ""; + bool ispublicspend = params.size() > 4 ? params[3].get_bool() : true; vector vMintsSelected; - return DoXionSpend(nAmount, fMintChange, fMinimizeChange, vMintsSelected, address_str); + if (!ispublicspend && Params().NetworkID() != CBaseChainParams::REGTEST) { + throw JSONRPCError(RPC_WALLET_ERROR, "xION old spend only available in regtest for tests purposes"); + } + + return DoXionSpend(nAmount, fMintChange, fMinimizeChange, vMintsSelected, address_str, ispublicspend); } @@ -3070,8 +3082,12 @@ UniValue spendzerocoinmints(const UniValue& params, bool fHelp) } -extern UniValue DoXionSpend(const CAmount nAmount, bool fMintChange, bool fMinimizeChange, vector& vMintsSelected, std::string address_str) +extern UniValue DoXionSpend(const CAmount nAmount, bool fMintChange, bool fMinimizeChange, vector& vMintsSelected, std::string address_str, bool ispublicspend) { + // zerocoin MINT is disabled. fMintChange should be false here. Double check + if (fMintChange && Params().NetworkID() != CBaseChainParams::REGTEST) + throw JSONRPCError(RPC_WALLET_ERROR, "xION minting is DISABLED, cannot mint change"); + int64_t nTimeStart = GetTimeMillis(); CBitcoinAddress address = CBitcoinAddress(); // Optional sending address. Dummy initialization here. CWalletTx wtx; @@ -3082,9 +3098,9 @@ extern UniValue DoXionSpend(const CAmount nAmount, bool fMintChange, bool fMinim address = CBitcoinAddress(address_str); if(!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid ION address"); - fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange, &address); + fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange, &address, ispublicspend); } else // Spend to newly generated local address - fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange); + fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange, nullptr, ispublicspend); if (!fSuccess) throw JSONRPCError(RPC_WALLET_ERROR, receipt.GetStatusMessage()); @@ -3111,7 +3127,7 @@ extern UniValue DoXionSpend(const CAmount nAmount, bool fMintChange, bool fMinim nValueOut += txout.nValue; CTxDestination dest; - if(txout.scriptPubKey.IsZerocoinMint()) + if(txout.IsZerocoinMint()) out.push_back(Pair("address", "zerocoinmint")); else if(ExtractDestination(txout.scriptPubKey, dest)) out.push_back(Pair("address", CBitcoinAddress(dest).ToString())); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index d82070c22f3df..5f9d1ad866882 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -9,8 +9,8 @@ #include #include -#include #include +#include "test_ion.h" // how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles #define RUN_TESTS 100 @@ -23,7 +23,7 @@ using namespace std; typedef set > CoinSet; -BOOST_AUTO_TEST_SUITE(wallet_tests) +BOOST_FIXTURE_TEST_SUITE(wallet_tests, TestingSetup) static CWallet wallet; static vector vCoins; @@ -52,7 +52,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa static void empty_wallet(void) { - BOOST_FOREACH(COutput output, vCoins) + for (COutput output : vCoins) delete output.tx; vCoins.clear(); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5d04b4109595a..47589ac703c69 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -272,7 +272,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool anonymizeOnly { LOCK(cs_wallet); - BOOST_FOREACH (const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) { + for (const MasterKeyMap::value_type& pMasterKey : mapMasterKeys) { if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) @@ -297,7 +297,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, CCrypter crypter; CKeyingMaterial vMasterKey; - BOOST_FOREACH (MasterKeyMap::value_type& pMasterKey, mapMasterKeys) { + for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys) { if (!crypter.SetKeyFromPassphrase(strOldWalletPassphraseFinal, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) @@ -388,8 +388,8 @@ set CWallet::GetConflicts(const uint256& txid) const std::pair range; - BOOST_FOREACH (const CTxIn& txin, wtx.vin) { - if (mapTxSpends.count(txin.prevout) <= 1 || wtx.IsZerocoinSpend()) + for (const CTxIn& txin : wtx.vin) { + if (mapTxSpends.count(txin.prevout) <= 1 || wtx.HasZerocoinSpendInputs()) continue; // No conflict if zero or one spends range = mapTxSpends.equal_range(txin.prevout); for (TxSpends::const_iterator it = range.first; it != range.second; ++it) @@ -465,7 +465,7 @@ void CWallet::AddToSpends(const uint256& wtxid) if (thisTx.IsCoinBase()) // Coinbases don't spend anything! return; - BOOST_FOREACH (const CTxIn& txin, thisTx.vin) + for (const CTxIn& txin : thisTx.vin) AddToSpends(txin.prevout, wtxid); } @@ -496,7 +496,7 @@ bool CWallet::GetMasternodeVinAndKeys(CTxIn& txinRet, CPubKey& pubKeyRet, CKey& return false; } - BOOST_FOREACH (COutput& out, vPossibleCoins) + for (COutput& out : vPossibleCoins) if (out.tx->GetHash() == txHash && out.i == nOutputIndex) // found it! return GetVinAndKeysFromOutput(out, txinRet, pubKeyRet, keyRet); @@ -638,7 +638,7 @@ void CWallet::MarkDirty() { { LOCK(cs_wallet); - BOOST_FOREACH (PAIRTYPE(const uint256, CWalletTx) & item, mapWallet) + for (PAIRTYPE(const uint256, CWalletTx) & item : mapWallet) item.second.MarkDirty(); } } @@ -743,8 +743,8 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) // If a transaction changes 'conflicted' state, that changes the balance // available of the outputs it spends. So force those to be // recomputed, also: - BOOST_FOREACH (const CTxIn& txin, tx.vin) { - if (!tx.IsZerocoinSpend() && mapWallet.count(txin.prevout.hash)) + for (const CTxIn& txin : tx.vin) { + if (!txin.IsZerocoinSpend() && mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); } } @@ -816,93 +816,6 @@ CAmount CWallet::GetDebit(const CTxIn& txin, const isminefilter& filter) const return 0; } -// Recursively determine the rounds of a given input (How deep is the Obfuscation chain for a given input) -int CWallet::GetRealInputObfuscationRounds(CTxIn in, int rounds) const -{ - static std::map mDenomWtxes; - - if (rounds >= 16) return 15; // 16 rounds max - - uint256 hash = in.prevout.hash; - unsigned int nout = in.prevout.n; - - const CWalletTx* wtx = GetWalletTx(hash); - if (wtx != NULL) { - std::map::const_iterator mdwi = mDenomWtxes.find(hash); - // not known yet, let's add it - if (mdwi == mDenomWtxes.end()) { - LogPrint("obfuscation", "GetInputObfuscationRounds INSERTING %s\n", hash.ToString()); - mDenomWtxes[hash] = CMutableTransaction(*wtx); - } - // found and it's not an initial value, just return it - else if (mDenomWtxes[hash].vout[nout].nRounds != -10) { - return mDenomWtxes[hash].vout[nout].nRounds; - } - - - // bounds check - if (nout >= wtx->vout.size()) { - // should never actually hit this - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, -4); - return -4; - } - - if (pwalletMain->IsCollateralAmount(wtx->vout[nout].nValue)) { - mDenomWtxes[hash].vout[nout].nRounds = -3; - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - //make sure the final output is non-denominate - if (/*rounds == 0 && */ !IsDenominatedAmount(wtx->vout[nout].nValue)) //NOT DENOM - { - mDenomWtxes[hash].vout[nout].nRounds = -2; - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - bool fAllDenoms = true; - BOOST_FOREACH (CTxOut out, wtx->vout) { - fAllDenoms = fAllDenoms && IsDenominatedAmount(out.nValue); - } - // this one is denominated but there is another non-denominated output found in the same tx - if (!fAllDenoms) { - mDenomWtxes[hash].vout[nout].nRounds = 0; - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - int nShortest = -10; // an initial value, should be no way to get this by calculations - bool fDenomFound = false; - // only denoms here so let's look up - BOOST_FOREACH (CTxIn in2, wtx->vin) { - if (IsMine(in2)) { - int n = GetRealInputObfuscationRounds(in2, rounds + 1); - // denom found, find the shortest chain or initially assign nShortest with the first found value - if (n >= 0 && (n < nShortest || nShortest == -10)) { - nShortest = n; - fDenomFound = true; - } - } - } - mDenomWtxes[hash].vout[nout].nRounds = fDenomFound ? (nShortest >= 15 ? 16 : nShortest + 1) // good, we a +1 to the shortest one but only 16 rounds max allowed - : - 0; // too bad, we are the fist one in that chain - LogPrint("obfuscation", "GetInputObfuscationRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); - return mDenomWtxes[hash].vout[nout].nRounds; - } - - return rounds - 1; -} - -// respect current settings -int CWallet::GetInputObfuscationRounds(CTxIn in) const -{ - LOCK(cs_wallet); - int realObfuscationRounds = GetRealInputObfuscationRounds(in, 0); - return realObfuscationRounds > nZeromintPercentage ? nZeromintPercentage : realObfuscationRounds; -} - bool CWallet::IsDenominated(const CTxIn& txin) const { { @@ -916,24 +829,9 @@ bool CWallet::IsDenominated(const CTxIn& txin) const return false; } -bool CWallet::IsDenominated(const CTransaction& tx) const -{ - /* - Return false if ANY inputs are non-denom - */ - bool ret = true; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { - if (!IsDenominated(txin)) { - ret = false; - } - } - return ret; -} - - bool CWallet::IsDenominatedAmount(CAmount nInputAmount) const { - BOOST_FOREACH (CAmount d, obfuScationDenominations) + for (CAmount d : obfuScationDenominations) if (nInputAmount == d) return true; return false; @@ -969,7 +867,7 @@ int64_t CWalletTx::GetTxTime() const int64_t CWalletTx::GetComputedTxTime() const { LOCK(cs_main); - if (IsZerocoinSpend() || IsZerocoinMint()) { + if (ContainsZerocoins()) { if (IsInMainChain()) return mapBlockIndex.at(hashBlock)->GetBlockTime(); else @@ -1110,73 +1008,6 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache) const return nCredit; } -CAmount CWalletTx::GetAnonymizableCredit(bool fUseCache) const -{ - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAnonymizableCreditCached) - return nAnonymizableCreditCached; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; - const CTxIn vin = CTxIn(hashTx, i); - - if (pwallet->IsSpent(hashTx, i) || pwallet->IsLockedCoin(hashTx, i)) continue; - if (fMasterNode && vout[i].nValue == MASTERNODE_COLLATERAL_AMOUNT * COIN) continue; // do not count MN-like outputs - - const int rounds = pwallet->GetInputObfuscationRounds(vin); - if (rounds >= -2 && rounds < nZeromintPercentage) { - nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); - if (!MoneyRange(nCredit)) - throw std::runtime_error("CWalletTx::GetAnonamizableCredit() : value out of range"); - } - } - - nAnonymizableCreditCached = nCredit; - fAnonymizableCreditCached = true; - return nCredit; -} - -CAmount CWalletTx::GetAnonymizedCredit(bool fUseCache) const -{ - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAnonymizedCreditCached) - return nAnonymizedCreditCached; - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; - const CTxIn vin = CTxIn(hashTx, i); - - if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominated(vin)) continue; - - const int rounds = pwallet->GetInputObfuscationRounds(vin); - if (rounds >= nZeromintPercentage) { - nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); - if (!MoneyRange(nCredit)) - throw std::runtime_error("CWalletTx::GetAnonymizedCredit() : value out of range"); - } - } - - nAnonymizedCreditCached = nCredit; - fAnonymizedCreditCached = true; - return nCredit; -} - // Return sum of unlocked coins CAmount CWalletTx::GetUnlockedCredit() const { @@ -1238,50 +1069,6 @@ CAmount CWalletTx::GetLockedCredit() const return nCredit; } -CAmount CWalletTx::GetDenominatedCredit(bool unconfirmed, bool fUseCache) const -{ - if (pwallet == 0) - return 0; - - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - int nDepth = GetDepthInMainChain(false); - if (nDepth < 0) return 0; - - bool isUnconfirmed = !IsFinalTx(*this) || (!IsTrusted() && nDepth == 0); - if (unconfirmed != isUnconfirmed) return 0; - - if (fUseCache) { - if (unconfirmed && fDenomUnconfCreditCached) - return nDenomUnconfCreditCached; - else if (!unconfirmed && fDenomConfCreditCached) - return nDenomConfCreditCached; - } - - CAmount nCredit = 0; - uint256 hashTx = GetHash(); - for (unsigned int i = 0; i < vout.size(); i++) { - const CTxOut& txout = vout[i]; - - if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominatedAmount(vout[i].nValue)) continue; - - nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); - if (!MoneyRange(nCredit)) - throw std::runtime_error("CWalletTx::GetDenominatedCredit() : value out of range"); - } - - if (unconfirmed) { - nDenomUnconfCreditCached = nCredit; - fDenomUnconfCreditCached = true; - } else { - nDenomConfCreditCached = nCredit; - fDenomConfCreditCached = true; - } - return nCredit; -} - CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const { LOCK(cs_main); @@ -1377,6 +1164,7 @@ void CWalletTx::GetAmounts(list& listReceived, } // Sent/received. + bool hasZerocoinSpends = HasZerocoinSpendInputs(); for (unsigned int i = 0; i < vout.size(); ++i) { const CTxOut& txout = vout[i]; isminetype fIsMine = pwallet->IsMine(txout); @@ -1387,12 +1175,12 @@ void CWalletTx::GetAmounts(list& listReceived, // Don't report 'change' txouts if (pwallet->IsChange(txout)) continue; - } else if (!(fIsMine & filter) && !IsZerocoinSpend()) + } else if (!(fIsMine & filter) && !hasZerocoinSpends) continue; // In either case, we need to get the destination address CTxDestination address; - if (txout.scriptPubKey.IsZerocoinMint()) { + if (txout.IsZerocoinMint()) { address = CNoDestination(); } else if (!ExtractDestination(txout.scriptPubKey, address)) { if (!IsCoinStake() && !IsCoinBase()) { @@ -1424,13 +1212,13 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived, GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); if (strAccount == strSentAccount) { - BOOST_FOREACH (const COutputEntry& s, listSent) + for (const COutputEntry& s : listSent) nSent += s.amount; nFee = allFee; } { LOCK(pwallet->cs_wallet); - BOOST_FOREACH (const COutputEntry& r, listReceived) { + for (const COutputEntry& r : listReceived) { if (pwallet->mapAddressBook.count(r.destination)) { map::const_iterator mi = pwallet->mapAddressBook.find(r.destination); if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount) @@ -1480,7 +1268,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) CBlock block; ReadBlockFromDisk(block, pindex); - BOOST_FOREACH (CTransaction& tx, block.vtx) { + for (CTransaction& tx : block.vtx) { if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) ret++; } @@ -1545,7 +1333,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) void CWallet::ReacceptWalletTransactions() { LOCK2(cs_main, cs_wallet); - BOOST_FOREACH (PAIRTYPE(const uint256, CWalletTx) & item, mapWallet) { + for (PAIRTYPE(const uint256, CWalletTx) & item : mapWallet) { const uint256& wtxid = item.first; CWalletTx& wtx = item.second; assert(wtx.GetHash() == wtxid); @@ -1621,14 +1409,14 @@ void CWallet::ResendWalletTransactions() LOCK(cs_wallet); // Sort them in chronological order multimap mapSorted; - BOOST_FOREACH (PAIRTYPE(const uint256, CWalletTx) & item, mapWallet) { + for (PAIRTYPE(const uint256, CWalletTx) & item : mapWallet) { CWalletTx& wtx = item.second; // Don't rebroadcast until it's had plenty of time that // it should have gotten in already by now. if (nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60) mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx)); } - BOOST_FOREACH (PAIRTYPE(const unsigned int, CWalletTx*) & item, mapSorted) { + for (PAIRTYPE(const unsigned int, CWalletTx*) & item : mapSorted) { CWalletTx& wtx = *item.second; wtx.RelayWalletTransaction(); } @@ -1659,20 +1447,25 @@ CAmount CWallet::GetBalance() const return nTotal; } -std::map mapMintMaturity; -int nLastMaturityCheck = 0; +//std::map mapMintMaturity; +//int nLastMaturityCheck = 0; + CAmount CWallet::GetZerocoinBalance(bool fMatureOnly) const { if (fMatureOnly) { - if (chainActive.Height() > nLastMaturityCheck) - mapMintMaturity = GetMintMaturityHeight(); - nLastMaturityCheck = chainActive.Height(); + // This code is not removed just for when we back to use xION in the future, for now it's useless, + // every public coin spend is now spendable without need to have new mints on top. + + //if (chainActive.Height() > nLastMaturityCheck) + // mapMintMaturity = GetMintMaturityHeight(); + //nLastMaturityCheck = chainActive.Height(); CAmount nBalance = 0; vector vMints = xionTracker->GetMints(true); for (auto meta : vMints) { - if (meta.nHeight >= mapMintMaturity.at(meta.denom) || meta.nHeight >= chainActive.Height() || meta.nHeight == 0) - continue; + // Every public coin spend is now spendable, no need to mint new coins on top. + //if (meta.nHeight >= mapMintMaturity.at(meta.denom) || meta.nHeight >= chainActive.Height() || meta.nHeight == 0) + // continue; nBalance += libzerocoin::ZerocoinDenominationToAmount(meta.denom); } return nBalance; @@ -1743,122 +1536,6 @@ std::map CWallet::GetMyZerocoinDistribut } -CAmount CWallet::GetAnonymizableBalance() const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - if (pcoin->IsTrusted()) - nTotal += pcoin->GetAnonymizableCredit(); - } - } - - return nTotal; -} - -CAmount CWallet::GetAnonymizedBalance() const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - if (pcoin->IsTrusted()) - nTotal += pcoin->GetAnonymizedCredit(); - } - } - - return nTotal; -} - -// Note: calculated including unconfirmed, -// that's ok as long as we use it for informational purposes only -double CWallet::GetAverageAnonymizedRounds() const -{ - if (fLiteMode) return 0; - - double fTotal = 0; - double fCount = 0; - - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - uint256 hash = (*it).first; - - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - CTxIn vin = CTxIn(hash, i); - - if (IsSpent(hash, i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(vin)) continue; - - int rounds = GetInputObfuscationRounds(vin); - fTotal += (float)rounds; - fCount += 1; - } - } - } - - if (fCount == 0) return 0; - - return fTotal / fCount; -} - -// Note: calculated including unconfirmed, -// that's ok as long as we use it for informational purposes only -CAmount CWallet::GetNormalizedAnonymizedBalance() const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - uint256 hash = (*it).first; - - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - CTxIn vin = CTxIn(hash, i); - - if (IsSpent(hash, i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(vin)) continue; - if (pcoin->GetDepthInMainChain() < 0) continue; - - int rounds = GetInputObfuscationRounds(vin); - nTotal += pcoin->vout[i].nValue * rounds / nZeromintPercentage; - } - } - } - - return nTotal; -} - -CAmount CWallet::GetDenominatedBalance(bool unconfirmed) const -{ - if (fLiteMode) return 0; - - CAmount nTotal = 0; - { - LOCK2(cs_main, cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - - nTotal += pcoin->GetDenominatedCredit(unconfirmed); - } - } - - return nTotal; -} - CAmount CWallet::GetUnconfirmedBalance() const { CAmount nTotal = 0; @@ -2040,7 +1717,7 @@ map > CWallet::AvailableCoinsByAddress(bool fCo AvailableCoins(vCoins, fConfirmed); map > mapCoins; - BOOST_FOREACH (COutput out, vCoins) { + for (COutput out : vCoins) { if (maxCoinValue > 0 && out.tx->vout[out.i].nValue > maxCoinValue) continue; @@ -2103,7 +1780,7 @@ bool less_then_denom(const COutput& out1, const COutput& out2) bool found1 = false; bool found2 = false; - BOOST_FOREACH (CAmount d, obfuScationDenominations) // loop through predefined denoms + for (CAmount d : obfuScationDenominations) // loop through predefined denoms { if (pcoin1->vout[out1.i].nValue == d) found1 = true; if (pcoin2->vout[out2.i].nValue == d) found2 = true; @@ -2126,7 +1803,7 @@ bool CWallet::SelectStakeCoins(std::list >& listInp //if zerocoinspend, then use the block time int64_t nTxTime = out.tx->GetTxTime(); - if (out.tx->IsZerocoinSpend()) { + if (out.tx->vin[0].IsZerocoinSpend()) { if (!out.tx->IsInMainChain()) continue; nTxTime = mapBlockIndex.at(out.tx->hashBlock)->GetBlockTime(); @@ -2149,6 +1826,7 @@ bool CWallet::SelectStakeCoins(std::list >& listInp } } + /* Disable xION Staking //xION if ((GetBoolArg("-xionstake", true) || fPrecompute) && chainActive.Height() > Params().Zerocoin_Block_V2_Start() && !IsSporkActive(SPORK_9_ZEROCOIN_MAINTENANCE_MODE)) { //Only update xION set once per update interval @@ -2178,7 +1856,7 @@ bool CWallet::SelectStakeCoins(std::list >& listInp } } } - + */ return true; } @@ -2200,7 +1878,7 @@ bool CWallet::MintableCoins() for (const COutput& out : vCoins) { int64_t nTxTime = out.tx->GetTxTime(); - if (out.tx->IsZerocoinSpend()) { + if (out.tx->vin[0].IsZerocoinSpend()) { if (!out.tx->IsInMainChain()) continue; nTxTime = mapBlockIndex.at(out.tx->hashBlock)->GetBlockTime(); @@ -2248,7 +1926,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int if (fDebug) LogPrint("selectcoins", "tryDenom: %d\n", tryDenom); vValue.clear(); nTotalLower = 0; - BOOST_FOREACH (const COutput& output, vCoins) { + for (const COutput& output : vCoins) { if (!output.fSpendable) continue; @@ -2342,325 +2020,26 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set return all selected outputs (we want all selected to go into the transaction for sure) if (coinControl && coinControl->HasSelected()) { - BOOST_FOREACH (const COutput& out, vCoins) { + for (const COutput& out : vCoins) { if (!out.fSpendable) continue; - if (coin_type == ONLY_DENOMINATED) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - int rounds = GetInputObfuscationRounds(vin); - // make sure it's actually anonymized - if (rounds < nZeromintPercentage) continue; - } - nValueRet += out.tx->vout[out.i].nValue; setCoinsRet.insert(make_pair(out.tx, out.i)); } return (nValueRet >= nTargetValue); } - //if we're doing only denominated, we need to round up to the nearest .1 ION - if (coin_type == ONLY_DENOMINATED) { - // Make outputs by looping through denominations, from large to small - BOOST_FOREACH (CAmount v, obfuScationDenominations) { - BOOST_FOREACH (const COutput& out, vCoins) { - if (out.tx->vout[out.i].nValue == v //make sure it's the denom we're looking for - && nValueRet + out.tx->vout[out.i].nValue < nTargetValue + (0.1 * COIN) + 100 //round the amount up to .1 ION over - ) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - int rounds = GetInputObfuscationRounds(vin); - // make sure it's actually anonymized - if (rounds < nZeromintPercentage) continue; - nValueRet += out.tx->vout[out.i].nValue; - setCoinsRet.insert(make_pair(out.tx, out.i)); - } - } - } - return (nValueRet >= nTargetValue); - } - return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) || SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) || (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet))); } -struct CompareByPriority { - bool operator()(const COutput& t1, - const COutput& t2) const - { - return t1.Priority() > t2.Priority(); - } -}; - -bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vCoinsRet, std::vector& vCoinsRet2, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax) -{ - vCoinsRet.clear(); - nValueRet = 0; - - vCoinsRet2.clear(); - vector vCoins; - AvailableCoins(vCoins, true, NULL, false, ONLY_DENOMINATED); - - std::random_shuffle(vCoins.rbegin(), vCoins.rend()); - - //keep track of each denomination that we have - bool fFound10000 = false; - bool fFound1000 = false; - bool fFound100 = false; - bool fFound10 = false; - bool fFound1 = false; - bool fFoundDot1 = false; - - //Check to see if any of the denomination are off, in that case mark them as fulfilled - if (!(nDenom & (1 << 0))) fFound10000 = true; - if (!(nDenom & (1 << 1))) fFound1000 = true; - if (!(nDenom & (1 << 2))) fFound100 = true; - if (!(nDenom & (1 << 3))) fFound10 = true; - if (!(nDenom & (1 << 4))) fFound1 = true; - if (!(nDenom & (1 << 5))) fFoundDot1 = true; - - BOOST_FOREACH (const COutput& out, vCoins) { - // masternode-like input should not be selected by AvailableCoins now anyway - //if(out.tx->vout[out.i].nValue == 20000*COIN) continue; - if (nValueRet + out.tx->vout[out.i].nValue <= nValueMax) { - bool fAccepted = false; - - // Function returns as follows: - // - // bit 0 - 10000 ION+1 ( bit on if present ) - // bit 1 - 1000 ION+1 - // bit 2 - 100 ION+1 - // bit 3 - 10 ION+1 - // bit 4 - 1 ION+1 - // bit 5 - .1 ION+1 - - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - int rounds = GetInputObfuscationRounds(vin); - if (rounds >= nObfuscationRoundsMax) continue; - if (rounds < nObfuscationRoundsMin) continue; - - if (fFound10000 && fFound1000 && fFound100 && fFound10 && fFound1 && fFoundDot1) { //if fulfilled - //we can return this for submission - if (nValueRet >= nValueMin) { - //random reduce the max amount we'll submit for anonymity - nValueMax -= (rand() % (nValueMax / 5)); - //on average use 50% of the inputs or less - int r = (rand() % (int)vCoins.size()); - if ((int)vCoinsRet.size() > r) return true; - } - //Denomination criterion has been met, we can take any matching denominations - if ((nDenom & (1 << 0)) && out.tx->vout[out.i].nValue == ((10000 * COIN) + 10000000)) { - fAccepted = true; - } else if ((nDenom & (1 << 1)) && out.tx->vout[out.i].nValue == ((1000 * COIN) + 1000000)) { - fAccepted = true; - } else if ((nDenom & (1 << 2)) && out.tx->vout[out.i].nValue == ((100 * COIN) + 100000)) { - fAccepted = true; - } else if ((nDenom & (1 << 3)) && out.tx->vout[out.i].nValue == ((10 * COIN) + 10000)) { - fAccepted = true; - } else if ((nDenom & (1 << 4)) && out.tx->vout[out.i].nValue == ((1 * COIN) + 1000)) { - fAccepted = true; - } else if ((nDenom & (1 << 5)) && out.tx->vout[out.i].nValue == ((.1 * COIN) + 100)) { - fAccepted = true; - } - } else { - //Criterion has not been satisfied, we will only take 1 of each until it is. - if ((nDenom & (1 << 0)) && out.tx->vout[out.i].nValue == ((10000 * COIN) + 10000000)) { - fAccepted = true; - fFound10000 = true; - } else if ((nDenom & (1 << 1)) && out.tx->vout[out.i].nValue == ((1000 * COIN) + 1000000)) { - fAccepted = true; - fFound1000 = true; - } else if ((nDenom & (1 << 2)) && out.tx->vout[out.i].nValue == ((100 * COIN) + 100000)) { - fAccepted = true; - fFound100 = true; - } else if ((nDenom & (1 << 3)) && out.tx->vout[out.i].nValue == ((10 * COIN) + 10000)) { - fAccepted = true; - fFound10 = true; - } else if ((nDenom & (1 << 4)) && out.tx->vout[out.i].nValue == ((1 * COIN) + 1000)) { - fAccepted = true; - fFound1 = true; - } else if ((nDenom & (1 << 5)) && out.tx->vout[out.i].nValue == ((.1 * COIN) + 100)) { - fAccepted = true; - fFoundDot1 = true; - } - } - if (!fAccepted) continue; - - vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey - nValueRet += out.tx->vout[out.i].nValue; - vCoinsRet.push_back(vin); - vCoinsRet2.push_back(out); - } - } - - return (nValueRet >= nValueMin && fFound10000 && fFound1000 && fFound100 && fFound10 && fFound1 && fFoundDot1); -} - -bool CWallet::SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector& setCoinsRet, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax) const -{ - CCoinControl* coinControl = NULL; - - setCoinsRet.clear(); - nValueRet = 0; - - vector vCoins; - AvailableCoins(vCoins, true, coinControl, false, nObfuscationRoundsMin < 0 ? ONLY_NONDENOMINATED_NOT20000IFMN : ONLY_DENOMINATED); - - set > setCoinsRet2; - - //order the array so largest nondenom are first, then denominations, then very small inputs. - sort(vCoins.rbegin(), vCoins.rend(), CompareByPriority()); - - BOOST_FOREACH (const COutput& out, vCoins) { - //do not allow inputs less than 1 CENT - if (out.tx->vout[out.i].nValue < CENT) continue; - //do not allow collaterals to be selected - if (IsCollateralAmount(out.tx->vout[out.i].nValue)) continue; - if (fMasterNode && out.tx->vout[out.i].nValue == MASTERNODE_COLLATERAL_AMOUNT * COIN) continue; //masternode input - - if (nValueRet + out.tx->vout[out.i].nValue <= nValueMax) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - int rounds = GetInputObfuscationRounds(vin); - if (rounds >= nObfuscationRoundsMax) continue; - if (rounds < nObfuscationRoundsMin) continue; - - vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey - nValueRet += out.tx->vout[out.i].nValue; - setCoinsRet.push_back(vin); - setCoinsRet2.insert(make_pair(out.tx, out.i)); - } - } - - // if it's more than min, we're good to return - if (nValueRet >= nValueMin) return true; - - return false; -} - -bool CWallet::SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nValueRet) const -{ - vector vCoins; - - //LogPrintf(" selecting coins for collateral\n"); - AvailableCoins(vCoins); - - //LogPrintf("found coins %d\n", (int)vCoins.size()); - - set > setCoinsRet2; - - BOOST_FOREACH (const COutput& out, vCoins) { - // collateral inputs will always be a multiple of DARSEND_COLLATERAL, up to five - if (IsCollateralAmount(out.tx->vout[out.i].nValue)) { - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey - nValueRet += out.tx->vout[out.i].nValue; - setCoinsRet.push_back(vin); - setCoinsRet2.insert(make_pair(out.tx, out.i)); - return true; - } - } - - return false; -} - -int CWallet::CountInputsWithAmount(CAmount nInputAmount) -{ - CAmount nTotal = 0; - { - LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx* pcoin = &(*it).second; - if (pcoin->IsTrusted()) { - int nDepth = pcoin->GetDepthInMainChain(false); - - for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - COutput out = COutput(pcoin, i, nDepth, true); - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - - if (out.tx->vout[out.i].nValue != nInputAmount) continue; - if (!IsDenominatedAmount(pcoin->vout[i].nValue)) continue; - if (IsSpent(out.tx->GetHash(), i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(vin)) continue; - - nTotal++; - } - } - } - } - - return nTotal; -} - -bool CWallet::HasCollateralInputs(bool fOnlyConfirmed) const -{ - vector vCoins; - AvailableCoins(vCoins, fOnlyConfirmed); - - int nFound = 0; - BOOST_FOREACH (const COutput& out, vCoins) - if (IsCollateralAmount(out.tx->vout[out.i].nValue)) nFound++; - - return nFound > 0; -} - bool CWallet::IsCollateralAmount(CAmount nInputAmount) const { return nInputAmount != 0 && nInputAmount % OBFUSCATION_COLLATERAL == 0 && nInputAmount < OBFUSCATION_COLLATERAL * 5 && nInputAmount > OBFUSCATION_COLLATERAL; } -bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason) -{ - /* - To doublespend a collateral transaction, it will require a fee higher than this. So there's - still a significant cost. - */ - CAmount nFeeRet = 1 * COIN; - - txCollateral.vin.clear(); - txCollateral.vout.clear(); - - CReserveKey reservekey(this); - CAmount nValueIn2 = 0; - std::vector vCoinsCollateral; - - if (!SelectCoinsCollateral(vCoinsCollateral, nValueIn2)) { - strReason = "Error: Obfuscation requires a collateral transaction and could not locate an acceptable input!"; - return false; - } - - // make our change address - CScript scriptChange; - CPubKey vchPubKey; - assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptChange = GetScriptForDestination(vchPubKey.GetID()); - reservekey.KeepKey(); - - BOOST_FOREACH (CTxIn v, vCoinsCollateral) - txCollateral.vin.push_back(v); - - if (nValueIn2 - OBFUSCATION_COLLATERAL - nFeeRet > 0) { - //pay collateral charge in fees - CTxOut vout3 = CTxOut(nValueIn2 - OBFUSCATION_COLLATERAL, scriptChange); - txCollateral.vout.push_back(vout3); - } - - int vinNumber = 0; - BOOST_FOREACH (CTxIn v, txCollateral.vin) { - if (!SignSignature(*this, v.prevPubKey, txCollateral, vinNumber, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { - BOOST_FOREACH (CTxIn v, vCoinsCollateral) - UnlockCoin(v.prevout); - - strReason = "CObfuscationPool::Sign - Unable to sign collateral transaction! \n"; - return false; - } - vinNumber++; - } - - return true; -} - bool CWallet::GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, bool useIX) { // make our change address @@ -2713,21 +2092,6 @@ bool CWallet::GetBudgetFinalizationCollateralTX(CWalletTx& tx, uint256 hash, boo return true; } -bool CWallet::ConvertList(std::vector vCoins, std::vector& vecAmounts) -{ - BOOST_FOREACH (CTxIn i, vCoins) { - if (mapWallet.count(i.prevout.hash)) { - CWalletTx& wtx = mapWallet[i.prevout.hash]; - if (i.prevout.n < wtx.vout.size()) { - vecAmounts.push_back(wtx.vout[i.prevout.n].nValue); - } - } else { - LogPrintf("ConvertList -- Couldn't find transaction\n"); - } - } - return true; -} - bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, @@ -2743,7 +2107,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CAmount nValue = 0; unsigned int nSubtractFeeFromAmount = 0; - BOOST_FOREACH (const CRecipient& recipient, vecSend) { + for (const CRecipient& recipient : vecSend) { if (nValue < 0 || recipient.nAmount < 0) { strFailReason = _("Transaction amounts must be positive"); return false; @@ -2781,7 +2145,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, // vouts to the payees if (coinControl && !coinControl->fSplitBlock) { - BOOST_FOREACH (const CRecipient& recipient, vecSend) { + for (const CRecipient& recipient : vecSend) { CTxOut txout(recipient.nAmount, recipient.scriptPubKey); if (recipient.fSubtractFeeFromAmount) @@ -2818,7 +2182,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, else nSplitBlock = 1; - BOOST_FOREACH (const CRecipient& recipient, vecSend) { + for (const CRecipient& recipient : vecSend) { for (int i = 0; i < nSplitBlock; i++) { if (i == nSplitBlock - 1) { uint64_t nRemainder = recipient.nAmount % nSplitBlock; @@ -2853,7 +2217,7 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, } - BOOST_FOREACH (PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { + for (PAIRTYPE(const CWalletTx*, unsigned int) pcoin : setCoins) { CAmount nCredit = pcoin.first->vout[pcoin.second].nValue; //The coin age after the next block (depth+1) is used instead of the current, //reflecting an assumption the user would accept a bit more delay for @@ -2960,12 +2324,12 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, reservekey.ReturnKey(); // Fill vin - BOOST_FOREACH (const PAIRTYPE(const CWalletTx*, unsigned int) & coin, setCoins) + for (const PAIRTYPE(const CWalletTx*, unsigned int) & coin : setCoins) txNew.vin.push_back(CTxIn(coin.first->GetHash(), coin.second)); // Sign int nIn = 0; - BOOST_FOREACH (const PAIRTYPE(const CWalletTx*, unsigned int) & coin, setCoins) + for (const PAIRTYPE(const CWalletTx*, unsigned int) & coin : setCoins) if (!SignSignature(*this, *coin.first, txNew, nIn++)) { strFailReason = _("Signing transaction failed"); return false; @@ -3220,9 +2584,9 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std: AddToWallet(wtxNew); // Notify that old coins are spent - if (!wtxNew.IsZerocoinSpend()) { + if (!wtxNew.HasZerocoinSpendInputs()) { set updated_hahes; - BOOST_FOREACH (const CTxIn& txin, wtxNew.vin) { + for (const CTxIn& txin : wtxNew.vin) { // notify only once if (updated_hahes.find(txin.prevout.hash) != updated_hahes.end()) continue; @@ -3291,154 +2655,6 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge return nFeeNeeded; } -CAmount CWallet::GetTotalValue(std::vector vCoins) -{ - CAmount nTotalValue = 0; - CWalletTx wtx; - BOOST_FOREACH (CTxIn i, vCoins) { - if (mapWallet.count(i.prevout.hash)) { - CWalletTx& wtx = mapWallet[i.prevout.hash]; - if (i.prevout.n < wtx.vout.size()) { - nTotalValue += wtx.vout[i.prevout.n].nValue; - } - } else { - LogPrintf("GetTotalValue -- Couldn't find transaction\n"); - } - } - return nTotalValue; -} - -string CWallet::PrepareObfuscationDenominate(int minRounds, int maxRounds) -{ - if (IsLocked()) - return _("Error: Wallet locked, unable to create transaction!"); - - if (obfuScationPool.GetState() != POOL_STATUS_ERROR && obfuScationPool.GetState() != POOL_STATUS_SUCCESS) - if (obfuScationPool.GetEntriesCount() > 0) - return _("Error: You already have pending entries in the Obfuscation pool"); - - // ** find the coins we'll use - std::vector vCoins; - std::vector vCoinsResult; - std::vector vCoins2; - CAmount nValueIn = 0; - CReserveKey reservekey(this); - - /* - Select the coins we'll use - - if minRounds >= 0 it means only denominated inputs are going in and coming out - */ - if (minRounds >= 0) { - if (!SelectCoinsByDenominations(obfuScationPool.sessionDenom, 0.1 * COIN, OBFUSCATION_POOL_MAX, vCoins, vCoins2, nValueIn, minRounds, maxRounds)) - return _("Error: Can't select current denominated inputs"); - } - - LogPrintf("PrepareObfuscationDenominate - preparing obfuscation denominate . Got: %d \n", nValueIn); - - { - LOCK(cs_wallet); - BOOST_FOREACH (CTxIn v, vCoins) - LockCoin(v.prevout); - } - - CAmount nValueLeft = nValueIn; - std::vector vOut; - - /* - TODO: Front load with needed denominations (e.g. .1, 1 ) - */ - - // Make outputs by looping through denominations: try to add every needed denomination, repeat up to 5-10 times. - // This way we can be pretty sure that it should have at least one of each needed denomination. - // NOTE: No need to randomize order of inputs because they were - // initially shuffled in CWallet::SelectCoinsByDenominations already. - int nStep = 0; - int nStepsMax = 5 + GetRandInt(5); - while (nStep < nStepsMax) { - BOOST_FOREACH (CAmount v, obfuScationDenominations) { - // only use the ones that are approved - bool fAccepted = false; - if ((obfuScationPool.sessionDenom & (1 << 0)) && v == ((10000 * COIN) + 10000000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 1)) && v == ((1000 * COIN) + 1000000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 2)) && v == ((100 * COIN) + 100000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 3)) && v == ((10 * COIN) + 10000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 4)) && v == ((1 * COIN) + 1000)) { - fAccepted = true; - } else if ((obfuScationPool.sessionDenom & (1 << 5)) && v == ((.1 * COIN) + 100)) { - fAccepted = true; - } - if (!fAccepted) continue; - - // try to add it - if (nValueLeft - v >= 0) { - // Note: this relies on a fact that both vectors MUST have same size - std::vector::iterator it = vCoins.begin(); - std::vector::iterator it2 = vCoins2.begin(); - while (it2 != vCoins2.end()) { - // we have matching inputs - if ((*it2).tx->vout[(*it2).i].nValue == v) { - // add new input in resulting vector - vCoinsResult.push_back(*it); - // remove corresponting items from initial vectors - vCoins.erase(it); - vCoins2.erase(it2); - - CScript scriptChange; - CPubKey vchPubKey; - // use a unique change address - assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptChange = GetScriptForDestination(vchPubKey.GetID()); - reservekey.KeepKey(); - - // add new output - CTxOut o(v, scriptChange); - vOut.push_back(o); - - // subtract denomination amount - nValueLeft -= v; - - break; - } - ++it; - ++it2; - } - } - } - - nStep++; - - if (nValueLeft == 0) break; - } - - { - // unlock unused coins - LOCK(cs_wallet); - BOOST_FOREACH (CTxIn v, vCoins) - UnlockCoin(v.prevout); - } - - if (obfuScationPool.GetDenominations(vOut) != obfuScationPool.sessionDenom) { - // unlock used coins on failure - LOCK(cs_wallet); - BOOST_FOREACH (CTxIn v, vCoinsResult) - UnlockCoin(v.prevout); - return "Error: can't make current denominated outputs"; - } - - // randomize the output order - std::random_shuffle(vOut.begin(), vOut.end()); - - // We also do not care about full amount as long as we have right denominations, just pass what we found - obfuScationPool.SendObfuscationDenominate(vCoinsResult, vOut, nValueIn - nValueLeft); - - return ""; -} - DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (!fFileBacked) @@ -3514,7 +2730,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address) if (fFileBacked) { // Delete destdata tuples associated with address std::string strAddress = CBitcoinAddress(address).ToString(); - BOOST_FOREACH (const PAIRTYPE(string, string) & item, mapAddressBook[address].destdata) { + for (const PAIRTYPE(string, string) & item : mapAddressBook[address].destdata) { CWalletDB(strWalletFile).EraseDestData(strAddress, item.first); } } @@ -3548,7 +2764,7 @@ bool CWallet::NewKeyPool() { LOCK(cs_wallet); CWalletDB walletdb(strWalletFile); - BOOST_FOREACH (int64_t nIndex, setKeyPool) + for (int64_t nIndex : setKeyPool) walletdb.ErasePool(nIndex); setKeyPool.clear(); @@ -3681,7 +2897,7 @@ std::map CWallet::GetAddressBalances() { LOCK(cs_wallet); - BOOST_FOREACH (PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) { + for (PAIRTYPE(uint256, CWalletTx) walletEntry : mapWallet) { CWalletTx* pcoin = &walletEntry.second; if (!IsFinalTx(*pcoin) || !pcoin->IsTrusted()) @@ -3719,13 +2935,13 @@ set > CWallet::GetAddressGroupings() set > groupings; set grouping; - BOOST_FOREACH (PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) { + for (PAIRTYPE(uint256, CWalletTx) walletEntry : mapWallet) { CWalletTx* pcoin = &walletEntry.second; if (pcoin->vin.size() > 0) { bool any_mine = false; // group all input addresses with each other - BOOST_FOREACH (CTxIn txin, pcoin->vin) { + for (CTxIn txin : pcoin->vin) { CTxDestination address; if (!IsMine(txin)) /* If this input isn't mine, ignore it */ continue; @@ -3737,7 +2953,7 @@ set > CWallet::GetAddressGroupings() // group change with input addresses if (any_mine) { - BOOST_FOREACH (CTxOut txout, pcoin->vout) + for (CTxOut txout : pcoin->vout) if (IsChange(txout)) { CTxDestination txoutAddr; if (!ExtractDestination(txout.scriptPubKey, txoutAddr)) @@ -3765,17 +2981,17 @@ set > CWallet::GetAddressGroupings() set*> uniqueGroupings; // a set of pointers to groups of addresses map*> setmap; // map addresses to the unique group containing it - BOOST_FOREACH (set grouping, groupings) { + for (set grouping : groupings) { // make a set of all the groups hit by this new group set*> hits; map*>::iterator it; - BOOST_FOREACH (CTxDestination address, grouping) + for (CTxDestination address : grouping) if ((it = setmap.find(address)) != setmap.end()) hits.insert((*it).second); // merge all hit groups into a new single group and delete old groups set* merged = new set(grouping); - BOOST_FOREACH (set* hit, hits) { + for (set* hit : hits) { merged->insert(hit->begin(), hit->end()); uniqueGroupings.erase(hit); delete hit; @@ -3783,12 +2999,12 @@ set > CWallet::GetAddressGroupings() uniqueGroupings.insert(merged); // update setmap - BOOST_FOREACH (CTxDestination element, *merged) + for (CTxDestination element : *merged) setmap[element] = merged; } set > ret; - BOOST_FOREACH (set* uniqueGrouping, uniqueGroupings) { + for (set* uniqueGrouping : uniqueGroupings) { ret.insert(*uniqueGrouping); delete uniqueGrouping; } @@ -3800,7 +3016,7 @@ set CWallet::GetAccountAddresses(string strAccount) const { LOCK(cs_wallet); set result; - BOOST_FOREACH (const PAIRTYPE(CTxDestination, CAddressBookData) & item, mapAddressBook) { + for (const PAIRTYPE(CTxDestination, CAddressBookData) & item : mapAddressBook) { const CTxDestination& address = item.first; const string& strName = item.second.name; if (strName == strAccount) @@ -3848,7 +3064,7 @@ void CWallet::GetAllReserveKeys(set& setAddress) const CWalletDB walletdb(strWalletFile); LOCK2(cs_main, cs_wallet); - BOOST_FOREACH (const int64_t& id, setKeyPool) { + for (const int64_t& id : setKeyPool) { CKeyPool keypool; if (!walletdb.ReadPool(id, keypool)) throw runtime_error("GetAllReserveKeyHashes() : read failed"); @@ -3927,7 +3143,7 @@ class CAffectedKeysVisitor : public boost::static_visitor std::vector vDest; int nRequired; if (ExtractDestinations(script, type, vDest, nRequired)) { - BOOST_FOREACH (const CTxDestination& dest, vDest) + for (const CTxDestination& dest : vDest) boost::apply_visitor(*this, dest); } } @@ -3963,7 +3179,7 @@ void CWallet::GetKeyBirthTimes(std::map& mapKeyBirth) const std::map mapKeyFirstBlock; std::set setKeys; GetKeys(setKeys); - BOOST_FOREACH (const CKeyID& keyid, setKeys) { + for (const CKeyID& keyid : setKeys) { if (mapKeyBirth.count(keyid) == 0) mapKeyFirstBlock[keyid] = pindexMax; } @@ -3982,10 +3198,10 @@ void CWallet::GetKeyBirthTimes(std::map& mapKeyBirth) const if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) { // ... which are already in a block int nHeight = blit->second->nHeight; - BOOST_FOREACH (const CTxOut& txout, wtx.vout) { + for (const CTxOut& txout : wtx.vout) { // iterate over all their outputs CAffectedKeysVisitor(*this, vAffected).Process(txout.scriptPubKey); - BOOST_FOREACH (const CKeyID& keyid, vAffected) { + for (const CKeyID& keyid : vAffected) { // ... and all their affected keys std::map::iterator rit = mapKeyFirstBlock.find(keyid); if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight) @@ -4069,20 +3285,6 @@ bool CWallet::LoadDestData(const CTxDestination& dest, const std::string& key, c return true; } -bool CWallet::GetDestData(const CTxDestination& dest, const std::string& key, std::string* value) const -{ - std::map::const_iterator i = mapAddressBook.find(dest); - if (i != mapAddressBook.end()) { - CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key); - if (j != i->second.destdata.end()) { - if (value) - *value = j->second; - return true; - } - } - return false; -} - void CWallet::InitAutoConvertAddresses() { CWalletDB walletdb(strWalletFile); @@ -4262,7 +3464,7 @@ void CWallet::AutoCombineDust() //find masternode rewards that need to be combined CCoinControl* coinControl = new CCoinControl(); CAmount nTotalRewardsValue = 0; - BOOST_FOREACH (const COutput& out, vCoins) { + for (const COutput& out : vCoins) { if (!out.fSpendable) continue; //no coins should get this far if they dont have proper maturity, this is double checking @@ -4759,14 +3961,28 @@ bool CWallet::CheckCoinSpend(libzerocoin::CoinSpend& spend, libzerocoin::Accumul return true; } -bool CWallet::MintToTxIn(CZerocoinMint mint, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint) +bool CWallet::MintToTxIn( + CZerocoinMint mint, + const uint256& hashTxOut, + CTxIn& newTxIn, + CZerocoinSpendReceipt& receipt, + libzerocoin::SpendType spendType, + CBlockIndex* pindexCheckpoint, + bool publicCoinSpend) { std::map mapMints; mapMints.insert(std::make_pair(mint.GetValue(), mint)); std::vector vin; - if (MintsToInputVector(mapMints, hashTxOut, vin, receipt, spendType, pindexCheckpoint)) { - newTxIn = vin[0]; - return true; + if (publicCoinSpend) { + if (MintsToInputVectorPublicSpend(mapMints, hashTxOut, vin, receipt, spendType, pindexCheckpoint)) { + newTxIn = vin[0]; + return true; + } + } else { + if (MintsToInputVector(mapMints, hashTxOut, vin, receipt, spendType, pindexCheckpoint)) { + newTxIn = vin[0]; + return true; + } } return false; @@ -4878,7 +4094,93 @@ bool CWallet::MintsToInputVector(std::map& mapMintsSelec return true; } -bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, CWalletTx& wtxNew, CReserveKey& reserveKey, CZerocoinSpendReceipt& receipt, vector& vSelectedMints, vector& vNewMints, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* address) +bool CWallet::MintsToInputVectorPublicSpend(std::map& mapMintsSelected, const uint256& hashTxOut, std::vector& vin, + CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint) +{ + // Default error status if not changed below + receipt.SetStatus(_("Transaction Mint Started"), XION_TXMINT_GENERAL); + + int nLockAttempts = 0; + while (nLockAttempts < 100) { + TRY_LOCK(xionTracker->cs_spendcache, lockSpendcache); + if (!lockSpendcache) { + fGlobalUnlockSpendCache = true; + MilliSleep(100); + ++nLockAttempts; + continue; + } + + for (auto &it : mapMintsSelected) { + CZerocoinMint mint = it.second; + + // Create the simple input and the scriptSig -> Serial + Randomness + Private key signature of both. + // As the mint doesn't have the output index search it.. + CTransaction txMint; + uint256 hashBlock; + if (!GetTransaction(mint.GetTxHash(), txMint, hashBlock)) { + receipt.SetStatus(strprintf(_("Unable to find transaction containing mint %s"), mint.GetTxHash().GetHex()), XION_TXMINT_GENERAL); + return false; + } else if (mapBlockIndex.count(hashBlock) < 1) { + // check that this mint made it into the blockchain + receipt.SetStatus(_("Mint did not make it into blockchain"), XION_TXMINT_GENERAL); + return false; + } + + int outputIndex = -1; + for (unsigned long i = 0; i < txMint.vout.size(); ++i) { + CTxOut out = txMint.vout[i]; + if (out.scriptPubKey.IsZerocoinMint()){ + libzerocoin::PublicCoin pubcoin(Params().Zerocoin_Params(false)); + CValidationState state; + if (!TxOutToPublicCoin(out, pubcoin, state)) + return error("%s: extracting pubcoin from txout failed", __func__); + + if (pubcoin.getValue() == mint.GetValue()){ + outputIndex = i; + break; + } + } + } + + if (outputIndex == -1) { + receipt.SetStatus(_("Pubcoin not found in mint tx"), XION_TXMINT_GENERAL); + return false; + } + + mint.SetOutputIndex(outputIndex); + CTxIn in; + if(!XIONModule::createInput(in, mint, hashTxOut)){ + receipt.SetStatus(_("Cannot create public spend input"), XION_TXMINT_GENERAL); + return false; + } + vin.emplace_back(in); + receipt.AddSpend(CZerocoinSpend(mint.GetSerialNumber(), 0, mint.GetValue(), mint.GetDenomination(), 0)); + } + break; + } + + if (nLockAttempts == 100) { + LogPrintf("%s : could not get lock on cs_spendcache\n", __func__); + receipt.SetStatus(_("could not get lock on cs_spendcache"), XION_TXMINT_GENERAL); + return false; + } + + receipt.SetStatus(_("Spend Valid"), XION_SPEND_OKAY); // Everything okay + + return true; +} + +bool CWallet::CreateZerocoinSpendTransaction( + CAmount nValue, + CWalletTx& wtxNew, + CReserveKey& reserveKey, + CZerocoinSpendReceipt& receipt, + vector& vSelectedMints, + vector& vNewMints, + bool fMintChange, + bool fMinimizeChange, + CBitcoinAddress* address, + bool isPublicSpend) { // Check available funds int nStatus = XION_TRX_FUNDS_PROBLEMS; @@ -4901,10 +4203,11 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, CWalletTx& wtxNew, CAmount nValueSelected = 0; int nCoinsReturned = 0; // Number of coins returned in change from function below (for debug) int nNeededSpends = 0; // Number of spends which would be needed if selection failed - const int nMaxSpends = Params().Zerocoin_MaxSpendsPerTransaction(); // Maximum possible spends for one xION transaction + const int nMaxSpends = Params().Zerocoin_MaxPublicSpendsPerTransaction(); // Maximum possible spends for one xION public spend transaction vector vMintsToFetch; if (vSelectedMints.empty()) { - setMints = xionTracker->ListMints(true, true, true); // need to find mints to spend + // All of the xION used in the public coin spend are mature by default (everything is public now.. no need to wait for any accumulation) + setMints = xionTracker->ListMints(true, false, true, true); // need to find mints to spend if(setMints.empty()) { receipt.SetStatus(_("Failed to find Zerocoins in wallet.dat"), nStatus); return false; @@ -4965,7 +4268,7 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, CWalletTx& wtxNew, uint256 hashBlock; bool fArchive = false; if (!GetTransaction(mint.GetTxHash(), txMint, hashBlock)) { - receipt.SetStatus(_("Unable to find transaction containing mint"), nStatus); + receipt.SetStatus(strprintf(_("Unable to find transaction containing mint, txHash: %s"), mint.GetTxHash().GetHex()), nStatus); fArchive = true; } else if (mapBlockIndex.count(hashBlock) < 1) { receipt.SetStatus(_("Mint did not make it into blockchain"), nStatus); @@ -4993,11 +4296,13 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, CWalletTx& wtxNew, return false; } - if ((static_cast(vSelectedMints.size()) > Params().Zerocoin_MaxSpendsPerTransaction())) { + + if (static_cast(vSelectedMints.size()) > nMaxSpends) { receipt.SetStatus(_("Failed to find coin set amongst held coins with less than maxNumber of Spends"), nStatus); return false; } + // Create change if needed nStatus = XION_TRX_CHANGE; @@ -5069,8 +4374,15 @@ bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, CWalletTx& wtxNew, //add all of the mints to the transaction as inputs std::vector vin; - if (!MintsToInputVector(mapSelectedMints, hashTxOut, vin, receipt, libzerocoin::SpendType::SPEND, pindexCheckpoint)) - return false; + if (isPublicSpend) { + if (!MintsToInputVectorPublicSpend(mapSelectedMints, hashTxOut, vin, receipt, + libzerocoin::SpendType::SPEND, pindexCheckpoint)) + return false; + } else { + if (!MintsToInputVector(mapSelectedMints, hashTxOut, vin, receipt, + libzerocoin::SpendType::SPEND, pindexCheckpoint)) + return false; + } txNew.vin = vin; // Limit size @@ -5376,7 +4688,7 @@ string CWallet::MintZerocoin(CAmount nValue, CWalletTx& wtxNew, vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* addressTo) +bool CWallet::SpendZerocoin(CAmount nAmount, CWalletTx& wtxNew, CZerocoinSpendReceipt& receipt, vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* addressTo, bool isPublicSpend) { // Default: assume something goes wrong. Depending on the problem this gets more specific below int nStatus = XION_SPEND_ERROR; @@ -5388,7 +4700,7 @@ bool CWallet::SpendZerocoin(CAmount nAmount, CWalletTx& wtxNew, CZerocoinSpendRe CReserveKey reserveKey(this); vector vNewMints; - if (!CreateZerocoinSpendTransaction(nAmount, wtxNew, reserveKey, receipt, vMintsSelected, vNewMints, fMintChange, fMinimizeChange, addressTo)) { + if (!CreateZerocoinSpendTransaction(nAmount, wtxNew, reserveKey, receipt, vMintsSelected, vNewMints, fMintChange, fMinimizeChange, addressTo, isPublicSpend)) { return false; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 7f98e38c3c853..596d45043c45f 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -18,11 +18,12 @@ #include "primitives/block.h" #include "primitives/transaction.h" #include "xion/zerocoin.h" -#include "ui_interface.h" +#include "guiinterface.h" #include "util.h" #include "validationinterface.h" #include "wallet/wallet_ismine.h" #include "wallet/walletdb.h" +#include "xion/xionmodule.h" #include "xion/xionwallet.h" #include "xion/xiontracker.h" @@ -203,25 +204,23 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface public: bool MintableCoins(); bool SelectStakeCoins(std::list >& listInputs, CAmount nTargetAmount, bool fPrecompute = false); - bool SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector& setCoinsRet, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax) const; - bool SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector& vCoinsRet, std::vector& vCoinsRet2, CAmount& nValueRet, int nObfuscationRoundsMin, int nObfuscationRoundsMax); - bool SelectCoinsDarkDenominated(CAmount nTargetValue, std::vector& setCoinsRet, CAmount& nValueRet) const; - bool HasCollateralInputs(bool fOnlyConfirmed = true) const; bool IsCollateralAmount(CAmount nInputAmount) const; - int CountInputsWithAmount(CAmount nInputAmount); - - bool SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nValueRet) const; // Zerocoin additions bool CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransaction& txNew, vector& vDMints, CReserveKey* reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl = NULL, const bool isZCSpendChange = false); - bool CreateZerocoinSpendTransaction(CAmount nValue, CWalletTx& wtxNew, CReserveKey& reserveKey, CZerocoinSpendReceipt& receipt, vector& vSelectedMints, vector& vNewMints, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* address = NULL); + bool CreateZerocoinSpendTransaction(CAmount nValue, CWalletTx& wtxNew, CReserveKey& reserveKey, CZerocoinSpendReceipt& receipt, vector& vSelectedMints, vector& vNewMints, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* address = NULL, bool isPublicSpend = true); bool CheckCoinSpend(libzerocoin::CoinSpend& spend, libzerocoin::Accumulator& accumulator, CZerocoinSpendReceipt& receipt); - bool MintToTxIn(CZerocoinMint mint, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr); + bool MintToTxIn(CZerocoinMint mint, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr, bool publicCoinSpend = true); bool MintsToInputVector(std::map& mapMintsSelected, const uint256& hashTxOut, std::vector& vin, CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr); + + // Public coin spend input creation + bool MintsToInputVectorPublicSpend(std::map& mapMintsSelected, const uint256& hashTxOut, std::vector& vin, + CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr); + std::string MintZerocoinFromOutPoint(CAmount nValue, CWalletTx& wtxNew, std::vector& vDMints, const vector vOutpts); std::string MintZerocoin(CAmount nValue, CWalletTx& wtxNew, vector& vDMints, const CCoinControl* coinControl = NULL); - bool SpendZerocoin(CAmount nValue, CWalletTx& wtxNew, CZerocoinSpendReceipt& receipt, vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* addressTo = NULL); + bool SpendZerocoin(CAmount nValue, CWalletTx& wtxNew, CZerocoinSpendReceipt& receipt, vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* addressTo = NULL, bool isPublicSpend = true); std::string ResetMintZerocoin(); std::string ResetSpentZerocoin(); void ReconsiderZerocoins(std::list& listMintsRestored, std::list& listDMintsRestored); @@ -417,7 +416,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface void UnlockCoin(COutPoint& output); void UnlockAllCoins(); void ListLockedCoins(std::vector& vOutpts); - CAmount GetTotalValue(std::vector vCoins); // keystore implementation // Generate a new key @@ -452,8 +450,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool EraseDestData(const CTxDestination& dest, const std::string& key); //! Adds a destination data tuple to the store, without saving it to disk bool LoadDestData(const CTxDestination& dest, const std::string& key, const std::string& value); - //! Look up a destination data tuple in the store, return true if found false otherwise - bool GetDestData(const CTxDestination& dest, const std::string& key, std::string* value) const; //! Adds a watch-only address to the store, and saves it to disk. bool AddWatchOnly(const CScript& dest); @@ -497,11 +493,6 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface std::map GetMyZerocoinDistribution() const; CAmount GetUnconfirmedBalance() const; CAmount GetImmatureBalance() const; - CAmount GetAnonymizableBalance() const; - CAmount GetAnonymizedBalance() const; - double GetAverageAnonymizedRounds() const; - CAmount GetNormalizedAnonymizedBalance() const; - CAmount GetDenominatedBalance(bool unconfirmed = false) const; CAmount GetWatchOnlyBalance() const; CAmount GetUnconfirmedWatchOnlyBalance() const; CAmount GetImmatureWatchOnlyBalance() const; @@ -519,10 +510,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool CreateTransaction(CScript scriptPubKey, const CAmount& nValue, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl = NULL, AvailableCoinsType coin_type = ALL_COINS, bool useIX = false, CAmount nFeePay = 0); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std::string strCommand = "tx"); bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb); - std::string PrepareObfuscationDenominate(int minRounds, int maxRounds); int GenerateObfuscationOutputs(int nTotalValue, std::vector& vout); - bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason); - bool ConvertList(std::vector vCoins, std::vector& vecAmounts); bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64_t nSearchInterval, CMutableTransaction& txNew, unsigned int& nTxNewTime); bool MultiSend(); void AutoCombineDust(); @@ -558,13 +546,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool GetBudgetSystemCollateralTX(CWalletTx& tx, uint256 hash, bool useIX); bool GetBudgetFinalizationCollateralTX(CWalletTx& tx, uint256 hash, bool useIX); // Only used for budget finalization - // get the Obfuscation chain depth for a given input - int GetRealInputObfuscationRounds(CTxIn in, int rounds) const; - // respect current settings - int GetInputObfuscationRounds(CTxIn in) const; - bool IsDenominated(const CTxIn& txin) const; - bool IsDenominated(const CTransaction& tx) const; bool IsDenominatedAmount(CAmount nInputAmount) const; @@ -593,7 +575,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface } bool IsMine(const CTransaction& tx) const { - BOOST_FOREACH (const CTxOut& txout, tx.vout) + for (const CTxOut& txout : tx.vout) if (IsMine(txout)) return true; return false; @@ -606,7 +588,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const { CAmount nDebit = 0; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { nDebit += GetDebit(txin, filter); if (!MoneyRange(nDebit)) throw std::runtime_error("CWallet::GetDebit() : value out of range"); @@ -616,7 +598,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const { CAmount nCredit = 0; - BOOST_FOREACH (const CTxOut& txout, tx.vout) { + for (const CTxOut& txout : tx.vout) { nCredit += GetCredit(txout, filter); if (!MoneyRange(nCredit)) throw std::runtime_error("CWallet::GetCredit() : value out of range"); @@ -626,7 +608,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetChange(const CTransaction& tx) const { CAmount nChange = 0; - BOOST_FOREACH (const CTxOut& txout, tx.vout) { + for (const CTxOut& txout : tx.vout) { nChange += GetChange(txout); if (!MoneyRange(nChange)) throw std::runtime_error("CWallet::GetChange() : value out of range"); @@ -1006,13 +988,10 @@ class CWalletTx : public CMerkleTx CAmount GetCredit(const isminefilter& filter) const; CAmount GetImmatureCredit(bool fUseCache = true) const; CAmount GetAvailableCredit(bool fUseCache = true) const; - CAmount GetAnonymizableCredit(bool fUseCache = true) const; - CAmount GetAnonymizedCredit(bool fUseCache = true) const; // Return sum of unlocked coins CAmount GetUnlockedCredit() const; // Return sum of unlocked coins CAmount GetLockedCredit() const; - CAmount GetDenominatedCredit(bool unconfirmed, bool fUseCache = true) const; CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache = true) const; CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache = true) const; CAmount GetLockedWatchOnlyCredit() const; @@ -1055,7 +1034,7 @@ class CWalletTx : public CMerkleTx return false; // Trusted if all inputs are from us and are in the mempool: - BOOST_FOREACH (const CTxIn& txin, vin) { + for (const CTxIn& txin : vin) { // Transactions not sent by us: not trusted const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash); if (parent == NULL) @@ -1097,7 +1076,7 @@ class COutput //Used with Obfuscation. Will return largest nondenom, then denominations, then very small inputs int Priority() const { - BOOST_FOREACH (CAmount d, obfuScationDenominations) + for (CAmount d : obfuScationDenominations) if (tx->vout[i].nValue == d) return 10000; if (tx->vout[i].nValue < 1 * COIN) return 20000; diff --git a/src/wallet/wallet_ismine.cpp b/src/wallet/wallet_ismine.cpp index f90db51c4e4c4..0c51a747792ca 100644 --- a/src/wallet/wallet_ismine.cpp +++ b/src/wallet/wallet_ismine.cpp @@ -13,7 +13,6 @@ #include "script/standard.h" #include "util.h" -#include using namespace std; @@ -22,7 +21,7 @@ typedef vector valtype; unsigned int HaveKeys(const vector& pubkeys, const CKeyStore& keystore) { unsigned int nResult = 0; - BOOST_FOREACH (const valtype& pubkey, pubkeys) { + for (const valtype& pubkey : pubkeys) { CKeyID keyID = CPubKey(pubkey).GetID(); if(keystore.HaveKey(keyID)) ++nResult; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index d583e5c9835c7..30023bfe6c947 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -344,7 +343,7 @@ CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount) ListAccountCreditDebit(strAccount, entries); CAmount nCreditDebit = 0; - BOOST_FOREACH (const CAccountingEntry& entry, entries) + for (const CAccountingEntry& entry : entries) nCreditDebit += entry.nCreditDebit; return nCreditDebit; @@ -408,7 +407,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet) } list acentries; ListAccountCreditDebit("", acentries); - BOOST_FOREACH (CAccountingEntry& entry, acentries) { + for (CAccountingEntry& entry : acentries) { txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); } @@ -431,7 +430,7 @@ DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet) return DB_LOAD_FAIL; } else { int64_t nOrderPosOff = 0; - BOOST_FOREACH (const int64_t& nOffsetStart, nOrderPosOffsets) { + for (const int64_t& nOffsetStart : nOrderPosOffsets) { if (nOrderPos >= nOffsetStart) ++nOrderPosOff; } @@ -805,7 +804,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta) pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value' - BOOST_FOREACH (uint256 hash, wss.vWalletUpgrade) + for (uint256 hash : wss.vWalletUpgrade) WriteTx(hash, pwallet->mapWallet[hash]); // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: @@ -820,7 +819,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) pwallet->laccentries.clear(); ListAccountCreditDebit("*", pwallet->laccentries); - BOOST_FOREACH(CAccountingEntry& entry, pwallet->laccentries) { + for (CAccountingEntry& entry : pwallet->laccentries) { pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry))); } @@ -896,7 +895,7 @@ DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector& vWtx) return err; // erase each wallet TX - BOOST_FOREACH (uint256& hash, vTxHash) { + for (uint256& hash : vTxHash) { if (!EraseTx(hash)) return DB_CORRUPT; } @@ -1116,8 +1115,8 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) int64_t now = GetTime(); std::string newFilename = strprintf("wallet.%d.bak", now); - int result = dbenv.dbenv.dbrename(NULL, filename.c_str(), NULL, - newFilename.c_str(), DB_AUTO_COMMIT); + int result = dbenv.dbenv->dbrename(NULL, filename.c_str(), NULL, + newFilename.c_str(), DB_AUTO_COMMIT); if (result == 0) LogPrintf("Renamed %s to %s\n", filename, newFilename); else { @@ -1134,12 +1133,12 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size()); bool fSuccess = allOK; - boost::scoped_ptr pdbCopy(new Db(&dbenv.dbenv, 0)); - int ret = pdbCopy->open(NULL, // Txn pointer - filename.c_str(), // Filename - "main", // Logical db name - DB_BTREE, // Database type - DB_CREATE, // Flags + boost::scoped_ptr pdbCopy(new Db(dbenv.dbenv, 0)); + int ret = pdbCopy->open(NULL, // Txn pointer + filename.c_str(), // Filename + "main", // Logical db name + DB_BTREE, // Database type + DB_CREATE, // Flags 0); if (ret > 0) { LogPrintf("Cannot create database file %s\n", filename); @@ -1149,7 +1148,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) CWalletScanState wss; DbTxn* ptxn = dbenv.TxnBegin(); - BOOST_FOREACH (CDBEnv::KeyValPair& row, salvagedData) { + for (CDBEnv::KeyValPair& row : salvagedData) { if (fOnlyKeys) { CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION); CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION); diff --git a/src/xion/accumulatorcheckpoints.json.h b/src/xion/accumulatorcheckpoints.json.h index 87d3da55425e4..7eab0e5f64db1 100644 --- a/src/xion/accumulatorcheckpoints.json.h +++ b/src/xion/accumulatorcheckpoints.json.h @@ -503,116 +503,6 @@ std::string GetMainCheckpoints() { " \"500\": \"5f637bc0beca8ed2b72498cbf2179ad195eab53b712b5a3088618fbf5eff44058007bca06d868fe1f96ac4185e941169cf514bb6e0d409f1aa5674fd7e1f547549dc34ee39a0f258eeae3c7ca4d858317b050aae12aa861c9c00b5ca8ac08d89a6dee15ef6757e0b4c989f7505d7366f50b9558a8e02d0f1676627d8ee21a198b6625a0be56a18df9f26651d8ef796623240940e33d2eb5bfb6e18eb1decb460979f00d8fc76a0d46b1e80b9e1d6fc1c9f47846c8ab0350293414236411459de390e4f5d6e709309b2af198b6ce69314bbd5bc71f64ff951a2e2ea23c6807ff359e088e4898c84f3f913fd2e4c932a69b5dad942c09943a56fb59e2e8d1b11e6\",\n" " \"1000\": \"ca05933280ffa6a31fadbbe8856e09abeef407de3ab0008562f11058ac03b62182d17130f1f432de295c66a8a6d1aad3d52fb69257fe6e6ac46596c01346ffc82c3486f9b5a650d2682da3c398c02f0c6f988952d10626bbf64efb39fb645ce53befe11d07a0012da554fe671cf8cb0e07886b4a62d6a624f42e11f44a3b49a3aade3cc1d5b9dca98f1ab108fd11a5f8314629636531dae030193f7b28d8826850b36f99a4b325bd9b6938131b15e46eae60d7fa24a96bfacf15081697fc1331e4dd0ad098d0dfdc1db02f1f1a49a134c73c3b4997b2c3068908a562bae9e6887aac713272785644519e767f27f913f9bf18f37574b0b8ab0fffb1c13fa7eda\",\n" " \"5000\": \"5e33c35654a34b971acd068760eda578a3e512e78b333cecaf7ae8cf3e665b19d091faa819f2a98063be4992b8beed47885e58fd5344d43fcdff14afb38da59fe3c4b22ff81c6730de6c6ddf8ea5c9f25305b5dbab276db410bfe3d59dfdb7bb3e664998696b00d25e1caf9f1d298b7276c9690c5fc2b2e3e77e89b57bb46a646b9955cf3d175a45b9337189ae4275898d10ecddc66955862ca42fcf18b44d43a0b89b13298e951f4ce5933beca41b4f1924d688415d255dab54ecb54e37bcc1174464be979cf79cb366387d9bd10afc4f20ba1494d87b680b15af2b492da18f375fac6eeccda47ea0eda6d8e22fa1d413a73a14febc23a867b5edfc263f6455\"\n" - " },\n" - " {\n" - " \"height\": 1010020,\n" - " \"1\": \"4d4fda56887766dcd8d477709d8de12704abfb681e5029ded8415baadd2464d40124392a7629b870de4e999197653f7edc004fce16e99b71f27a38d33122315fe80b3116dd54c8647e0d0085a4e16df39203a76bb5e6af42766feab253f9eeae003f008f14c5111d625606510f8ebd95996aeb3801a12a53ff0d29b04ae09d1e74f007a206d14787a9febb99e342875e09eedc7f343ab421aca69c4d3cd0cfed5778912dedb4e21fc2b99dd3b9dd31147646fc12318a73be0cd0952bc143a1726a7acde0d59d05524f3f930b455a37ea100b4184518c7a0fcdc8a3df0eb76d850484a66797588be499fce72a4969a626ed92caaf1cab2aaad9da7bdca4a5a4e3\",\n" - " \"5\": \"541a059d70c208c871ca8fb8120f48fdd6c483d6a20811f295339c17765778eb7ae77603ef4a1e121f79f24ed74d124e71d45d163f51c325e1581eaa7a715e30748bef4d78f4215112d99fc422fa64fee17eb619d926c0f551a71eb6d4ce7265fbcaddd137d8aa8c89b37cd095847d7e38b221e39f277c2b52d442a512848da1b71c70467c53dcb09167c7ac88486c8c3f349c5077ebdcad2a44d9ea9cc1dad9b6820992b9f6ec759b4bda79a4b44e5edfe086ece5feaffeed8e95aabfac505c24be67245f9439cb2dc019cfb664e156f28b3487ad82a7c6664556bce63fe35f75035272c6c0ff3e7aca3d70b6498f29c786eea3bed47dccbbf46013f4fc1b51\",\n" - " \"10\": \"9199a94d492ded52ec18214d757f5a834dc1402786f29b59f74f35b9021568f58b64eee8b70e304d08d3ff48403bb81c7cf0076c6fa50f816c62c9382b5c97c28c5f269b5efb2f1c429e804773b5179d7deea7c34cb97084a031121a5428d1ad00152dc4c84a9b9663fddf1b5579cc43ccd3f1fd2bcb989e29f0e2a466eff26b8519731d9b614954c27510c6376290c08a9dfecec4857909ebf847333cb8da156ad57df3bd6d723e28ac56a1f620d6381e35b76a545b4a839d5a4e925a11da194b466fbfb69a9a66e2b2a85ff7bb5c5f11639f71be0980861e8d2b299f65366152d47ac93937ab0411af26c36120b1061258cce9f6acd50503e69a64d011e4ac\",\n" - " \"50\": \"237f7b87f44908b138213a3c38a2eb583cc2855b2b1c3b4e64ff341b8ea0768f2d5b083ea3e0ad84c4b7bd790014fb76716be9807a7c1c5b98f2103b5edfc18c66fd9729b8d19f8fa41bc9425cb29a0db88ed03dfa30b51eb7e462d404ddd6af381299e0a3273d55653efa6d0623435d15df1304c2cb02991f3a8540d4942a26c44883f3aba63c8f4f0ce753adbe08842886c02a47056037dc86f5abd25df21ef59b71620fe0a929a686c4f42e1e37f4804e79a521b98d21987f94ba628a29858bfc1749ab974380f3b863e42575280b7afcb4f5adba5861ed7e935cc9623386e9800e209a9495fb40d34fa28a22a453b5b2affeda71c06e0672298597578912\",\n" - " \"100\": \"193ffef3ccd865fbbf7b3e0acdc7112709da3c200a95dacf5d7b1def812b993936ac2ec8b0a7ed383d407ed96250bc455e43af80f94b6b6a0ce9b9f9262c96c8c10bd301561b29268440e01ca6155ce6de6708aa3bd9e8082f82ff7b07d33d56c4e911c0deeaa6220e2f664866fbfd15585afde89020a9ea5e2639ec3a759bba231e952308a75e5b48d789825a95fd20a507a9e4300f035708bf1b1072ff5eadad1f69a6ac41aae6238752b6c23873f1dae5bb87a2920d796c310280bb39dd9da70c23b291eb197627f43562fe52a1fc01a90d933add8dbcb1a845106fbf5c42c6cb2e5d2e4871874b05481a0802039151a44d52d10583edfd28b5a9742b1d19\",\n" - " \"500\": \"5f637bc0beca8ed2b72498cbf2179ad195eab53b712b5a3088618fbf5eff44058007bca06d868fe1f96ac4185e941169cf514bb6e0d409f1aa5674fd7e1f547549dc34ee39a0f258eeae3c7ca4d858317b050aae12aa861c9c00b5ca8ac08d89a6dee15ef6757e0b4c989f7505d7366f50b9558a8e02d0f1676627d8ee21a198b6625a0be56a18df9f26651d8ef796623240940e33d2eb5bfb6e18eb1decb460979f00d8fc76a0d46b1e80b9e1d6fc1c9f47846c8ab0350293414236411459de390e4f5d6e709309b2af198b6ce69314bbd5bc71f64ff951a2e2ea23c6807ff359e088e4898c84f3f913fd2e4c932a69b5dad942c09943a56fb59e2e8d1b11e6\",\n" - " \"1000\": \"ca05933280ffa6a31fadbbe8856e09abeef407de3ab0008562f11058ac03b62182d17130f1f432de295c66a8a6d1aad3d52fb69257fe6e6ac46596c01346ffc82c3486f9b5a650d2682da3c398c02f0c6f988952d10626bbf64efb39fb645ce53befe11d07a0012da554fe671cf8cb0e07886b4a62d6a624f42e11f44a3b49a3aade3cc1d5b9dca98f1ab108fd11a5f8314629636531dae030193f7b28d8826850b36f99a4b325bd9b6938131b15e46eae60d7fa24a96bfacf15081697fc1331e4dd0ad098d0dfdc1db02f1f1a49a134c73c3b4997b2c3068908a562bae9e6887aac713272785644519e767f27f913f9bf18f37574b0b8ab0fffb1c13fa7eda\",\n" - " \"5000\": \"5e33c35654a34b971acd068760eda578a3e512e78b333cecaf7ae8cf3e665b19d091faa819f2a98063be4992b8beed47885e58fd5344d43fcdff14afb38da59fe3c4b22ff81c6730de6c6ddf8ea5c9f25305b5dbab276db410bfe3d59dfdb7bb3e664998696b00d25e1caf9f1d298b7276c9690c5fc2b2e3e77e89b57bb46a646b9955cf3d175a45b9337189ae4275898d10ecddc66955862ca42fcf18b44d43a0b89b13298e951f4ce5933beca41b4f1924d688415d255dab54ecb54e37bcc1174464be979cf79cb366387d9bd10afc4f20ba1494d87b680b15af2b492da18f375fac6eeccda47ea0eda6d8e22fa1d413a73a14febc23a867b5edfc263f6455\"\n" - " },\n" - " {\n" - " \"height\": 1020020,\n" - " \"1\": \"954c98510fc255d2a6cf00e5e0c15612f237bc1995dec7b5605a6a9778fa93cdcc2dc947cd8c4ced9266fc35c0b4ee12bb99a486ee4926d04ee44ea2eca2103fadabbded05ea592a64bf7a51fe42f6b815111730d0df7ce73cb75d9fcc51be683a3ce8e96818372d82f73fb9e16b4997491bc8a19aed250300abe45f7428f7cf1d5d4f173a4a19e7427069fc2938e93bb9df6787cdf27ec4e89bf56af5ef184c289c009ef7e507a8b87239002cc36ee75d38d0bdfd8e4f6442fd30e539b192061296d2ddb5aa3d4d50ba96e6e5283092b7a70329a05f34c0824915c1cbca371c18408f358d8979ae416097a61fb07efcd7c192c0ded1bc65b8be1d98d6c77829\",\n" - " \"5\": \"4522063a7449a81c672d049b7f3277ebe3863e2878c69350c930f8350633fcf0a35ede539b172666af7d8596a8b1dfd88349b360e60b105bcb4aafbeee13252eb01b71d3c0778e2ccf1be57bc24b6e25b772e64448231dae8d3ac526b709c106276967bfb1e280d0bce4fbc109dc5f61f69f269b885c125bdb0b7c09dfb08c64e474d7e1d5409ccdadf9d6ca280ed8dcf07643d94b5e45ef1ec17d886a95f1cb250deb3e6e5e81d98b18f72190ae20b69882ee11a2c8bf5af4bc691df2cc9e30bf25b4a374c7b3d30e4705a2d6562fff64ab18d4eb117d68551217d0221efa1f4310deec3e8b4b94fd71efe939715472287d35b4f72b2485767863446b2b3c44\",\n" - " \"10\": \"e2c2fc2e867854fc8619278c67a9c7c2223a734cbc6616f1591ea7f859e6630366db0702c4b2bce704b5ec5a2a48da5cdc8591f438a79aee4046b981e99c79515bcde1fb4f761c30789b42e3c3e5a942b06ec973e30e28a0902bc2d4e0ea861692f7860c27a2588c745b5079f524a47c0d96c1b216f43fb86ea7bbdc70892500f7273202bac677be03c3adff4163f42a2e4498515e70a8f61337e4f5b53666f406dc0a9ff8497336511713823d12bb45db72a714e3d8ba518e4898a18edc81ec32d97cf2bd21cb8c6d3b736789ceae312996e87e65a413a48c5d14ac85e6d2b352a89fe53c4c534c50980416c37311589e6019b34138a10519cb7f548cb8fdc\",\n" - " \"50\": \"4897bce1c913e931529fcf7365a9e755a6bc9dfa1ba5cb69cb00c7cf1dc2649acc153861700394ea50a13f80a5f62e880f0cd200e90065dba576e6c0767de5bb63f758c7ec6ef12f9b4aa44359ca87928073b5e09825e07a978a78486745f51a5be92e53fa0eeedd26934e0b705b3647d33b967d40eddcafc89388ed398cb5e6483c118ae6e84f11edab2e7abeac1844767f67af3c20c7614074931795316e9dbc3db530f896b811c0017ea24352ebeaa2a9b56e0b0fbd895b33fd28c9639efbf224401b7aaaea4fef2c4d808aaff0050f9a650d30fc0e8d18aa2de1c76f14cb5f4c91858530391a4f7bd2678a925da2b3b08d17b4309654f9cdf968a434e3bc\",\n" - " \"100\": \"9d42753d2b01681db0ba0e2c2bc864167612a484430a36c768c8bbb3d39443ff8de095c3c17bee5be3dec62787c9bd231e8b6f8ace9e1db185952e032740a682a68259b1537410c73064fa8cc170593bd392a4a4fe53d60ceb8884b72bbc9800f69191be502aec10e9157fc80bdd2f2ec0091437ba3b7f92c6bcaed02492e2805343f8849de878729fd219772cc33dce2a8f1371428b65930743fa513fadba6f2259407b06da980c7d2b030ff7dee9e19d5adfdc0c64081742ce45f1da553bdffd09870a5c0baa087dbfd1bcf5de63dc3efe95115969a048b04d57104139ac0a23f3e2e4d75718f4688d4be1693ee8eed69294cc365b330ee4ef2f3a2cbf6b7c\",\n" - " \"500\": \"944d4f57204ec3f79c1776011a45bb159a752871e390c8e39560adfe8f42f55907628dea5947d6e01838a27266c085d0a954e8542edbf5fc4abde04c66fb069f76b26ce33dd040cdaf03e2c29f1e8c1ca0a50470851318b9f564154e49f5ca6a59710360b4f37330cb4870692fcdf2ca78666a447a13d825e3009f8209e51f23455ddaecde15dd9cb29a15f81f9e2aea02a6fdd130b2fc5ff450227684e548f18782569c6fcdacb59dd80e68a6048c9d83b47a21d9763a1ef8eed269b3bf8e778655a6e5f1e0783f12c8605d4a45aa00ce9f9547adf2835326e4b18bf770f4425c91f6c0d06af3d28335001e78241f3fcfcaa193a134d5bc3dfc5fce127b9e6\",\n" - " \"1000\": \"11370c99501bd9f05c6cd0c9a00a79bc0abecf8b43ca61a2f3073b535e1b1d3579d11cf4db3eeecc6aa4d96867bbbfad215e2910302173767275a8a48e4b49d2214890f42ec9638cb90bcbb272ce85e5055b91c59363b753bdc9308bc920151290ec0f6f70c381625634cfcb12d19dabd8c67d80e7727ed8368767a53882b11a849556a7366090e25cccfa564cd28e7687991e0c4bd1807661f4b16f8d298f6b4d0d645b111a3223f797e7576a3093c0d5c6d81b6d59492dbe1e081fc5e8dbc33e1f74dffb8ebb3d4ddb60de7ed3b6d5b33b0f67d5379e39946e59dabc7298051b44cb8842e124f3410d49ff9d875a217e30bc1e175d4aae795dd0f800059da3\",\n" - " \"5000\": \"9bb2cfed4b931dcf4ec9299838a4fd50333bea7fbfe905db491cf3271d81e10f6af8e2ccd7cf9d4b5e5cfcead23cf661106b4c394aa2591fc6514dc8d22c27afb9a5f03f0684debfd1137cc9693bb8cab44ae45f50d9db6a3a5f624ce8d8d5e755c47318ce61e16f693270506909a608ed34df2e1a463d37c715fcc5df174cc8ca0607f77fe059650c80dd94df39fd65401ab2cfeac69e34a96d4d013ed5a62e69681ea6b38742c0a57e79e8d7bab6547fa40b4b0cb90c901c190919fde5fcd73b348d2aa6833d7dd9f2632da365c52b569e666f623b556f185a510ee77a3171425e980e5e7720757da53c410eed0c32f0f7d0b8bb5deb17df7a409226761100\"\n" - " },\n" - " {\n" - " \"height\": 1030020,\n" - " \"1\": \"1e742a010cb27c136875ed0c058867bc0253605d4729aeeecd30335a5a27c08c489509b4071d995c1877afadee5f24fea006d0b45d9733ef3d71bb427887391e2eb4912d18b86cb423fe3590a9d817fa8e6cba5886874b0c65a87f19588ac443513084fba8bd3778939f62985d845c2adef332b268a6ce51c6364110b8d4ad0cdcf277a1874c6aa74e964bb6d09c664b46e045c3409953a532dec4031104917149ab5b931dafa1617ecde18fd5aee6549481dc62f1fc8f1a08488b3e2bf60c2e0df3bcd2fe0ec6cfa7ee90b33e5073bffab94649994889b8e81ee773328ff4731f4b3881dec8c113607cf2e339a247e4d2c56424f8ac47cb41302a52f9067598\",\n" - " \"5\": \"bfca2bb6d46ea4b155800a243e221b6c94384acc7705726d64757487a83c85dbfc486f5a3b770d09c58ee30b38b8d5c42fcfbde4cda71c37a2c584dfe9d36e4a9292ee429756dde259b04443b8f3aa84b058c6ef308d659acb798be099b946b8aa009e3c4446cd4f725c1bc328d0b0f346040b2e6b23c325a9a69ef7e91b03ce17a55b8dc057af41f6f0c013b693575f27b68511a6b7c19474915ece657b78b6e1ce52dbc141f5fa948f8d78b42c02ca2c5adc2571fc2630a5f1bc4d2b0abc8af80216cdb95f4ac9e1c99140423415b182bc89387ab03bf076e06a51f73100850c1997bd6465c8f73b09893692eecbfa78e5a5c068d33bb68834d732910811a1\",\n" - " \"10\": \"7140d12a3a1505977b56037b0b2424783eab026564d14f7607f70cf78bbf0aeb0750dd0dcf3bd8a04a69c17340f6f8ef4a1624c8723f70ea6066105405d036930f76a0842fec3444aec73afd74ca08e25cf34ee956fafbe75b984525d4f7cdf4553f1f148ae3c021ceecc4fb50c523c34af06c1a09a8a039f83dbbe1710271e9570be4cd3a2f2b269fb71da3e90662b2e09b91892162409b396ceb9d724841bfff4dad7aaa8c35fff02e431a113e8eb111a6a68ba1a0846cc69bad62287fdc906cb79566bba19c26494fca609f9c3fe02816c94f8e8a847dfcd90eccec6254105177ccc6c7ec7c951e65fb8f4fdc039137aeaa2d2e7b6dbef5be4763be11129d\",\n" - " \"50\": \"a338facb807a478dfd8a21f73ab9a39bc875b98a1e1e7492459f315be3b81b5723c75b3e4af08710ab7c0f5655a7d586fe09228308a92d7b46622cd807837c25cff0045a59b0df554db70ee02b8fdd7d0a73e5f26e98efc2007392deecf0d02f8a37fcf8ae8d7b294c36f71b286db4da9598a37f0902d5174f6ca99f44763c4cdfe278d4909fdce5ad65264e47c3ecd24e39e216c38ecb108f191161bfd49804cb09cc540efa957b3cc66bc1041483adeec6749a968396a7cf6942843e1f6d593bffe441d57794a7ab5147ea4c7468d2c525edc99cd60fcb41aa418f27310ad345acc4d47e1410b7a3dc9afd4c295aeedd2d99e4bd4bb48351886555a77f0280\",\n" - " \"100\": \"7dbadac1111af5312af9674d6885823119d471fd3ea6eeb4fd68d2a93fb3516955909530a7357b1718a92582a7c941b14fdb697a74135f6eac0e225edfc72b7ae4d6cbf2dbe36305b7c3a9ae7e2e4031d80a670623264e5184964a34c1db1f1ab013027d3985dfea387ffaf496e205c5d8d4660f8e2648a77ad51b0a03c8c3342db84a6b81a98ae532d493c03698c88d327812673d7dd14c4d8d0484591b52455504410c1fe7c09c3511cf621259da61fa23130e32ded5829939656ff8c3ca2f4dd0bce040e07bf1b131fe69f9674d25b41de64d9ca42f05da5aa21092bd0866cb91658e403e05d68ce70c60601a87591c54dfe5e3b6ec489cdcafceac210f90\",\n" - " \"500\": \"1709a23121c524d2dc3926e74ae860993bedbf7cb039dc0474e20f343a9db8e028c684a29629846b73de9b0275b2ad61adc483e94cf1b5ea0470eee39015b87da2d9216f5fae1802756d49d341461488cd96ee57cb218f2f5f50ed1d0509758dfe41282e018d5e08a9c8844e2a6f9af3bcbc14fd60d7442bbf16251c579d0893736afafc68f5bf10c56d8bb8e3f05a2012946ca2ea41381636bc2127ac54aba1acd6d530c66b93a7f863a8298af0b7599d07779cd871f45ad76ad9e30eb090f1595940fafee08330be04af889c0f4ae1a8494e2e8690f2ef92b2c4cc7d012ba891a89676b31acf38ed1d0e45f4c18f6f6d1a9b1d0a32650ebe213d0a5ecc183f\",\n" - " \"1000\": \"840fdf9a6cc31c7df5c8aead9d484cd00e479c7c9897301c43031f7014a5b1e839968c0660b0bb378eb160d77fcb262ab34950ebe084b61b00b22525422a4ec2c50ccc6fbd29d033dc9cf79a1d740fb9eacefa33c9829b877a04d11c9dd3007d3ad12fa23dec619c6d096134029f052dad9089fde0221a1786cc562f2a086f7a1072741a94e3ffe695edc8f1469c624d5464db155f791794f4716b87f19184f5abfcec65e697895cf405795b894453ff083cbfd7c118a786a5d22ee31c9d3b0172b5cc449e4df9241382cec18596b49ab32a0028f799e6dc7d21a16100a8dc16aee30503f703da62a3818dfa0d17af5063e015d4235b4a8d225cde139b0834c9\",\n" - " \"5000\": \"c53cad3ea56f09f5c26dac22a1dc1f8fe5b92c9aae1bc41d964e5b80286cd9b7dd8e74e1acdc05a738f5e44d0989ab3c3bcab3fdbee62e20c1501cffca2457c59a894ec93d00c05e23d1f36fa78add902caeb539baf39fa61fab8c2d4135518c9d85eb775edd306557821f60ae83961c7aee5ba75a4abc920195441b58657d97078d684bbaf95a1d1c33bb2be3fa7fe939b7919d326e6c4deab9768e2908ea2297df46646c65af583935d38413c692bbfcb525fa332a5b5f722dea19806c2e30070744ba1ccb3c452b4f45873865935098993668b57a15aa7a1bee3738bc035444735b5493168a7506a300711b1878c7ec68d660c4f4b278cdc647d1921b4ec\"\n" - " },\n" - " {\n" - " \"height\": 1040020,\n" - " \"1\": \"ad5ffbb853aa51ac4b5600ad67dafaf69e229b991b31b6597db4d65e5755fb226cb2f850d462663bbe7b5e8b639d7d617259d1227c823942a86a5a39820511428f5eb319bb7271b41f9cd15ff20d5a8196b7193543863ab24b07c5657be89888036d57c81dab77942921cd6eecf53a406a5d9f261b226a0571d6fc42f89541ab435f2dca8e7908de4c82066955a0ffefb5314710abcdfdee85b6f7d685bd9d85645c2d8c19a3ad1d5560afefd7e052d123633d5e5759bbbd8956dd44e4350a4e726ae7d917f89f64957ddb04ed022e91f530ffc23d043065837ad7d3e70759296f75c745cd7fa8528df79d8bd7fb3124d93cbcb8b228f7df4d6043b19e9db0ab\",\n" - " \"5\": \"7d455f432ef380ecd8bebac53d79d001e110a17928c1d5462b0dbfaf1b3731ea2d7ab23faf0b2b78c16a705d0cd4140c4404f9dfbcc4bb99b2bdba16f4c01ca4619c1fb19b6801cbc68610896011dfcbdbc28d911524d57023908c62cca9707955fdb6b160a69bc0f16b49be3061a2b30715b957d1a68d9f85e8cccd198fffcc76a7f8ebb710b338272a8756d291c5f1b95e01b74350835bcbb3f12169b0675de99b6abdaa4305ab5993e837f5afe5fdb4f5236405e81751508dc7161952038944140082c0423325084cdff74b3729bce3b80c7ed61d050068ea14e9713f97fabd4d0181d4dc40a336a1bc177ed6b56e2a65d8aedb70a76a2e518041bceee97b\",\n" - " \"10\": \"67d6c638f1cdcdafeaf7761599a4a439fdd1bff9496b59e6b9fe3bb0b5db52b13b4119f68cf85f7eed18a56ac0dd33964d6e443dfa9f2c66db1cdc7f58608ad213f16e0c81ce264c5dbe5cbed9637693117875625093a2b7c99e8d4661c2d7a4936ce6b6bbdb2f1c71e0ab5cdd9836217a959e9d6ab49292e13006490aefaa7e83bf82414bc265a90fef245981e3811e73c007bc121b5a8a218153d2c2627b0015e09527f9ee37e05acb6de1102d188038ccfe14429f3fae9dc432f5475102a24b642131b57923a6a81eda3db1821fd0eaea972aa53b3b902c7eeeec798e1d153e5befac83a5e7a831d1b8926f4ee755fc1dac3e266c6492e6c5e0251a5d2167\",\n" - " \"50\": \"a5eadcad3ba6492855142342b2a9a866dd43f0b2e56a3e60b5227f80646b777ef3982b3c629c892e1fb4b1af1962596afd8035d5c9f8e96f4133c945a02f0aeeb12e6aff4f18ecef4c8faebadff45bfba6391b8093fcc0a70eab9df845dfdf3495394320d3d57eb22bd87cf2a2702edc99d2dcaa32eec6076d68d0842334d4f4583f40c33b7ccbceef5c8cc48ac4073d3cebbf42e8d797d842749137da8bc495fcb8b8ac1e289cce0f3ce5bbd2726bcd53b6651274e7e382851636519eee7de96a823810c300cc862d56b0df1a787712ec34f74175916f62b6a8e361927045ce0befeb7fceda62412a48603ea3645708229c61907384622a4204d6aed2d3b6a9\",\n" - " \"100\": \"a2063bf6b97d8206d91445a3d4fdfad3448fcce54614ba0fa5dcb19170d51a7a9253e6376ae2ef79c9cf31d0eb7e16692b28287956601d7d6ffdd97621e5f9e56888782b2293894696ea9db5f4ac02e0b1278843fdd127a2218c7c4cc539ebb5bbb55c5c29ae5307b6c9943b39dce3d38c75e75a8027a35b44eba6f2b98655bc15718b379243f95031a52d8c1a8e5ec39328042eb27d3c3f3244c845db1a97f11b5f90aa8c51a992093b4c77c3fcd320bf940335f91b0aa6351cb856528f2212866a242ac63b2b2e8f4f6489105d48fb74fe870d7d7165fd41901ffe4a55ccd849343b04be58d7ad7ead907ea0437bfd517f84be554e083e40a7567a688128a5\",\n" - " \"500\": \"98d037dd5f0a9ce9fb8120eca0d3f6e0ae89aae0b3439af26d731593ffa91a6f2a81875ae54c526ec5325251e78c7747387ca7cd56d24715b3eb661373d5bbb4aad25b97215f397ef1d9a459d10f4d4a37aae232d8bc845df970d250a0d82d28587dd459a83cdf8f7fb3cb1f78efe4b9d61f8944af16586e70ef5544b0e5785a8503ec86a4470ff857888d2c7c6a4559a25c6d8cae4728218d95ee647773c2c0b554c6bbd81e926f94d2aa1ff4c51f411dcf5a405d0a5bcb56fb282c1f368651ddcd66d837bbbfb2d0294d9c82baade9802e6376e978109a62223a3393905c90fed6de7db3cbd4e2d226984043dec0a7d815373528f1d39dbd7b71669f7abd60\",\n" - " \"1000\": \"2d50181e75ec6a1cc4ac0c0aafe855c45613a422595dd7a1abdb9534bed57fd81ecacbf9732ef52d53508c2472bd1945995524628d9ba444c0d6e32cdef07d29ddef5fa5b4d66db6efb9b7dfbfc504adc4a4f4940c89c83023d5d15c7bac10adc728ceab40248c64a5ca66cbc9a41b6d75d079e9f530cf103f0a145a4616c3cb89615bcc11aae7cacfcf351356495eca2341a5e2065852e7df12f82c05e7184f54335686ed95fc061fb822434e6e8d129ae7cb1419e4a0f1ceb682603683994a65d499cf490493bc798016c52ba3b5e418756b3253771fc23ed3b858a521da8d03e384a18e06499e478c2acf665f6597dfcbf49aed61b641fef4bec360cbd0c2\",\n" - " \"5000\": \"72293b9538b65002faedec5647a9d249999e62799602bf38e9b9ab7258689c9f12aff53f65c59a32e84c3f1bae3c81cb9c5f2a8728e9d145dfc8ac77c9f62b2d5d04d203d5fdec0457789fa8d8277577abe5b18d8e69419f4f56dd69eb1ed86e7bd76488c8c62719972975ff3c09df54c6f25ef629e493111628a73b20d787e91b8576601409e396a33d61ddcf40dbf1197cf59c66784f7c993a7302b1b3df2d38037ac482ac2db5e395c04e17fb622c7036cb90aa8a3398b90f895c1f0133df36131c6a01878778a03b90125d74dd2c34d736cf5bc5fe2d2922ecec420edcf97076ea700ca6d20deeedc7dcd7920f008a6028d285f2fe5aac68d4ffbb1e01f6\"\n" - " },\n" - " {\n" - " \"height\": 1050020,\n" - " \"1\": \"17b7ea3631c064f56746ce358a086e0b80e9db72736d654316b134148c8942d085c9991cb4453d047ddfa713256a9a96bcc6b896a5be2da97c97568b528c26553401af8736f34e7050bea3da670bb54df76d7848fdd704cf6aa9282794eb91fc7202d167089cc2ba0d78d291a002f55611a4bd312c44c6cd139442684ad385bbad2ec6a36c2bddfe74adc9240d0dece89dcfe393806cbcb4c8f4a823ecc1acd5a634c524c0a7ae0dc7ebf3f01da90f05aaca10db27c284b42182f5d6958b79780d0aae94b644e50df7f00fd26c36fe79ff23c85e0535d51464df0618a409c8aa5f034fef0a226d55d945abbaf06f2342d73905052a8aedc8b267cc1ee40c05f5\",\n" - " \"5\": \"58666f17dafd3bd630f3a0113ad68306928522486cdd98cc64533f8dcecea2cccca3644a2d70d9739c5865f9e8b16009947e1865f8d9d811ea1e02d0fd5de92f771bc778a416a666e3418fd1e9fab467b3fbc7366b6e1df7a23245037ccf1c33c371a38d551fc63a48ca968e5ae1aaf041624a617f37e7a2d3322478c6fa962fbb10327fc8da7505c87fe0059dbc910911212f1e10d1993cb39c0a5ae2fefa6873e93fcc8c2e4748fcb5dd25ed634d22cd8fa36d7407f51e599098af425a085d1581e455d3cf8e21960aebe0519c06e3dbaf87786fc09346082ffa1e9e3e76e05892e63bce82581df13d5c102080f14d2579ecea92a80b8332a6130ccf54ab1\",\n" - " \"10\": \"23310b5e1657dd565e29b3774675c09c70268cd1b3e98b7e5c80bcb1fc792332a704b9163548494343c3f0802ce0c978d0fd715b3deefce65b567b3c03f1d6bb86454f340bdd2bcb2f7072209cedec8d066cb0caafaa63765693ffd89f97fe667bcf5e53d0c5f508074c259daee21c23f279451346e11f6243b6ffd595818f6f4c33282ce931300bf8503d43d6aded2159303c8af432b9797797e76ab517b14224b842cc81bb8d757015ad894337501cf84c6edc1736f96d88ab1b89ba47b0800428689bdb81799f80c90f84c16c2d81a5f9d4bfdd5963a8421e10e7d6ae37def1f7745d2f5accfbd80f43ceb8ef737e0820a9ade199fd73290cd59101582d1b\",\n" - " \"50\": \"6c1cef5f7fc0d6707a0c8c0ef40fb3de8d4f05a84fbf07997682551e7602e048e7af7b54cb968704008b7a871d197d518e3cef7e4b4aa7419b9a6ecbc0db713aa0c234a4838dd25bc2a1b75d75ca4c1bebec76035ea52d6cd87541ae7a65318753dd5d3b98643921659af0d3d34575591b26f55648f31e4ca45fa025aaffd8e8296324f779b1789ad85589249bca8b713668ebcd49391180086a7ad2014f96042560c889a36d85c54b1b434ca999c254c53fab32334630f6dfa542f1c67c14b46ed9205926df3b79f595779fa6ecae037fbf2e7eb5cd1f9e180f7dba79c3d20f4ad4f459dceedeb4bd53666ae87ca8f0c5c8f2483d5c0e34ea7a2bb1fad3b561\",\n" - " \"100\": \"905d2ec8cf413b754b1252bb36190d5b64aff04b7bebdce5abf62f24dfd61d77997c3c8086a358ddfb6b4905885bab04d6c80c11ea0d5740cd1893fa72cb426378a2ccd937912dc24e57b6108b83bb3ddb8b22ce8abe5552c614b9ea2f721d90d777edff4f49eacf5b3b45e8bc2bb76eb98a2f2a7741ecf1d806bfe6df97a766fee01fddea22d99d8c95298ca4f3c44a4adc0a036a3b5bbd4127c092b0ccdbb99349877b0127427bb6a816a753021a1504af101fa869b4f6faa1267e346cb86a1e04e2baaafe06e4114dc8abec9a1e18827f6ae7a085a8589ee9d440827aeea27bbfbc993fee4534d7bef177c419b40db8aa3db63538a007788cc7ff4f198a05\",\n" - " \"500\": \"4363bdc53b4026875bd62fd48282f623f3f96f2db84fcc4cdb12dc7ce4977c24306ee32dfc2f67d11634849489da61ec3e457fb7a84502f1a9f64fb3982ff18987afb9b7dd187df9bf68aa3d2ef087ae5a2063f3b6f73def6ff4837caf9faf4997a16e752e2669c0900e8c8358b41f3a06f413c6f84c65de08d9ee2ceed920bf11846c40457754df87ee3a752abf6f3e99ee710efbdf69bae8ac8e2a033c576fcb8a8bca8ad3a5aaa819fa2f7be2ce3165913678ed141d1490ee63742c7887f6d560b7518ee961ff7fbab7700c6c383ee9e6460632385bb9e8cf34ae4fa849c8aa247c7588dea7a6ea0f69660b5c8d1711ba6a10e4815a35e3d4190a20653533\",\n" - " \"1000\": \"817b4efe5eb3e939b6a1a5f69dde9a9706c8c84be4fd2643cc2f10e8ac1c3dfddd139ab177d35c92dca39d9c9373e54261196fc1827f7424ad2c75e645b5abb5e698a01e6f774dd217362e0b1ae7e841329bbe8b156041fdd6dc1654567bfc461aebd1c118db30c9ca78a8465b9aa73c1392eae0a8407c6d578bbf9c254e448f6adea6665c8d41bba252cf782ebc45e1c9e242e0e7e8c4da9e1677b8739a9e74fe6ab96b42208a0aa7f0c88fea0fdee648424a37a1e36b26908098e2ce6c7a42c6e4e0b7f3680b1a6c0a70353b1a39f95cf98ec9cc92ca6072f75f55a4eb0fe5ef4ae2f2849ae66e08e060d8dd94f59a01878dbb71c8e525689483fadd216258\",\n" - " \"5000\": \"78c50888f8b2905e1fe608f46b2734a7516868ffc0f350cc65fab54a6f48f83137e2a1305dd52f4325dc95c13d9b922b4e41ac3bbe2c04941617f12ece948a4446c3b24177f36aaafe211954330f30e1618172c1e7cd3c4eec4d5cc4d42497c813a96e3d8ec493397edcdc2ed5aa4bfebcef717586b564309ea75a7d048088ac6658736f06f2ce722ffbacba9988de3a8c92d9d13eb3d2c062f82c392e03fc3bb5ef3d6454064abb21d6be78c3ed830951c50024a2a4e492d8caab316c5a8e959bc00bfab664fec47364ceb796cd0a1b1a7e391317e84998ce1d0856fc19b4cf27252ab1ca82b51feea8a585a8178ddd298a910f17f3428463655c7c24a16d76\"\n" - " },\n" - " {\n" - " \"height\": 1060020,\n" - " \"1\": \"bb4d4aba1c8289c0ef84affb2c63351cf10700745a30d1a6cc96b0d16cbc4d7af58b9d8fb7908b2268f0e5b1624e719fa897ca6146b1abcf197aaea84b76c803d2c0a1c3692765b23fe7caa44980cfde2ed0bb54647c74f017ed4e065b22ed59ce3f755764ab96fc98d9bf5cab5f2e3b9e5462c4672537c4b6a3997152a123bc18a9d7cfd9f4c09b2e674115c3817f9face664f464a93e2b079f7c44e8c544e391fcf5bb140182ece31db51c4624bdd93723d603210fccd2ecd1cf29604f54aaa148878d9f84595348153df14bc3b2a663e78c727f8b9490d20f633b099e1c57d0e75a342e3e842c02f653284d7e668023e75cfd08bb13270c6a253ce6e912ff\",\n" - " \"5\": \"99b1be3a92428d390552fd1560c3df47d4af2b566c59bf9da83b1cc6a2a702fd8e99dc355779547788cc3068d171493e103bee0f243d3e0c9c994a823bbfd2fc45d101b7012ddbc083409bcc650f299ca592fa1f034d3fc05280f8cc22f5af08a9fbeb7ded2068d978fb853f65de6bf4ad9b783c3291bd37a7f8a9f6e27771b1d597d613b12a55fac3d7c83985b62d9726925779d0aeb94821fe1310d486b4eeefef6c456152a9a20a006d01f275830133aeda1eaadbd6a3d3c478fa18b35b161a628850d7acab2fb1384e6cfabc11cd99737d9aa13a3d93bea3406a9f2f3310be51ee415c80fc296b31009ec863c1cc3657e5ee41054c05444624abe25f61fe\",\n" - " \"10\": \"3bcd60907ba904d5682eab1cdd9341c9a99a17f85c2b9ce6139094f8bb8d3ef3c98d43006511f69d18c24bc4335d33af3c9dab532aa8679294a89b6e47fa849d99f405426ea066157b31702e1a51346b95330dd31c6972544d0014c83aaf60ada894fe2daa73e1416afbacc564e3da36dc1ea2652c4486cdb82c9be2c6e217ff6acdb8390842c2a5ff54fa5953177bd826572ab0a538f9858e9a3fd95a06e84c314cc3776d1b545f2ae867c0a88e7753585a9c1fdcb40f59edd35d7fa73885d22b1782fe25b40591a63906748ee2d1f8b8545dd84e0e4ff9d75970c883f59849596e993353377a8cc8f25f4f28c7eb572f6130b8e80ee9ce3feaec8e19b750f9\",\n" - " \"50\": \"5bf7820b1cf4a4480c8d364ab122a7abe74addbb51e0e21bb7c928cda213e17347331748a74d802f41b62d9674bbed22baaca4dd86a005b8a8c212404f328f9ae9c14d3d97d70606698a89be8a1488a55faccbfd5a0215b047a3af38b1e5e07f79da96706309c71b0f1fdacdbde1a4771f4176e9889741832c882720f873932e78c27dad10bbd8afff80e360e193f1239dba8affcaee13a05be9290a481155e3359eff376b718793c512f31146c1eee2065efd64fc2805e6b85a252cba14487ab84c4aae8299a63e0d6d0fd9dcfe555f0fcd4dfc2351bdeb557270a7b51b8c76418c58538cef8a55b8a5c7132209f877f38af8ab2b743d7f68652479332c84bf\",\n" - " \"100\": \"926a5c1472f3a222b732878fa59b6e477e1910099ce3a47f9878a58a164eb22d10b43cdb1252c09838def4054a026d3526b0ae202aeea1e13d846c8a416c07439bf6e41c370524e52fa2e214e2746a5225289eaacff447a41fca58369bc51996ebfdd64e286795280b38408f04401566b8a44ee36840267fbad6683258bba4a83558611e3a9b8c1024dccac65a6a552ddf5932feeca7659e5626d97fadc93f1eb77a7d53d7c2b389eaf4fba337c01d73213fb92d7ef1ec335cbfe8f0e978c80c210475dbe0c15efa1d26eec6a61881deaab3203bac0a80c1ac5c580b236c69ae3f2796fb33f2f21ec3bca69b92ea62675f226d7f3647adec200c0eada4cca931\",\n" - " \"500\": \"63a64ea5fb1fff6954a146b83d9ca5e8adee3c2eca8717b16feb28abf0402f1ece2c709a2441bf7ddd2230b3d99c600e290b07552a985e9d3bd3f245f69fe9c0a2fc7c25b9ef33137484985e6bf1aead8ce23fbb3fbf392a625f1bba9a02cb76965891e2d2b6aef8a7b308de5e5d927c6d56b49a326e60bb47d46744f4a02e101decef48d7346752507293a56af54e9226d7a5fe4201aeee4b96ae03058461f49122f885972e585ccb2aa73f05a7ca62fc14d73d710f146aa66e7a83abbdfd761c706a1f7df98f0d4d1148aedb6dd0759dd491573630f482477cb2449c4a9aa005fed29ba1a7dd97e645c69b9f481e2aacba54bb0f5252d750a6498fdf542ab1\",\n" - " \"1000\": \"29b5bfb308a476b7c63a8cf026cc9647add61fc8f277658467f32a129483bd032595fe8f80311cc77fd602340079a1a4451e76ca422da988a62e1a3f913912d0963fc3c9a6987eaba59433df83c1ea2396f466bad4d91b0a2923fe9a1326b56dc5174174cb1e37bb52119780d7ee62b96cdbfae93f2d23be221b704210deece493d37afdbccd383d7ce54343a48b85d2bcfe7fb54bea6eeb2159ae8c4505ef9f92e5afef50847d52ca66af3d5ed504ca889c049e6c88db0a9928e3e18641571d921f4534b8008fdd103dadece5e4495c670a03da0c3ee8b7d91b5f53d2c2dbc06a8696032711ada128dcc85823873002d741010734acd9e69976b88dff33e32c\",\n" - " \"5000\": \"8db0b3495edb380ef7dda75a0ce2c53427b7a5ca70e0f6e93596a23e77d1c2e3244b581506ced3492ffb6ed53b42ce9eec293fc8f44bc59dcc5dd449ab6e93f087cf37f11aecf84386328e50fe14251fecfef7dbf5d33d07068f68a7466921c0267f38ca0b79ff30876d3e6c06a878b30d4bd17e35e53c3fcfc886200ee216401ee1dc90ba7c4345c01fc00aa4cf4540d51158f76da334226d076de56f9b5f8d32791cff7ed51af5054e9beb05237c330f24430ac7c2ffe5cf1a6b4fed14600e18e635d848476b826a12e2a9429170e7cc6dbdb44e04dfe00f3b7660bb083a1942aaee19d30a848cdb1228efd9ec3e7a8af611c8822d930f62cf73d4c0f1597c\"\n" - " },\n" - " {\n" - " \"height\": 1070020,\n" - " \"1\": \"bb4d4aba1c8289c0ef84affb2c63351cf10700745a30d1a6cc96b0d16cbc4d7af58b9d8fb7908b2268f0e5b1624e719fa897ca6146b1abcf197aaea84b76c803d2c0a1c3692765b23fe7caa44980cfde2ed0bb54647c74f017ed4e065b22ed59ce3f755764ab96fc98d9bf5cab5f2e3b9e5462c4672537c4b6a3997152a123bc18a9d7cfd9f4c09b2e674115c3817f9face664f464a93e2b079f7c44e8c544e391fcf5bb140182ece31db51c4624bdd93723d603210fccd2ecd1cf29604f54aaa148878d9f84595348153df14bc3b2a663e78c727f8b9490d20f633b099e1c57d0e75a342e3e842c02f653284d7e668023e75cfd08bb13270c6a253ce6e912ff\",\n" - " \"5\": \"99b1be3a92428d390552fd1560c3df47d4af2b566c59bf9da83b1cc6a2a702fd8e99dc355779547788cc3068d171493e103bee0f243d3e0c9c994a823bbfd2fc45d101b7012ddbc083409bcc650f299ca592fa1f034d3fc05280f8cc22f5af08a9fbeb7ded2068d978fb853f65de6bf4ad9b783c3291bd37a7f8a9f6e27771b1d597d613b12a55fac3d7c83985b62d9726925779d0aeb94821fe1310d486b4eeefef6c456152a9a20a006d01f275830133aeda1eaadbd6a3d3c478fa18b35b161a628850d7acab2fb1384e6cfabc11cd99737d9aa13a3d93bea3406a9f2f3310be51ee415c80fc296b31009ec863c1cc3657e5ee41054c05444624abe25f61fe\",\n" - " \"10\": \"3bcd60907ba904d5682eab1cdd9341c9a99a17f85c2b9ce6139094f8bb8d3ef3c98d43006511f69d18c24bc4335d33af3c9dab532aa8679294a89b6e47fa849d99f405426ea066157b31702e1a51346b95330dd31c6972544d0014c83aaf60ada894fe2daa73e1416afbacc564e3da36dc1ea2652c4486cdb82c9be2c6e217ff6acdb8390842c2a5ff54fa5953177bd826572ab0a538f9858e9a3fd95a06e84c314cc3776d1b545f2ae867c0a88e7753585a9c1fdcb40f59edd35d7fa73885d22b1782fe25b40591a63906748ee2d1f8b8545dd84e0e4ff9d75970c883f59849596e993353377a8cc8f25f4f28c7eb572f6130b8e80ee9ce3feaec8e19b750f9\",\n" - " \"50\": \"5bf7820b1cf4a4480c8d364ab122a7abe74addbb51e0e21bb7c928cda213e17347331748a74d802f41b62d9674bbed22baaca4dd86a005b8a8c212404f328f9ae9c14d3d97d70606698a89be8a1488a55faccbfd5a0215b047a3af38b1e5e07f79da96706309c71b0f1fdacdbde1a4771f4176e9889741832c882720f873932e78c27dad10bbd8afff80e360e193f1239dba8affcaee13a05be9290a481155e3359eff376b718793c512f31146c1eee2065efd64fc2805e6b85a252cba14487ab84c4aae8299a63e0d6d0fd9dcfe555f0fcd4dfc2351bdeb557270a7b51b8c76418c58538cef8a55b8a5c7132209f877f38af8ab2b743d7f68652479332c84bf\",\n" - " \"100\": \"926a5c1472f3a222b732878fa59b6e477e1910099ce3a47f9878a58a164eb22d10b43cdb1252c09838def4054a026d3526b0ae202aeea1e13d846c8a416c07439bf6e41c370524e52fa2e214e2746a5225289eaacff447a41fca58369bc51996ebfdd64e286795280b38408f04401566b8a44ee36840267fbad6683258bba4a83558611e3a9b8c1024dccac65a6a552ddf5932feeca7659e5626d97fadc93f1eb77a7d53d7c2b389eaf4fba337c01d73213fb92d7ef1ec335cbfe8f0e978c80c210475dbe0c15efa1d26eec6a61881deaab3203bac0a80c1ac5c580b236c69ae3f2796fb33f2f21ec3bca69b92ea62675f226d7f3647adec200c0eada4cca931\",\n" - " \"500\": \"63a64ea5fb1fff6954a146b83d9ca5e8adee3c2eca8717b16feb28abf0402f1ece2c709a2441bf7ddd2230b3d99c600e290b07552a985e9d3bd3f245f69fe9c0a2fc7c25b9ef33137484985e6bf1aead8ce23fbb3fbf392a625f1bba9a02cb76965891e2d2b6aef8a7b308de5e5d927c6d56b49a326e60bb47d46744f4a02e101decef48d7346752507293a56af54e9226d7a5fe4201aeee4b96ae03058461f49122f885972e585ccb2aa73f05a7ca62fc14d73d710f146aa66e7a83abbdfd761c706a1f7df98f0d4d1148aedb6dd0759dd491573630f482477cb2449c4a9aa005fed29ba1a7dd97e645c69b9f481e2aacba54bb0f5252d750a6498fdf542ab1\",\n" - " \"1000\": \"29b5bfb308a476b7c63a8cf026cc9647add61fc8f277658467f32a129483bd032595fe8f80311cc77fd602340079a1a4451e76ca422da988a62e1a3f913912d0963fc3c9a6987eaba59433df83c1ea2396f466bad4d91b0a2923fe9a1326b56dc5174174cb1e37bb52119780d7ee62b96cdbfae93f2d23be221b704210deece493d37afdbccd383d7ce54343a48b85d2bcfe7fb54bea6eeb2159ae8c4505ef9f92e5afef50847d52ca66af3d5ed504ca889c049e6c88db0a9928e3e18641571d921f4534b8008fdd103dadece5e4495c670a03da0c3ee8b7d91b5f53d2c2dbc06a8696032711ada128dcc85823873002d741010734acd9e69976b88dff33e32c\",\n" - " \"5000\": \"8db0b3495edb380ef7dda75a0ce2c53427b7a5ca70e0f6e93596a23e77d1c2e3244b581506ced3492ffb6ed53b42ce9eec293fc8f44bc59dcc5dd449ab6e93f087cf37f11aecf84386328e50fe14251fecfef7dbf5d33d07068f68a7466921c0267f38ca0b79ff30876d3e6c06a878b30d4bd17e35e53c3fcfc886200ee216401ee1dc90ba7c4345c01fc00aa4cf4540d51158f76da334226d076de56f9b5f8d32791cff7ed51af5054e9beb05237c330f24430ac7c2ffe5cf1a6b4fed14600e18e635d848476b826a12e2a9429170e7cc6dbdb44e04dfe00f3b7660bb083a1942aaee19d30a848cdb1228efd9ec3e7a8af611c8822d930f62cf73d4c0f1597c\"\n" - " },\n" - " {\n" - " \"height\": 1080020,\n" - " \"1\": \"bb4d4aba1c8289c0ef84affb2c63351cf10700745a30d1a6cc96b0d16cbc4d7af58b9d8fb7908b2268f0e5b1624e719fa897ca6146b1abcf197aaea84b76c803d2c0a1c3692765b23fe7caa44980cfde2ed0bb54647c74f017ed4e065b22ed59ce3f755764ab96fc98d9bf5cab5f2e3b9e5462c4672537c4b6a3997152a123bc18a9d7cfd9f4c09b2e674115c3817f9face664f464a93e2b079f7c44e8c544e391fcf5bb140182ece31db51c4624bdd93723d603210fccd2ecd1cf29604f54aaa148878d9f84595348153df14bc3b2a663e78c727f8b9490d20f633b099e1c57d0e75a342e3e842c02f653284d7e668023e75cfd08bb13270c6a253ce6e912ff\",\n" - " \"5\": \"99b1be3a92428d390552fd1560c3df47d4af2b566c59bf9da83b1cc6a2a702fd8e99dc355779547788cc3068d171493e103bee0f243d3e0c9c994a823bbfd2fc45d101b7012ddbc083409bcc650f299ca592fa1f034d3fc05280f8cc22f5af08a9fbeb7ded2068d978fb853f65de6bf4ad9b783c3291bd37a7f8a9f6e27771b1d597d613b12a55fac3d7c83985b62d9726925779d0aeb94821fe1310d486b4eeefef6c456152a9a20a006d01f275830133aeda1eaadbd6a3d3c478fa18b35b161a628850d7acab2fb1384e6cfabc11cd99737d9aa13a3d93bea3406a9f2f3310be51ee415c80fc296b31009ec863c1cc3657e5ee41054c05444624abe25f61fe\",\n" - " \"10\": \"3bcd60907ba904d5682eab1cdd9341c9a99a17f85c2b9ce6139094f8bb8d3ef3c98d43006511f69d18c24bc4335d33af3c9dab532aa8679294a89b6e47fa849d99f405426ea066157b31702e1a51346b95330dd31c6972544d0014c83aaf60ada894fe2daa73e1416afbacc564e3da36dc1ea2652c4486cdb82c9be2c6e217ff6acdb8390842c2a5ff54fa5953177bd826572ab0a538f9858e9a3fd95a06e84c314cc3776d1b545f2ae867c0a88e7753585a9c1fdcb40f59edd35d7fa73885d22b1782fe25b40591a63906748ee2d1f8b8545dd84e0e4ff9d75970c883f59849596e993353377a8cc8f25f4f28c7eb572f6130b8e80ee9ce3feaec8e19b750f9\",\n" - " \"50\": \"5bf7820b1cf4a4480c8d364ab122a7abe74addbb51e0e21bb7c928cda213e17347331748a74d802f41b62d9674bbed22baaca4dd86a005b8a8c212404f328f9ae9c14d3d97d70606698a89be8a1488a55faccbfd5a0215b047a3af38b1e5e07f79da96706309c71b0f1fdacdbde1a4771f4176e9889741832c882720f873932e78c27dad10bbd8afff80e360e193f1239dba8affcaee13a05be9290a481155e3359eff376b718793c512f31146c1eee2065efd64fc2805e6b85a252cba14487ab84c4aae8299a63e0d6d0fd9dcfe555f0fcd4dfc2351bdeb557270a7b51b8c76418c58538cef8a55b8a5c7132209f877f38af8ab2b743d7f68652479332c84bf\",\n" - " \"100\": \"926a5c1472f3a222b732878fa59b6e477e1910099ce3a47f9878a58a164eb22d10b43cdb1252c09838def4054a026d3526b0ae202aeea1e13d846c8a416c07439bf6e41c370524e52fa2e214e2746a5225289eaacff447a41fca58369bc51996ebfdd64e286795280b38408f04401566b8a44ee36840267fbad6683258bba4a83558611e3a9b8c1024dccac65a6a552ddf5932feeca7659e5626d97fadc93f1eb77a7d53d7c2b389eaf4fba337c01d73213fb92d7ef1ec335cbfe8f0e978c80c210475dbe0c15efa1d26eec6a61881deaab3203bac0a80c1ac5c580b236c69ae3f2796fb33f2f21ec3bca69b92ea62675f226d7f3647adec200c0eada4cca931\",\n" - " \"500\": \"63a64ea5fb1fff6954a146b83d9ca5e8adee3c2eca8717b16feb28abf0402f1ece2c709a2441bf7ddd2230b3d99c600e290b07552a985e9d3bd3f245f69fe9c0a2fc7c25b9ef33137484985e6bf1aead8ce23fbb3fbf392a625f1bba9a02cb76965891e2d2b6aef8a7b308de5e5d927c6d56b49a326e60bb47d46744f4a02e101decef48d7346752507293a56af54e9226d7a5fe4201aeee4b96ae03058461f49122f885972e585ccb2aa73f05a7ca62fc14d73d710f146aa66e7a83abbdfd761c706a1f7df98f0d4d1148aedb6dd0759dd491573630f482477cb2449c4a9aa005fed29ba1a7dd97e645c69b9f481e2aacba54bb0f5252d750a6498fdf542ab1\",\n" - " \"1000\": \"29b5bfb308a476b7c63a8cf026cc9647add61fc8f277658467f32a129483bd032595fe8f80311cc77fd602340079a1a4451e76ca422da988a62e1a3f913912d0963fc3c9a6987eaba59433df83c1ea2396f466bad4d91b0a2923fe9a1326b56dc5174174cb1e37bb52119780d7ee62b96cdbfae93f2d23be221b704210deece493d37afdbccd383d7ce54343a48b85d2bcfe7fb54bea6eeb2159ae8c4505ef9f92e5afef50847d52ca66af3d5ed504ca889c049e6c88db0a9928e3e18641571d921f4534b8008fdd103dadece5e4495c670a03da0c3ee8b7d91b5f53d2c2dbc06a8696032711ada128dcc85823873002d741010734acd9e69976b88dff33e32c\",\n" - " \"5000\": \"8db0b3495edb380ef7dda75a0ce2c53427b7a5ca70e0f6e93596a23e77d1c2e3244b581506ced3492ffb6ed53b42ce9eec293fc8f44bc59dcc5dd449ab6e93f087cf37f11aecf84386328e50fe14251fecfef7dbf5d33d07068f68a7466921c0267f38ca0b79ff30876d3e6c06a878b30d4bd17e35e53c3fcfc886200ee216401ee1dc90ba7c4345c01fc00aa4cf4540d51158f76da334226d076de56f9b5f8d32791cff7ed51af5054e9beb05237c330f24430ac7c2ffe5cf1a6b4fed14600e18e635d848476b826a12e2a9429170e7cc6dbdb44e04dfe00f3b7660bb083a1942aaee19d30a848cdb1228efd9ec3e7a8af611c8822d930f62cf73d4c0f1597c\"\n" - " },\n" - " {\n" - " \"height\": 1090020,\n" - " \"1\": \"bb4d4aba1c8289c0ef84affb2c63351cf10700745a30d1a6cc96b0d16cbc4d7af58b9d8fb7908b2268f0e5b1624e719fa897ca6146b1abcf197aaea84b76c803d2c0a1c3692765b23fe7caa44980cfde2ed0bb54647c74f017ed4e065b22ed59ce3f755764ab96fc98d9bf5cab5f2e3b9e5462c4672537c4b6a3997152a123bc18a9d7cfd9f4c09b2e674115c3817f9face664f464a93e2b079f7c44e8c544e391fcf5bb140182ece31db51c4624bdd93723d603210fccd2ecd1cf29604f54aaa148878d9f84595348153df14bc3b2a663e78c727f8b9490d20f633b099e1c57d0e75a342e3e842c02f653284d7e668023e75cfd08bb13270c6a253ce6e912ff\",\n" - " \"5\": \"99b1be3a92428d390552fd1560c3df47d4af2b566c59bf9da83b1cc6a2a702fd8e99dc355779547788cc3068d171493e103bee0f243d3e0c9c994a823bbfd2fc45d101b7012ddbc083409bcc650f299ca592fa1f034d3fc05280f8cc22f5af08a9fbeb7ded2068d978fb853f65de6bf4ad9b783c3291bd37a7f8a9f6e27771b1d597d613b12a55fac3d7c83985b62d9726925779d0aeb94821fe1310d486b4eeefef6c456152a9a20a006d01f275830133aeda1eaadbd6a3d3c478fa18b35b161a628850d7acab2fb1384e6cfabc11cd99737d9aa13a3d93bea3406a9f2f3310be51ee415c80fc296b31009ec863c1cc3657e5ee41054c05444624abe25f61fe\",\n" - " \"10\": \"3bcd60907ba904d5682eab1cdd9341c9a99a17f85c2b9ce6139094f8bb8d3ef3c98d43006511f69d18c24bc4335d33af3c9dab532aa8679294a89b6e47fa849d99f405426ea066157b31702e1a51346b95330dd31c6972544d0014c83aaf60ada894fe2daa73e1416afbacc564e3da36dc1ea2652c4486cdb82c9be2c6e217ff6acdb8390842c2a5ff54fa5953177bd826572ab0a538f9858e9a3fd95a06e84c314cc3776d1b545f2ae867c0a88e7753585a9c1fdcb40f59edd35d7fa73885d22b1782fe25b40591a63906748ee2d1f8b8545dd84e0e4ff9d75970c883f59849596e993353377a8cc8f25f4f28c7eb572f6130b8e80ee9ce3feaec8e19b750f9\",\n" - " \"50\": \"5bf7820b1cf4a4480c8d364ab122a7abe74addbb51e0e21bb7c928cda213e17347331748a74d802f41b62d9674bbed22baaca4dd86a005b8a8c212404f328f9ae9c14d3d97d70606698a89be8a1488a55faccbfd5a0215b047a3af38b1e5e07f79da96706309c71b0f1fdacdbde1a4771f4176e9889741832c882720f873932e78c27dad10bbd8afff80e360e193f1239dba8affcaee13a05be9290a481155e3359eff376b718793c512f31146c1eee2065efd64fc2805e6b85a252cba14487ab84c4aae8299a63e0d6d0fd9dcfe555f0fcd4dfc2351bdeb557270a7b51b8c76418c58538cef8a55b8a5c7132209f877f38af8ab2b743d7f68652479332c84bf\",\n" - " \"100\": \"926a5c1472f3a222b732878fa59b6e477e1910099ce3a47f9878a58a164eb22d10b43cdb1252c09838def4054a026d3526b0ae202aeea1e13d846c8a416c07439bf6e41c370524e52fa2e214e2746a5225289eaacff447a41fca58369bc51996ebfdd64e286795280b38408f04401566b8a44ee36840267fbad6683258bba4a83558611e3a9b8c1024dccac65a6a552ddf5932feeca7659e5626d97fadc93f1eb77a7d53d7c2b389eaf4fba337c01d73213fb92d7ef1ec335cbfe8f0e978c80c210475dbe0c15efa1d26eec6a61881deaab3203bac0a80c1ac5c580b236c69ae3f2796fb33f2f21ec3bca69b92ea62675f226d7f3647adec200c0eada4cca931\",\n" - " \"500\": \"63a64ea5fb1fff6954a146b83d9ca5e8adee3c2eca8717b16feb28abf0402f1ece2c709a2441bf7ddd2230b3d99c600e290b07552a985e9d3bd3f245f69fe9c0a2fc7c25b9ef33137484985e6bf1aead8ce23fbb3fbf392a625f1bba9a02cb76965891e2d2b6aef8a7b308de5e5d927c6d56b49a326e60bb47d46744f4a02e101decef48d7346752507293a56af54e9226d7a5fe4201aeee4b96ae03058461f49122f885972e585ccb2aa73f05a7ca62fc14d73d710f146aa66e7a83abbdfd761c706a1f7df98f0d4d1148aedb6dd0759dd491573630f482477cb2449c4a9aa005fed29ba1a7dd97e645c69b9f481e2aacba54bb0f5252d750a6498fdf542ab1\",\n" - " \"1000\": \"29b5bfb308a476b7c63a8cf026cc9647add61fc8f277658467f32a129483bd032595fe8f80311cc77fd602340079a1a4451e76ca422da988a62e1a3f913912d0963fc3c9a6987eaba59433df83c1ea2396f466bad4d91b0a2923fe9a1326b56dc5174174cb1e37bb52119780d7ee62b96cdbfae93f2d23be221b704210deece493d37afdbccd383d7ce54343a48b85d2bcfe7fb54bea6eeb2159ae8c4505ef9f92e5afef50847d52ca66af3d5ed504ca889c049e6c88db0a9928e3e18641571d921f4534b8008fdd103dadece5e4495c670a03da0c3ee8b7d91b5f53d2c2dbc06a8696032711ada128dcc85823873002d741010734acd9e69976b88dff33e32c\",\n" - " \"5000\": \"8db0b3495edb380ef7dda75a0ce2c53427b7a5ca70e0f6e93596a23e77d1c2e3244b581506ced3492ffb6ed53b42ce9eec293fc8f44bc59dcc5dd449ab6e93f087cf37f11aecf84386328e50fe14251fecfef7dbf5d33d07068f68a7466921c0267f38ca0b79ff30876d3e6c06a878b30d4bd17e35e53c3fcfc886200ee216401ee1dc90ba7c4345c01fc00aa4cf4540d51158f76da334226d076de56f9b5f8d32791cff7ed51af5054e9beb05237c330f24430ac7c2ffe5cf1a6b4fed14600e18e635d848476b826a12e2a9429170e7cc6dbdb44e04dfe00f3b7660bb083a1942aaee19d30a848cdb1228efd9ec3e7a8af611c8822d930f62cf73d4c0f1597c\"\n" - " },\n" - " {\n" - " \"height\": 1100020,\n" - " \"1\": \"bb4d4aba1c8289c0ef84affb2c63351cf10700745a30d1a6cc96b0d16cbc4d7af58b9d8fb7908b2268f0e5b1624e719fa897ca6146b1abcf197aaea84b76c803d2c0a1c3692765b23fe7caa44980cfde2ed0bb54647c74f017ed4e065b22ed59ce3f755764ab96fc98d9bf5cab5f2e3b9e5462c4672537c4b6a3997152a123bc18a9d7cfd9f4c09b2e674115c3817f9face664f464a93e2b079f7c44e8c544e391fcf5bb140182ece31db51c4624bdd93723d603210fccd2ecd1cf29604f54aaa148878d9f84595348153df14bc3b2a663e78c727f8b9490d20f633b099e1c57d0e75a342e3e842c02f653284d7e668023e75cfd08bb13270c6a253ce6e912ff\",\n" - " \"5\": \"99b1be3a92428d390552fd1560c3df47d4af2b566c59bf9da83b1cc6a2a702fd8e99dc355779547788cc3068d171493e103bee0f243d3e0c9c994a823bbfd2fc45d101b7012ddbc083409bcc650f299ca592fa1f034d3fc05280f8cc22f5af08a9fbeb7ded2068d978fb853f65de6bf4ad9b783c3291bd37a7f8a9f6e27771b1d597d613b12a55fac3d7c83985b62d9726925779d0aeb94821fe1310d486b4eeefef6c456152a9a20a006d01f275830133aeda1eaadbd6a3d3c478fa18b35b161a628850d7acab2fb1384e6cfabc11cd99737d9aa13a3d93bea3406a9f2f3310be51ee415c80fc296b31009ec863c1cc3657e5ee41054c05444624abe25f61fe\",\n" - " \"10\": \"3bcd60907ba904d5682eab1cdd9341c9a99a17f85c2b9ce6139094f8bb8d3ef3c98d43006511f69d18c24bc4335d33af3c9dab532aa8679294a89b6e47fa849d99f405426ea066157b31702e1a51346b95330dd31c6972544d0014c83aaf60ada894fe2daa73e1416afbacc564e3da36dc1ea2652c4486cdb82c9be2c6e217ff6acdb8390842c2a5ff54fa5953177bd826572ab0a538f9858e9a3fd95a06e84c314cc3776d1b545f2ae867c0a88e7753585a9c1fdcb40f59edd35d7fa73885d22b1782fe25b40591a63906748ee2d1f8b8545dd84e0e4ff9d75970c883f59849596e993353377a8cc8f25f4f28c7eb572f6130b8e80ee9ce3feaec8e19b750f9\",\n" - " \"50\": \"5bf7820b1cf4a4480c8d364ab122a7abe74addbb51e0e21bb7c928cda213e17347331748a74d802f41b62d9674bbed22baaca4dd86a005b8a8c212404f328f9ae9c14d3d97d70606698a89be8a1488a55faccbfd5a0215b047a3af38b1e5e07f79da96706309c71b0f1fdacdbde1a4771f4176e9889741832c882720f873932e78c27dad10bbd8afff80e360e193f1239dba8affcaee13a05be9290a481155e3359eff376b718793c512f31146c1eee2065efd64fc2805e6b85a252cba14487ab84c4aae8299a63e0d6d0fd9dcfe555f0fcd4dfc2351bdeb557270a7b51b8c76418c58538cef8a55b8a5c7132209f877f38af8ab2b743d7f68652479332c84bf\",\n" - " \"100\": \"926a5c1472f3a222b732878fa59b6e477e1910099ce3a47f9878a58a164eb22d10b43cdb1252c09838def4054a026d3526b0ae202aeea1e13d846c8a416c07439bf6e41c370524e52fa2e214e2746a5225289eaacff447a41fca58369bc51996ebfdd64e286795280b38408f04401566b8a44ee36840267fbad6683258bba4a83558611e3a9b8c1024dccac65a6a552ddf5932feeca7659e5626d97fadc93f1eb77a7d53d7c2b389eaf4fba337c01d73213fb92d7ef1ec335cbfe8f0e978c80c210475dbe0c15efa1d26eec6a61881deaab3203bac0a80c1ac5c580b236c69ae3f2796fb33f2f21ec3bca69b92ea62675f226d7f3647adec200c0eada4cca931\",\n" - " \"500\": \"63a64ea5fb1fff6954a146b83d9ca5e8adee3c2eca8717b16feb28abf0402f1ece2c709a2441bf7ddd2230b3d99c600e290b07552a985e9d3bd3f245f69fe9c0a2fc7c25b9ef33137484985e6bf1aead8ce23fbb3fbf392a625f1bba9a02cb76965891e2d2b6aef8a7b308de5e5d927c6d56b49a326e60bb47d46744f4a02e101decef48d7346752507293a56af54e9226d7a5fe4201aeee4b96ae03058461f49122f885972e585ccb2aa73f05a7ca62fc14d73d710f146aa66e7a83abbdfd761c706a1f7df98f0d4d1148aedb6dd0759dd491573630f482477cb2449c4a9aa005fed29ba1a7dd97e645c69b9f481e2aacba54bb0f5252d750a6498fdf542ab1\",\n" - " \"1000\": \"29b5bfb308a476b7c63a8cf026cc9647add61fc8f277658467f32a129483bd032595fe8f80311cc77fd602340079a1a4451e76ca422da988a62e1a3f913912d0963fc3c9a6987eaba59433df83c1ea2396f466bad4d91b0a2923fe9a1326b56dc5174174cb1e37bb52119780d7ee62b96cdbfae93f2d23be221b704210deece493d37afdbccd383d7ce54343a48b85d2bcfe7fb54bea6eeb2159ae8c4505ef9f92e5afef50847d52ca66af3d5ed504ca889c049e6c88db0a9928e3e18641571d921f4534b8008fdd103dadece5e4495c670a03da0c3ee8b7d91b5f53d2c2dbc06a8696032711ada128dcc85823873002d741010734acd9e69976b88dff33e32c\",\n" - " \"5000\": \"8db0b3495edb380ef7dda75a0ce2c53427b7a5ca70e0f6e93596a23e77d1c2e3244b581506ced3492ffb6ed53b42ce9eec293fc8f44bc59dcc5dd449ab6e93f087cf37f11aecf84386328e50fe14251fecfef7dbf5d33d07068f68a7466921c0267f38ca0b79ff30876d3e6c06a878b30d4bd17e35e53c3fcfc886200ee216401ee1dc90ba7c4345c01fc00aa4cf4540d51158f76da334226d076de56f9b5f8d32791cff7ed51af5054e9beb05237c330f24430ac7c2ffe5cf1a6b4fed14600e18e635d848476b826a12e2a9429170e7cc6dbdb44e04dfe00f3b7660bb083a1942aaee19d30a848cdb1228efd9ec3e7a8af611c8822d930f62cf73d4c0f1597c\"\n" " }\n" "]"; return strMainCheckpoints; diff --git a/src/xion/accumulators.cpp b/src/xion/accumulators.cpp index 75eb1369239a0..b02cdbe2c6fda 100644 --- a/src/xion/accumulators.cpp +++ b/src/xion/accumulators.cpp @@ -147,7 +147,7 @@ bool LoadAccumulatorValuesFromDB(const uint256 nCheckpoint) if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnValue)) { if (!count(listAccCheckpointsNoDB.begin(), listAccCheckpointsNoDB.end(), nCheckpoint)) listAccCheckpointsNoDB.push_back(nCheckpoint); - LogPrint("zero", "%s : Missing databased value for checksum %d", __func__, nChecksum); + LogPrint("zero", "%s : Missing databased value for checksum %d\n", __func__, nChecksum); return false; } mapAccumulatorValues.insert(make_pair(nChecksum, bnValue)); diff --git a/src/xion/xionmodule.cpp b/src/xion/xionmodule.cpp new file mode 100644 index 0000000000000..447bc95566dee --- /dev/null +++ b/src/xion/xionmodule.cpp @@ -0,0 +1,129 @@ +// Copyright (c) 2019 The ion developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "xion/xionmodule.h" +#include "xionchain.h" +#include "libzerocoin/Commitment.h" +#include "libzerocoin/Coin.h" +#include "hash.h" +#include "main.h" +#include "iostream" + +bool PublicCoinSpend::Verify(const libzerocoin::Accumulator& a, bool verifyParams) const { + return validate(); +} + +bool PublicCoinSpend::validate() const { + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + // Check that it opens to the input values + libzerocoin::Commitment commitment( + ¶ms->coinCommitmentGroup, getCoinSerialNumber(), randomness); + + if (commitment.getCommitmentValue() != pubCoin.getValue()){ + return error("%s: commitments values are not equal\n", __func__); + } + // Now check that the signature validates with the serial + if (!HasValidSignature()) { + return error("%s: signature invalid\n", __func__);; + } + return true; +} + +const uint256 PublicCoinSpend::signatureHash() const +{ + CHashWriter h(0, 0); + h << ptxHash << denomination << getCoinSerialNumber() << randomness << txHash << outputIndex << getSpendType(); + return h.GetHash(); +} + +namespace XIONModule { + + bool createInput(CTxIn &in, CZerocoinMint &mint, uint256 hashTxOut) { + libzerocoin::ZerocoinParams *params = Params().Zerocoin_Params(false); + uint8_t nVersion = mint.GetVersion(); + if (nVersion < libzerocoin::PrivateCoin::PUBKEY_VERSION) { + // No v1 serials accepted anymore. + return error("%s: failed to set xION privkey mint version=%d\n", __func__, nVersion); + } + + CKey key; + if (!mint.GetKeyPair(key)) + return error("%s: failed to set xION privkey mint version=%d\n", __func__, nVersion); + + PublicCoinSpend spend(params, mint.GetSerialNumber(), mint.GetRandomness(), key.GetPubKey()); + spend.setTxOutHash(hashTxOut); + spend.outputIndex = mint.GetOutputIndex(); + spend.txHash = mint.GetTxHash(); + spend.setDenom(mint.GetDenomination()); + + std::vector vchSig; + if (!key.Sign(spend.signatureHash(), vchSig)) + throw std::runtime_error("XIONModule failed to sign signatureHash\n"); + + spend.setVchSig(vchSig); + + CDataStream ser(SER_NETWORK, PROTOCOL_VERSION); + ser << spend; + + std::vector data(ser.begin(), ser.end()); + CScript scriptSigIn = CScript() << OP_ZEROCOINPUBLICSPEND << data.size(); + scriptSigIn.insert(scriptSigIn.end(), data.begin(), data.end()); + in = CTxIn(mint.GetTxHash(), mint.GetOutputIndex(), scriptSigIn, mint.GetDenomination()); + in.nSequence = mint.GetDenomination(); + return true; + } + + bool parseCoinSpend(const CTxIn &in, const CTransaction &tx, const CTxOut &prevOut, PublicCoinSpend &publicCoinSpend) { + if (!in.IsZerocoinPublicSpend() || !prevOut.IsZerocoinMint()) + return error("%s: invalid argument/s\n", __func__); + + std::vector > data; + data.insert(data.end(), in.scriptSig.begin() + 4, in.scriptSig.end()); + CDataStream serializedCoinSpend(data, SER_NETWORK, PROTOCOL_VERSION); + libzerocoin::ZerocoinParams *params = Params().Zerocoin_Params(false); + PublicCoinSpend spend(params, serializedCoinSpend); + + spend.outputIndex = in.prevout.n; + spend.txHash = in.prevout.hash; + CMutableTransaction txNew(tx); + txNew.vin.clear(); + spend.setTxOutHash(txNew.GetHash()); + + // Check prev out now + CValidationState state; + if (!TxOutToPublicCoin(prevOut, spend.pubCoin, state)) + return error("%s: cannot get mint from output\n", __func__); + + spend.setDenom(spend.pubCoin.getDenomination()); + publicCoinSpend = spend; + return true; + } + + bool validateInput(const CTxIn &in, const CTxOut &prevOut, const CTransaction &tx, PublicCoinSpend &publicSpend) { + // Now prove that the commitment value opens to the input + if (!parseCoinSpend(in, tx, prevOut, publicSpend)) { + return false; + } + if (libzerocoin::ZerocoinDenominationToAmount( + libzerocoin::IntToZerocoinDenomination(in.nSequence)) != prevOut.nValue) { + return error("PublicCoinSpend validateInput :: input nSequence different to prevout value\n"); + } + + return publicSpend.validate(); + } + + bool ParseZerocoinPublicSpend(const CTxIn &txIn, const CTransaction& tx, CValidationState& state, PublicCoinSpend& publicSpend) + { + CTxOut prevOut; + if(!GetOutput(txIn.prevout.hash, txIn.prevout.n ,state, prevOut)){ + return state.DoS(100, error("%s: public zerocoin spend prev output not found, prevTx %s, index %d\n", + __func__, txIn.prevout.hash.GetHex(), txIn.prevout.n)); + } + if (!XIONModule::parseCoinSpend(txIn, tx, prevOut, publicSpend)) { + return state.Invalid(error("%s: invalid public coin spend parse %s\n", __func__, + tx.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-xion"); + } + return true; + } +} diff --git a/src/xion/xionmodule.h b/src/xion/xionmodule.h new file mode 100644 index 0000000000000..6aa0762dfd50f --- /dev/null +++ b/src/xion/xionmodule.h @@ -0,0 +1,92 @@ +// Copyright (c) 2019 The ion developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +#ifndef ION_XIONMODULE_H +#define ION_XIONMODULE_H + +#include "libzerocoin/bignum.h" +#include "libzerocoin/Denominations.h" +#include "libzerocoin/CoinSpend.h" +#include "libzerocoin/Coin.h" +#include "libzerocoin/SpendType.h" +#include "primitives/transaction.h" +#include "script/script.h" +#include "serialize.h" +#include "uint256.h" +#include +#include +#include "xion/zerocoin.h" +#include "chainparams.h" + +static int const COIN_SPEND_PUBLIC_SPEND_VERSION = 3; + +class PublicCoinSpend : public libzerocoin::CoinSpend{ +public: + + PublicCoinSpend(libzerocoin::ZerocoinParams* params):pubCoin(params){}; + + PublicCoinSpend(libzerocoin::ZerocoinParams* params, + CBigNum serial, CBigNum randomness, CPubKey pubkey):pubCoin(params){ + this->coinSerialNumber = serial; + this->randomness = randomness; + this->pubkey = pubkey; + this->spendType = libzerocoin::SpendType::SPEND; + this->version = COIN_SPEND_PUBLIC_SPEND_VERSION; + }; + + ~PublicCoinSpend(){}; + + template + PublicCoinSpend( + libzerocoin::ZerocoinParams* params, + Stream& strm):pubCoin(params){ + strm >> *this; + this->spendType = libzerocoin::SpendType::SPEND; + } + + const uint256 signatureHash() const override; + void setVchSig(std::vector vchSig) { this->vchSig = vchSig; }; + bool Verify(const libzerocoin::Accumulator& a, bool verifyParams = true) const override; + bool validate() const; + + // Members + CBigNum randomness; + // prev out values + uint256 txHash = 0; + unsigned int outputIndex = -1; + libzerocoin::PublicCoin pubCoin; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(version); + READWRITE(coinSerialNumber); + READWRITE(randomness); + READWRITE(pubkey); + READWRITE(vchSig); + } +}; + + +class CValidationState; + +namespace XIONModule { + bool createInput(CTxIn &in, CZerocoinMint& mint, uint256 hashTxOut); + bool parseCoinSpend(const CTxIn &in, const CTransaction& tx, const CTxOut &prevOut, PublicCoinSpend& publicCoinSpend); + bool validateInput(const CTxIn &in, const CTxOut &prevOut, const CTransaction& tx, PublicCoinSpend& ret); + + // Public zc spend parse + /** + * + * @param in --> public zc spend input + * @param tx --> input parent + * @param publicCoinSpend ---> return the publicCoinSpend parsed + * @return true if everything went ok + */ + bool ParseZerocoinPublicSpend(const CTxIn &in, const CTransaction& tx, CValidationState& state, PublicCoinSpend& publicCoinSpend); +}; + + +#endif //ION_XIONMODULE_H diff --git a/src/xion/xiontracker.cpp b/src/xion/xiontracker.cpp index 9f0e4b59148be..0c42f1cc22a9d 100644 --- a/src/xion/xiontracker.cpp +++ b/src/xion/xiontracker.cpp @@ -460,7 +460,7 @@ bool CxIONTracker::UpdateStatusInternal(const std::set& setMempool, CMi return false; } -std::set CxIONTracker::ListMints(bool fUnusedOnly, bool fMatureOnly, bool fUpdateStatus, bool fWrongSeed) +std::set CxIONTracker::ListMints(bool fUnusedOnly, bool fMatureOnly, bool fUpdateStatus, bool fWrongSeed, bool fExcludeV1) { CWalletDB walletdb(strWalletFile); if (fUpdateStatus) { @@ -473,6 +473,8 @@ std::set CxIONTracker::ListMints(bool fUnusedOnly, bool fMatureOnly, CxIONWallet* xIONWallet = new CxIONWallet(strWalletFile); for (auto& dMint : listDeterministicDB) { + if (fExcludeV1 && dMint.GetVersion() < 2) + continue; Add(dMint, false, false, xIONWallet); } delete xIONWallet; diff --git a/src/xion/xiontracker.h b/src/xion/xiontracker.h index c8dc9f84a0f2d..664eb76c16301 100644 --- a/src/xion/xiontracker.h +++ b/src/xion/xiontracker.h @@ -45,7 +45,7 @@ class CxIONTracker bool ClearSpendCache() EXCLUSIVE_LOCKS_REQUIRED(cs_spendcache); std::vector GetMints(bool fConfirmedOnly) const; CAmount GetUnconfirmedBalance() const; - std::set ListMints(bool fUnusedOnly, bool fMatureOnly, bool fUpdateStatus, bool fWrongSeed = false); + std::set ListMints(bool fUnusedOnly, bool fMatureOnly, bool fUpdateStatus, bool fWrongSeed = false, bool fExcludeV1 = false); void RemovePending(const uint256& txid); void SetPubcoinUsed(const uint256& hashPubcoin, const uint256& txid); void SetPubcoinNotUsed(const uint256& hashPubcoin); diff --git a/src/xion/xionwallet.cpp b/src/xion/xionwallet.cpp index 52b790e9935a7..65357d967e2d3 100644 --- a/src/xion/xionwallet.cpp +++ b/src/xion/xionwallet.cpp @@ -229,7 +229,7 @@ void CxIONWallet::SyncWithChain(bool fGenerateMintPool) bool fFoundMint = false; CBigNum bnValue = 0; for (const CTxOut& out : tx.vout) { - if (!out.scriptPubKey.IsZerocoinMint()) + if (!out.IsZerocoinMint()) continue; PublicCoin pubcoin(Params().Zerocoin_Params(false)); diff --git a/src/xion/zerocoin.h b/src/xion/zerocoin.h index fb64a2ae8cf07..4c64cdf215917 100644 --- a/src/xion/zerocoin.h +++ b/src/xion/zerocoin.h @@ -43,6 +43,7 @@ class CZerocoinMint CBigNum randomness; CBigNum serialNumber; uint256 txid; + int outputIndex = -1; CPrivKey privkey; uint8_t version; bool isUsed; @@ -104,6 +105,9 @@ class CZerocoinMint void SetPrivKey(const CPrivKey& privkey) { this->privkey = privkey; } bool GetKeyPair(CKey& key) const; + int GetOutputIndex() { return this->outputIndex; } + void SetOutputIndex(int index) { this->outputIndex = index; } + inline bool operator <(const CZerocoinMint& a) const { return GetHeight() < a.GetHeight(); } CZerocoinMint(const CZerocoinMint& other) { diff --git a/src/xionchain.cpp b/src/xionchain.cpp index 86100a7d84e8f..00c77c530259d 100644 --- a/src/xionchain.cpp +++ b/src/xionchain.cpp @@ -4,10 +4,11 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "xionchain.h" +#include "xion/xionmodule.h" #include "invalid.h" #include "main.h" #include "txdb.h" -#include "ui_interface.h" +#include "guiinterface.h" // 6 comes from OPCODE (1) + vch.size() (1) + BIGNUM size (4) #define SCRIPT_OFFSET 6 @@ -17,11 +18,11 @@ bool BlockToMintValueVector(const CBlock& block, const libzerocoin::CoinDenomination denom, vector& vValues) { for (const CTransaction& tx : block.vtx) { - if(!tx.IsZerocoinMint()) + if(!tx.HasZerocoinMintOutputs()) continue; for (const CTxOut& txOut : tx.vout) { - if(!txOut.scriptPubKey.IsZerocoinMint()) + if(!txOut.IsZerocoinMint()) continue; CValidationState state; @@ -42,7 +43,7 @@ bool BlockToMintValueVector(const CBlock& block, const libzerocoin::CoinDenomina bool BlockToPubcoinList(const CBlock& block, std::list& listPubcoins, bool fFilterInvalid) { for (const CTransaction& tx : block.vtx) { - if(!tx.IsZerocoinMint()) + if(!tx.HasZerocoinMintOutputs()) continue; // Filter out mints that have used invalid outpoints @@ -65,7 +66,7 @@ bool BlockToPubcoinList(const CBlock& block, std::list& break; const CTxOut txOut = tx.vout[i]; - if(!txOut.scriptPubKey.IsZerocoinMint()) + if(!txOut.IsZerocoinMint()) continue; CValidationState state; @@ -84,7 +85,7 @@ bool BlockToPubcoinList(const CBlock& block, std::list& bool BlockToZerocoinMintList(const CBlock& block, std::list& vMints, bool fFilterInvalid) { for (const CTransaction& tx : block.vtx) { - if(!tx.IsZerocoinMint()) + if(!tx.HasZerocoinMintOutputs()) continue; // Filter out mints that have used invalid outpoints @@ -107,7 +108,7 @@ bool BlockToZerocoinMintList(const CBlock& block, std::list& vMin break; const CTxOut txOut = tx.vout[i]; - if(!txOut.scriptPubKey.IsZerocoinMint()) + if(!txOut.IsZerocoinMint()) continue; CValidationState state; @@ -284,18 +285,28 @@ std::string ReindexZerocoinDB() if (tx.ContainsZerocoins()) { uint256 txid = tx.GetHash(); //Record Serials - if (tx.IsZerocoinSpend()) { + if (tx.HasZerocoinSpendInputs()) { for (auto& in : tx.vin) { - if (!in.scriptSig.IsZerocoinSpend()) + bool isPublicSpend = in.IsZerocoinPublicSpend(); + if (!in.IsZerocoinSpend() && !isPublicSpend) continue; - - libzerocoin::CoinSpend spend = TxInToZerocoinSpend(in); - vSpendInfo.push_back(make_pair(spend, txid)); + if (isPublicSpend) { + libzerocoin::ZerocoinParams* params = Params().Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + CValidationState state; + if (!XIONModule::ParseZerocoinPublicSpend(in, tx, state, publicSpend)){ + return _("Failed to parse public spend"); + } + vSpendInfo.push_back(make_pair(publicSpend, txid)); + } else { + libzerocoin::CoinSpend spend = TxInToZerocoinSpend(in); + vSpendInfo.push_back(make_pair(spend, txid)); + } } } //Record mints - if (tx.IsZerocoinMint()) { + if (tx.HasZerocoinMintOutputs()) { for (auto& out : tx.vout) { if (!out.IsZerocoinMint()) continue; @@ -373,14 +384,15 @@ std::list ZerocoinSpendListFromBlock(const CBlock { std::list vSpends; for (const CTransaction& tx : block.vtx) { - if (!tx.IsZerocoinSpend()) + if (!tx.HasZerocoinSpendInputs()) continue; for (const CTxIn& txin : tx.vin) { - if (!txin.scriptSig.IsZerocoinSpend()) + bool isPublicSpend = txin.IsZerocoinPublicSpend(); + if (!txin.IsZerocoinSpend() && !isPublicSpend) continue; - if (fFilterInvalid) { + if (fFilterInvalid && !isPublicSpend) { libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txin); if (invalid_out::ContainsSerial(spend.getCoinSerialNumber())) continue; diff --git a/test/functional/README.md b/test/functional/README.md index f9e5a1c70064a..c9f1bfcca569c 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -1,67 +1,136 @@ -Regression tests -================ +# Functional tests + +### Writing Functional Tests + +#### Example test + +The [example_test.py](example_test.py) is a heavily commented example of a test case that uses both +the RPC and P2P interfaces. If you are writing your first test, copy that file +and modify to fit your needs. + +#### Coverage + +Running `test_runner.py` with the `--coverage` argument tracks which RPCs are +called by the tests and prints a report of uncovered RPCs in the summary. This +can be used (along with the `--extended` argument) to find out which RPCs we +don't have test cases for. + +#### Style guidelines + +- Where possible, try to adhere to [PEP-8 guidelines](https://www.python.org/dev/peps/pep-0008/) +- Use a python linter like flake8 before submitting PRs to catch common style + nits (eg trailing whitespace, unused imports, etc) +- The oldest supported Python version is specified in [doc/dependencies.md](/doc/dependencies.md). + Consider using [pyenv](https://github.com/pyenv/pyenv), which checks [.python-version](/.python-version), + to prevent accidentally introducing modern syntax from an unsupported Python version. + The Travis linter also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126). +- See [the python lint script](/test/lint/lint-python.sh) that checks for violations that + could lead to bugs and issues in the test code. +- Avoid wildcard imports +- Use a module-level docstring to describe what the test is testing, and how it + is testing it. +- When subclassing the BitcoinTestFramwork, place overrides for the + `set_test_params()`, `add_options()` and `setup_xxxx()` methods at the top of + the subclass, then locally-defined helper methods, then the `run_test()` method. +- Use `'{}'.format(x)` for string formatting, not `'%s' % x`. + +#### Naming guidelines + +- Name the test `_test.py`, where area can be one of the following: + - `feature` for tests for full features that aren't wallet/mining/mempool, eg `feature_rbf.py` + - `interface` for tests for other interfaces (REST, ZMQ, etc), eg `interface_rest.py` + - `mempool` for tests for mempool behaviour, eg `mempool_reorg.py` + - `mining` for tests for mining features, eg `mining_prioritisetransaction.py` + - `p2p` for tests that explicitly test the p2p interface, eg `p2p_disconnect_ban.py` + - `rpc` for tests for individual RPC methods or features, eg `rpc_listtransactions.py` + - `tool` for tests for tools, eg `tool_wallet.py` + - `wallet` for tests for wallet features, eg `wallet_keypool.py` +- use an underscore to separate words + - exception: for tests for specific RPCs or command line options which don't include underscores, name the test after the exact RPC or argument name, eg `rpc_decodescript.py`, not `rpc_decode_script.py` +- Don't use the redundant word `test` in the name, eg `interface_zmq.py`, not `interface_zmq_test.py` + +#### General test-writing advice + +- Set `self.num_nodes` to the minimum number of nodes necessary for the test. + Having additional unrequired nodes adds to the execution time of the test as + well as memory/CPU/disk requirements (which is important when running tests in + parallel or on Travis). +- Avoid stop-starting the nodes multiple times during the test if possible. A + stop-start takes several seconds, so doing it several times blows up the + runtime of the test. +- Set the `self.setup_clean_chain` variable in `set_test_params()` to control whether + or not to use the cached data directories. The cached data directories + contain a 200-block pre-mined blockchain and wallets for four nodes. Each node + has 25 mature blocks (25x50=1250 BTC) in its wallet. +- When calling RPCs with lots of arguments, consider using named keyword + arguments instead of positional arguments to make the intent of the call + clear to readers. +- Many of the core test framework classes such as `CBlock` and `CTransaction` + don't allow new attributes to be added to their objects at runtime like + typical Python objects allow. This helps prevent unpredictable side effects + from typographical errors or usage of the objects outside of their intended + purpose. + +#### RPC and P2P definitions + +Test writers may find it helpful to refer to the definitions for the RPC and +P2P messages. These can be found in the following source files: + +- `/src/rpc/*` for RPCs +- `/src/wallet/rpc*` for wallet RPCs +- `ProcessMessage()` in `/src/net_processing.cpp` for parsing P2P messages + +#### Using the P2P interface + +- `messages.py` contains all the definitions for objects that pass +over the network (`CBlock`, `CTransaction`, etc, along with the network-level +wrappers for them, `msg_block`, `msg_tx`, etc). + +- P2P tests have two threads. One thread handles all network communication +with the iond(s) being tested in a callback-based event loop; the other +implements the test logic. + +- `P2PConnection` is the class used to connect to a iond. `P2PInterface` +contains the higher level logic for processing P2P payloads and connecting to +the Bitcoin Core node application logic. For custom behaviour, subclass the +P2PInterface object and override the callback methods. + +- Can be used to write tests where specific P2P protocol behavior is tested. +Examples tests are `p2p_unrequested_blocks.py`, `p2p_compactblocks.py`. + +### test-framework modules -### [test_framework/authproxy.py](test_framework/authproxy.py) +#### [test_framework/authproxy.py](test_framework/authproxy.py) Taken from the [python-bitcoinrpc repository](https://github.com/jgarzik/python-bitcoinrpc). -### [test_framework/test_framework.py](test_framework/test_framework.py) -Base class for new regression tests. +#### [test_framework/test_framework.py](test_framework/test_framework.py) +Base class for functional tests. -### [test_framework/util.py](test_framework/util.py) +#### [test_framework/util.py](test_framework/util.py) Generally useful functions. -### [test_framework/mininode.py](test_framework/mininode.py) -Basic code to support p2p connectivity to a iond. +#### [test_framework/mininode.py](test_framework/mininode.py) +Basic code to support P2P connectivity to a iond. -### [test_framework/comptool.py](test_framework/comptool.py) +#### [test_framework/comptool.py](test_framework/comptool.py) Framework for comparison-tool style, p2p tests. -### [test_framework/script.py](test_framework/script.py) +#### [test_framework/script.py](test_framework/script.py) Utilities for manipulating transaction scripts (originally from python-bitcoinlib) -### [test_framework/blockstore.py](test_framework/blockstore.py) +#### [test_framework/blockstore.py](test_framework/blockstore.py) Implements disk-backed block and tx storage. -### [test_framework/key.py](test_framework/key.py) +#### [test_framework/key.py](test_framework/key.py) Wrapper around OpenSSL EC_Key (originally from python-bitcoinlib) -### [test_framework/bignum.py](test_framework/bignum.py) +#### [test_framework/bignum.py](test_framework/bignum.py) Helpers for script.py -### [test_framework/blocktools.py](test_framework/blocktools.py) +#### [test_framework/blocktools.py](test_framework/blocktools.py) Helper functions for creating blocks and transactions. -P2P test design notes ---------------------- - -## Mininode - -* ```mininode.py``` contains all the definitions for objects that pass -over the network (```CBlock```, ```CTransaction```, etc, along with the network-level -wrappers for them, ```msg_block```, ```msg_tx```, etc). - -* P2P tests have two threads. One thread handles all network communication -with the iond(s) being tested (using python's asyncore package); the other -implements the test logic. - -* ```NodeConn``` is the class used to connect to a iond. If you implement -a callback class that derives from ```NodeConnCB``` and pass that to the -```NodeConn``` object, your code will receive the appropriate callbacks when -events of interest arrive. - -* You can pass the same handler to multiple ```NodeConn```'s if you like, or pass -different ones to each -- whatever makes the most sense for your test. - -* Call ```NetworkThread.start()``` after all ```NodeConn``` objects are created to -start the networking thread. (Continue with the test logic in your existing -thread.) - -* RPC calls are available in p2p tests. - -* Can be used to write free-form tests, where specific p2p-protocol behavior -is tested. Examples: ```p2p-accept-block.py```, ```maxblocksinflight.py```. - -## Comptool +### Comptool * Testing framework for writing tests that compare the block/tx acceptance behavior of a iond against 1 or more other iond instances, or against diff --git a/test/functional/fake_stake/base_test.py b/test/functional/fake_stake/base_test.py index f135b6f600416..a4879a48f3944 100644 --- a/test/functional/fake_stake/base_test.py +++ b/test/functional/fake_stake/base_test.py @@ -48,7 +48,9 @@ def init_test(self): :param: :return: ''' - self.log.info("\n\n*** Starting %s ***\n------------------------\n%s\n", self.__class__.__name__, self.description) + title = "*** Starting %s ***" % self.__class__.__name__ + underline = "-" * len(title) + self.log.info("\n\n%s\n%s\n%s\n", title, underline, self.description) # Global Test parameters (override in run_test) self.DEFAULT_FEE = 0.1 # Spam blocks to send in current test @@ -92,8 +94,6 @@ def create_spam_block(self, hashPrevBlock, stakingPrevOuts, height, fStakeDouble :return block: (CBlock) generated block ''' - self.log.info("Creating Spam Block") - # If not given inputs to create spam txes, use a copy of the staking inputs if len(spendingPrevOuts) == 0: spendingPrevOuts = dict(stakingPrevOuts) @@ -117,8 +117,6 @@ def create_spam_block(self, hashPrevBlock, stakingPrevOuts, height, fStakeDouble if not block.solve_stake(stakingPrevOuts): raise Exception("Not able to solve for any prev_outpoint") - self.log.info("Stake found. Signing block...") - # Sign coinstake TX and add it to the block signed_stake_tx = self.sign_stake_tx(block, stakingPrevOuts[block.prevoutStake][0], fZPoS) block.vtx.append(signed_stake_tx) @@ -130,10 +128,10 @@ def create_spam_block(self, hashPrevBlock, stakingPrevOuts, height, fStakeDouble # remove a random prevout from the list # (to randomize block creation if the same height is picked two times) - del spendingPrevOuts[choice(list(spendingPrevOuts))] + if len(spendingPrevOuts) > 0: + del spendingPrevOuts[choice(list(spendingPrevOuts))] # Create spam for the block. Sign the spendingPrevouts - self.log.info("Creating spam TXes...") for outPoint in spendingPrevOuts: value_out = int(spendingPrevOuts[outPoint][0] - self.DEFAULT_FEE * COIN) tx = create_transaction(outPoint, b"", value_out, nTime, scriptPubKey=CScript([self.block_sig_key.get_pubkey(), OP_CHECKSIG])) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 53bfbb3aa3149..47e709e211466 100755 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -297,6 +297,7 @@ def initialize_datadir(dirname, n): f.write("listenonion=0\n") f.write("litemode=1\n") f.write("enablezeromint=0\n") + f.write("precompute=0\n") f.write("staking=0\n") f.write("spendzeroconfchange=1\n") return datadir diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index b446878d52c90..0536b784ef6bb 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -168,7 +168,7 @@ def main(): parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit') parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.') parser.add_argument('--keepcache', '-k', action='store_true', help='the default behavior is to flush the cache directory on startup. --keepcache retains the cache from the previous testrun.') - parser.add_argument('--quiet', '-q', action='store_true', help='only print results summary and failure logs') + parser.add_argument('--quiet', '-q', action='store_true', help='only print dots, results summary and failure logs') parser.add_argument('--tmpdirprefix', '-t', default=tempfile.gettempdir(), help="Root directory for datadirs") args, unknown_args = parser.parse_known_args() @@ -300,17 +300,17 @@ def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_cove test_results = [] max_len_name = len(max(test_list, key=len)) - - for _ in range(len(test_list)): + test_count = len(test_list) + for i in range(test_count): test_result, testdir, stdout, stderr = job_queue.get_next() test_results.append(test_result) - + done_str = "{}/{} - {}{}{}".format(i + 1, test_count, BOLD[1], test_result.name, BOLD[0]) if test_result.status == "Passed": - logging.debug("\n%s%s%s passed, Duration: %s s" % (BOLD[1], test_result.name, BOLD[0], test_result.time)) + logging.debug("%s passed, Duration: %s s" % (done_str, test_result.time)) elif test_result.status == "Skipped": - logging.debug("\n%s%s%s skipped" % (BOLD[1], test_result.name, BOLD[0])) + logging.debug("%s skipped" % (done_str)) else: - print("\n%s%s%s failed, Duration: %s s\n" % (BOLD[1], test_result.name, BOLD[0], test_result.time)) + print("%s failed, Duration: %s s\n" % (done_str, test_result.time)) print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n') print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n') if combined_logs_len and os.path.isdir(testdir): @@ -398,6 +398,12 @@ def get_next(self): log_stderr)) if not self.jobs: raise IndexError('pop from empty list') + + # Print remaining running jobs when all jobs have been started. + if not self.test_list: + print("Remaining jobs: [{}]".format(", ".join(j[0] for j in self.jobs))) + + dot_count = 0 while True: # Return first proc that finishes time.sleep(.5) @@ -419,9 +425,12 @@ def get_next(self): status = "Failed" self.num_running -= 1 self.jobs.remove(j) - + clearline = '\r' + (' ' * dot_count) + '\r' + print(clearline, end='', flush=True) + dot_count = 0 return TestResult(name, status, int(time.time() - time0)), testdir, stdout, stderr print('.', end='', flush=True) + dot_count += 1 class TestResult(): def __init__(self, name, status, time): diff --git a/test/functional/zerocoin_publicSpend_reorg.py b/test/functional/zerocoin_publicSpend_reorg.py new file mode 100644 index 0000000000000..35ecff3c72151 --- /dev/null +++ b/test/functional/zerocoin_publicSpend_reorg.py @@ -0,0 +1,208 @@ +# !/usr/bin/env python3 +# Copyright (c) 2019 The ion Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +''' +Covers the scenario of two valid PoS blocks with same height +and same coinstake input. +''' + +from copy import deepcopy +from io import BytesIO +import time +from test_framework.messages import CTransaction, CBlock +from test_framework.util import bytes_to_hex_str, hex_str_to_bytes, assert_equal +from fake_stake.base_test import ION_FakeStakeTest + + +class ZerocoinPublicSpendReorg(ION_FakeStakeTest): + + def run_test(self): + self.description = "Covers the reorg with a zc public spend in vtx" + self.init_test() + DENOM_TO_USE = 10 # zc denomination + INITAL_MINED_BLOCKS = 321 # First mined blocks (rewards collected to mint) + MORE_MINED_BLOCKS = 105 # More blocks mined before spending zerocoins + + # 1) Starting mining blocks + self.log.info("Mining %d blocks.." % INITAL_MINED_BLOCKS) + self.node.generate(INITAL_MINED_BLOCKS) + + # 2) Mint 2 zerocoins + self.node.mintzerocoin(DENOM_TO_USE) + self.node.generate(1) + self.node.mintzerocoin(DENOM_TO_USE) + self.node.generate(1) + + # 3) Mine additional blocks and collect the mints + self.log.info("Mining %d blocks.." % MORE_MINED_BLOCKS) + self.node.generate(MORE_MINED_BLOCKS) + self.log.info("Collecting mints...") + mints = self.node.listmintedzerocoins(True, False) + assert len(mints) == 2, "mints list has len %d (!= 2)" % len(mints) + + # 4) Get unspent coins and chain tip + self.unspent = self.node.listunspent() + block_count = self.node.getblockcount() + pastBlockHash = self.node.getblockhash(block_count) + self.log.info("Block count: %d - Current best: %s..." % (self.node.getblockcount(), self.node.getbestblockhash()[:5])) + pastBlock = CBlock() + pastBlock.deserialize(BytesIO(hex_str_to_bytes(self.node.getblock(pastBlockHash, False)))) + checkpoint = pastBlock.nAccumulatorCheckpoint + + # 5) get the raw zerocoin spend txes + self.log.info("Getting the raw zerocoin public spends...") + public_spend_A = self.node.createrawzerocoinpublicspend(mints[0].get("serial hash")) + tx_A = CTransaction() + tx_A.deserialize(BytesIO(hex_str_to_bytes(public_spend_A))) + tx_A.rehash() + public_spend_B = self.node.createrawzerocoinpublicspend(mints[1].get("serial hash")) + tx_B = CTransaction() + tx_B.deserialize(BytesIO(hex_str_to_bytes(public_spend_B))) + tx_B.rehash() + # Spending same coins to different recipients to get different txids + my_addy = "yAVWM5urwaTyhiuFQHP2aP47rdZsLUG5PH" + public_spend_A2 = self.node.createrawzerocoinpublicspend(mints[0].get("serial hash"), my_addy) + tx_A2 = CTransaction() + tx_A2.deserialize(BytesIO(hex_str_to_bytes(public_spend_A2))) + tx_A2.rehash() + public_spend_B2 = self.node.createrawzerocoinpublicspend(mints[1].get("serial hash"), my_addy) + tx_B2 = CTransaction() + tx_B2.deserialize(BytesIO(hex_str_to_bytes(public_spend_B2))) + tx_B2.rehash() + self.log.info("tx_A id: %s" % str(tx_A.hash)) + self.log.info("tx_B id: %s" % str(tx_B.hash)) + self.log.info("tx_A2 id: %s" % str(tx_A2.hash)) + self.log.info("tx_B2 id: %s" % str(tx_B2.hash)) + + + self.test_nodes[0].handle_connect() + + # 6) create block_A --> main chain + self.log.info("") + self.log.info("*** block_A ***") + self.log.info("Creating block_A [%d] with public spend tx_A in it." % (block_count + 1)) + block_A = self.new_block(block_count, pastBlock, checkpoint, tx_A) + self.log.info("Hash of block_A: %s..." % block_A.hash[:5]) + self.log.info("sending block_A...") + var = self.node.submitblock(bytes_to_hex_str(block_A.serialize())) + if var is not None: + self.log.info("result: %s" % str(var)) + raise Exception("block_A not accepted") + time.sleep(2) + assert_equal(self.node.getblockcount(), block_count+1) + assert_equal(self.node.getbestblockhash(), block_A.hash) + self.log.info(" >> block_A connected <<") + self.log.info("Current chain: ... --> block_0 [%d] --> block_A [%d]\n" % (block_count, block_count+1)) + + # 7) create block_B --> forked chain + self.log.info("*** block_B ***") + self.log.info("Creating block_B [%d] with public spend tx_B in it." % (block_count + 1)) + block_B = self.new_block(block_count, pastBlock, checkpoint, tx_B) + self.log.info("Hash of block_B: %s..." % block_B.hash[:5]) + self.log.info("sending block_B...") + var = self.node.submitblock(bytes_to_hex_str(block_B.serialize())) + self.log.info("result of block_B submission: %s" % str(var)) + time.sleep(2) + assert_equal(self.node.getblockcount(), block_count+1) + assert_equal(self.node.getbestblockhash(), block_A.hash) + # block_B is not added. Chain remains the same + self.log.info(" >> block_B not connected <<") + self.log.info("Current chain: ... --> block_0 [%d] --> block_A [%d]\n" % (block_count, block_count+1)) + + # 8) Create new block block_C on the forked chain (block_B) + block_count += 1 + self.log.info("*** block_C ***") + self.log.info("Creating block_C [%d] on top of block_B triggering the reorg" % (block_count + 1)) + block_C = self.new_block(block_count, block_B, checkpoint) + self.log.info("Hash of block_C: %s..." % block_C.hash[:5]) + self.log.info("sending block_C...") + var = self.node.submitblock(bytes_to_hex_str(block_C.serialize())) + if var is not None: + self.log.info("result: %s" % str(var)) + raise Exception("block_C not accepted") + time.sleep(2) + assert_equal(self.node.getblockcount(), block_count+1) + assert_equal(self.node.getbestblockhash(), block_C.hash) + self.log.info(" >> block_A disconnected / block_B and block_C connected <<") + self.log.info("Current chain: ... --> block_0 [%d] --> block_B [%d] --> block_C [%d]\n" % ( + block_count - 1, block_count, block_count+1 + )) + + # 7) Now create block_D which tries to spend same coin of tx_B again on the (new) main chain + # (this block will be rejected) + block_count += 1 + self.log.info("*** block_D ***") + self.log.info("Creating block_D [%d] trying to double spend the coin of tx_B" % (block_count + 1)) + block_D = self.new_block(block_count, block_C, checkpoint, tx_B2) + self.log.info("Hash of block_D: %s..." % block_D.hash[:5]) + self.log.info("sending block_D...") + var = self.node.submitblock(bytes_to_hex_str(block_D.serialize())) + self.log.info("result of block_D submission: %s" % str(var)) + time.sleep(2) + assert_equal(self.node.getblockcount(), block_count) + assert_equal(self.node.getbestblockhash(), block_C.hash) + # block_D is not added. Chain remains the same + self.log.info(" >> block_D rejected <<") + self.log.info("Current chain: ... --> block_0 [%d] --> block_B [%d] --> block_C [%d]\n" % ( + block_count - 2, block_count - 1, block_count + )) + + # 8) Now create block_E which spends tx_A again on main chain + # (this block will be accepted and connected since tx_A was spent on block_A now disconnected) + self.log.info("*** block_E ***") + self.log.info("Creating block_E [%d] trying spend tx_A on main chain" % (block_count + 1)) + block_E = self.new_block(block_count, block_C, checkpoint, tx_A) + self.log.info("Hash of block_E: %s..." % block_E.hash[:5]) + self.log.info("sending block_E...") + var = self.node.submitblock(bytes_to_hex_str(block_E.serialize())) + if var is not None: + self.log.info("result: %s" % str(var)) + raise Exception("block_E not accepted") + time.sleep(2) + assert_equal(self.node.getblockcount(), block_count+1) + assert_equal(self.node.getbestblockhash(), block_E.hash) + self.log.info(" >> block_E connected <<") + self.log.info("Current chain: ... --> block_0 [%d] --> block_B [%d] --> block_C [%d] --> block_E [%d]\n" % ( + block_count - 2, block_count - 1, block_count, block_count+1 + )) + + # 9) Now create block_F which tries to double spend the coin in tx_A + # # (this block will be rejected) + block_count += 1 + self.log.info("*** block_F ***") + self.log.info("Creating block_F [%d] trying to double spend the coin in tx_A" % (block_count + 1)) + block_F = self.new_block(block_count, block_E, checkpoint, tx_A2) + self.log.info("Hash of block_F: %s..." % block_F.hash[:5]) + self.log.info("sending block_F...") + var = self.node.submitblock(bytes_to_hex_str(block_F.serialize())) + self.log.info("result of block_F submission: %s" % str(var)) + time.sleep(2) + assert_equal(self.node.getblockcount(), block_count) + assert_equal(self.node.getbestblockhash(), block_E.hash) + self.log.info(" >> block_F rejected <<") + self.log.info("Current chain: ... --> block_0 [%d] --> block_B [%d] --> block_C [%d] --> block_E [%d]\n" % ( + block_count - 3, block_count - 2, block_count - 1, block_count + )) + self.log.info("All good.") + + + + def new_block(self, block_count, prev_block, checkpoint, zcspend = None): + if prev_block.hash is None: + prev_block.rehash() + staking_utxo_list = [self.unspent.pop()] + pastBlockHash = prev_block.hash + stakingPrevOuts = self.get_prevouts(staking_utxo_list, block_count) + block = self.create_spam_block(pastBlockHash, stakingPrevOuts, block_count + 1) + if zcspend is not None: + block.vtx.append(zcspend) + block.hashMerkleRoot = block.calc_merkle_root() + block.nAccumulatorCheckpoint = checkpoint + block.rehash() + block.sign_block(self.block_sig_key) + return block + +if __name__ == '__main__': + ZerocoinPublicSpendReorg().main() diff --git a/test/functional/zerocoin_valid_public_spend.py b/test/functional/zerocoin_valid_public_spend.py new file mode 100755 index 0000000000000..0a18308b1a8b5 --- /dev/null +++ b/test/functional/zerocoin_valid_public_spend.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019 The ion Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +''' +Covers the 'Wrapped Serials Attack' scenario +''' + +import random +from time import sleep + +from test_framework.authproxy import JSONRPCException +from test_framework.util import assert_equal, assert_greater_than + +from fake_stake.base_test import ION_FakeStakeTest + +class xIONValidCoinSpendTest(ION_FakeStakeTest): + + def run_test(self): + self.description = "Covers the 'valid publicCoinSpend spend' scenario." + self.init_test() + + INITAL_MINED_BLOCKS = 301 # Blocks mined before minting + MORE_MINED_BLOCKS = 52 # Blocks mined after minting (before spending) + DENOM_TO_USE = 1 # zc denomination used for double spending attack + + # 1) Start mining blocks + self.log.info("Mining %d first blocks..." % INITAL_MINED_BLOCKS) + self.node.generate(INITAL_MINED_BLOCKS) + sleep(2) + + # 2) Mint zerocoins + self.log.info("Minting %d-denom xIONs..." % DENOM_TO_USE) + self.node.mintzerocoin(DENOM_TO_USE) + self.node.generate(1) + sleep(2) + self.node.mintzerocoin(DENOM_TO_USE) + sleep(2) + + # 3) Mine more blocks and collect the mint + self.log.info("Mining %d more blocks..." % MORE_MINED_BLOCKS) + self.node.generate(MORE_MINED_BLOCKS) + sleep(2) + list = self.node.listmintedzerocoins(True, True) + mint = list[0] + + # 4) Get the raw zerocoin data + exported_zerocoins = self.node.exportzerocoins(False) + zc = [x for x in exported_zerocoins if mint["serial hash"] == x["id"]] + if len(zc) == 0: + raise AssertionError("mint not found") + + # 5) Spend the minted coin (mine six more blocks) + self.log.info("Spending the minted coin with serial %s and mining six more blocks..." % zc[0]["s"]) + txid = self.node.spendzerocoinmints([mint["serial hash"]])['txid'] + self.log.info("Spent on tx %s" % txid) + self.node.generate(6) + sleep(2) + + rawTx = self.node.getrawtransaction(txid, 1) + if rawTx is None: + self.log.warning("rawTx is: %s" % rawTx) + raise AssertionError("TEST FAILED") + else: + assert (rawTx["confirmations"] == 6) + + self.log.info("%s VALID PUBLIC COIN SPEND PASSED" % self.__class__.__name__) + + self.log.info("%s Trying to spend the serial twice now" % self.__class__.__name__) + + serial = zc[0]["s"] + randomness = zc[0]["r"] + privkey = zc[0]["k"] + + tx = None + try: + tx = self.node.spendrawzerocoin(serial, randomness, DENOM_TO_USE, privkey) + except JSONRPCException as e: + self.log.info("GOOD: Transaction did not verify") + + if tx is not None: + self.log.warning("Tx is: %s" % tx) + raise AssertionError("TEST FAILED") + + self.log.info("%s DOUBLE SPENT SERIAL NOT VERIFIED, TEST PASSED" % self.__class__.__name__) + + self.log.info("%s Trying to spend using the old coin spend method.." % self.__class__.__name__) + + tx = None + try: + tx = self.node.spendzerocoin(DENOM_TO_USE, False, False, "", False) + raise AssertionError("TEST FAILED, old coinSpend spent") + except JSONRPCException as e: + self.log.info("GOOD: spendzerocoin old spend did not verify") + + + self.log.info("%s OLD COIN SPEND NON USABLE ANYMORE, TEST PASSED" % self.__class__.__name__) + + +if __name__ == '__main__': + xIONValidCoinSpendTest().main() diff --git a/test/functional/zerocoin_wrapped_serials.py b/test/functional/zerocoin_wrapped_serials.py index ca17c84dccff2..58b4e96a6a8ae 100755 --- a/test/functional/zerocoin_wrapped_serials.py +++ b/test/functional/zerocoin_wrapped_serials.py @@ -91,7 +91,7 @@ def run_test(self): tx = self.node.spendrawzerocoin(serial, randomness, DENOM_TO_USE, privkey) except JSONRPCException as e: exc_msg = str(e) - if exc_msg == "The new spend coin transaction did not verify (-4)": + if exc_msg == "CoinSpend: failed check (-4)": self.log.info("GOOD: Transaction did not verify") else: raise e