diff --git a/.gitignore b/.gitignore index 0485ba8f6..308c2a7e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,47 @@ - \.DS_Store + +.vscode/ +autom4te.cache/ +build-aux/ +contrib/devtools/split-debug.sh +qa/pull-tester/run-bitcoind-for-test.sh +qa/pull-tester/tests-config.sh +share/qt/Info.plist +share/setup.nsi + +**/.deps/ +**/.dirstamp + +src/**/*.o +src/**/*.a +src/**/*.pb.cc +src/**/*.pb.h + +src/config/ +src/leveldb/build_config.mk + +src/qt/forms/*.h +src/qt/locale/*.qm + +src/qt/**/moc_*.cpp +src/qt/**/*.moc +src/qt/**/qrc_*.cpp + +src/test/data/*.h +src/test/buildenv.py + +aclocal.m4 +config.log +config.status +configure +libtool +Makefile +Makefile.in + +# Output binaries +src/bulwarkd +src/bulwark-cli +src/bulwark-tx +src/qt/bulwark-qt +src/qt/test/test_bulwark-qt +src/test/test_bulwark \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 05399a82f..738091f0b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,88 +1,152 @@ -sudo: required +language: cpp dist: trusty -group: deprecated-2017Q3 -os: -- linux -language: generic +sudo: false +branches: + only: + - master cache: - apt: true ccache: true directories: - depends/built - depends/sdk-sources - "$HOME/.ccache" +addons: + apt: + sources: + - ppa:bitcoin/bitcoin + packages: + - autoconf + - autotools-dev + - binutils + - bsdmainutils + - build-essential + - cmake + - curl + - libboost-all-dev + - libbz2-dev + - libcap-dev + - libdb4.8-dev + - libdb4.8++-dev + - libevent-dev + - libssl-dev + - libtool + - linux-libc-dev + - miniupnpc + - pkg-config + - python-dev + - python-setuptools + - python3 + - python3-zmq + - zlib1g-dev env: global: - - MAKEJOBS=-j5 - - RUN_TESTS=false - - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID - - CCACHE_SIZE=400M - - CCACHE_TEMPDIR=/tmp/.ccache-temp + - BULWARK_VERSION=2.0.0.0 - CCACHE_COMPRESS=1 - - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out - - SDK_URL=https://github.com/phracker/MacOSX-SDKs/releases/download/10.13/ - - PYTHON_DEBUG=1 - - WINEDEBUG=fixme-all - matrix: - - HOST=arm-linux-gnueabihf PPA="ppa:bitcoin/bitcoin" PACKAGES="g++-arm-linux-gnueabihf" - CHECK_DOC=1 GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" - - HOST=i686-pc-linux-gnu PPA="ppa:bitcoin/bitcoin" PACKAGES="g++-multilib bc python3-zmq" - RUN_TESTS=false GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat - --enable-reduce-exports LDFLAGS=-static-libstdc++" PYZMQ=true - - HOST=x86_64-unknown-linux-gnu PPA="ppa:bitcoin/bitcoin" PACKAGES="bc python3-zmq" - RUN_TESTS=false GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat - --enable-reduce-exports" CPPFLAGS="-DDEBUG_LOCKORDER -DENABLE_DASH_DEBUG" PYZMQ=true - - HOST=i686-w64-mingw32 DPKG_ADD_ARCH="i386" PPA="ppa:bitcoin/bitcoin" PACKAGES="python3 - nsis g++-mingw-w64-i686 wine1.7 bc" RUN_TESTS=false GOAL="install" BITCOIN_CONFIG="--enable-gui - --enable-reduce-exports" MAKEJOBS="-j4" WINE=true - - HOST=x86_64-w64-mingw32 DPKG_ADD_ARCH="i386" PPA="ppa:bitcoin/bitcoin" PACKAGES="python3 - nsis g++-mingw-w64-x86-64 wine1.7 bc" RUN_TESTS=false GOAL="install" BITCOIN_CONFIG="--enable-gui - --enable-reduce-exports" MAKEJOBS="-j4" WINE=true + - CCACHE_SIZE=500M + - CCACHE_TEMPDIR=/tmp/.ccache-temp + - MAKEJOBS="-s -j 2" +matrix: + include: + - name: Linux ARM 32 Bit + addons: + apt: + packages: + - g++-arm-linux-gnueabihf + - binutils-arm-linux-gnueabihf + env: + - BULWARK_CONFIG="--enable-glibc-back-compat --with-gui=no" + - HOST=arm-linux-gnueabihf + - LABEL=ARM + os: linux + - name: Linux i686 32 Bit + addons: + apt: + packages: + - bc + - g++-multilib + - libprotobuf-dev + - libqrencode-dev + - python3-zmq + - qtdeclarative5-dev + env: + - BULWARK_CONFIG="--enable-zmq --enable-glibc-back-compat LDFLAGS=-static-libstdc++ + --with-gui=qt5" + - HOST=i686-pc-linux-gnu + - LABEL=linux32 + - PYZMQ=true + os: linux + - name: Linux x86 64 Bit + addons: + apt: + packages: + - bc + - libprotobuf-dev + - libqrencode-dev + - python3-zmq + - qtdeclarative5-dev + env: + - BULWARK_CONFIG="--enable-zmq --enable-glibc-back-compat LDFLAGS=-static-libstdc++ + --with-gui=qt5" + - CPPFLAGS="-DDEBUG_LOCKORDER -DENABLE_DASH_DEBUG" + - HOST=x86_64-pc-linux-gnu + - LABEL=linux64 + - PYZMQ=true + os: linux + - name: Windows i686 32 Bit + addons: + apt: + packages: + - g++-mingw-w64-i686 bc + - libprotobuf-dev + - libqrencode-dev + - linux-libc-dev:i386 + - nsis + - python3 + - qtdeclarative5-dev + env: + - BULWARK_CONFIG="--with-gui=qt5" + - HOST=i686-w64-mingw32 + - LABEL=win32 + os: linux + - name: Windows x86 64 Bit + addons: + apt: + packages: + - bc + - g++-mingw-w64-x86-64 + - libprotobuf-dev + - libqrencode-dev + - linux-libc-dev:i386 + - nsis + - python3 + - qtdeclarative5-dev + env: + - BULWARK_CONFIG="--with-gui=qt5" + - HOST=x86_64-w64-mingw32 + - LABEL=win64 + os: linux + - name: macOS x86 64 Bit + env: + - HOST=x86_64-apple-darwin + - LABEL=macOS + os: osx + osx_image: xcode9.2 before_install: -- travis_retry sudo apt-get install python-dev -- travis_retry sudo add-apt-repository ppa:ubuntu-wine/ppa -y -- export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | - sed "s|::|:|g") +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi install: +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall mercurial python; brew + bundle; brew link --overwrite --force boost@1.57; fi - if [ "$PYZMQ" = "true" ]; then pip install pyzmq --user ; fi -- if [ -n "$PPA" ]; then travis_retry sudo add-apt-repository "$PPA" -y; fi -- if [ -n "$DPKG_ADD_ARCH" ]; then sudo dpkg --add-architecture "$DPKG_ADD_ARCH" ; - fi -- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi -- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends - --no-upgrade -qq $PACKAGES; fi before_script: -- unset CC; unset CXX -- unset DISPLAY -- mkdir -p depends/SDKs depends/sdk-sources -- if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.xz ]; then - curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.xz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.xz; - fi -- if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.xz ]; then - tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.xz; fi -- make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS +- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then unset CC CXX DISPLAY; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export LDFLAGS=-L/usr/local/opt/openssl/lib; + export CPPFLAGS=-I/usr/local/opt/openssl/include; fi +- GLOBAL_CONFIG="--enable-reduce-exports --enable-tests --prefix=$TRAVIS_BUILD_DIR/depends/$HOST" script: -- if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi -- OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST -- BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST - --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" -- depends/$HOST/native/bin/ccache --max-size=$CCACHE_SIZE -- test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh -- "./configure --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( - cat config.log && false)" -- make distdir PACKAGE=bulwark VERSION=$HOST -- cd bulwark-$HOST -- "./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || - ( cat config.log && false)" -- make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL - V=1 ; false ) -- export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib -- if [ "$RUN_TESTS" = "true" -a "$WINE" != "true" ]; then make $MAKEJOBS check VERBOSE=1; - fi -- if [ "$RUN_TESTS" = "true" -a "$WINE" = "true" ]; then wine src/test/test_bulwark.exe; - fi -- if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py --coverage; fi -after_script: - - if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then (echo "Upload goes here. Something like: scp -r $BASE_OUTDIR server" || echo "upload failed"); fi - - echo $TRAVIS_COMMIT_RANGE - - echo $TRAVIS_COMMIT_LOG +- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then make $MAKEJOBS -C depends HOST="$HOST"; + depends/$HOST/native/bin/ccache --max-size=$CCACHE_SIZE; sh ./autogen.sh; ./configure + --cache-file=config.cache $GLOBAL_CONFIG $BULWARK_CONFIG; make; fi +- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sh ./autogen.sh; ./configure --enable-reduce-exports; + make deploy; fi +before_deploy: +- true diff --git a/Brewfile b/Brewfile new file mode 100644 index 000000000..7d25af4ee --- /dev/null +++ b/Brewfile @@ -0,0 +1,14 @@ +brew "autoconf" +brew "automake" +brew "berkeley-db@4" +brew "boost@1.57" +brew "git" +brew "libevent" +brew "libtool" +brew "miniupnpc" +brew "openssl" +brew "pkg-config" +brew "protobuf" +brew "qt" +brew "zeromq" +brew "librsvg" \ No newline at end of file diff --git a/README.md b/README.md index 4f3256465..24d22ced7 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Bulwark offers both SwiftTX and Obfuscation to enable speedy transactions with a | Circulation (5 Years) | 27,668,220 BWK | | PoW Period | nHeight ≤ 182,700 | | PoS Period | nHeight ≥ 182,701 | -| Protocol Support | IPV4, IPV6, TOR | +| Protocol Support | IPV4, IPV6, TOR, I2P | | PoS | SeeSaw & Split Rewards | ## PoW Block Reward diff --git a/configure.ac b/configure.ac index 9608bb45b..485e44368 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) -define(_CLIENT_VERSION_MAJOR, 1) -define(_CLIENT_VERSION_MINOR, 3) -define(_CLIENT_VERSION_REVISION, 1) +define(_CLIENT_VERSION_MAJOR, 2) +define(_CLIENT_VERSION_MINOR, 0) +define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2018) @@ -64,6 +64,7 @@ if test "x${OBJCXX+set}" = "x"; then fi AC_PROG_OBJCXX ]) + dnl Libtool init checks. LT_INIT([pic-only]) @@ -169,6 +170,13 @@ AC_ARG_ENABLE([zmq], [use_zmq=$enableval], [use_zmq=yes]) +AC_ARG_WITH([system-univalue], + [AS_HELP_STRING([--with-system-univalue], + [Build with system UniValue (default is no)])], + [system_univalue=$withval], + [system_univalue=no] +) + AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], []) # Enable debug @@ -477,6 +485,11 @@ if test x$use_hardening != xno; then CPPFLAGS="$CPPFLAGS $HARDENED_CPPFLAGS" LDFLAGS="$LDFLAGS $HARDENED_LDFLAGS" OBJCXXFLAGS="$CXXFLAGS" +else + CXXFLAGS="$CXXFLAGS -no-pie" + CPPFLAGS="$CPPFLAGS -no-pie" + LDFLAGS="$LDFLAGS -no-pie" + OBJCXXFLAGS="$CXXFLAGS" fi dnl this flag screws up non-darwin gcc even when the check fails. special-case it. @@ -809,6 +822,44 @@ AC_CHECK_LIB([crypto],[RAND_egd],[],[ ) ]) +dnl univalue check + +if test x$system_univalue != xno ; then + found_univalue=no + if test x$use_pkgconfig = xyes; then + : #NOP + m4_ifdef( + [PKG_CHECK_MODULES], + [ + PKG_CHECK_MODULES([UNIVALUE],[libunivalue],[found_univalue=yes],[true]) + ] + ) + else + AC_CHECK_HEADER([univalue.h],[ + AC_CHECK_LIB([univalue], [main],[ + UNIVALUE_LIBS=-lunivalue + found_univalue=yes + ],[true]) + ],[true]) + fi + + if test x$found_univalue = xyes ; then + system_univalue=yes + elif test x$system_univalue = xyes ; then + AC_MSG_ERROR([univalue not found]) + else + system_univalue=no + fi +fi + +if test x$system_univalue = xno ; then + UNIVALUE_CFLAGS='-I$(srcdir)/univalue/include' + UNIVALUE_LIBS='univalue/libunivalue.la' +fi +AM_CONDITIONAL([EMBEDDED_UNIVALUE],[test x$system_univalue = xno]) +AC_SUBST(UNIVALUE_CFLAGS) +AC_SUBST(UNIVALUE_LIBS) + CFLAGS_TEMP="$CFLAGS" LIBS_TEMP="$LIBS" CFLAGS="$CFLAGS $SSL_CFLAGS $CRYPTO_CFLAGS" @@ -974,16 +1025,16 @@ AC_DEFINE(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION, [Build revision]) AC_DEFINE(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD, [Version Build]) AC_DEFINE(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE, [Version is release]) AC_DEFINE(COPYRIGHT_YEAR, _COPYRIGHT_YEAR, [Version is release]) -AC_SUBST(BITCOIN_DAEMON_NAME) -AC_SUBST(BITCOIN_GUI_NAME) -AC_SUBST(BITCOIN_CLI_NAME) -AC_SUBST(BITCOIN_TX_NAME) AC_SUBST(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR) AC_SUBST(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR) AC_SUBST(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION) AC_SUBST(CLIENT_VERSION_BUILD, _CLIENT_VERSION_BUILD) AC_SUBST(CLIENT_VERSION_IS_RELEASE, _CLIENT_VERSION_IS_RELEASE) AC_SUBST(COPYRIGHT_YEAR, _COPYRIGHT_YEAR) +AC_SUBST(BITCOIN_DAEMON_NAME) +AC_SUBST(BITCOIN_GUI_NAME) +AC_SUBST(BITCOIN_CLI_NAME) +AC_SUBST(BITCOIN_TX_NAME) AC_SUBST(RELDFLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) @@ -1033,6 +1084,10 @@ PKGCONFIG_LIBDIR_TEMP="$PKG_CONFIG_LIBDIR" unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" +if test x$system_univalue = xno; then + AC_CONFIG_SUBDIRS([src/univalue]) +fi + ac_configure_args="${ac_configure_args} --disable-shared --with-pic" AC_CONFIG_SUBDIRS([src/secp256k1]) @@ -1049,7 +1104,6 @@ case $host in ;; esac - echo echo "Options used to compile and link:" echo " with wallet = $enable_wallet" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 0b1ef1b7a..0b7a26cf4 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -147,12 +147,12 @@ script: | make install DESTDIR=${INSTALLPATH} cp -f bulwark-*setup*.exe $OUTDIR/ cd installed - mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/ - find . -name "lib*.la" -delete - find . -name "lib*.a" -delete + # mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/ # temporarily disabled for Zerocoin + # find . -name "lib*.la" -delete # temporarily disabled for Zerocoin + # find . -name "lib*.a" -delete # temporarily disabled for Zerocoin rm -rf ${DISTNAME}/lib/pkgconfig find ${DISTNAME}/bin -type f -executable -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; - find ${DISTNAME}/lib -type f -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; + # find ${DISTNAME}/lib -type f -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \; find ${DISTNAME} -not -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}.zip find ${DISTNAME} -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}-debug.zip cd ../../ diff --git a/contrib/linearize/README.md b/contrib/linearize/README.md index 53d732201..cb9cae954 100644 --- a/contrib/linearize/README.md +++ b/contrib/linearize/README.md @@ -1,57 +1,49 @@ # Linearize -Construct a linear, no-fork, best version of the Bitcoin blockchain. The scripts +Construct a linear, no-fork, best version of the Bulwark blockchain. The scripts run using Python 3 but are compatible with Python 2. -REQUIRED: [nist5_hash](https://github.com/bulwark-crypto/nist5_hash) +## Prerequisites -## Step 1: Download hash list +[nist5_hash](https://github.com/bulwark-crypto/nist5_hash) must be installed. - $ ./linearize-hashes.py linearize.cfg > hashlist.txt +## Configuration -Required configuration file settings for linearize-hashes: -* RPC: `datadir` (Required if `rpcuser` and `rpcpassword` are not specified) -* RPC: `rpcuser`, `rpcpassword` (Required if `datadir` is not specified) +Copy example-linearize.cfg to linearize.cfg and edit. -Optional config file setting for linearize-hashes: -* RPC: `host` (Default: `127.0.0.1`) -* RPC: `port` (Default: `8332`) -* Blockchain: `min_height`, `max_height` -* `rev_hash_bytes`: If true, the written block hash list will be -byte-reversed. (In other words, the hash returned by getblockhash will have its -bytes reversed.) False by default. Intended for generation of -standalone hash lists but safe to use with linearize-data.py, which will output -the same data no matter which byte format is chosen. +### Required configuration file settings +* `datadir` (Required if `rpcuser` and `rpcpassword` are not specified) +* `rpcuser`, `rpcpassword` (Required if `datadir` is not specified) +* `output_file`: The file that will contain the final blockchain. -The `linearize-hashes` script requires a connection, local or remote, to a -JSON-RPC server. Running `bitcoind` or `bitcoin-qt -server` will be sufficient. +### Optional config file settings +* `host` (Default: `127.0.0.1`) +* `port` (Default: `8332`) +* `min_height`, `max_height`: Height of the blockchain to be considered. +* `rev_hash_bytes`: If true, the written block hash list will be byte-reversed. (In other words, the hash returned by getblockhash will have its bytes reversed.) False by default. Intended for generation of standalone hash lists but safe to use with linearize-data.py, which will output the same data no matter which byte format is chosen. +* `debug_output`: Some printouts may not always be desired. If true, such output will be printed. +* `file_timestamp`: Set each file's last-accessed and last-modified times, respectively, to the current time and to the timestamp of the most recent block written to the script's blockchain. +* `genesis`: The hash of the genesis block in the blockchain. +* `input`: bulwarkd blocks/ directory containing blkNNNNN.dat +* `hashlist`: text file containing list of block hashes created by linearize-hashes.py. +* `max_out_sz`: Maximum size for files created by the `output_file` option. (Default: `1000*1000*1000 bytes`) +* `netmagic`: Network magic number. +* `out_of_order_cache_sz`: If out-of-order blocks are being read, the block can be written to a cache so that the blockchain doesn't have to be sought again. This option specifies the cache size. (Default: `100*1000*1000 bytes`) +* `rev_hash_bytes`: If true, the block hash list written by linearize-hashes.py will be byte-reversed when read by linearize-data.py. +* `split_timestamp`: Split blockchain files when a new month is first seen, in addition to reaching a maximum +file size (`max_out_sz`). -## Step 2: Copy local block data +## Usage - $ ./linearize-data.py linearize.cfg +The script requires a connection, local or remote, to a JSON-RPC server. Running `bulwarkd` or `bulwark-qt -server` will be sufficient. -Required configuration file settings: -* `output_file`: The file that will contain the final blockchain. - or -* `output`: Output directory for linearized `blocks/blkNNNNN.dat` output. - -Optional config file setting for linearize-data: -* `debug_output`: Some printouts may not always be desired. If true, such output -will be printed. -* `file_timestamp`: Set each file's last-accessed and last-modified times, -respectively, to the current time and to the timestamp of the most recent block -written to the script's blockchain. -* `genesis`: The hash of the genesis block in the blockchain. -* `input`: bitcoind blocks/ directory containing blkNNNNN.dat -* `hashlist`: text file containing list of block hashes created by -linearize-hashes.py. -* `max_out_sz`: Maximum size for files created by the `output_file` option. -(Default: `1000*1000*1000 bytes`) -* `netmagic`: Network magic number. -* `out_of_order_cache_sz`: If out-of-order blocks are being read, the block can -be written to a cache so that the blockchain doesn't have to be sought again. -This option specifies the cache size. (Default: `100*1000*1000 bytes`) -* `rev_hash_bytes`: If true, the block hash list written by linearize-hashes.py -will be byte-reversed when read by linearize-data.py. See the linearize-hashes -entry for more information. -* `split_timestamp`: Split blockchain files when a new month is first seen, in -addition to reaching a maximum file size (`max_out_sz`). +To create the bootstrap.dat, run + +``` bash +buildbootstrap.sh BLOCKHEIGHT +``` + +where _BLOCKHEIGHT_ is the newest block you want to add to the bootstrap. Example: + +``` bash +buildbootstrap.sh 200000 +``` diff --git a/contrib/linearize/buildbootstrap.sh b/contrib/linearize/buildbootstrap.sh new file mode 100755 index 000000000..6d2e3703b --- /dev/null +++ b/contrib/linearize/buildbootstrap.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +if [[ -z $1 ]]; then + echo "Usage: $0 BLOCKHEIGHT" + exit +fi + +if [ "$1" -eq "$1" ] 2>/dev/null; then + sed -i -e "s/^max_height=.*$/max_height=$1/g" linearize.cfg + ./linearize-hashes.py linearize.cfg > hashlist.txt + ./linearize-data.py linearize.cfg + rm hashlist.txt +else + echo "BLOCKHEIGHT must be an integer" + exit +fi diff --git a/contrib/linearize/example-linearize.cfg b/contrib/linearize/example-linearize.cfg index 695fc8b06..ab3bf85fa 100644 --- a/contrib/linearize/example-linearize.cfg +++ b/contrib/linearize/example-linearize.cfg @@ -1,6 +1,6 @@ # bitcoind RPC settings (linearize-hashes) -rpcuser=someuser -rpcpassword=somepassword +rpcuser=RPCUSERNAME +rpcpassword=RPCPASSWORD #datadir=~/.bulwark host=127.0.0.1 @@ -11,19 +11,19 @@ port=52541 #port=42132 # bootstrap.dat hashlist settings (linearize-hashes) -max_height=313000 +max_height=1000 # bootstrap.dat input/output settings (linearize-data) # mainnet netmagic=08020117 genesis=00000908a5fd7c4c863c9a0281def7b5b9c137b782d66a75753c3954d369eb5c -input=/home/example/.bulwark/blocks +input=/home/bulwark/.bulwark/blocks # "output" option causes blockchain files to be written to the given location, # with "output_file" ignored. If not used, "output_file" is used instead. # output=/home/example/blockchain_directory -output_file=/home/example/Downloads/bootstrap.dat +output_file=/home/bulwark/bootstrap.dat hashlist=hashlist.txt # Maximum size in bytes of out-of-order blocks cache in memory diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py index 9f2129c14..8dd757098 100644 --- a/contrib/seeds/makeseeds.py +++ b/contrib/seeds/makeseeds.py @@ -26,7 +26,7 @@ PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$") PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$") PATTERN_ONION = re.compile(r"^([abcdefghijklmnopqrstuvwxyz234567]{16}\.onion):(\d+)$") -PATTERN_AGENT = re.compile(r"^(/BulwarkCore:1.3.(0|1|99)/)$") +PATTERN_AGENT = re.compile(r"^(/BulwarkCore:2.0.0/)$") def parseline(line): sline = line.split() diff --git a/doc/build-osx.md b/doc/build-osx.md index 7c0ebbcf4..07c2d9cd7 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -38,7 +38,7 @@ Instructions: Homebrew #### Install dependencies using Homebrew - brew install autoconf automake berkeley-db4 libtool boost miniupnpc openssl pkg-config protobuf qt5 + brew install autoconf automake berkeley-db4 libtool boost miniupnpc openssl pkg-config protobuf qt5 libzmq ### Building `bulwarkd` diff --git a/doc/build-unix.md b/doc/build-unix.md index e60e9606c..d4f635a25 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -43,6 +43,7 @@ Optional dependencies: qt | GUI | GUI toolkit (only needed when GUI enabled) protobuf | Payments in GUI | Data interchange format used for payment protocol (only needed when GUI enabled) libqrencode | QR codes in GUI | Optional for generating QR codes (only needed when GUI enabled) + univalue | Utility | JSON parsing and encoding (bundled version will be used unless --with-system-univalue passed to configure) For the versions used in the release, see [release-process.md](release-process.md) under *Fetch and build inputs*. diff --git a/doc/pivx-doc/developer-notes.md b/doc/pivx-doc/developer-notes.md index 07dc0de53..2d34ead31 100644 --- a/doc/pivx-doc/developer-notes.md +++ b/doc/pivx-doc/developer-notes.md @@ -118,7 +118,7 @@ to see it. **testnet mode** -Run with the -testnet option to run with "play PIVs (tPIV)" on the test network, if you +Run with the -testnet option to run with "play BWK (tBWK" on the test network, if you are testing multi-machine code that needs to operate across the internet. **DEBUG_LOCKORDER** diff --git a/doc/pivx-doc/translation_process.md b/doc/pivx-doc/translation_process.md index 2840626ec..97410e626 100644 --- a/doc/pivx-doc/translation_process.md +++ b/doc/pivx-doc/translation_process.md @@ -106,6 +106,6 @@ To create a new language template, you will need to edit the languages manifest **Note:** that the language translation file **must end in `.qm`** (the compiled extension), and not `.ts`. ### Questions and general assistance -The PIVX Core translation maintainers include *Fuzzbawls and s3v3nh4cks*. You can find them, and others, in the [PIVX Slack](https://pivx.slack.com). +The PIVX Core translation maintainers include *Fuzzbawls and s3v3nh4cks*. You can find them, and others, in the [PIVX Discord](https://discord.pivx.org). Announcements will be posted during application pre-releases to notify translators to check for updates. diff --git a/doc/release-notes/release-notes-2.3.0.md b/doc/release-notes/release-notes-2.3.0.md new file mode 100644 index 000000000..f1779acb0 --- /dev/null +++ b/doc/release-notes/release-notes-2.3.0.md @@ -0,0 +1,198 @@ +PIVX Core version 2.3.0 is now available from: + + + +This is a new major version release, including various bug fixes and +performance improvements, as well as updated translations. + +Please report bugs using the issue tracker at github: + + + +Mandatory Update +============== + +PIVX Core v2.3.0 is a mandatory update for all users. This release contains validation and security improvements that are not backwards compatible with older versions. Users will have a grace period of no less than two weeks to update their clients before enforcement of this update is enabled. + +How to Upgrade +-------------- + +If you are running an older version, shut it down. Wait until it has completely shut down (which might take a few minutes for older versions), then run the installer (on Windows) or just copy over /Applications/PIVX-Qt (on Mac) or pivxd/pivx-qt (on Linux). + + +Compatibility +============== + +PIVX Core is extensively tested on multiple operating systems using the Linux kernel, macOS 10.8+, and Windows Vista and later. + +Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support), No attempt is made to prevent installing or running the software on Windows XP, you can still do so at your own risk but be aware that there are known instabilities and issues. Please do not report issues about Windows XP to the issue tracker. + +PIVX Core should also work on most other Unix-like systems but is not frequently tested on them. + +Notable Changes +=============== + +RPC changes +-------------- + +#### masternode command +The `masternode` RPC command has been re-worked to ease it's usage and return valid JSON in it's results. The following is an overview of the changed command parameters: + +| Command Parameter | Changes | +| --- | --- | +| `budget` | Removed (did nothing) | +| `count` | The optional "mode" paramater has been removed. Command now always outputs full details in JSON format. | +| `current` | Result fields changed: IP:Port removed, vin renamed to txhash | +| `list-conf` | Result is now an array of objects, instead of an object of objects | +| `outputs` | Result is now an array of objects instead of a list of *n* objects | +| `status` | Added additional fields for txhash, outputidx, netaddr, and message | +| `winners` | Result is now an array of objects instead of a list of *n* objects. See below | +| `list` | Remove all optional "modes" and standardized the results. Note: `masternode list` is the same as `masternodelist`. See below | + +For the `winners` parameter, the results are now in a standard JSON format as follows: + +``` +[ + { + nHeight: n, (int) block height + winner: { + address: addr, (string) PIVX MN Address, + nVotes: n, (int) Number of votes for winner, + } + }, + ... +] +``` + +In the case of multiple winners being associated with a single block, the results are in the following format (the `winner` object becomes an array of objects): + +``` +[ + { + nHeight: n, (int) block height, + winner: [ + { + address: addr, (string) PIVX MN Address, + nVotes: n, (int) Number of votes for winner, + }, + ... + ] + }, + ... +] +``` + +For the `list` (aka `masternodelist`) parameter, the various "modes" have been removed in favor of a unified and standardized result format. The result is now an array of objects instead of an object of objects. Further, the individual objects now have a standard JSON format. The result format is as follows: + +``` +[ + { + "rank": n, (numeric) Masternode rank (or 0 if not enabled) + "txhash": hash, (string) Collateral transaction hash + "outidx": n, (numeric) Collateral transaction output index + "status": s, (string) Status (ENABLED/EXPIRED/REMOVE/etc) + "addr": addr, (string) Masternode PIVX address + "version": v, (numeric) Masternode Protocol version + "lastseen": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) the masternode was last seen + "activetime": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) masternode has been active + "lastpaid": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) masternode was last paid + }, + ... +] +``` + +#### mnbudget command + +An additional parameter has been added to `mnbudget` to allow a controller wallet to issue per-MN votes. The new parameter is `vote-alias` and it's use format is as follows: + +`mnbudget vote-alias ` + +All fields are required to successfully vote. + +#### walletpassphrase command + +CLI users that are staking their coins will now have the option of unlocking the wallet with no re-lock timeout. Similar to using `9999999` as the timeout, the `walletpassphrase` command now accepts `0` as a timeout to indicate that no re-locking should occur based on elapsed time. + +Usage: `walletpassphrase 0 ` + +The third parameter indicates if the wallet should be unlocked for staking and anonymization only (true), or to allow send operations (false, full unlock). + +ZeroMQ (ZMQ) Notifications +-------------- + +pivxd can now (optionally) asynchronously notify clients through a ZMQ-based PUB socket of the arrival of new transactions and blocks. This feature requires installation of the ZMQ C API library 4.x and configuring its use through the command line or configuration file. Please see [docs/zmq.md](/doc/zmq.md) for details of operation. + +**All** Masternodes List GUI Removal +-------------- + +With the standardization and reformatting of the `masternode list` (`masternodelist`) RPC command, there is no real use case to keep the full list of masternodes in the GUI. This GUI element causes a great deal of extra overhead, even when it is not being actively displayed. The removal of this list has also proven to resolve a number of linux-based errors + +Note that the GUI list of masternodes associated with a controller wallet remains intact. + +SPV Client Support +-------------- + +PIVX Core now enables bloom filters by default to support SPV clients like mobile wallets. This feature can be disabled by using the `-peerbloomfilters` option on startup. + +2.3.0 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### RPC and other APIs +- #179 `a64fa3d` [RPC] Allow infinite unlock (Mrs-X) +- #183 `dc77b86` [RPC] Add proposal name to removal log (Mrs-X) +- #189 `6dd8146` [RPC] Add missing 'vote-alias' implementation (Mrs-X) +- #195 `aee05fe` [ZMQ] ZMQ integration for PIVX (Mrs-X) +- #211 `b8c110b` [RPC] Refactor & JSONify results from masternode command(s) (Fuzzbawls) +- #201 `f0e87b1` [RPC] Add active/incative flag to getstakingstatus RPC call (Mrs-X) + +### Configuration and command-line options +- #180 `16b8601` [Wallet] Add parameter interaction between -disablewallet and -staking (Aaron Miller) +- #208 `5f494c4` [Qt] Fix segfault when running with `-help` (Fuzzbawls) +- #193 `ac7590b` [Output] Reformat help messages (Fuzzbawls) +- #230 `aa47fa4` [Output] Update default value for -peerbloomfilters in help (Fuzzbawls) + +### Wallet +- #192 `283cf3b` [Trivial] Pre-release warning message fixed. (Mrs-X) +- #169 `05c9a75` Add IsNull and SetNull interfaces to uint256 (Jon Spock) +- #198 `d45c869` Update EXT_COIN_TYPE according to BIP44 (Jon Spock) + +### P2P Protocol and Network Code +- #219 `d2c3fdf` [P2P] Enable Bloom filter and add new nService for light clients. (furszy) +- #234 `ed99e7b` [Consensus/Net] Ignore newly activated MNs in ranking/seesaw (Mrs-X Fuzzbawls presstab) + +### GUI +- #200 `bb1f255` [UI] Improved unlock usability (Mrs-X) +- #207 `7a41f46` [Qt] Adjust size of splash screen image. (Fuzzbawls) +- #206 `9c675ee` [Qt] Remove the All Masternodes UI tab/list (Fuzzbawls) +- #220 `b80bc29` [Qt] Add "NODE_BLOOM" and "NODE_BLOOM_WITHOUT_MN" to guiutil (Fuzzbawls) +- #225 `02209ec` [Qt] Add autocomplete to Qt client's debug console (Fuzzbawls) +- #233 `2921a4d` [Qt] Enable support for Qt's HighDpiScaling (Fuzzbawls) + +### Tests and QA +- #191 `3a778c3` [Tests] Fix the unit test suite for use with PIVX (Fuzzbawls) +- #122 `7d135a1` [Utils] updated netmagic/port for linearize script (Satoshi Ninja) + +### Miscellaneous +- #231 `af0aa68` [Utils] Fix update-translations.py to allow % end of string (Fuzzbawls) +- #175 `8727f1c` [Docs] Reformat main README.md (Fuzzbawls) +- #213 `ddd8994` [Trivial] Reduce debug.log spam for masternode messages (Fuzzbawls) + +Credits +======= + +Thanks to everyone who directly contributed to this release: +- Aaron Miller +- Fuzzbawls +- Mrs-X +- PIVX +- Satoshi Ninja +- Jon Spock +- furszy +- presstab + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/pivx-project-translations/). diff --git a/doc/release-notes/release-notes-2.3.1.md b/doc/release-notes/release-notes-2.3.1.md new file mode 100644 index 000000000..374c22890 --- /dev/null +++ b/doc/release-notes/release-notes-2.3.1.md @@ -0,0 +1,213 @@ +PIVX Core version 2.3.1 is now available from: + + + +This is a new minor version release, including various bug fixes and +performance improvements, as well as updated translations. + +Please report bugs using the issue tracker at github: + + + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely shut down (which might take a few minutes for older versions), then run the installer (on Windows) or just copy over /Applications/PIVX-Qt (on Mac) or pivxd/pivx-qt (on Linux). + +Compatibility +============== + +PIVX Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. + +Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support), +No attempt is made to prevent installing or running the software on Windows XP, you +can still do so at your own risk but be aware that there are known instabilities and issues. +Please do not report issues about Windows XP to the issue tracker. + +PIVX Core should also work on most other Unix-like systems but is not +frequently tested on them. + +Notable Changes +=============== + +RPC changes +-------------- + +#### Update of RPC commands to comply with the forthcoming RPC Standards PIP #### + +| Old Command | New Command | Notes | +| --- | --- | --- | +| `masternode count` | `getmasternodecount` | | +| `masternode list` | `listmasternodes` | | +| `masternodelist` | `listmasternodes` | renamed | +| `masternode connect` | `masternodeconnect` | | +| `masternode current` | `getcurrentmasternode` | | +| `masternode debug` | `masternodedebug` | | +| `masternode enforce` | | removed | +| `masternode outputs` | `getmasternodeoutputs` | | +| `masternode status` | `getmasternodestatus` | | +| `masternode list-conf` | `listmasternodeconf` | added optional filter | +| `masternode genkey` | `createmasternodekey` | | +| `masternode winners` | `listmasternodewinners` | | +| `masternode start` | `startmasternode` | see notes below | +| `masternode start-alias` | `startmasternode` | see notes below | +| `masternode start-` | `startmasternode` | see notes below | +| `masternode create` | | removed - not implemented | +| `masternode calcscore` | `listmasternodescores` | | +| --- | --- | --- | +| `mnbudget prepare` | `preparebudget` | see notes below | +| `mnbudget submit` | `submitbudget` | see notes below | +| `mnbudget vote-many` | `mnbudgetvote` | see notes below | +| `mnbudget vote-alias` | `mnbudgetvote` | see notes below | +| `mnbudget vote` | `mnbudgetvote` | see notes below | +| `mnbudget getvotes` | `getbudgetvotes` | | +| `mnbudget getinfo` | `getbudgetinfo` | see notes below | +| `mnbudget show` | `getbudgetinfo` | see notes below | +| `mnbudget projection` | `getbudgetprojection` | | +| `mnbudget check` | `checkbudgets` | | +| `mnbudget nextblock` | `getnextsuperblock` | | + +##### `startmasternode` Command ##### +This command now handles all cases for starting a masternode instead of having multiple commands based on the context. Command arguments have changed slightly to allow the user to decide wither or not to re-lock the wallet after the command is run. Below is the help documentation: + +``` +startmasternode "local|all|many|missing|disabled|alias" lockwallet ( "alias" ) + + Attempts to start one or more masternode(s) + +Arguments: +1. set (string, required) Specify which set of masternode(s) to start. +2. lockWallet (boolean, required) Lock wallet after completion. +3. alias (string) Masternode alias. Required if using 'alias' as the set. + +Result: (for 'local' set): +"status" (string) Masternode status message + +Result: (for other sets): +{ + "overall": "xxxx", (string) Overall status message + "detail": [ + { + "node": "xxxx", (string) Node name or alias + "result": "xxxx", (string) 'success' or 'failed' + "error": "xxxx" (string) Error message, if failed + } + ,... + ] +} + +Examples: +> pivx-cli startmasternode "alias" true "my_mn" +> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "startmasternode", "params": ["alias" true "my_mn"] }' -H 'content-type: text/plain;' http://127.0.0.1:51473/ +``` + +##### `preparebudget` & `submitbudget` Commands ##### +Due to the requirement of maintaining backwards compatibility with the legacy command, these two new commands are created to handle the preparation/submission of budget proposals. Future intention is to roll these two commands back into a single command to reduce code-duplication. Paramater arguments currently remain unchanged from the legacy command equivilent. + +##### `mnbudgetvote` Command ##### +This command now handles all cases for submitting MN votes on a budget proposal. Backwards compatibility with the legacy command(s) has been retained, with the exception of the `vote-alias` case due to a conflict in paramater type casting. A user running `mnbudget vote-alias` will be instructed to instead use the new `mnvote` command. Below is the full help documentation for this new command: + +``` +mnbudgetvote "local|many|alias" "votehash" "yes|no" ( "alias" ) + +Vote on a budget proposal + +Arguments: +1. "mode" (string, required) The voting mode. 'local' for voting directly from a masternode, 'many' for voting with a MN controller and casting the same vote for each MN, 'alias' for voting with a MN controller and casting a vote for a single MN +2. "votehash" (string, required) The vote hash for the proposal +3. "votecast" (string, required) Your vote. 'yes' to vote for the proposal, 'no' to vote against +4. "alias" (string, required for 'alias' mode) The MN alias to cast a vote for. + +Result: +{ + "overall": "xxxx", (string) The overall status message for the vote cast + "detail": [ + { + "node": "xxxx", (string) 'local' or the MN alias + "result": "xxxx", (string) Either 'Success' or 'Failed' + "error": "xxxx", (string) Error message, if vote failed + } + ,... + ] +} + +Examples: +> pivx-cli mnbudgetvote "local" "ed2f83cedee59a91406f5f47ec4d60bf5a7f9ee6293913c82976bd2d3a658041" "yes" +> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "mnbudgetvote", "params": ["local" "ed2f83cedee59a91406f5f47ec4d60bf5a7f9ee6293913c82976bd2d3a658041" "yes"] }' -H 'content-type: text/plain;' http://127.0.0.1:51473/ +``` + +##### `getbudgetinfo` Command ##### +This command now combines the old `mnbudget show` and `mnbudget getinfo` commands to reduce code duplication while still maintaining backwards compatibility with the legacy commands. Given no parameters, it returns the full list of budget proposals (`mnbudget show`). A single optional parameter allows to return information on just that proposal (`mnbudget getinfo`). Below is the full help documentation: + +``` +getbudgetinfo ( "proposal" ) + +Show current masternode budgets + +Arguments: +1. "proposal" (string, optional) Proposal name + +Result: +[ + { + "Name": "xxxx", (string) Proposal Name + "URL": "xxxx", (string) Proposal URL + "Hash": "xxxx", (string) Proposal vote hash + "FeeHash": "xxxx", (string) Proposal fee hash + "BlockStart": n, (numeric) Proposal starting block + "BlockEnd": n, (numeric) Proposal ending block + "TotalPaymentCount": n, (numeric) Number of payments + "RemainingPaymentCount": n, (numeric) Number of remaining payments + "PaymentAddress": "xxxx", (string) PIVX address of payment + "Ratio": x.xxx, (numeric) Ratio of yeas vs nays + "Yeas": n, (numeric) Number of yea votes + "Nays": n, (numeric) Number of nay votes + "Abstains": n, (numeric) Number of abstains + "TotalPayment": xxx.xxx, (numeric) Total payment amount + "MonthlyPayment": xxx.xxx, (numeric) Monthly payment amount + "IsEstablished": true|false, (boolean) Established (true) or (false) + "IsValid": true|false, (boolean) Valid (true) or Invalid (false) + "IsValidReason": "xxxx", (string) Error message, if any + "fValid": true|false, (boolean) Valid (true) or Invalid (false) + } + ,... +] + +Examples: +> pivx-cli getbudgetinfo +> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getbudgetinfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:51473/ +``` + +#### Masternode network protocol layer reporting #### +The results from the `listmasternodes` and `getmasternodecount` commands now includes details about which network protocol layer is being used (IPv4, IPV6, or Tor). + + +2.3.1 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### RPC and other APIs +- #239 `e8b92f4` [RPC] Make 'masternode status' more verbose (Mrs-X) +- #244 `eac60dd` [RPC] Standardize RPC Commands (Fuzzbawls) + +### P2P Protocol and Network Code +- #248 `0d44ca2` [core] fix payment disagreements, reduce log-verbosity (Mrs-X) + +### Miscellaneous +- #240 `1957445` [Debug Log] Increase verbosity of error-message (Mrs-X) +- #241 #249 `b60118b` `7405e31` Nullpointer reference fixed (Mrs-X) + +Credits +======= + +Thanks to everyone who directly contributed to this release: +- Fuzzbawls +- Mrs-X +- amirabrams + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/pivx-project-translations/). diff --git a/doc/release-notes/release-notes-3.0.0.md b/doc/release-notes/release-notes-3.0.0.md new file mode 100644 index 000000000..a45159f29 --- /dev/null +++ b/doc/release-notes/release-notes-3.0.0.md @@ -0,0 +1,135 @@ +PIVX Core version 3.0.0 is now available from: + + + +This is a new major version release, including various bug fixes and +performance improvements, as well as updated translations. + +Please report bugs using the issue tracker at github: + + + +Mandatory Update +============== + +PIVX Core v3.0.0 is a mandatory update for all users. This release contains new consensus rules and improvements that are not backwards compatible with older versions. Users will have a grace period of one week to update their clients before enforcement of this update is enabled. + +Users updating from a previous version after the 13th of October will require a full resync of their local blockchain from either the P2P network or by way of the bootstrap. + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely shut down (which might take a few minutes for older versions), then run the installer (on Windows) or just copy over /Applications/PIVX-Qt (on Mac) or pivxd/pivx-qt (on Linux). + +Compatibility +============== + +PIVX Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. + +Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support), +No attempt is made to prevent installing or running the software on Windows XP, you +can still do so at your own risk but be aware that there are known instabilities and issues. +Please do not report issues about Windows XP to the issue tracker. + +PIVX Core should also work on most other Unix-like systems but is not +frequently tested on them. + +### :exclamation::exclamation::exclamation: MacOS 10.13 High Sierra :exclamation::exclamation::exclamation: + +**Currently there are issues with the 3.0.0 gitian release on MacOS version 10.13 (High Sierra), no reports of issues on older versions of MacOS.** + + +Notable Changes +=============== + +Zerocoin (zBWK Protocol +--------------------- + +At long last, the zBWKrelease is here and the zerocoin protocol has been fully implemented! This allows users to send transactions with 100% fungible coins and absolutely zero history or link-ability to their previous owners. + +The Zerocoin protocol allows user to convert (mint) their *BWK to zerocoins, which we call *zBWK. When zBWKare converted back to BWKthere is no trail associated with the coins being sent, such as who originally minted those coins. Essentially the only thing the receiver of the zBWKtransaction will see is that it came from the zerocoin protocol. + +### zBWKDenominations +zBWKcomes in specific denominations of 1, 5, 10, 50, 100, 500, and 1000. A denomination is a similar concept to paper currency, where you can hold a $100 bill but there is no available $99 bill for you to hold. + +Other implementations of the zerocoin protocol only allow for spending of one denomination/zerocoin at a time. The PIVX implementation of zerocoin allows users to spend any amount of zBWKthey would like (with certain limitations). If a user held two denominations of 5 and they send 7.75 to a merchant, the wallet will automatically grab the two denominations of 5 and then issue 2.25 BWKin change to the spender. There is currently a limit of up to 6 individual zerocoin `coins` that can be combined into a spend, where each `coin` could be a different or similar denomination + +The PIVX zerocoin implementation is structured in such a way that denominations aren't needed to be known by the average user. + +### Fees +zPiv transactions require more computation and disk space than typical PIVX transactions, and as such require a higher transaction fee in order to prevent network spam. Fees are only charged when minting zPiv, each minted denomination is charged a flat rate of 0.01 Piv. zPiv spends are not charged a transaction fee unless the change is minted into zPiv, see the *Minting Change* section for details on fees for zPiv spends with minted change. + +### Converting BWKto zBWK(*zBWKMint*) +**GUI** - Conversion from BWKto zBWKcan be done using the `Privacy Dialog` in the QT wallet. Enter the amount of BWKyou would like to convert and click `Mint Zerocoin`. + +**RPC** - Conversion from BWKto zBWKcan be done using the `mintzerocoin` command. + +**Automint** - The PIVX wallet is set to convert 10% of the wallets available BWKto zBWKautomatically. This can be adjusted in the GUI within the Options dialog, which allows the preferred % to be adjusted as well as the ability to set the preferred zBWKdenomination that will be minted. Automint is set to be triggered when additional blocks are added to the block chain and is programmed *not* to convert your coins all at once. + +Automint can be disabled by adding `enablezeromint=0` to the wallet configuration file. The preferred mint % and denomination can also be set by the configuration file using `zeromintpercentage=` and `preferredDenom=`. + +### Converting zBWKto BWK(*zBWKSpend*) +Redeeming zBWKis done by converting it back to BWK With the 3.0.0 software release, users are not able to send zBWKto each other directly in an atomic fashion. + +**GUI** - Conversion from zBWKto BWKcan be done using the `Privacy Dialog` in the QT wallet. Enter a PIVX address that you would like to Pay To, enter the amount of BWKthe receiver should be sent, click `Spend Zerocoin`. + +**RPC** - Conversion from zBWKto BWKcan be done using the `spendzerocoin` command. + +### Advanced Use & Privacy Considerations +**Security Level** - When spending zBWK a user is prompted to enter a *Security Level* choosing from 1-100. In an indirect way, the Security Level parameter allows the user to choose how many coins to obfuscate their transaction with. + +A Security Level of 1 for example would take all of the minted coins in the blockchain before your mint was added to the blockchain, and would then add any coins that were minted within the next 10 blocks as well. A Security Level of 2 would do the same thing, except add the next 20 blocks worth of mints. A **Security Level of 100 will add the maximum amount of mints** up to the current end of the blockchain. + +The higher the Security Level, the more computation and time it will take to spend. Although it takes longer, a level of 100 is recommended for transactions that need maximum anonymity. + + +**Minting Change** - The PIVX implementation of the zerocoin protocol also allows the spender to choose how to receive their leftover change from a Spend transaction. For maximum anonymity it is recommended that the spender choose to receive the change in zBWK which prevents situations where change from a zBWKspend that is redeemed in BWKis accidentally mixed with the rest of the users BWK thus linking transactions back to a PIVX address. + +Since the lowest denomination of zBWKis 1, and a fee is required to mint zBWK in most situations a high fee will be paid to mint change. The fee is the remainder of the change that cannot be converted back to zBWK For example this would mean a spending a denomination of 10 that yields change of 6.75 in change, would issue zBWKdenominations of 5 and 1 back to the sender with the remaining 0.75 that is unmintable being contributed as a fee. + +**zBWKControl** +Similar to the concept of Coin Control in the QT wallet, zBWKControl allows users to select exactly which zBWKmints they would like to spend. This gives a flexibility to choose which denominations can be picked for a spend that wouldn't otherwise be available. + + +Tor Service Integration Improvements +--------------------- + +Integrating with Tor is now easier than ever! 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. PIVX Core has been updated to make use of this. + +This means that if Tor is running (and proper authorization is available), PIVX Core automatically creates a hidden service to listen on, without manual configuration. PIVX Core will also use Tor automatically to connect to other .onion nodes if the control socket can be successfully opened. This will positively affect the number of available .onion nodes and their usage. + +This new feature is enabled by default if PIVX Core is listening, and a connection to Tor can be made. It can be configured with the `-listenonion`, `-torcontrol` and `-torpassword` settings. To show verbose debugging information, pass `-debug=tor`. + +3.0.0 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### Broad Features +- #264 `15e84e5` zBWKis here! (Fuzzbawls Mrs-X Presstab Spock PIVX) + +### P2P Protocol and Network Code +- #242 `0ecd77f` [P2P] Improve TOR service connectivity (Fuzzbawls) + +### GUI +- #251 `79af8d2` [Qt] Adjust masternode count in information UI (Mrs-X) + +### Miscellaneous +- #258 `c950765` [Depends] Update Depends with newer versions (Fuzzbawls) + +Credits +======= + +Thanks to everyone who directly contributed to this release: +- Fuzzbawls +- Jon Spock +- Mrs-X +- PIVX +- amirabrams +- presstab + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/pivx-project-translations/). diff --git a/doc/release-notes/release-notes-3.0.2.md b/doc/release-notes/release-notes-3.0.2.md new file mode 100644 index 000000000..bfa224c90 --- /dev/null +++ b/doc/release-notes/release-notes-3.0.2.md @@ -0,0 +1,128 @@ +PIVX Core version 3.0.2 is now available from: + + + +This is a new minor-revision version release, including various bug fixes and +performance improvements, as well as updated translations. + +Please report bugs using the issue tracker at github: + + + +Recommended Update +============== + +PIVX Core v3.0.2 is a recommended, semi-mandatory update for all users. This release contains transaction creation bug fixes for zBWKspends, automint calculation adjustments, and other various updates/fixes. + +zBWKspending requires this update. + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely shut down (which might take a few minutes for older versions), then run the installer (on Windows) or just copy over /Applications/PIVX-Qt (on Mac) or pivxd/pivx-qt (on Linux). + +Compatibility +============== + +PIVX Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. + +Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support), +No attempt is made to prevent installing or running the software on Windows XP, you +can still do so at your own risk but be aware that there are known instabilities and issues. +Please do not report issues about Windows XP to the issue tracker. + +PIVX Core should also work on most other Unix-like systems but is not +frequently tested on them. + +### :exclamation::exclamation::exclamation: MacOS 10.13 High Sierra :exclamation::exclamation::exclamation: + +**Currently there are issues with the 3.0.x gitian releases on MacOS version 10.13 (High Sierra), no reports of issues on older versions of MacOS.** + + +Notable Changes +=============== + +Auto Wallet Backup +--------------------- +In addition to the automatic wallet backup that is done at each start of the client, a new automatic backup function has been added that will, by default, create a backup of the wallet file during each zBWKmint operation (zBWKspends which re-mint their change are also included in this). This functionality is controlled by the `-backupzBWK command-line option, which defaults to `1` (enabled, auto-backup). + +Users that wish to prevent this behavior (not recommended) can pass `-backupzBWK0` at the command-line when starting the client, or add `backupzBWK0` to their `pivx.conf` file. + +zBWKAutomint Calculations +--------------------- +A bug in the automint calculations was made apparent on mainnet when block times exceeded expectations, resulting in zBWKmint transactions that were in an unconfirmed state to still be treated as if they had never been minted. This caused automint to effectively mint more than what was intended. + +zBWKSpending Fix +--------------------- +The size of zBWKspend transactions is knowingly larger than normal transactions, and while this was expected, a much stricter check against the scriptsig size is used for mainnet, causing the transactions to be rejected by the mempool, and thus not being packaged into any blocks. + +zBWKTransaction Recovery +--------------------- +Due to the aforementioned issue with zBWKspending, users may find that their attempted spends are now conflicted and zBWKbalances are not represented as expected. "Recovery" of these transactions can be done using the following methods: + +1. GUI: + + The Privacy tab has the `Reset` and `Rescan` buttons that can be used to restore these mints/spends from a state of being marked as unavailable. + +2. RPC: + + The RPC commands `resetspentzerocoin` and `resetmintzerocoin` are the command-line counterparts to the above, and can be used by users that do not use the GUI wallet. + +RPC Changes +--------------------- +The `bip38decrypt` command has had it's parameter order changed to be more consistent with it's counterpart. The command now expects the PIVX address as it's first parameter and the passphrase as it's second parameter. + +Bip38 Compatibility With 3rd Party Tools +--------------------- +The in-wallet bip38 encryption method was leaving the final 4 bytes of the encrypted key blank. This caused an incompatibility issue with 3rd party tools like the paper wallet generators that could decrypt bip38 encrypted keys. Cross-tool compatibility has now been restored. + +3.0.2 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### RPC and other APIs +- #275 `059aaa9` [RPC] Change Parameter Order of bip38decrypt (presstab) + +### P2P Protocol and Network Code +- #286 `85c0f53` [Main] Change sporkDB from smart ptr to ptr. (presstab) +- #292 `feadab4` Additional checks for double spending of zPiv serials. (presstab) + +### Wallet +- #271 `5e9a086` [Wallet] Remove unused member wallet in UnlockContext inner class (Jon Spock) +- #279 `e734010` Add -backupzBWKstartup flag. (presstab) +- #280 `fdc182d` [Wallet] Fix zPiv spending errors. (presstab) +- #282 `310f216` [Wallet] Count pending zPiv balance for automint. (presstab) +- #290 `004d7b6` Include both pending and mature zerocoins for automint calculations (presstab) + +### GUI +- #268 `bc63f24` [GUI/RPC] Changed bubblehelp text + RPC startmasternode help text fixed (Mrs-X) +- #269 `5466a9b` Check if model is valid before using in transactionView (Jon Spock) +- #270 `bd2328e` [Qt] Make lock icon clickable to toggle wallet lock state (Fuzzbawls) +- #273 `f31136e` [Qt] Fix UI tab order and shortcuts (Mrs-X) +- #287 `74a1c3c` [Qt] Don't allow the Esc key to close the privacy tab (Fuzzbawls) +- #291 `cb314e6` [Qt] zPiv control quantity/amount fixes (rejectedpromise) + +### Miscellaneous +- #266 `2d97b54` [Scripts] Fix location for aarch64 outputs in gitian-build.sh (Fuzzbawls) +- #272 `958f51e` [Minting] Replace deprecated auto_ptr. (presstab) +- #276 `03f14ba` Append BIP38 encrypted key with an 4 byte Base58 Checksum (presstab) +- #288 `2522aa1` Bad CBlockHeader copy. (furszy) + +Credits +======= + +Thanks to everyone who directly contributed to this release: +- Fuzzbawls +- Jon Spock +- Mrs-X +- furszy +- presstab +- rejectedpromise +- Warrows + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/pivx-project-translations/). diff --git a/doc/release-process.md b/doc/release-process.md index ff6904063..5e0e77354 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -113,6 +113,10 @@ The gbuild invocations below DO NOT DO THIS by default. ./bin/gsign --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../bulwark/contrib/gitian-descriptors/gitian-osx.yml mv build/out/bulwark-*-osx-unsigned.tar.gz inputs/bulwark-osx-unsigned.tar.gz mv build/out/bulwark-*.tar.gz build/out/bulwark-*.dmg ../ + + ./bin/gbuild --memory 3000 --commit bulwark=v${VERSION} ../bulwark/contrib/gitian-descriptors/gitian-aarch64.yml + ./bin/gsign --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bulwark/contrib/gitian-descriptors/gitian-aarch64.yml + mv build/out/bulwark-*.tar.gz build/out/src/bulwark-*.tar.gz ../ popd Build output expected: @@ -136,6 +140,7 @@ Verify the signatures ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../bulwark/contrib/gitian-descriptors/gitian-linux.yml ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../bulwark/contrib/gitian-descriptors/gitian-win.yml ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../bulwark/contrib/gitian-descriptors/gitian-osx.yml + ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-aarch64 ../bulwark/contrib/gitian-descriptors/gitian-aarch64.yml popd ### Next steps: @@ -146,6 +151,7 @@ Commit your signature to 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 commit -a git push # Assuming you can push to the gitian.sigs tree popd diff --git a/doc/swifttx.md b/doc/swifttx.md index c3420fb9f..baa81ee33 100644 --- a/doc/swifttx.md +++ b/doc/swifttx.md @@ -1,6 +1,6 @@ -##SwiftTX Technical Information +##SwiftX Technical Information -SwiftTX has been integrated into the Core Daemon in two ways: +SwiftX has been integrated into the Core Daemon in two ways: * "push" notifications (ZMQ and `-swifttxnotify` cmd-line/config option); * RPC commands. @@ -8,8 +8,8 @@ SwiftTX has been integrated into the Core Daemon in two ways: When a "Transaction Lock" occurs the hash of the related transaction is broadcasted through ZMQ using both the `zmqpubrawtxlock` and `zmqpubhashtxlock` channels. -* `zmqpubrawtxlock`: publishes the raw transaction when locked via SwiftTX -* `zmqpubhashtxlock`: publishes the transaction hash when locked via SwiftTX +* `zmqpubrawtxlock`: publishes the raw transaction when locked via SwiftX +* `zmqpubhashtxlock`: publishes the transaction hash when locked via SwiftX This mechanism has been integrated into Bitcore-Node-Bulwark which allows for notification to be broadcast through Insight API in one of two ways: * WebSocket: [https://github.com/bulwark-crypto/insight-api-bulwark#web-socket-api](https://github.com/bulwark-crypto/insight-api-bulwark#web-socket-api) @@ -17,7 +17,7 @@ This mechanism has been integrated into Bitcore-Node-Bulwark which allows for no ####Command line option -When a wallet SwiftTX transaction is successfully locked a shell command provided in this option is executed (`%s` in `` is replaced by TxID): +When a wallet SwiftX transaction is successfully locked a shell command provided in this option is executed (`%s` in `` is replaced by TxID): ``` -swifttxnotify= @@ -39,20 +39,20 @@ This value can be overridden by passing the following argument to the Bulwark Co -swifttxdepth= ``` -The key thing to understand is that this value indicates the number of "confirmations" a successful Transaction Lock represents. When Wallet RPC commands are performed (such as `listsinceblock`) this attribute is taken into account when returning information about the transaction. The value in `confirmations` field you see through RPC is showing the number of `"Blockchain Confirmations" + "SwiftTX Depth"` (assuming the funds were sent via SwiftTX). +The key thing to understand is that this value indicates the number of "confirmations" a successful Transaction Lock represents. When Wallet RPC commands are performed (such as `listsinceblock`) this attribute is taken into account when returning information about the transaction. The value in `confirmations` field you see through RPC is showing the number of `"Blockchain Confirmations" + "SwiftX Depth"` (assuming the funds were sent via SwiftX). -There is also a field named `bcconfirmations`. The value in this field represents the total number of `"Blockchain Confirmations"` for a given transaction without taking into account whether it was SwiftTX or not. +There is also a field named `bcconfirmations`. The value in this field represents the total number of `"Blockchain Confirmations"` for a given transaction without taking into account whether it was SwiftX or not. **Examples** -* SwiftTX transaction just occurred: +* SwiftX transaction just occurred: * confirmations: 5 * bcconfirmations: 0 -* SwiftTX transaction received one confirmation from blockchain: +* SwiftX transaction received one confirmation from blockchain: * confirmations: 6 * bcconfirmations: 1 -* non-SwiftTX transaction just occurred: +* non-SwiftX transaction just occurred: * confirmations: 0 * bcconfirmations: 0 -* non-SwiftTX transaction received one confirmation from blockchain: +* non-SwiftX transaction received one confirmation from blockchain: * confirmations: 1 * bcconfirmations: 1 diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index d6ee00bb7..755b9949e 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -26,6 +26,7 @@ if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then ${BUILDDIR}/qa/rpc-tests/mempool_spendcoinbase.py --srcdir "${BUILDDIR}/src" ${BUILDDIR}/qa/rpc-tests/httpbasics.py --srcdir "${BUILDDIR}/src" ${BUILDDIR}/qa/rpc-tests/mempool_coinbase_spends.py --srcdir "${BUILDDIR}/src" + ${BUILDDIR}/qa/rpc-tests/proxy_test.py --srcdir "${BUILDDIR}/src" #${BUILDDIR}/qa/rpc-tests/forknotify.py --srcdir "${BUILDDIR}/src" else echo "No rpc tests to run. Wallet, utils, and bitcoind must all be enabled" diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py new file mode 100755 index 000000000..0eae4e520 --- /dev/null +++ b/qa/rpc-tests/proxy_test.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +import socket +import traceback, sys +from binascii import hexlify +import time, os + +from socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType +from test_framework import BitcoinTestFramework +from util import * +''' +Test plan: +- Start bitcoind's with different proxy configurations +- Use addnode to initiate connections +- Verify that proxies are connected to, and the right connection command is given +- Proxy configurations to test on bitcoind side: + - `-proxy` (proxy everything) + - `-onion` (proxy just onions) + - `-proxyrandomize` Circuit randomization +- Proxy configurations to test on proxy side, + - support no authentication (other proxy) + - support no authentication + user/pass authentication (Tor) + - proxy on IPv6 + +- Create various proxies (as threads) +- Create bitcoinds that connect to them +- Manipulate the bitcoinds using addnode (onetry) an observe effects + +addnode connect to IPv4 +addnode connect to IPv6 +addnode connect to onion +addnode connect to generic DNS name +''' + +class ProxyTest(BitcoinTestFramework): + def __init__(self): + # Create two proxies on different ports + # ... one unauthenticated + self.conf1 = Socks5Configuration() + self.conf1.addr = ('127.0.0.1', 13000 + (os.getpid() % 1000)) + self.conf1.unauth = True + self.conf1.auth = False + # ... one supporting authenticated and unauthenticated (Tor) + self.conf2 = Socks5Configuration() + self.conf2.addr = ('127.0.0.1', 14000 + (os.getpid() % 1000)) + self.conf2.unauth = True + self.conf2.auth = True + # ... one on IPv6 with similar configuration + self.conf3 = Socks5Configuration() + self.conf3.af = socket.AF_INET6 + self.conf3.addr = ('::1', 15000 + (os.getpid() % 1000)) + self.conf3.unauth = True + self.conf3.auth = True + + self.serv1 = Socks5Server(self.conf1) + self.serv1.start() + self.serv2 = Socks5Server(self.conf2) + self.serv2.start() + self.serv3 = Socks5Server(self.conf3) + self.serv3.start() + + def setup_nodes(self): + # Note: proxies are not used to connect to local nodes + # this is because the proxy to use is based on CService.GetNetwork(), which return NET_UNROUTABLE for localhost + return start_nodes(4, self.options.tmpdir, extra_args=[ + ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'], + ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'], + ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'], + ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0'] + ]) + + def node_test(self, node, proxies, auth): + rv = [] + # Test: outgoing IPv4 connection through node + node.addnode("15.61.23.23:1234", "onetry") + cmd = proxies[0].queue.get() + assert(isinstance(cmd, Socks5Command)) + # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, "15.61.23.23") + assert_equal(cmd.port, 1234) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) + + # Test: outgoing IPv6 connection through node + node.addnode("[1233:3432:2434:2343:3234:2345:6546:4534]:5443", "onetry") + cmd = proxies[1].queue.get() + assert(isinstance(cmd, Socks5Command)) + # Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6 + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, "1233:3432:2434:2343:3234:2345:6546:4534") + assert_equal(cmd.port, 5443) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) + + # Test: outgoing onion connection through node + node.addnode("pivxvj7kcklujarx.onion:51472", "onetry") + cmd = proxies[2].queue.get() + assert(isinstance(cmd, Socks5Command)) + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, "pivxvj7kcklujarx.onion") + assert_equal(cmd.port, 51472) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) + + # Test: outgoing DNS name connection through node + node.addnode("node.noumenon:8333", "onetry") + cmd = proxies[3].queue.get() + assert(isinstance(cmd, Socks5Command)) + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, "node.noumenon") + assert_equal(cmd.port, 8333) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) + + return rv + + def run_test(self): + # basic -proxy + self.node_test(self.nodes[0], [self.serv1, self.serv1, self.serv1, self.serv1], False) + + # -proxy plus -onion + self.node_test(self.nodes[1], [self.serv1, self.serv1, self.serv2, self.serv1], False) + + # -proxy plus -onion, -proxyrandomize + rv = self.node_test(self.nodes[2], [self.serv2, self.serv2, self.serv2, self.serv2], True) + # Check that credentials as used for -proxyrandomize connections are unique + credentials = set((x.username,x.password) for x in rv) + assert_equal(len(credentials), 4) + + # proxy on IPv6 localhost + self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False) + +if __name__ == '__main__': + ProxyTest().main() diff --git a/qa/rpc-tests/socks5.py b/qa/rpc-tests/socks5.py new file mode 100755 index 000000000..3fb04f7dc --- /dev/null +++ b/qa/rpc-tests/socks5.py @@ -0,0 +1,159 @@ +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +''' +Dummy Socks5 server for testing. +''' +from __future__ import print_function, division, unicode_literals +import socket, threading, Queue +import traceback, sys + +### Protocol constants +class Command: + CONNECT = 0x01 + +class AddressType: + IPV4 = 0x01 + DOMAINNAME = 0x03 + IPV6 = 0x04 + +### Utility functions +def recvall(s, n): + '''Receive n bytes from a socket, or fail''' + rv = bytearray() + while n > 0: + d = s.recv(n) + if not d: + raise IOError('Unexpected end of stream') + rv.extend(d) + n -= len(d) + return rv + +### Implementation classes +class Socks5Configuration(object): + '''Proxy configuration''' + def __init__(self): + self.addr = None # Bind address (must be set) + self.af = socket.AF_INET # Bind address family + self.unauth = False # Support unauthenticated + self.auth = False # Support authentication + +class Socks5Command(object): + '''Information about an incoming socks5 command''' + def __init__(self, cmd, atyp, addr, port, username, password): + self.cmd = cmd # Command (one of Command.*) + self.atyp = atyp # Address type (one of AddressType.*) + self.addr = addr # Address + self.port = port # Port to connect to + self.username = username + self.password = password + def __repr__(self): + return 'Socks5Command(%s,%s,%s,%s,%s,%s)' % (self.cmd, self.atyp, self.addr, self.port, self.username, self.password) + +class Socks5Connection(object): + def __init__(self, serv, conn, peer): + self.serv = serv + self.conn = conn + self.peer = peer + + def handle(self): + ''' + Handle socks5 request according to RFC1928 + ''' + try: + # Verify socks version + ver = recvall(self.conn, 1)[0] + if ver != 0x05: + raise IOError('Invalid socks version %i' % ver) + # Choose authentication method + nmethods = recvall(self.conn, 1)[0] + methods = bytearray(recvall(self.conn, nmethods)) + method = None + if 0x02 in methods and self.serv.conf.auth: + method = 0x02 # username/password + elif 0x00 in methods and self.serv.conf.unauth: + method = 0x00 # unauthenticated + if method is None: + raise IOError('No supported authentication method was offered') + # Send response + self.conn.sendall(bytearray([0x05, method])) + # Read authentication (optional) + username = None + password = None + if method == 0x02: + ver = recvall(self.conn, 1)[0] + if ver != 0x01: + raise IOError('Invalid auth packet version %i' % ver) + ulen = recvall(self.conn, 1)[0] + username = str(recvall(self.conn, ulen)) + plen = recvall(self.conn, 1)[0] + password = str(recvall(self.conn, plen)) + # Send authentication response + self.conn.sendall(bytearray([0x01, 0x00])) + + # Read connect request + (ver,cmd,rsv,atyp) = recvall(self.conn, 4) + if ver != 0x05: + raise IOError('Invalid socks version %i in connect request' % ver) + if cmd != Command.CONNECT: + raise IOError('Unhandled command %i in connect request' % cmd) + + if atyp == AddressType.IPV4: + addr = recvall(self.conn, 4) + elif atyp == AddressType.DOMAINNAME: + n = recvall(self.conn, 1)[0] + addr = str(recvall(self.conn, n)) + elif atyp == AddressType.IPV6: + addr = recvall(self.conn, 16) + else: + raise IOError('Unknown address type %i' % atyp) + port_hi,port_lo = recvall(self.conn, 2) + port = (port_hi << 8) | port_lo + + # Send dummy response + self.conn.sendall(bytearray([0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + + cmdin = Socks5Command(cmd, atyp, addr, port, username, password) + self.serv.queue.put(cmdin) + print('Proxy: ', cmdin) + # Fall through to disconnect + except Exception,e: + traceback.print_exc(file=sys.stderr) + self.serv.queue.put(e) + finally: + self.conn.close() + +class Socks5Server(object): + def __init__(self, conf): + self.conf = conf + self.s = socket.socket(conf.af) + self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.s.bind(conf.addr) + self.s.listen(5) + self.running = False + self.thread = None + self.queue = Queue.Queue() # report connections and exceptions to client + + def run(self): + while self.running: + (sockconn, peer) = self.s.accept() + if self.running: + conn = Socks5Connection(self, sockconn, peer) + thread = threading.Thread(None, conn.handle) + thread.daemon = True + thread.start() + + def start(self): + assert(not self.running) + self.running = True + self.thread = threading.Thread(None, self.run) + self.thread.daemon = True + self.thread.start() + + def stop(self): + self.running = False + # connect to self to end run loop + s = socket.socket(self.conf.af) + s.connect(self.conf.addr) + s.close() + self.thread.join() diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index bf71d5ebc..727ba9da4 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -4,14 +4,14 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -# Exercise the wallet. Ported from wallet.sh. +# Exercise the wallet. Ported from wallet.sh. # Does the following: # a) creates 3 nodes, with an empty chain (no blocks). # b) node0 mines a block -# c) node1 mines 101 blocks, so now nodes 0 and 1 have 50btc, node2 has none. -# d) node0 sends 21 btc to node2, in two transactions (11 btc, then 10 btc). +# c) node1 mines 32 blocks, so now node 0 has 60001BWK node 1 has 4250BWK node2 has none. +# d) node0 sends 601 BWKto node2, in two transactions (301 BWK then 300 BWK. # e) node0 mines a block, collects the fee on the second transaction -# f) node1 mines 100 blocks, to mature node0's just-mined block +# f) node1 mines 16 blocks, to mature node0's just-mined block # g) check that node0 has 100-21, node2 has 21 # h) node0 should now have 2 unspent outputs; send these to node2 via raw tx broadcast by node1 # i) have node1 mine a block @@ -42,40 +42,40 @@ def run_test (self): self.nodes[0].setgenerate(True, 1) self.sync_all() - self.nodes[1].setgenerate(True, 101) + self.nodes[1].setgenerate(True, 32) self.sync_all() - assert_equal(self.nodes[0].getbalance(), 50) - assert_equal(self.nodes[1].getbalance(), 50) + assert_equal(self.nodes[0].getbalance(), 60001) + assert_equal(self.nodes[1].getbalance(), 4250) assert_equal(self.nodes[2].getbalance(), 0) - # Send 21 BTC from 0 to 2 using sendtoaddress call. + # Send 601 BTC from 0 to 2 using sendtoaddress call. # Second transaction will be child of first, and will require a fee - self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) - self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 351) + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 350) - # Have node0 mine a block, thus he will collect his own fee. + # Have node0 mine a block, thus he will collect his own fee. self.nodes[0].setgenerate(True, 1) self.sync_all() # Have node1 generate 100 blocks (so node0 can recover the fee) - self.nodes[1].setgenerate(True, 100) + self.nodes[1].setgenerate(True, 16) self.sync_all() # node0 should end up with 100 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 - assert_equal(self.nodes[0].getbalance(), 100-21) - assert_equal(self.nodes[2].getbalance(), 21) + assert_greater_than(self.nodes[0].getbalance(), 59549) + assert_equal(self.nodes[2].getbalance(), 701) # Node0 should have two unspent outputs. - # Create a couple of transactions to send them to node2, submit them through - # node1, and make sure both node0 and node2 pick them up properly: + # Create a couple of transactions to send them to node2, submit them through + # node1, and make sure both node0 and node2 pick them up properly: node0utxos = self.nodes[0].listunspent(1) assert_equal(len(node0utxos), 2) # create both transactions txns_to_send = [] - for utxo in node0utxos: + for utxo in node0utxos: inputs = [] outputs = {} inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]}) @@ -92,8 +92,8 @@ def run_test (self): self.sync_all() assert_equal(self.nodes[0].getbalance(), 0) - assert_equal(self.nodes[2].getbalance(), 100) - assert_equal(self.nodes[2].getbalance("from1"), 100-21) + assert_greater_than(self.nodes[2].getbalance(), 60250) + assert_greater_than(self.nodes[2].getbalance("from1"), 59549) if __name__ == '__main__': diff --git a/share/genbuild.sh b/share/genbuild.sh index ffa89ca6e..caf928a42 100755 --- a/share/genbuild.sh +++ b/share/genbuild.sh @@ -21,14 +21,9 @@ if [ -e "$(which git 2>/dev/null)" -a "$(git rev-parse --is-inside-work-tree 2>/ git diff >/dev/null 2>/dev/null # if latest commit is tagged and not dirty, then override using the tag name + DESC=$(git describe 2>/dev/null) RAWDESC=$(git describe --abbrev=0 2>/dev/null) - if [ "$(git rev-parse HEAD)" = "$(git rev-list -1 $RAWDESC)" ]; then - git diff-index --quiet HEAD -- && DESC=$RAWDESC - fi - - # otherwise generate suffix from git, i.e. string like "59887e8-dirty" - SUFFIX=$(git rev-parse --short HEAD) - git diff-index --quiet HEAD -- || SUFFIX="$SUFFIX-dirty" + git diff-index --quiet HEAD -- || DESC="$DESC-dirty" # get a string like "2012-04-10 16:27:19 +0200" LAST_COMMIT_DATE="$(git log -n 1 --format="%ci")" @@ -36,8 +31,6 @@ fi if [ -n "$DESC" ]; then NEWINFO="#define BUILD_DESC \"$DESC\"" -elif [ -n "$SUFFIX" ]; then - NEWINFO="#define BUILD_SUFFIX $SUFFIX" else NEWINFO="// No build information available" fi diff --git a/src/Makefile.am b/src/Makefile.am index 4e7b76a4f..085ace67a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,8 +1,16 @@ -DIST_SUBDIRS = secp256k1 +DIST_SUBDIRS = secp256k1 univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) +if EMBEDDED_UNIVALUE +LIBUNIVALUE = univalue/libunivalue.la -if EMBEDDED_LEVELDB +$(LIBUNIVALUE): $(wildcard univalue/lib/*) $(wildcard univalue/include/*) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) +else +LIBUNIVALUE = $(UNIVALUE_LIBS) +endif + +#if EMBEDDED_LEVELDB LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/include LEVELDB_CPPFLAGS += -I$(srcdir)/leveldb/helpers/memenv LIBLEVELDB += $(builddir)/leveldb/libleveldb.a @@ -15,12 +23,13 @@ $(LIBLEVELDB) $(LIBMEMENV): @echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \ CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \ OPT="$(CXXFLAGS) $(CPPFLAGS)" -endif +#endif BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include +BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS) LIBBITCOIN_SERVER=libbitcoin_server.a LIBBITCOIN_WALLET=libbitcoin_wallet.a @@ -28,7 +37,7 @@ LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a -LIBBITCOIN_UNIVALUE=univalue/libbitcoin_univalue.a +LIBBITCOIN_ZEROCOIN=libzerocoin/libbitcoin_zerocoin.a LIBBITCOINQT=qt/libbitcoinqt.a LIBSECP256K1=secp256k1/libsecp256k1.la @@ -41,7 +50,7 @@ EXTRA_LIBRARIES = \ crypto/libbitcoin_crypto.a \ libbitcoin_util.a \ libbitcoin_common.a \ - univalue/libbitcoin_univalue.a \ + libzerocoin/libbitcoin_zerocoin.a \ libbitcoin_server.a \ libbitcoin_cli.a if ENABLE_WALLET @@ -75,6 +84,8 @@ endif # bulwark core # BITCOIN_CORE_H = \ activemasternode.h \ + accumulators.h \ + accumulatormap.h \ addrdb.h \ addrman.h \ alert.h \ @@ -98,8 +109,10 @@ BITCOIN_CORE_H = \ compressor.h \ primitives/block.h \ primitives/transaction.h \ + primitives/zerocoin.h \ core_io.h \ crypter.h \ + denomination_functions.h \ obfuscation.h \ obfuscation-relay.h \ db.h \ @@ -131,6 +144,7 @@ BITCOIN_CORE_H = \ protocol.h \ pubkey.h \ random.h \ + reverse_iterate.h \ rpcclient.h \ rpcprotocol.h \ rpcserver.h \ @@ -142,6 +156,7 @@ BITCOIN_CORE_H = \ script/script_error.h \ serialize.h \ spork.h \ + sporkdb.h \ streams.h \ sync.h \ threadsafety.h \ @@ -164,18 +179,8 @@ BITCOIN_CORE_H = \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h \ zmq/zmqnotificationinterface.h \ - zmq/zmqpublishnotifier.h - -JSON_H = \ - json/json_spirit.h \ - json/json_spirit_error_position.h \ - json/json_spirit_reader.h \ - json/json_spirit_reader_template.h \ - json/json_spirit_stream_reader.h \ - json/json_spirit_utils.h \ - json/json_spirit_value.h \ - json/json_spirit_writer.h \ - json/json_spirit_writer_template.h + zmq/zmqpublishnotifier.h \ + compat/sanity.h obj/build.h: FORCE @$(MKDIR_P) $(builddir)/obj @@ -184,7 +189,7 @@ obj/build.h: FORCE libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h # server: shared between bulwarkd and bulwark-qt -libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) libbitcoin_server_a_SOURCES = \ addrdb.cpp \ addrman.cpp \ @@ -215,7 +220,6 @@ libbitcoin_server_a_SOURCES = \ txdb.cpp \ txmempool.cpp \ validationinterface.cpp \ - $(JSON_H) \ $(BITCOIN_CORE_H) if ENABLE_ZMQ @@ -237,6 +241,7 @@ libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_wallet_a_SOURCES = \ activemasternode.cpp \ bip38.cpp \ + denomination_functions.cpp \ obfuscation.cpp \ obfuscation-relay.cpp \ db.cpp \ @@ -249,6 +254,7 @@ libbitcoin_wallet_a_SOURCES = \ masternodeconfig.cpp \ masternodeman.cpp \ rpcdump.cpp \ + primitives/zerocoin.cpp \ rpcwallet.cpp \ kernel.cpp \ wallet.cpp \ @@ -290,6 +296,29 @@ crypto_libbitcoin_crypto_a_SOURCES = \ crypto/sph_skein.h \ crypto/sph_types.h +# libzerocoin library +libzerocoin_libbitcoin_zerocoin_a_SOURCES = \ + libzerocoin/Accumulator.h \ + libzerocoin/AccumulatorProofOfKnowledge.h \ + libzerocoin/bignum.h \ + libzerocoin/Coin.h \ + libzerocoin/CoinSpend.h \ + libzerocoin/Commitment.h \ + libzerocoin/Denominations.h \ + libzerocoin/ParamGeneration.h \ + libzerocoin/Params.h \ + libzerocoin/SerialNumberSignatureOfKnowledge.h \ + libzerocoin/ZerocoinDefines.h \ + libzerocoin/Accumulator.cpp \ + libzerocoin/AccumulatorProofOfKnowledge.cpp \ + libzerocoin/Coin.cpp \ + libzerocoin/Denominations.cpp \ + libzerocoin/CoinSpend.cpp \ + libzerocoin/Commitment.cpp \ + libzerocoin/ParamGeneration.cpp \ + libzerocoin/Params.cpp \ + libzerocoin/SerialNumberSignatureOfKnowledge.cpp + # univalue JSON library univalue_libbitcoin_univalue_a_SOURCES = \ univalue/univalue.cpp \ @@ -301,6 +330,8 @@ univalue_libbitcoin_univalue_a_SOURCES = \ # common: shared between bulwarkd, and bulwark-qt and non-server tools libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_common_a_SOURCES = \ + accumulators.cpp \ + accumulatormap.cpp \ allocators.cpp \ amount.cpp \ base58.cpp \ @@ -310,6 +341,7 @@ libbitcoin_common_a_SOURCES = \ compressor.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ + primitives/zerocoin.cpp \ core_read.cpp \ core_write.cpp \ eccryptoverify.cpp \ @@ -326,6 +358,7 @@ libbitcoin_common_a_SOURCES = \ script/standard.cpp \ script/script_error.cpp \ spork.cpp \ + sporkdb.cpp \ $(BITCOIN_CORE_H) # util: shared between all executables. @@ -367,7 +400,8 @@ nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h bulwarkd_LDADD = \ $(LIBBITCOIN_SERVER) \ $(LIBBITCOIN_COMMON) \ - $(LIBBITCOIN_UNIVALUE) \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_ZEROCOIN) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(LIBLEVELDB) \ @@ -388,7 +422,7 @@ if TARGET_WINDOWS bulwarkd_SOURCES += bulwarkd-res.rc endif -bulwarkd_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) +bulwarkd_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) bulwarkd_CPPFLAGS = $(BITCOIN_INCLUDES) bulwarkd_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -396,11 +430,11 @@ bulwarkd_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) # bulwark-cli binary # bulwark_cli_LDADD = \ $(LIBBITCOIN_CLI) \ + $(LIBUNIVALUE) \ $(LIBBITCOIN_UTIL) \ $(BOOST_LIBS) \ $(SSL_LIBS) \ - $(CRYPTO_LIBS) \ - $(EVENT_LIBS) + $(CRYPTO_LIBS) bulwark_cli_SOURCES = \ bulwark-cli.cpp @@ -410,8 +444,9 @@ bulwark_cli_CPPFLAGS = $(BITCOIN_INCLUDES) # bulwark-tx binary # bulwark_tx_LDADD = \ - $(LIBBITCOIN_UNIVALUE) \ + $(LIBUNIVALUE) \ $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_ZEROCOIN) \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) \ @@ -478,6 +513,7 @@ EXTRA_DIST = leveldb clean-local: -$(MAKE) -C leveldb clean -$(MAKE) -C secp256k1 clean + -$(MAKE) -C univalue clean rm -f leveldb/*/*.gcno leveldb/helpers/memenv/*.gcno -rm -f config.h diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 0e378b6f2..1288ca613 100755 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -24,6 +24,7 @@ QT_TS = \ qt/locale/bulwark_ru.ts \ qt/locale/bulwark_sk.ts \ qt/locale/bulwark_sv.ts \ + qt/locale/bulwark_tr.ts \ qt/locale/bulwark_uk.ts \ qt/locale/bulwark_zh_CN.ts \ qt/locale/bulwark_zh_TW.ts @@ -46,12 +47,14 @@ QT_FORMS_UI = \ qt/forms/optionsdialog.ui \ qt/forms/overviewpage.ui \ qt/forms/receivecoinsdialog.ui \ + qt/forms/privacydialog.ui \ qt/forms/receiverequestdialog.ui \ qt/forms/rpcconsole.ui \ qt/forms/sendcoinsdialog.ui \ qt/forms/sendcoinsentry.ui \ qt/forms/signverifymessagedialog.ui \ - qt/forms/transactiondescdialog.ui + qt/forms/transactiondescdialog.ui \ + qt/forms/zbwkcontroldialog.ui QT_MOC_CPP = \ qt/moc_addressbookpage.cpp \ @@ -90,6 +93,7 @@ QT_MOC_CPP = \ qt/moc_qvalidatedlineedit.cpp \ qt/moc_qvaluecombobox.cpp \ qt/moc_receivecoinsdialog.cpp \ + qt/moc_privacydialog.cpp \ qt/moc_receiverequestdialog.cpp \ qt/moc_recentrequeststablemodel.cpp \ qt/moc_rpcconsole.cpp \ @@ -107,6 +111,7 @@ QT_MOC_CPP = \ qt/moc_walletframe.cpp \ qt/moc_walletmodel.cpp \ qt/moc_walletview.cpp \ + qt/moc_zbwkcontroldialog.cpp \ qt/moc_qtmaterialcheckable.cpp \ qt/moc_qtmaterialcheckable_internal.cpp \ qt/moc_qtmaterialoverlaywidget.cpp \ @@ -183,6 +188,7 @@ BITCOIN_QT_H = \ qt/qvalidatedlineedit.h \ qt/qvaluecombobox.h \ qt/receivecoinsdialog.h \ + qt/privacydialog.h \ qt/receiverequestdialog.h \ qt/recentrequeststablemodel.h \ qt/rpcconsole.h \ @@ -203,6 +209,7 @@ BITCOIN_QT_H = \ qt/walletmodeltransaction.h \ qt/walletview.h \ qt/winshutdownmonitor.h \ + qt/zbwkcontroldialog.h \ qt/qtmaterialcheckable.h \ qt/qtmaterialcheckable_internal.h \ qt/qtmaterialcheckable_p.h \ @@ -268,6 +275,8 @@ RES_ICONS = \ qt/res/icons/qrcode.png \ qt/res/icons/quit.png \ qt/res/icons/receive.png \ + qt/res/icons/privacy.png \ + qt/res/icons/privacy_m.png \ qt/res/icons/remove.png \ qt/res/icons/send.png \ qt/res/icons/staking_active.png \ @@ -346,6 +355,7 @@ BITCOIN_QT_CPP += \ qt/paymentrequestplus.cpp \ qt/paymentserver.cpp \ qt/receivecoinsdialog.cpp \ + qt/privacydialog.cpp \ qt/receiverequestdialog.cpp \ qt/recentrequeststablemodel.cpp \ qt/sendcoinsdialog.cpp \ @@ -360,7 +370,8 @@ BITCOIN_QT_CPP += \ qt/walletframe.cpp \ qt/walletmodel.cpp \ qt/walletmodeltransaction.cpp \ - qt/walletview.cpp + qt/walletview.cpp \ + qt/zbwkcontroldialog.cpp endif @@ -369,11 +380,13 @@ RES_IMAGES = \ qt/res/images/splash.png \ qt/res/images/splash_testnet.png \ qt/res/images/bulwark_logo_horizontal.png \ - qt/res/images/downArrow.png \ + qt/res/images/downArrow_dark.png \ + qt/res/images/downArrow_small_dark.png \ qt/res/images/downArrow_small.png \ + qt/res/images/upArrow_small_dark.png \ qt/res/images/upArrow_small.png \ - qt/res/images/leftArrow_small.png \ - qt/res/images/rightArrow_small.png \ + qt/res/images/leftArrow_small_dark.png \ + qt/res/images/rightArrow_small_dark.png \ qt/res/images/qtreeview_selected.png \ qt/res/images/walletFrame.png \ qt/res/images/walletFrame_bg.png \ @@ -429,7 +442,7 @@ endif if ENABLE_ZMQ qt_bulwark_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif -qt_bulwark_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ +qt_bulwark_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBBITCOIN_ZEROCOIN) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) @@ -485,4 +498,4 @@ moc_%.cpp: %.h %.qm: %.ts @test -f $(LRELEASE) @$(MKDIR_P) $(@D) - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LRELEASE) -silent $< -qm $@ + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LRELEASE) -silent $< -qm $@ \ No newline at end of file diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 480281d86..84e35559b 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -33,7 +33,7 @@ endif if ENABLE_ZMQ qt_test_test_bulwark_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif -qt_test_test_bulwark_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \ +qt_test_test_bulwark_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBBITCOIN_ZEROCOIN) $(LIBLEVELDB) \ $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index d40d8c69c..598767a51 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -35,6 +35,12 @@ GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.r BITCOIN_TESTS =\ test/bignum.h \ + test/zerocoin_implementation_tests.cpp\ + test/zerocoin_denomination_tests.cpp\ + test/zerocoin_transactions_tests.cpp \ + test/benchmark_zerocoin.cpp \ + test/tutorial_zerocoin.cpp \ + test/libzerocoin_tests.cpp \ test/allocator_tests.cpp \ test/base32_tests.cpp \ test/base58_tests.cpp \ @@ -79,7 +85,7 @@ endif test_test_bulwark_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_bulwark_CPPFLAGS = $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) -test_test_bulwark_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ +test_test_bulwark_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBBITCOIN_ZEROCOIN) $(LIBLEVELDB) $(LIBMEMENV) \ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) if ENABLE_WALLET @@ -111,6 +117,9 @@ bulwark_test_clean : FORCE check-local: $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check +if EMBEDDED_UNIVALUE + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check +endif %.json.h: %.json @$(MKDIR_P) $(@D) diff --git a/src/accumulatormap.cpp b/src/accumulatormap.cpp new file mode 100644 index 000000000..7e9919a2a --- /dev/null +++ b/src/accumulatormap.cpp @@ -0,0 +1,89 @@ +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "accumulatormap.h" +#include "accumulators.h" +#include "main.h" +#include "txdb.h" +#include "libzerocoin/Denominations.h" + +using namespace libzerocoin; +using namespace std; + +//Construct accumulators for all denominations +AccumulatorMap::AccumulatorMap() +{ + for (auto& denom : zerocoinDenomList) { + unique_ptr uptr(new Accumulator(Params().Zerocoin_Params(), denom)); + mapAccumulators.insert(make_pair(denom, std::move(uptr))); + } +} + +//Reset each accumulator to its default state +void AccumulatorMap::Reset() +{ + mapAccumulators.clear(); + for (auto& denom : zerocoinDenomList) { + unique_ptr uptr(new Accumulator(Params().Zerocoin_Params(), denom)); + mapAccumulators.insert(make_pair(denom, std::move(uptr))); + } +} + +//Load a checkpoint containing 32bit checksums of accumulator values. +bool AccumulatorMap::Load(uint256 nCheckpoint) +{ + for (auto& denom : zerocoinDenomList) { + uint32_t nChecksum = ParseChecksum(nCheckpoint, denom); + + CBigNum bnValue; + if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnValue)) { + LogPrintf("%s : cannot find checksum %d", __func__, nChecksum); + return false; + } + + mapAccumulators.at(denom)->setValue(bnValue); + } + return true; +} + +//Add a zerocoin to the accumulator of its denomination. +bool AccumulatorMap::Accumulate(PublicCoin pubCoin, bool fSkipValidation) +{ + CoinDenomination denom = pubCoin.getDenomination(); + if (denom == CoinDenomination::ZQ_ERROR) + return false; + + if (fSkipValidation) + mapAccumulators.at(denom)->increment(pubCoin.getValue()); + else + mapAccumulators.at(denom)->accumulate(pubCoin); + return true; +} + +//Get the value of a specific accumulator +CBigNum AccumulatorMap::GetValue(CoinDenomination denom) +{ + if (denom == CoinDenomination::ZQ_ERROR) + return CBigNum(0); + return mapAccumulators.at(denom)->getValue(); +} + +//Calculate a 32bit checksum of each accumulator value. Concatenate checksums into uint256 +uint256 AccumulatorMap::GetCheckpoint() +{ + uint256 nCheckpoint; + + //Prevent possible overflows from future changes to the list and forgetting to update this code + assert(zerocoinDenomList.size() == 7); + for (auto& denom : zerocoinDenomList) { + CBigNum bnValue = mapAccumulators.at(denom)->getValue(); + uint32_t nCheckSum = GetChecksum(bnValue); + nCheckpoint = nCheckpoint << 32 | nCheckSum; + } + + return nCheckpoint; +} + + diff --git a/src/accumulatormap.h b/src/accumulatormap.h new file mode 100644 index 000000000..e4bcc50f9 --- /dev/null +++ b/src/accumulatormap.h @@ -0,0 +1,23 @@ +// Copyright (c) 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 BWK_ACCUMULATORMAP_H +#define BWK_ACCUMULATORMAP_H + +#include "libzerocoin/Accumulator.h" +#include "libzerocoin/Coin.h" + +//A map with an accumulator for each denomination +class AccumulatorMap +{ +private: + std::map > mapAccumulators; +public: + AccumulatorMap(); + bool Load(uint256 nCheckpoint); + bool Accumulate(libzerocoin::PublicCoin pubCoin, bool fSkipValidation = false); + CBigNum GetValue(libzerocoin::CoinDenomination denom); + uint256 GetCheckpoint(); + void Reset(); +}; +#endif //BWK_ACCUMULATORMAP_H diff --git a/src/accumulators.cpp b/src/accumulators.cpp new file mode 100644 index 000000000..f9482b60c --- /dev/null +++ b/src/accumulators.cpp @@ -0,0 +1,372 @@ +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "accumulators.h" +#include "accumulatormap.h" +#include "chainparams.h" +#include "main.h" +#include "txdb.h" +#include "init.h" +#include "spork.h" + +using namespace libzerocoin; + +std::map mapAccumulatorValues; +std::list listAccCheckpointsNoDB; + +uint32_t ParseChecksum(uint256 nChecksum, CoinDenomination denomination) +{ + //shift to the beginning bit of this denomination and trim any remaining bits by returning 32 bits only + int pos = distance(zerocoinDenomList.begin(), find(zerocoinDenomList.begin(), zerocoinDenomList.end(), denomination)); + nChecksum = nChecksum >> (32*((zerocoinDenomList.size() - 1) - pos)); + return nChecksum.Get32(); +} + +uint32_t GetChecksum(const CBigNum &bnValue) +{ + CDataStream ss(SER_GETHASH, 0); + ss << bnValue; + uint256 hash = Hash(ss.begin(), ss.end()); + + return hash.Get32(); +} + +bool GetAccumulatorValueFromChecksum(uint32_t nChecksum, bool fMemoryOnly, CBigNum& bnAccValue) +{ + if (mapAccumulatorValues.count(nChecksum)) { + bnAccValue = mapAccumulatorValues.at(nChecksum); + return true; + } + + if (fMemoryOnly) + return false; + + if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnAccValue)) { + bnAccValue = 0; + } + + return true; +} + +bool GetAccumulatorValueFromDB(uint256 nCheckpoint, CoinDenomination denom, CBigNum& bnAccValue) +{ + uint32_t nChecksum = ParseChecksum(nCheckpoint, denom); + return GetAccumulatorValueFromChecksum(nChecksum, false, bnAccValue); +} + +void AddAccumulatorChecksum(const uint32_t nChecksum, const CBigNum &bnValue, bool fMemoryOnly) +{ + if(!fMemoryOnly) + zerocoinDB->WriteAccumulatorValue(nChecksum, bnValue); + mapAccumulatorValues.insert(make_pair(nChecksum, bnValue)); +} + +void DatabaseChecksums(AccumulatorMap& mapAccumulators) +{ + uint256 nCheckpoint = 0; + for (auto& denom : zerocoinDenomList) { + CBigNum bnValue = mapAccumulators.GetValue(denom); + uint32_t nCheckSum = GetChecksum(bnValue); + AddAccumulatorChecksum(nCheckSum, bnValue, false); + nCheckpoint = nCheckpoint << 32 | nCheckSum; + } +} + +bool EraseChecksum(uint32_t nChecksum) +{ + //erase from both memory and database + mapAccumulatorValues.erase(nChecksum); + return zerocoinDB->EraseAccumulatorValue(nChecksum); +} + +bool EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nCheckpointPrevious) +{ + for (auto& denomination : zerocoinDenomList) { + uint32_t nChecksumErase = ParseChecksum(nCheckpointErase, denomination); + uint32_t nChecksumPrevious = ParseChecksum(nCheckpointPrevious, denomination); + + //if the previous checksum is the same, then it should remain in the database and map + if(nChecksumErase == nChecksumPrevious) + continue; + + if (!EraseChecksum(nChecksumErase)) + return false; + } + + return true; +} + +bool LoadAccumulatorValuesFromDB(const uint256 nCheckpoint) +{ + for (auto& denomination : zerocoinDenomList) { + uint32_t nChecksum = ParseChecksum(nCheckpoint, denomination); + + //if read is not successful then we are not in a state to verify zerocoin transactions + CBigNum bnValue; + if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnValue)) { + LogPrint("zero","%s : Missing databased value for checksum %d\n", __func__, nChecksum); + if (!count(listAccCheckpointsNoDB.begin(), listAccCheckpointsNoDB.end(), nCheckpoint)) + listAccCheckpointsNoDB.push_back(nCheckpoint); + return false; + } + mapAccumulatorValues.insert(make_pair(nChecksum, bnValue)); + } + return true; +} + +//Erase accumulator checkpoints for a certain block range +bool EraseCheckpoints(int nStartHeight, int nEndHeight) +{ + if (chainActive.Height() < nStartHeight) + return false; + + nEndHeight = min(chainActive.Height(), nEndHeight); + + CBlockIndex* pindex = chainActive[nStartHeight]; + uint256 nCheckpointPrev = pindex->pprev->nAccumulatorCheckpoint; + + //Keep a list of checkpoints from the previous block so that we don't delete them + list listCheckpointsPrev; + for (auto denom : zerocoinDenomList) + listCheckpointsPrev.emplace_back(ParseChecksum(nCheckpointPrev, denom)); + + while (true) { + uint256 nCheckpointDelete = pindex->nAccumulatorCheckpoint; + + for (auto denom : zerocoinDenomList) { + uint32_t nChecksumDelete = ParseChecksum(nCheckpointDelete, denom); + if (count(listCheckpointsPrev.begin(), listCheckpointsPrev.end(), nCheckpointDelete)) + continue; + EraseChecksum(nChecksumDelete); + } + LogPrintf("%s : erasing checksums for block %d\n", __func__, pindex->nHeight); + + if (pindex->nHeight + 1 <= nEndHeight) + pindex = chainActive.Next(pindex); + else + break; + } + + return true; +} + +//Get checkpoint value for a specific block height +bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint) +{ + if (nHeight <= chainActive.Height() && chainActive[nHeight]->GetBlockHeader().nVersion < Params().Zerocoin_HeaderVersion()) { + nCheckpoint = 0; + return true; + } + + //the checkpoint is updated every ten blocks, return current active checkpoint if not update block + if (nHeight % 10 != 0) { + nCheckpoint = chainActive[nHeight - 1]->nAccumulatorCheckpoint; + return true; + } + + //set the accumulators to last checkpoint value + AccumulatorMap mapAccumulators; + if (!mapAccumulators.Load(chainActive[nHeight - 1]->nAccumulatorCheckpoint)) { + if (chainActive[nHeight - 1]->nAccumulatorCheckpoint == 0) { + //Before zerocoin is fully activated so set to init state + mapAccumulators.Reset(); + } else { + LogPrintf("%s: failed to reset to previous checkpoint\n", __func__); + return false; + } + } + + //Accumulate all coins over the last ten blocks that havent been accumulated (height - 20 through height - 11) + int nTotalMintsFound = 0; + CBlockIndex *pindex = chainActive[nHeight - 20]; + + while (pindex->nHeight < nHeight - 10) { + // checking whether we should stop this process due to a shutdown request + if (ShutdownRequested()) { + return false; + } + + //make sure this block is eligible for accumulation + if (pindex->GetBlockHeader().nVersion < Params().Zerocoin_HeaderVersion()) { + pindex = chainActive[pindex->nHeight + 1]; + continue; + } + + //grab mints from this block + CBlock block; + if(!ReadBlockFromDisk(block, pindex)) { + LogPrint("zero","%s: failed to read block from disk\n", __func__); + return false; + } + + std::list listPubcoins; + if (!BlockToPubcoinList(block, listPubcoins)) { + LogPrint("zero","%s: failed to get zerocoin mintlist from block %n\n", __func__, pindex->nHeight); + return false; + } + + nTotalMintsFound += listPubcoins.size(); + LogPrint("zero", "%s found %d mints\n", __func__, listPubcoins.size()); + + //add the pubcoins to accumulator + for (const PublicCoin pubcoin : listPubcoins) { + if(!mapAccumulators.Accumulate(pubcoin, true)) { + LogPrintf("%s: failed to add pubcoin to accumulator at height %n\n", __func__, pindex->nHeight); + return false; + } + } + pindex = chainActive.Next(pindex); + } + + // if there were no new mints found, the accumulator checkpoint will be the same as the last checkpoint + if (nTotalMintsFound == 0) { + nCheckpoint = chainActive[nHeight - 1]->nAccumulatorCheckpoint; + } + else + nCheckpoint = mapAccumulators.GetCheckpoint(); + + // make sure that these values are databased because reorgs may have deleted the checksums from DB + DatabaseChecksums(mapAccumulators); + + LogPrint("zero", "%s checkpoint=%s\n", __func__, nCheckpoint.GetHex()); + return true; +} + +bool GenerateAccumulatorWitness(const PublicCoin &coin, Accumulator& accumulator, AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, string& strError) +{ + uint256 txid; + if (!zerocoinDB->ReadCoinMint(coin.getValue(), txid)) { + LogPrint("zero","%s failed to read mint from db\n", __func__); + return false; + } + + CTransaction txMinted; + uint256 hashBlock; + if (!GetTransaction(txid, txMinted, hashBlock)) { + LogPrint("zero","%s failed to read tx\n", __func__); + return false; + } + + int nHeightMintAdded = mapBlockIndex[hashBlock]->nHeight; + uint256 nCheckpointBeforeMint = 0; + CBlockIndex* pindex = chainActive[nHeightMintAdded]; + int nChanges = 0; + + //find the checksum when this was added to the accumulator officially, which will be two checksum changes later + //reminder that checksums are generated when the block height is a multiple of 10 + while (pindex->nHeight < chainActive.Tip()->nHeight - 1) { + if (pindex->nHeight == nHeightMintAdded) { + pindex = chainActive[pindex->nHeight + 1]; + continue; + } + + //check if the next checksum was generated + if (pindex->nHeight % 10 == 0) { + nChanges++; + + if (nChanges == 1) { + nCheckpointBeforeMint = pindex->nAccumulatorCheckpoint; + break; + } + } + pindex = chainActive.Next(pindex); + } + + //the height to start accumulating coins to add to witness + int nAccStartHeight = nHeightMintAdded - (nHeightMintAdded % 10); + + //Get the accumulator that is right before the cluster of blocks containing our mint was added to the accumulator + CBigNum bnAccValue = 0; + if (GetAccumulatorValueFromDB(nCheckpointBeforeMint, coin.getDenomination(), bnAccValue)) { + if (bnAccValue > 0) { + accumulator.setValue(bnAccValue); + witness.resetValue(accumulator, coin); + } + } + + //security level: this is an important prevention of tracing the coins via timing. Security level represents how many checkpoints + //of accumulated coins are added *beyond* the checkpoint that the mint being spent was added too. If each spend added the exact same + //amounts of checkpoints after the mint was accumulated, then you could know the range of blocks that the mint originated from. + if (nSecurityLevel < 100) { + //add some randomness to the user's selection so that it is not always the same + nSecurityLevel += CBigNum::randBignum(10).getint(); + + //security level 100 represents adding all available coins that have been accumulated - user did not select this + if (nSecurityLevel >= 100) + nSecurityLevel = 99; + } + + //add the pubcoins (zerocoinmints that have been published to the chain) up to the next checksum starting from the block + pindex = chainActive[nAccStartHeight]; + int nChainHeight = chainActive.Height(); + int nHeightStop = nChainHeight % 10; + nHeightStop = nChainHeight - nHeightStop - 20; // at least two checkpoints deep + int nCheckpointsAdded = 0; + nMintsAdded = 0; + while (pindex->nHeight < nHeightStop + 1) { + if (pindex->nHeight != nAccStartHeight && pindex->pprev->nAccumulatorCheckpoint != pindex->nAccumulatorCheckpoint) + ++nCheckpointsAdded; + + //if a new checkpoint was generated on this block, and we have added the specified amount of checkpointed accumulators, + //then initialize the accumulator at this point and break + if ((pindex->nHeight >= nHeightStop || (nSecurityLevel != 100 && nCheckpointsAdded >= nSecurityLevel))) { + uint32_t nChecksum = ParseChecksum(chainActive[pindex->nHeight + 10]->nAccumulatorCheckpoint, coin.getDenomination()); + CBigNum bnAccValue = 0; + if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnAccValue)) { + LogPrintf("%s : failed to find checksum in database for accumulator\n", __func__); + return false; + } + accumulator.setValue(bnAccValue); + break; + } + + // if this block contains mints of the denomination that is being spent, then add them to the witness + if (pindex->MintedDenomination(coin.getDenomination())) { + //grab mints from this block + CBlock block; + if(!ReadBlockFromDisk(block, pindex)) { + LogPrintf("%s: failed to read block from disk while adding pubcoins to witness\n", __func__); + return false; + } + + list listPubcoins; + if(!BlockToPubcoinList(block, listPubcoins)) { + LogPrintf("%s: failed to get zerocoin mintlist from block %n\n", __func__, pindex->nHeight); + return false; + } + + //add the mints to the witness + for (const PublicCoin pubcoin : listPubcoins) { + if (pubcoin.getDenomination() != coin.getDenomination()) + continue; + + if (pindex->nHeight == nHeightMintAdded && pubcoin.getValue() == coin.getValue()) + continue; + + witness.addRawValue(pubcoin.getValue()); + ++nMintsAdded; + } + } + + pindex = chainActive[pindex->nHeight + 1]; + } + + if (nMintsAdded < Params().Zerocoin_RequiredAccumulation()) { + strError = _(strprintf("Less than %d mints added, unable to create spend", Params().Zerocoin_RequiredAccumulation()).c_str()); + LogPrintf("%s : %s\n", __func__, strError); + return false; + } + + // calculate how many mints of this denomination existed in the accumulator we initialized + int nZerocoinStartHeight = GetZerocoinStartHeight(); + pindex = chainActive[nZerocoinStartHeight]; + while (pindex->nHeight < nAccStartHeight) { + nMintsAdded += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), coin.getDenomination()); + pindex = chainActive[pindex->nHeight + 1]; + } + + LogPrint("zero","%s : %d mints added to witness\n", __func__, nMintsAdded); + return true; +} \ No newline at end of file diff --git a/src/accumulators.h b/src/accumulators.h new file mode 100644 index 000000000..c3ed547ee --- /dev/null +++ b/src/accumulators.h @@ -0,0 +1,24 @@ +// Copyright (c) 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 BWK_ACCUMULATORS_H +#define BWK_ACCUMULATORS_H + +#include "libzerocoin/Accumulator.h" +#include "libzerocoin/Denominations.h" +#include "libzerocoin/Coin.h" +#include "primitives/zerocoin.h" +#include "uint256.h" + +bool GenerateAccumulatorWitness(const libzerocoin::PublicCoin &coin, libzerocoin::Accumulator& accumulator, libzerocoin::AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, std::string& strError); +bool GetAccumulatorValueFromDB(uint256 nCheckpoint, libzerocoin::CoinDenomination denom, CBigNum& bnAccValue); +bool GetAccumulatorValueFromChecksum(uint32_t nChecksum, bool fMemoryOnly, CBigNum& bnAccValue); +void AddAccumulatorChecksum(const uint32_t nChecksum, const CBigNum &bnValue, bool fMemoryOnly); +bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint); +bool LoadAccumulatorValuesFromDB(const uint256 nCheckpoint); +bool EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nCheckpointPrevious); +uint32_t ParseChecksum(uint256 nChecksum, libzerocoin::CoinDenomination denomination); +uint32_t GetChecksum(const CBigNum &bnValue); + +#endif //BWK_ACCUMULATORS_H diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 80aa3277b..1f005ad3d 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2014-2016 The Dash developers +// Copyright (c) 2015-2017 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 "activemasternode.h" #include "addrman.h" diff --git a/src/activemasternode.h b/src/activemasternode.h index f0a4fce64..071956f31 100644 --- a/src/activemasternode.h +++ b/src/activemasternode.h @@ -1,8 +1,8 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2012 The Bitcoin developers -// Copyright (c) 2015-2016 The Dash developers +// Copyright (c) 2014-2016 The Dash developers +// Copyright (c) 2015-2017 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 ACTIVEMASTERNODE_H #define ACTIVEMASTERNODE_H diff --git a/src/bip38.cpp b/src/bip38.cpp index 211c6173c..f7fc01bde 100644 --- a/src/bip38.cpp +++ b/src/bip38.cpp @@ -1,3 +1,6 @@ +// Copyright (c) 2017 The PIVX Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "bip38.h" #include "base58.h" @@ -74,7 +77,7 @@ std::string AddressToBip38Hash(std::string address) return HexStr(addrCheck).substr(0, 8); } -std::string BIP38_Encrypt(std::string strAddress, std::string strPassphrase, uint256 privKey) +std::string BIP38_Encrypt(std::string strAddress, std::string strPassphrase, uint256 privKey, bool fCompressed) { string strAddressHash = AddressToBip38Hash(strAddress); @@ -103,7 +106,10 @@ std::string BIP38_Encrypt(std::string strAddress, std::string strPassphrase, uin uint512 encrypted2; AES_encrypt(block2.begin(), encrypted2.begin(), &key); - uint512 encryptedKey(ReverseEndianString("0142E0" + strAddressHash)); + string strPrefix = "0142"; + strPrefix += (fCompressed ? "E0" : "C0"); + + uint512 encryptedKey(ReverseEndianString(strPrefix + strAddressHash)); //add encrypted1 to the end of encryptedKey encryptedKey = encryptedKey | (encrypted1 << 56); @@ -111,7 +117,14 @@ std::string BIP38_Encrypt(std::string strAddress, std::string strPassphrase, uin //add encrypted2 to the end of encryptedKey encryptedKey = encryptedKey | (encrypted2 << (56 + 128)); - //TODO: ensure +43 works on different OS + //Base58 checksum is the 4 bytes of dSHA256 hash of the encrypted key + uint256 hashChecksum = Hash(encryptedKey.begin(), encryptedKey.begin() + 39); + uint512 b58Checksum(hashChecksum.ToString().substr(64 - 8, 8)); + + // append the encrypted key with checksum (currently occupies 312 bits) + encryptedKey = encryptedKey | (b58Checksum << 312); + + //43 bytes is the total size that we are encoding return EncodeBase58(encryptedKey.begin(), encryptedKey.begin() + 43); } diff --git a/src/bip38.h b/src/bip38.h index 8cb746869..c1ffd48af 100644 --- a/src/bip38.h +++ b/src/bip38.h @@ -1,3 +1,7 @@ +// Copyright (c) 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 BITCOIN_BIP38_H #define BITCOIN_BIP38_H @@ -24,13 +28,11 @@ void ComputePassfactor(std::string ownersalt, uint256 prefactor, uint256& passfa bool ComputePasspoint(uint256 passfactor, CPubKey& passpoint); - void ComputeSeedBPass(CPubKey passpoint, std::string strAddressHash, std::string strOwnerSalt, uint512& seedBPass); - void ComputeFactorB(uint256 seedB, uint256& factorB); -std::string BIP38_Encrypt(std::string strAddress, std::string strPassphrase, uint256 privKey); +std::string BIP38_Encrypt(std::string strAddress, std::string strPassphrase, uint256 privKey, bool fCompressed); bool BIP38_Decrypt(std::string strPassphrase, std::string strEncryptedKey, uint256& privKey, bool& fCompressed); std::string AddressToBip38Hash(std::string address); diff --git a/src/bulwark-cli.cpp b/src/bulwark-cli.cpp index 5ba64ed01..f65c22af5 100644 --- a/src/bulwark-cli.cpp +++ b/src/bulwark-cli.cpp @@ -15,12 +15,13 @@ #include +#include + #define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */ using namespace std; using namespace boost; using namespace boost::asio; -using namespace json_spirit; std::string HelpMessageCli() { @@ -99,14 +100,8 @@ static bool AppInitRPC(int argc, char* argv[]) return true; } -Object CallRPC(const string& strMethod, const Array& params) +UniValue CallRPC(const string& strMethod, const UniValue& params) { - if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") - throw runtime_error(strprintf( - _("You must set rpcpassword= in the configuration file:\n%s\n" - "If the file does not exist, create it with owner-readable-only file permissions."), - GetConfigFile().string().c_str())); - // Connect to localhost bool fUseSSL = GetBoolArg("-rpcssl", false); asio::io_service io_service; @@ -120,10 +115,24 @@ Object CallRPC(const string& strMethod, const Array& params) if (!fConnected) throw CConnectionFailed("couldn't connect to server"); + // Find credentials to use + std::string strRPCUserColonPass; + if (mapArgs["-rpcpassword"] == "") { + // Try fall back to cookie-based authentication if no password is provided + if (!GetAuthCookie(&strRPCUserColonPass)) { + throw runtime_error(strprintf( + _("You must set rpcpassword= in the configuration file:\n%s\n" + "If the file does not exist, create it with owner-readable-only file permissions."), + GetConfigFile().string().c_str())); + + } + } else { + strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; + } + // HTTP basic authentication - string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]); map mapRequestHeaders; - mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64; + mapRequestHeaders["Authorization"] = string("Basic ") + EncodeBase64(strRPCUserColonPass); // Send request string strRequest = JSONRPCRequest(strMethod, params, 1); @@ -147,10 +156,10 @@ Object CallRPC(const string& strMethod, const Array& params) throw runtime_error("no response from server"); // Parse reply - Value valReply; - if (!read_string(strReply, valReply)) + UniValue valReply(UniValue::VSTR); + if (!valReply.read(strReply)) throw runtime_error("couldn't parse reply from server"); - const Object& reply = valReply.get_obj(); + const UniValue& reply = valReply.get_obj(); if (reply.empty()) throw runtime_error("expected reply to have result, error and id properties"); @@ -175,35 +184,34 @@ int CommandLineRPC(int argc, char* argv[]) // Parameters default to strings std::vector strParams(&argv[2], &argv[argc]); - Array params = RPCConvertValues(strMethod, strParams); + UniValue params = RPCConvertValues(strMethod, strParams); // Execute and handle connection failures with -rpcwait const bool fWait = GetBoolArg("-rpcwait", false); do { try { - const Object reply = CallRPC(strMethod, params); + const UniValue reply = CallRPC(strMethod, params); // Parse reply - const Value& result = find_value(reply, "result"); - const Value& error = find_value(reply, "error"); + const UniValue& result = find_value(reply, "result"); + const UniValue& error = find_value(reply, "error"); - if (error.type() != null_type) { + if (!error.isNull()) { // Error - const int code = find_value(error.get_obj(), "code").get_int(); + int code = error["code"].get_int(); if (fWait && code == RPC_IN_WARMUP) throw CConnectionFailed("server in warmup"); - strPrint = "error: " + write_string(error, false); + strPrint = "error: " + error.write(); nRet = abs(code); } else { // Result - if (result.type() == null_type) + if (result.isNull()) strPrint = ""; - else if (result.type() == str_type) + else if (result.isStr()) strPrint = result.get_str(); else - strPrint = write_string(result, true); + strPrint = result.write(2); } - // Connection succeeded, no need to retry. break; } catch (const CConnectionFailed& e) { diff --git a/src/bulwark-tx.cpp b/src/bulwark-tx.cpp index ffd9122c6..349e3cb3b 100644 --- a/src/bulwark-tx.cpp +++ b/src/bulwark-tx.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,7 +13,7 @@ #include "script/script.h" #include "script/sign.h" #include "ui_interface.h" // for _(...) -#include "univalue/univalue.h" +#include #include "util.h" #include "utilmoneystr.h" #include "utilstrencodings.h" @@ -190,7 +191,8 @@ static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput) uint256 txid(strTxid); static const unsigned int minTxOutSz = 9; - static const unsigned int maxVout = MAX_BLOCK_SIZE / minTxOutSz; + unsigned int nMaxSize = MAX_BLOCK_SIZE_LEGACY; + static const unsigned int maxVout = nMaxSize / minTxOutSz; // extract and validate vout string strVout = strInput.substr(pos + 1, string::npos); @@ -349,7 +351,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) UniValue keysObj = registers["privatekeys"]; fGivenKeys = true; - for (unsigned int kidx = 0; kidx < keysObj.count(); kidx++) { + for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) { if (!keysObj[kidx].isStr()) throw runtime_error("privatekey not a string"); CBitcoinSecret vchSecret; @@ -366,7 +368,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) throw runtime_error("prevtxs register variable must be set."); UniValue prevtxsObj = registers["prevtxs"]; { - for (unsigned int previdx = 0; previdx < prevtxsObj.count(); previdx++) { + for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) { UniValue prevOut = prevtxsObj[previdx]; if (!prevOut.isObject()) throw runtime_error("expected prevtxs internal object"); diff --git a/src/chain.h b/src/chain.h index 597130111..96d1963d9 100644 --- a/src/chain.h +++ b/src/chain.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,6 +12,7 @@ #include "tinyformat.h" #include "uint256.h" #include "util.h" +#include "libzerocoin/Denominations.h" #include @@ -171,10 +173,15 @@ class CBlockIndex unsigned int nTime; unsigned int nBits; unsigned int nNonce; + uint256 nAccumulatorCheckpoint; //! (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; @@ -203,6 +210,12 @@ class CBlockIndex nTime = 0; nBits = 0; nNonce = 0; + nAccumulatorCheckpoint = 0; + // Start supply of each denomination with 0s + for (auto& denom : libzerocoin::zerocoinDenomList) { + mapZerocoinSupply.insert(make_pair(denom, 0)); + } + vMintDenominationsInBlock.clear(); } CBlockIndex() @@ -219,6 +232,8 @@ class CBlockIndex nTime = block.nTime; nBits = block.nBits; nNonce = block.nNonce; + if(block.nVersion > 3) + nAccumulatorCheckpoint = block.nAccumulatorCheckpoint; //Proof of Stake bnChainTrust = uint256(); @@ -238,6 +253,7 @@ class CBlockIndex nStakeTime = 0; } } + CDiskBlockPos GetBlockPos() const { @@ -269,9 +285,24 @@ class CBlockIndex block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; + block.nAccumulatorCheckpoint = nAccumulatorCheckpoint; return block; } + int64_t GetZerocoinSupply() const + { + int64_t nTotal = 0; + for (auto& denom : libzerocoin::zerocoinDenomList) { + nTotal += libzerocoin::ZerocoinDenominationToAmount(denom) * mapZerocoinSupply.at(denom); + } + return nTotal; + } + + bool MintedDenomination(libzerocoin::CoinDenomination denom) const + { + return std::find(vMintDenominationsInBlock.begin(), vMintDenominationsInBlock.end(), denom) != vMintDenominationsInBlock.end(); + } + uint256 GetBlockHash() const { return *phashBlock; @@ -441,6 +472,12 @@ class CDiskBlockIndex : public CBlockIndex READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); + if(this->nVersion > 3) { + READWRITE(nAccumulatorCheckpoint); + READWRITE(mapZerocoinSupply); + READWRITE(vMintDenominationsInBlock); + } + } uint256 GetBlockHash() const @@ -452,6 +489,7 @@ class CDiskBlockIndex : public CBlockIndex block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; + block.nAccumulatorCheckpoint = nAccumulatorCheckpoint; return block.GetHash(); } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index c55d63c4d..d16f844d9 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -6,6 +6,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "libzerocoin/Params.h" #include "chainparams.h" #include "random.h" @@ -46,12 +47,12 @@ static void convertSeed6(std::vector& vSeedsOut, const SeedSpec6* data vSeedsOut.push_back(addr); } } + // What makes a good checkpoint block? // + Is surrounded by blocks with reasonable timestamps // (no blocks before with a timestamp after, none after with // timestamp before) // + Contains no strange transactions - static Checkpoints::MapCheckpoints mapCheckpoints = boost::assign::map_list_of (0, uint256("0x0000068e7ab8e264f6759d2d81b29e8b917c10b04db47a9a0bb3cba3fba5d574")) @@ -65,12 +66,13 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (59200, uint256("000000000000a4d9ec8b2fa71028b1def77606b015622949a997d92503bbcc37")) (59400, uint256("000000000000880f972b364e7dc7c67093109e862b23ffecf2d3f2f87c24d0cf")) (95600, uint256("0000000000084e401f85d9f393e2d61428352f20bbb51ccfe2483e49423b89ce")) - (173559, uint256("0000000000002b887e1d437a7a41dc628f96f45c1cc63f13e9fb518ca1ae3883")); + (173559, uint256("0000000000002b887e1d437a7a41dc628f96f45c1cc63f13e9fb518ca1ae3883")) + (273433, uint256("65e0e26d76bb5e3fc27fe0fefd9071f5d3a705b2d26ee76b20b9481217425dc2")); static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1528675501,// * UNIX timestamp of last checkpoint block - 311898, // * total number of transactions between genesis and last checkpoint + 1538006698,// * UNIX timestamp of last checkpoint block + 537501, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 2000 // * estimated number of transactions per day after checkpoint }; @@ -82,6 +84,7 @@ static const Checkpoints::CCheckpointData dataTestnet = { 1514516171, 0, 250}; + static Checkpoints::MapCheckpoints mapCheckpointsRegtest = boost::assign::map_list_of(0, uint256("0x001")); static const Checkpoints::CCheckpointData dataRegtest = { @@ -89,6 +92,16 @@ static const Checkpoints::CCheckpointData dataRegtest = { 1454124731, 0, 100}; + +libzerocoin::ZerocoinParams* CChainParams::Zerocoin_Params() const +{ + assert(this); + static CBigNum bnTrustedModulus(zerocoinModulus); + static libzerocoin::ZerocoinParams ZCParams = libzerocoin::ZerocoinParams(bnTrustedModulus); + + return &ZCParams; +} + class CMainParams : public CChainParams { public: @@ -126,6 +139,16 @@ class CMainParams : public CChainParams nRejectBlockOutdatedMajority = 950; nToCheckBlockUpgradeMajority = 1000; + /** + * Build the genesis block. Note that the output of the genesis coinbase cannot + * be spent as it did not originally exist in the database. + * + * CBlock(hash=00000ffd590b14, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=e0028e, nTime=1390095618, nBits=1e0ffff0, nNonce=28917698, vtx=1) + * CTransaction(hash=e0028e, ver=1, vin.size=1, vout.size=1, nLockTime=0) + * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d01044c5957697265642030392f4a616e2f3230313420546865204772616e64204578706572696d656e7420476f6573204c6976653a204f76657273746f636b2e636f6d204973204e6f7720416363657074696e6720426974636f696e73) + * CTxOut(nValue=50.00000000, scriptPubKey=0xA9037BAC7050C479B121CF) + * vMerkleTree: e0028e + */ const char* pszTimestamp = "November 30 2017 - Niger Approves Armed U.S. Drone Flights, Expanding Pentagon’s Role in Africa"; CMutableTransaction txNew; txNew.vin.resize(1); @@ -162,12 +185,11 @@ class CMainParams : public CChainParams base58Prefixes[SECRET_KEY] = std::vector(1, 212); base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x02)(0x2D)(0x25)(0x33).convert_to_container >(); base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x02)(0x21)(0x31)(0x2B).convert_to_container >(); - //BIP44 as defined by https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki + // BIP44 coin type is from https://github.com/satoshilabs/slips/blob/master/slip-0044.md base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0x77).convert_to_container >(); - convertSeed6(vFixedSeeds, pnSeed6_main, ARRAYLEN(pnSeed6_main)); - - fRequireRPCPassword = true; + convertSeed6(vFixedSeeds, pnSeed6_main, ARRAYLEN(pnSeed6_main)); + fMiningRequiresPeers = true; fAllowMinDifficultyBlocks = false; fDefaultConsistencyChecks = false; @@ -176,18 +198,41 @@ class CMainParams : public CChainParams fSkipProofOfWorkCheck = false; fTestnetToBeDeprecatedFieldRPC = false; fHeadersFirstSyncingActive = false; - + nPoolMaxTransactions = 3; strSporkKey = "0453748e298a34e32d760a3d64b7b517c952c10024a4160a3a746d9bce572f85e13ac6d4f518ac110ba807ce19fb657bc2696ca02013290e3fbe517adf09c95787"; strObfuscationPoolDummyAddress = "bDiJwVuKv9dcKBN4KCfX6UmXbkpqLfzGyf"; nStartMasternodePayments = 1511092620; + + /** Zerocoin */ + zerocoinModulus = "b2275261dcaa303374af30576c5f676c8c2f1596aae7814f932f08839d442a5b2f7eaac75ffe9481321cbaae1c48703eff" + "384222885cf9e07e3996fa36d25f0866a7f3834c2457b253b0bbbd0ec23036fcc6c84886cce4d6bcc917ce7fb40d3ffcc12984db02e55e4e" + "ccd205f7a239fe48ab27ea1124efa0a545ae434876b0b934ebcc54b03375c78bdbb1cde74c8e42048839e191f3986436f757c11d36b60942" + "f6b88f40acbcd4b36d82890e05b6e508192873dee5be51352e7215fbca7dfe30daac0efd8435426313557b1d193be3fa3be8c3c81f5501e0" + "52478afcfc1bd1f06ff429ecae3b682faa26bda5bb530fe1eca4d630fadc3b5d15e3d1feeeb161812894d3f17f497bb321c224f5419e30d2" + "b79511979fa41d24bc78c0aa18e12dc668b164841ce56bc8de5b7386cff2bb314b11094a4ad5661a7fd7b517181f8a999e61ddadc6936262" + "80b2692bc5b62bd328eb0b4c7d48b98942b0e6037add6568897f41adb825482057ae6224531047eef0cfd8f5510eb64e0610d83a1c7181"; + nMaxZerocoinSpendsPerTransaction = 7; // Assume about 20kb each + nMinZerocoinMintFee = 1 * CENT; //high fee required for zerocoin mints + nMintRequiredConfirmations = 20; //the maximum amount of confirmations until accumulated in 19 + nRequiredAccumulation = 1; + nDefaultSecurityLevel = 100; //full security level for accumulators + nZerocoinHeaderVersion = 4; //Block headers must be this version once zerocoin is active + nBudget_Fee_Confirmations = 6; // Number of confirmations for the finalization fee + + /** Staking Requirements */ + nStakeMinStartProtocol = 70850; // Starting protocol version (ActiveProtocol()) + nStakeMinConfirmations = 475; // Required number of confirmations + nStakeMinAmount = 100 * COIN; // Minimum required staking amount } + const Checkpoints::CCheckpointData& Checkpoints() const { return data; } }; static CMainParams mainParams; + /** * Testnet (v3) */ @@ -206,13 +251,13 @@ class CTestNetParams : public CMainParams vAlertPubKey = ParseHex("04795fde7bfc6347248a901aca81dd6a9f3acdeb5272f1c831f5147b139a4e1bacaa253541d9ebdfba982fb5cc45df3e34a8e98cdce9329037f009af217bc64ed9"); nDefaultPort = 42133; nMinerThreads = 0; - nTargetTimespan = 1 * 30; // 30 Seconds - nTargetSpacing = 1 * 30; // 30 Seconds - nTargetSpacingSlowLaunch = 1 * 30; // Kludgy but don't want to check for testnet each time in GetNextWorkRequired + nTargetTimespan = 1 * 15; // 30 Seconds + nTargetSpacing = 1 * 15; // 30 Seconds + nTargetSpacingSlowLaunch = 1 * 15; // Kludgy but don't want to check for testnet each time in GetNextWorkRequired - nLastPOWBlock = 1000; - nLastPOWBlockOld = 1100; - nLastSeeSawBlock = 1200; + nLastPOWBlock = 200; + nLastPOWBlockOld = 500; + nLastSeeSawBlock = 200; nMaturity = 15; nMaxMoneyOut = 33284220 * COIN; // 2032 Maximum nRampToBlock = 100; @@ -220,14 +265,16 @@ class CTestNetParams : public CMainParams nEnforceBlockUpgradeMajority = 51; nRejectBlockOutdatedMajority = 75; nToCheckBlockUpgradeMajority = 100; + nMasternodeCountDrift = 4; + nModifierUpdateBlock = 51197; //approx Mon, 17 Apr 2017 04:00:00 GMT //! Modify the testnet genesis block so the timestamp is valid for a later start. - genesis.nTime = 1514516171; - genesis.nNonce = 250375; + genesis.nTime = 1537896086; + genesis.nNonce = 2334133; genesis.nBits = bnProofOfWorkLimit.GetCompact(); - + hashGenesisBlock = genesis.GetHash(); - assert(hashGenesisBlock == uint256("0x000001a2f1a9a313468d66b81dd2cb199f6f8f5d426198a7c4daa9c3f9498285")); + assert(hashGenesisBlock == uint256("0x00000f8390c6d8820091f16f24b5d299a38d91372398288a5d67e84680eb0bf3")); assert(genesis.hashMerkleRoot == uint256("0x77976d6bd593c84063ac3937525bc15e25188d96871b13d4451ffc382999f64f")); vFixedSeeds.clear(); @@ -246,17 +293,25 @@ class CTestNetParams : public CMainParams // Testnet bulwark BIP44 coin type is '1' (All coin's testnet default) base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x01)(0x00)(0x00)(0x80).convert_to_container >(); convertSeed6(vFixedSeeds, pnSeed6_test, ARRAYLEN(pnSeed6_test)); - fRequireRPCPassword = true; + fMiningRequiresPeers = false; fAllowMinDifficultyBlocks = true; fDefaultConsistencyChecks = false; fRequireStandard = false; fMineBlocksOnDemand = false; fTestnetToBeDeprecatedFieldRPC = true; + nPoolMaxTransactions = 2; - strSporkKey = "04af2f9be75132357063236a59f9bf71ccb9ef8373c33146714ff4f6b1a3a2b97933c633f805c7b598ba023088bf13474e735b694d4959432bb58053910341bf66"; + strSporkKey = "048abad405bde958ad46d7eac0a359c80b001c3628cc1437a56420434ae6c2b4f1a18addd35a2e2b3c3bbe35d8b2bb6d387b4df3fac5156f92f8ded76f0cfc7a71"; strObfuscationPoolDummyAddress = "TUQ57Fbh1crybrDhV6X9SDH95H4oSq4v6p"; nStartMasternodePayments = 1420837558; //Fri, 09 Jan 2015 21:05:58 GMT + 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 + + /** Staking Requirements */ + nStakeMinStartProtocol = 70850; // Starting protocol version (ActiveProtocol()) + nStakeMinConfirmations = 30; // Required number of confirmations + nStakeMinAmount = 500 * COIN; // Minimum required staking amount } const Checkpoints::CCheckpointData& Checkpoints() const { @@ -264,6 +319,7 @@ class CTestNetParams : public CMainParams } }; static CTestNetParams testNetParams; + /** * Regression test */ @@ -286,12 +342,13 @@ class CRegTestParams : public CTestNetParams genesis.nTime = 1454124731; genesis.nBits = 0x207fffff; genesis.nNonce = 12345; + hashGenesisBlock = genesis.GetHash(); nDefaultPort = 51476; // assert(hashGenesisBlock == uint256("0x4f023a2120d9127b21bbad01724fdb79b519f593f2a85b60d3d79160ec5f29df")); vFixedSeeds.clear(); //! Testnet mode doesn't have any fixed seeds. vSeeds.clear(); //! Testnet mode doesn't have any DNS seeds. - fRequireRPCPassword = false; + fMiningRequiresPeers = false; fAllowMinDifficultyBlocks = true; fDefaultConsistencyChecks = true; @@ -305,6 +362,7 @@ class CRegTestParams : public CTestNetParams } }; static CRegTestParams regTestParams; + /** * Unit test */ @@ -318,17 +376,19 @@ class CUnitTestParams : public CMainParams, public CModifiableParams nDefaultPort = 51478; vFixedSeeds.clear(); //! Unit test mode doesn't have any fixed seeds. vSeeds.clear(); //! Unit test mode doesn't have any DNS seeds. - fRequireRPCPassword = false; + fMiningRequiresPeers = false; fDefaultConsistencyChecks = true; fAllowMinDifficultyBlocks = false; fMineBlocksOnDemand = true; } + const Checkpoints::CCheckpointData& Checkpoints() const { // UnitTest share the same checkpoints as MAIN return data; } + //! Published setters to allow changing values in unit test cases virtual void setDefaultConsistencyChecks(bool afDefaultConsistencyChecks) { fDefaultConsistencyChecks = afDefaultConsistencyChecks; } virtual void setAllowMinDifficultyBlocks(bool afAllowMinDifficultyBlocks) { fAllowMinDifficultyBlocks = afAllowMinDifficultyBlocks; } @@ -338,18 +398,23 @@ class CUnitTestParams : public CMainParams, public CModifiableParams virtual void setToCheckBlockUpgradeMajority(int anToCheckBlockUpgradeMajority) { nToCheckBlockUpgradeMajority = anToCheckBlockUpgradeMajority; } }; static CUnitTestParams unitTestParams; + + static CChainParams* pCurrentParams = 0; + CModifiableParams* ModifiableParams() { assert(pCurrentParams); assert(pCurrentParams == &unitTestParams); return (CModifiableParams*)&unitTestParams; } + const CChainParams& Params() { assert(pCurrentParams); return *pCurrentParams; } + CChainParams& Params(CBaseChainParams::Network network) { switch (network) { @@ -366,16 +431,19 @@ CChainParams& Params(CBaseChainParams::Network network) return mainParams; } } + void SelectParams(CBaseChainParams::Network network) { SelectBaseParams(network); pCurrentParams = &Params(network); } + bool SelectParamsFromCommandLine() { CBaseChainParams::Network network = NetworkIdFromCommandLine(); if (network == CBaseChainParams::MAX_NETWORK_TYPES) return false; + SelectParams(network); return true; } diff --git a/src/chainparams.h b/src/chainparams.h index 744f76b18..9674ff8e3 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -1,5 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2014-2015 The Dash developers +// Copyright (c) 2015-2017 The PIVX Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,6 +14,7 @@ #include "protocol.h" #include "uint256.h" +#include "libzerocoin/Params.h" #include typedef unsigned char MessageStartChars[MESSAGE_START_SIZE]; @@ -56,7 +59,6 @@ class CChainParams /** Used if GenerateBitcoins is called with a negative number of threads */ int DefaultMinerThreads() const { return nMinerThreads; } const CBlock& GenesisBlock() const { return genesis; } - bool RequireRPCPassword() const { return fRequireRPCPassword; } /** Make miner wait to have peers to avoid wasting work */ bool MiningRequiresPeers() const { return fMiningRequiresPeers; } /** Headers first syncing is disabled */ @@ -73,13 +75,11 @@ class CChainParams int64_t TargetSpacing() const { return nTargetSpacing; } int64_t TargetSpacingSlowLaunch() const { return nTargetSpacingSlowLaunch; } int64_t Interval() const { return nTargetTimespan / nTargetSpacing; } - int LAST_POW_BLOCK() const { return nLastPOWBlock; } int LAST_POW_BLOCK_OLD() const { return nLastPOWBlockOld; } int LAST_SEESAW_BLOCK() const { return nLastSeeSawBlock; } /** Slow Start, Ramp up linearly to block **/ int RAMP_TO_BLOCK() const { return nRampToBlock; } int COINBASE_MATURITY() const { return nMaturity; } - int ModifierUpgradeBlock() const { return nModifierUpdateBlock; } CAmount MaxMoneyOut() const { return nMaxMoneyOut; } /** The masternode count that we will allow the see-saw reward payments to be off by */ @@ -98,8 +98,28 @@ class CChainParams std::string SporkKey() const { return strSporkKey; } std::string ObfuscationPoolDummyAddress() const { return strObfuscationPoolDummyAddress; } int64_t StartMasternodePayments() const { return nStartMasternodePayments; } + int64_t Budget_Fee_Confirmations() const { return nBudget_Fee_Confirmations; } CBaseChainParams::Network NetworkID() const { return networkID; } + /** Zerocoin **/ + std::string Zerocoin_Modulus() const { return zerocoinModulus; } + libzerocoin::ZerocoinParams* Zerocoin_Params() const; + int Zerocoin_MaxSpendsPerTransaction() const { return nMaxZerocoinSpendsPerTransaction; } + CAmount Zerocoin_MintFee() const { return nMinZerocoinMintFee; } + int Zerocoin_MintRequiredConfirmations() const { return nMintRequiredConfirmations; } + int Zerocoin_RequiredAccumulation() const { return nRequiredAccumulation; } + int Zerocoin_DefaultSpendSecurity() const { return nDefaultSecurityLevel; } + int Zerocoin_HeaderVersion() const { return nZerocoinHeaderVersion; } + + /** Height or Time Based Activations **/ + int ModifierUpgradeBlock() const { return nModifierUpdateBlock; } + int LAST_POW_BLOCK() const { return nLastPOWBlock; } + + /** Staking Requirements */ + int Stake_MinProtocol() const { return nStakeMinStartProtocol; } + int Stake_MinConfirmations() const { return nStakeMinConfirmations; } + CAmount Stake_MinAmount() const { return nStakeMinAmount; } + protected: CChainParams() {} @@ -131,7 +151,6 @@ class CChainParams std::string strNetworkID; CBlock genesis; std::vector vFixedSeeds; - bool fRequireRPCPassword; bool fMiningRequiresPeers; bool fAllowMinDifficultyBlocks; bool fDefaultConsistencyChecks; @@ -144,9 +163,22 @@ class CChainParams std::string strSporkKey; std::string strObfuscationPoolDummyAddress; int64_t nStartMasternodePayments; + std::string zerocoinModulus; + int nMaxZerocoinSpendsPerTransaction; + CAmount nMinZerocoinMintFee; + int nMintRequiredConfirmations; + int nRequiredAccumulation; + int nDefaultSecurityLevel; + int nZerocoinHeaderVersion; + int64_t nBudget_Fee_Confirmations; + + /** Staking Requirements */ + int nStakeMinStartProtocol; + int nStakeMinConfirmations; + CAmount nStakeMinAmount; }; -/** +/** * Modifiable parameters interface is used by test cases to adapt the parameters in order * to test specific features more easily. Test cases should always restore the previous * values after finalization. diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index b9d1f5140..489e8217f 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -28,7 +28,7 @@ static const double SIGCHECK_VERIFICATION_FACTOR = 5.0; bool fEnabled = true; -bool CheckBlock(int nHeight, const uint256& hash) +bool CheckBlock(int nHeight, const uint256& hash, bool fMatchesCheckpoint) { if (!fEnabled) return true; @@ -36,7 +36,8 @@ bool CheckBlock(int nHeight, const uint256& hash) const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints; MapCheckpoints::const_iterator i = checkpoints.find(nHeight); - if (i == checkpoints.end()) return true; + // If looking for an exact match, then return false + if (i == checkpoints.end()) return !fMatchesCheckpoint; return hash == i->second; } diff --git a/src/checkpoints.h b/src/checkpoints.h index c21294c0b..2fdb2c978 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -27,7 +27,7 @@ struct CCheckpointData { }; //! Returns true if block passes checkpoint checks -bool CheckBlock(int nHeight, const uint256& hash); +bool CheckBlock(int nHeight, const uint256& hash, bool fMatchesCheckpoint = false); //! Return conservative estimate of total number of blocks, 0 if unknown int GetTotalBlocksEstimate(); diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 4128c4316..98ce1d088 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -43,7 +43,6 @@ const std::string CLIENT_NAME("Bulwark Core"); #endif //! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. -#define GIT_ARCHIVE 1 #ifdef GIT_ARCHIVE #define GIT_COMMIT_ID "cbcb549" #define GIT_COMMIT_DATE "Tue, 9 Feb 2016 16:54:57 -0500" @@ -89,7 +88,8 @@ static std::string FormatVersion(int nVersion) std::string FormatFullVersion() { - return CLIENT_BUILD; + return FormatVersion(CLIENT_VERSION); + //return CLIENT_BUILD; } /** diff --git a/src/clientversion.h b/src/clientversion.h index 28ab0dd3e..0dc692af7 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -14,9 +14,9 @@ */ //! These need to be macros, as clientversion.cpp's and bulwark*-res.rc's voodoo requires it -#define CLIENT_VERSION_MAJOR 1 -#define CLIENT_VERSION_MINOR 3 -#define CLIENT_VERSION_REVISION 1 +#define CLIENT_VERSION_MAJOR 2 +#define CLIENT_VERSION_MINOR 0 +#define CLIENT_VERSION_REVISION 0 #define CLIENT_VERSION_BUILD 0 //! Set to true for release, false for prerelease or test build diff --git a/src/coincontrol.h b/src/coincontrol.h index fcebaf49c..0e9ffdfca 100644 --- a/src/coincontrol.h +++ b/src/coincontrol.h @@ -1,4 +1,6 @@ // Copyright (c) 2011-2013 The Bitcoin developers +// Copyright (c) 2014-2016 The Dash developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -34,7 +36,7 @@ class CCoinControl destChange = CNoDestination(); setSelected.clear(); useSwiftTX = false; - useObfuScation = true; + useObfuScation = false; fAllowOtherInputs = false; fAllowWatchOnly = true; nMinimumTotalFee = 0; diff --git a/src/coins.cpp b/src/coins.cpp index e5e8ba8f0..81b141f57 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2012-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -222,6 +223,10 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const if (tx.IsCoinBase()) return 0; + //todo are there any security precautions to take here? + if (tx.IsZerocoinSpend()) + return tx.GetZerocoinSpent(); + CAmount nResult = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) nResult += GetOutputFor(tx.vin[i]).nValue; @@ -231,7 +236,7 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const { - if (!tx.IsCoinBase()) { + if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { 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 38bb877a0..13044a473 100644 --- a/src/coins.h +++ b/src/coins.h @@ -271,7 +271,7 @@ class CCoins //! check whether a particular output is still available bool IsAvailable(unsigned int nPos) const { - return (nPos < vout.size() && !vout[nPos].IsNull()); + return (nPos < vout.size() && !vout[nPos].IsNull() && !vout[nPos].scriptPubKey.IsZerocoinMint()); } //! check whether the entire CCoins is spent diff --git a/src/core_read.cpp b/src/core_read.cpp index b0ea3395d..c2e8c447f 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,7 +10,7 @@ #include "script/script.h" #include "serialize.h" #include "streams.h" -#include "univalue/univalue.h" +#include #include "util.h" #include "utilstrencodings.h" #include "version.h" @@ -31,7 +32,7 @@ CScript ParseScript(std::string s) static map mapOpNames; if (mapOpNames.empty()) { - for (int op = 0; op <= OP_NOP10; op++) { + for (int op = 0; op <= OP_ZEROCOINSPEND; op++) { // Allow OP_RESERVED to get into mapOpNames if (op < OP_NOP && op != OP_RESERVED) continue; diff --git a/src/core_write.cpp b/src/core_write.cpp index 10359fa5f..f0af3e619 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -10,7 +10,7 @@ #include "script/standard.h" #include "serialize.h" #include "streams.h" -#include "univalue/univalue.h" +#include #include "util.h" #include "utilmoneystr.h" #include "utilstrencodings.h" diff --git a/src/denomination_functions.cpp b/src/denomination_functions.cpp new file mode 100644 index 000000000..5087a8ebb --- /dev/null +++ b/src/denomination_functions.cpp @@ -0,0 +1,443 @@ +/** + * @file denominations_functions.cpp + * + * @brief Denomination functions for the Zerocoin library. + * + * @copyright Copyright 2017 PIVX Developers + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2015-2017 The PIVX developers + +#include "denomination_functions.h" + +using namespace libzerocoin; + +// ------------------------------------------------------------------------------------------------------- +// Number of coins used for either change or a spend given a map of coins used +// ------------------------------------------------------------------------------------------------------- +int getNumberOfCoinsUsed( + const std::map& mapChange) +{ + int nChangeCount = 0; + for (const auto& denom : zerocoinDenomList) { + nChangeCount += mapChange.at(denom); + } + return nChangeCount; +} + +// ------------------------------------------------------------------------------------------------------- +// Find the max CoinDenomination amongst held coins +// ------------------------------------------------------------------------------------------------------- +CoinDenomination getMaxDenomHeld( + const std::map& mapCoinsHeld) +{ + CoinDenomination maxDenom = ZQ_ERROR; + for (auto& coin : reverse_iterate(zerocoinDenomList)) { + if (mapCoinsHeld.at(coin)) { + maxDenom = coin; + break; + } + } + return maxDenom; +} +// ------------------------------------------------------------------------------------------------------- +// Get Exact Amount with CoinsHeld +// ------------------------------------------------------------------------------------------------------- +std::map getSpendCoins(const CAmount nValueTarget, + const std::map mapOfDenomsHeld) + +{ + std::map mapUsed; + CAmount nRemainingValue = nValueTarget; + // Initialize + for (const auto& denom : zerocoinDenomList) + mapUsed.insert(std::pair(denom, 0)); + + // Start with the Highest Denomination coin and grab coins as long as the remaining amount is greater than the + // current denomination value and we have the denom + for (auto& coin : reverse_iterate(zerocoinDenomList)) { + CAmount nValue = ZerocoinDenominationToAmount(coin); + do { + if ((nRemainingValue >= nValue) && (mapUsed.at(coin) < mapOfDenomsHeld.at(coin))) { + mapUsed.at(coin)++; + nRemainingValue -= nValue; + } + } while ((nRemainingValue >= nValue) && (mapUsed.at(coin) < mapOfDenomsHeld.at(coin))); + } + return mapUsed; +} + +// ------------------------------------------------------------------------------------------------------- +// Get change (no limits) +// ------------------------------------------------------------------------------------------------------- +std::map getChange(const CAmount nValueTarget) +{ + std::map mapChange; + CAmount nRemainingValue = nValueTarget; + // Initialize + for (const auto& denom : zerocoinDenomList) + mapChange.insert(std::pair(denom, 0)); + + // Start with the Highest Denomination coin and grab coins as long as the remaining amount is greater than the + // current denomination value + for (auto& coin : reverse_iterate(zerocoinDenomList)) { + CAmount nValue = ZerocoinDenominationToAmount(coin); + do { + if (nRemainingValue >= nValue) { + mapChange.at(coin)++; + nRemainingValue -= nValue; + } + } while (nRemainingValue >= nValue); + } + return mapChange; +} + +// ------------------------------------------------------------------------------------------------------- +// Attempt to use coins held to exactly reach nValueTarget, return mapOfDenomsUsed with the coin set used +// Return false if exact match is not possible +// ------------------------------------------------------------------------------------------------------- +bool getIdealSpends( + const CAmount nValueTarget, + const std::list& listMints, + const std::map mapOfDenomsHeld, + std::map& mapOfDenomsUsed) +{ + CAmount nRemainingValue = nValueTarget; + // Initialize + for (const auto& denom : zerocoinDenomList) + mapOfDenomsUsed.insert(std::pair(denom, 0)); + + // Start with the Highest Denomination coin and grab coins as long as the remaining amount is greater than the + // current denomination value + for (auto& coin : reverse_iterate(zerocoinDenomList)) { + for (const CZerocoinMint mint : listMints) { + if (mint.IsUsed()) continue; + if (nRemainingValue >= ZerocoinDenominationToAmount(coin) && coin == mint.GetDenomination()) { + mapOfDenomsUsed.at(coin)++; + nRemainingValue -= mint.GetDenominationAsAmount(); + } + if (nRemainingValue < ZerocoinDenominationToAmount(coin)) break; + } + } + return (nRemainingValue == 0); +} + +// ------------------------------------------------------------------------------------------------------- +// Return a list of Mint coins based on mapOfDenomsUsed and the overall value in nCoinsSpentValue +// ------------------------------------------------------------------------------------------------------- +std::vector getSpends( + const std::list& listMints, + std::map& mapOfDenomsUsed, + CAmount& nCoinsSpentValue) +{ + std::vector vSelectedMints; + nCoinsSpentValue = 0; + for (auto& coin : reverse_iterate(zerocoinDenomList)) { + do { + for (const CZerocoinMint mint : listMints) { + if (mint.IsUsed()) continue; + if (coin == mint.GetDenomination() && mapOfDenomsUsed.at(coin)) { + vSelectedMints.push_back(mint); + nCoinsSpentValue += ZerocoinDenominationToAmount(coin); + mapOfDenomsUsed.at(coin)--; + } + } + } while (mapOfDenomsUsed.at(coin)); + } + return vSelectedMints; +} +// ------------------------------------------------------------------------------------------------------- +// Just for printing/debuggin +// ------------------------------------------------------------------------------------------------------- +void listSpends(const std::vector& vSelectedMints) +{ + std::map mapZerocoinSupply; + for (auto& denom : libzerocoin::zerocoinDenomList) + mapZerocoinSupply.insert(std::make_pair(denom, 0)); + + for (const CZerocoinMint mint : vSelectedMints) { + libzerocoin::CoinDenomination denom = mint.GetDenomination(); + mapZerocoinSupply.at(denom)++; + } + + CAmount nTotal = 0; + for (auto& denom : libzerocoin::zerocoinDenomList) { + LogPrint("zero", "%s %d coins for denomination %d used\n", __func__, mapZerocoinSupply.at(denom), denom); + nTotal += libzerocoin::ZerocoinDenominationToAmount(denom); + } + LogPrint("zero", "Total value of coins %d\n", nTotal); +} + +// ------------------------------------------------------------------------------------------------------- +// Find the CoinDenomination with the most number for a given amount +// ------------------------------------------------------------------------------------------------------- +CoinDenomination getDenomWithMostCoins( + const std::map& mapOfDenomsUsed) +{ + CoinDenomination maxCoins = ZQ_ERROR; + CAmount nMaxNumber = 0; + for (const auto& denom : zerocoinDenomList) { + CAmount amount = mapOfDenomsUsed.at(denom); + if (amount > nMaxNumber) { + nMaxNumber = amount; + maxCoins = denom; + } + } + return maxCoins; +} +// ------------------------------------------------------------------------------------------------------- +// Get the next denomination above the current one. Return ZQ_ERROR if already at the highest +// ------------------------------------------------------------------------------------------------------- +CoinDenomination getNextHighestDenom(const CoinDenomination& this_denom) +{ + CoinDenomination nextValue = ZQ_ERROR; + for (const auto& denom : zerocoinDenomList) { + if (ZerocoinDenominationToAmount(denom) > ZerocoinDenominationToAmount(this_denom)) { + nextValue = denom; + break; + } + } + return nextValue; +} +// ------------------------------------------------------------------------------------------------------- +// Get the next denomination below the current one that is also amongst those held. +// Return ZQ_ERROR if none found +// ------------------------------------------------------------------------------------------------------- +CoinDenomination getNextLowerDenomHeld(const CoinDenomination& this_denom, + const std::map& mapCoinsHeld) +{ + CoinDenomination nextValue = ZQ_ERROR; + for (auto& denom : reverse_iterate(zerocoinDenomList)) { + if ((denom < this_denom) && (mapCoinsHeld.at(denom) != 0)) { + nextValue = denom; + break; + } + } + return nextValue; +} + +int minimizeChange( + int nMaxNumberOfSpends, + int nChangeCount, + const CoinDenomination nextToMaxDenom, + const CAmount nValueTarget, + const std::map& mapOfDenomsHeld, + std::map& mapOfDenomsUsed) +{ + // Now find out if possible without using 1 coin such that we have more spends but less change + // First get set of coins close to value but still less than value (since not exact) + CAmount nRemainingValue = nValueTarget; + CAmount AmountUsed = 0; + int nCoinCount = 0; + + // Re-clear this + std::map savedMapOfDenomsUsed = mapOfDenomsUsed; + for (const auto& denom : zerocoinDenomList) + mapOfDenomsUsed.at(denom) = 0; + + // Find the amount this is less than total but uses up higher denoms first, + // starting at the denom that is not greater than the overall total + for (const auto& denom : reverse_iterate(zerocoinDenomList)) { + if (denom <= nextToMaxDenom) { + CAmount nValue = ZerocoinDenominationToAmount(denom); + do { + if ((nRemainingValue > nValue) && (mapOfDenomsUsed.at(denom) < mapOfDenomsHeld.at(denom))) { + mapOfDenomsUsed.at(denom)++; + nRemainingValue -= nValue; + AmountUsed += nValue; + nCoinCount++; + } + } while ((nRemainingValue > nValue) && (mapOfDenomsUsed.at(denom) < mapOfDenomsHeld.at(denom))); + } + } + + // Now work way back up from the bottom filling in with the denom that we have that is just + // bigger than the remaining amount + // Shouldn't need more than one coin here? + for (const auto& denom : zerocoinDenomList) { + CAmount nValue = ZerocoinDenominationToAmount(denom); + if ((nValue > nRemainingValue) && (mapOfDenomsUsed.at(denom) < mapOfDenomsHeld.at(denom))) { + mapOfDenomsUsed.at(denom)++; + nRemainingValue -= nValue; + AmountUsed += nValue; + nCoinCount++; + } + if (nRemainingValue < 0) break; + } + + // This can still result in a case where you've used an extra spend than needed. + // e.g Spend of 26, while having 1*5 + 4*10 + // First stage may be 2*10+5 (i.e < 26) + // Second stage can be 3*10+5 (no more fives, so add a 10) + // So 5 is no longer needed and will become change also + + CAmount nAltChangeAmount = AmountUsed - nValueTarget; + std::map mapAltChange = getChange(nAltChangeAmount); + + // Check if there is overlap between change and spend denominations + // And if so, remove those that overlap + for (const auto& denom : zerocoinDenomList) { + do { + if (mapAltChange.at(denom) && mapOfDenomsUsed.at(denom)) { + mapOfDenomsUsed.at(denom)--; + mapAltChange.at(denom)--; + nCoinCount--; + CAmount nValue = ZerocoinDenominationToAmount(denom); + AmountUsed -= nValue; + } + } while (mapAltChange.at(denom) && mapOfDenomsUsed.at(denom)); + } + + // Still possible to have wrong mix. So meet exact amount found above - with least number of coins + mapOfDenomsUsed = getSpendCoins(AmountUsed, mapOfDenomsHeld); + nCoinCount = getNumberOfCoinsUsed(mapOfDenomsUsed); + + // Re-calculate change + nAltChangeAmount = AmountUsed - nValueTarget; + mapAltChange = getChange(nAltChangeAmount); + int AltChangeCount = getNumberOfCoinsUsed(mapAltChange); + + // Alternative method yields less mints and is less than MaxNumberOfSpends if true + if ((AltChangeCount < nChangeCount) && (nCoinCount <= nMaxNumberOfSpends)) { + return AltChangeCount; + } else { + // if we don't meet above go back to what we started with + mapOfDenomsUsed = savedMapOfDenomsUsed; + return nChangeCount; + } +} + + +// ------------------------------------------------------------------------------------------------------- +// Couldn't meet amount exactly, will need to generate change +// returning with a 0 means either too many spends or no change +// Latter should never happen since we should only get here if exact is not possible +// ------------------------------------------------------------------------------------------------------- +int calculateChange( + int nMaxNumberOfSpends, + bool fMinimizeChange, + const CAmount nValueTarget, + const std::map& mapOfDenomsHeld, + std::map& mapOfDenomsUsed) +{ + CoinDenomination minDenomOverTarget = ZQ_ERROR; + // Initialize + mapOfDenomsUsed.clear(); + for (const auto& denom : zerocoinDenomList) + mapOfDenomsUsed.insert(std::pair(denom, 0)); + + for (const auto& denom : zerocoinDenomList) { + if (nValueTarget < ZerocoinDenominationToAmount(denom) && mapOfDenomsHeld.at(denom)) { + minDenomOverTarget = denom; + break; + } + } + // OK so if != ZQ_ERROR we have a solution using 1 coin + if (minDenomOverTarget != ZQ_ERROR) { + mapOfDenomsUsed.at(minDenomOverTarget) = 1; + + // Now find out # of coins in change + CAmount nChangeAmount = ZerocoinDenominationToAmount(minDenomOverTarget) - nValueTarget; + std::map mapChange = getChange(nChangeAmount); + int nChangeCount = getNumberOfCoinsUsed(mapChange); + + if (fMinimizeChange) { + CoinDenomination nextToMaxDenom = getNextLowerDenomHeld(minDenomOverTarget, mapOfDenomsHeld); + int newChangeCount = minimizeChange(nMaxNumberOfSpends, nChangeCount, + nextToMaxDenom, nValueTarget, + mapOfDenomsHeld, mapOfDenomsUsed); + + // Alternative method yields less mints and is less than MaxNumberOfSpends if true + if (newChangeCount < nChangeCount) return newChangeCount; + + // Reclear + for (const auto& denom : zerocoinDenomList) + mapOfDenomsUsed.at(denom) = 0; + // Then reset as before previous clearing + mapOfDenomsUsed.at(minDenomOverTarget) = 1; + } + + return nChangeCount; + + } else { + // Try to meet a different way + for (const auto& denom : zerocoinDenomList) + mapOfDenomsUsed.at(denom) = 0; + CAmount nRemainingValue = nValueTarget; + int nCoinCount = 0; + CAmount AmountUsed = 0; + for (const auto& denom : reverse_iterate(zerocoinDenomList)) { + CAmount nValue = ZerocoinDenominationToAmount(denom); + do { + if (mapOfDenomsHeld.at(denom) && nRemainingValue > 0) { + mapOfDenomsUsed.at(denom)++; + AmountUsed += nValue; + nRemainingValue -= nValue; + nCoinCount++; + } + } while ((nRemainingValue > 0) && (mapOfDenomsUsed.at(denom) < mapOfDenomsHeld.at(denom))); + if (nRemainingValue < 0) break; + } + + CAmount nChangeAmount = AmountUsed - nValueTarget; + std::map mapChange = getChange(nChangeAmount); + int nMaxChangeCount = getNumberOfCoinsUsed(mapChange); + + // Instead get max Denom held + CoinDenomination maxDenomHeld = getMaxDenomHeld(mapOfDenomsHeld); + + // Assign for size (only) + std::map mapOfMinDenomsUsed = mapOfDenomsUsed; + + int nChangeCount = minimizeChange(nMaxNumberOfSpends, nMaxChangeCount, + maxDenomHeld, nValueTarget, + mapOfDenomsHeld, mapOfMinDenomsUsed); + + int nNumSpends = getNumberOfCoinsUsed(mapOfMinDenomsUsed); + + if (!fMinimizeChange && (nCoinCount < nNumSpends)) { + return nMaxChangeCount; + } + + mapOfDenomsUsed = mapOfMinDenomsUsed; + return nChangeCount; + } +} + +// ------------------------------------------------------------------------------------------------------- +// Given a Target Spend Amount, attempt to meet it with a set of coins where less than nMaxNumberOfSpends +// 'spends' are required +// ------------------------------------------------------------------------------------------------------- +std::vector SelectMintsFromList(const CAmount nValueTarget, CAmount& nSelectedValue, int nMaxNumberOfSpends, bool fMinimizeChange, + int& nCoinsReturned, const std::list& listMints, + const std::map mapOfDenomsHeld, int& nNeededSpends) +{ + std::vector vSelectedMints; + std::map mapOfDenomsUsed; + + nNeededSpends = 0; + bool fCanMeetExactly = getIdealSpends(nValueTarget, listMints, mapOfDenomsHeld, mapOfDenomsUsed); + if (fCanMeetExactly) { + nCoinsReturned = 0; + nSelectedValue = nValueTarget; + vSelectedMints = getSpends(listMints, mapOfDenomsUsed, nSelectedValue); + // If true, we are good and done! + if (vSelectedMints.size() <= (size_t)nMaxNumberOfSpends) { + return vSelectedMints; + } + else { + nNeededSpends = vSelectedMints.size(); + } + } + // Since either too many spends needed or can not spend the exact amount, + // calculate the change needed and the map of coins used + nCoinsReturned = calculateChange(nMaxNumberOfSpends, fMinimizeChange, nValueTarget, mapOfDenomsHeld, mapOfDenomsUsed); + if (nCoinsReturned == 0) { + LogPrint("zero", "%s: Problem getting change (TBD) or Too many spends %d\n", __func__, nValueTarget); + vSelectedMints.clear(); + } else { + vSelectedMints = getSpends(listMints, mapOfDenomsUsed, nSelectedValue); + LogPrint("zero", "%s: %d coins in change for %d\n", __func__, nCoinsReturned, nValueTarget); + } + return vSelectedMints; +} diff --git a/src/denomination_functions.h b/src/denomination_functions.h new file mode 100644 index 000000000..7350769b6 --- /dev/null +++ b/src/denomination_functions.h @@ -0,0 +1,33 @@ +/** + * @file denominations_functions.h + * + * @brief Denomination functions for the Zerocoin library. + * + * @copyright Copyright 2017 PIVX Developers + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2015-2017 The PIVX developers + +#include "reverse_iterate.h" +#include "util.h" +#include "libzerocoin/Denominations.h" +#include "primitives/zerocoin.h" +#include +#include +std::vector SelectMintsFromList(const CAmount nValueTarget, CAmount& nSelectedValue, + int nMaxNumberOfSpends, + bool fMinimizeChange, + int& nCoinsReturned, + const std::list& listMints, + const std::map mapDenomsHeld, + int& nNeededSpends + ); + +int calculateChange( + int nMaxNumberOfSpends, + bool fMinimizeChange, + const CAmount nValueTarget, + const std::map& mapOfDenomsHeld, + std::map& mapOfDenomsUsed); + +void listSpends(const std::vector& vSelectedMints); diff --git a/src/init.cpp b/src/init.cpp index 7d975672c..3c06e3322 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -12,6 +12,7 @@ #include "init.h" +#include "accumulators.h" #include "activemasternode.h" #include "addrman.h" #include "amount.h" @@ -28,6 +29,7 @@ #include "rpcserver.h" #include "script/standard.h" #include "spork.h" +#include "sporkdb.h" #include "txdb.h" #include "ui_interface.h" #include "util.h" @@ -37,6 +39,8 @@ #include "db.h" #include "wallet.h" #include "walletdb.h" +#include "accumulators.h" + #endif #include @@ -65,8 +69,9 @@ using namespace std; CWallet* pwalletMain = NULL; int nWalletBackups = 10; #endif -bool fFeeEstimatesInitialized = false; -bool fRestartRequested = false; // true: restart false: shutdown +volatile bool fFeeEstimatesInitialized = false; +volatile bool fRestartRequested = false; // true: restart false: shutdown +extern std::list listAccCheckpointsNoDB; #if ENABLE_ZMQ static CZMQNotificationInterface* pzmqNotificationInterface = NULL; @@ -213,6 +218,10 @@ void PrepareShutdown() pcoinsdbview = NULL; delete pblocktree; pblocktree = NULL; + delete zerocoinDB; + zerocoinDB = NULL; + delete pSporkDB; + pSporkDB = NULL; } #ifdef ENABLE_WALLET if (pwalletMain) @@ -297,6 +306,7 @@ bool static Bind(const CService& addr, unsigned int flags) std::string HelpMessage(HelpMessageMode mode) { + // When adding new options to the categories, please keep and ensure alphabetical ordering. string strUsage = HelpMessageGroup(_("Options:")); strUsage += HelpMessageOpt("-?", _("This help message")); @@ -315,12 +325,16 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-datadir=", _("Specify data directory")); strUsage += HelpMessageOpt("-dbcache=", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache)); strUsage += HelpMessageOpt("-loadblock=", _("Imports blocks from external blk000??.dat file") + " " + _("on startup")); + strUsage += HelpMessageOpt("-maxreorg=", strprintf(_("Set the Maximum reorg depth (default: %u)"), Params(CBaseChainParams::MAIN).MaxReorganizationDepth())); strUsage += HelpMessageOpt("-maxorphantx=", strprintf(_("Keep at most unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); strUsage += HelpMessageOpt("-par=", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS)); #ifndef WIN32 strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), "bulwarkd.pid")); #endif strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files") + " " + _("on startup")); + strUsage += HelpMessageOpt("-reindexaccumulators", _("Reindex the accumulator database") + " " + _("on startup")); + strUsage += HelpMessageOpt("-reindexmoneysupply", _("Reindex the BWK and zBWK money supply statistics") + " " + _("on startup")); + strUsage += HelpMessageOpt("-resync", _("Delete blockchain folders and resync from scratch") + " " + _("on startup")); #if !defined(WIN32) strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); #endif @@ -348,6 +362,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-peerbloomfilters", strprintf(_("Support filtering of blocks and transaction with bloom filters (default: %u)"), DEFAULT_PEERBLOOMFILTERS)); strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), 52543, 42133)); strUsage += HelpMessageOpt("-proxy=", _("Connect through SOCKS5 proxy")); + strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), 1)); strUsage += HelpMessageOpt("-seednode=", _("Connect to a node to retrieve peer addresses, and disconnect")); strUsage += HelpMessageOpt("-timeout=", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT)); #ifdef USE_UPNP @@ -375,6 +390,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup")); strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0)); strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1)); + strUsage += HelpMessageOpt("-disablesystemnotifications", strprintf(_("Disable OS notifications for incoming transactions (default: %u)"), 0)); strUsage += HelpMessageOpt("-txconfirmtarget=", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), 1)); strUsage += HelpMessageOpt("-maxtxfee=", strprintf(_("Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s)"), FormatMoney(maxTxFee))); @@ -391,10 +407,10 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("ZeroMQ notification options:")); strUsage += HelpMessageOpt("-zmqpubhashblock=
", _("Enable publish hash block in
")); strUsage += HelpMessageOpt("-zmqpubhashtx=
", _("Enable publish hash transaction in
")); - strUsage += HelpMessageOpt("-zmqpubhashtxlock=
", _("Enable publish hash transaction (locked via SwiftTX) in
")); + strUsage += HelpMessageOpt("-zmqpubhashtxlock=
", _("Enable publish hash transaction (locked via SwiftX) in
")); strUsage += HelpMessageOpt("-zmqpubrawblock=
", _("Enable publish raw block in
")); strUsage += HelpMessageOpt("-zmqpubrawtx=
", _("Enable publish raw transaction in
")); - strUsage += HelpMessageOpt("-zmqpubrawtxlock=
", _("Enable publish raw transaction (locked via SwiftTX) in
")); + strUsage += HelpMessageOpt("-zmqpubrawtxlock=
", _("Enable publish raw transaction (locked via SwiftX) in
")); #endif strUsage += HelpMessageGroup(_("Debugging/Testing options:")); @@ -408,14 +424,17 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-dropmessagestest=", _("Randomly drop 1 of every network messages")); strUsage += HelpMessageOpt("-fuzzmessagestest=", _("Randomly fuzz 1 of every network messages")); strUsage += HelpMessageOpt("-flushwallet", strprintf(_("Run a thread to flush wallet periodically (default: %u)"), 1)); + strUsage += HelpMessageOpt("-maxreorg", strprintf(_("Use a custom max chain reorganization depth (default: %u)"), 100)); strUsage += HelpMessageOpt("-stopafterblockimport", strprintf(_("Stop running after importing blocks from disk (default: %u)"), 0)); strUsage += HelpMessageOpt("-sporkkey=", _("Enable spork administration functionality with the appropriate private key.")); } - string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net, bulwark, (obfuscation, swifttx, masternode, mnpayments, mnbudget)"; // Don't translate these and qt below + string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, tor, mempool, net, proxy, bulwark, (obfuscation, swiftx, masternode, mnpayments, mnbudget, zero)"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; - strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + - _("If is not supplied, output all debugging information.") + _(" can be:") + " " + debugCategories + "."); + strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + + _("If is not supplied, output all debugging information.") + _(" can be:") + " " + debugCategories + "."); + if (GetBoolArg("-help-debug", false)) + strUsage += HelpMessageOpt("-nodebug", "Turn off debugging messages, same as -debug=0"); #ifdef ENABLE_WALLET strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0)); strUsage += HelpMessageOpt("-genproclimit=", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1)); @@ -439,7 +458,7 @@ std::string HelpMessage(HelpMessageMode mode) } strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)")); strUsage += HelpMessageOpt("-testnet", _("Use the test network")); - strUsage += HelpMessageOpt("-litemode=", strprintf(_("Disable all BWK specific functionality (Masternodes, Obfuscation, SwiftTX, Budgeting) (0-1, default: %u)"), 0)); + strUsage += HelpMessageOpt("-litemode=", strprintf(_("Disable all BWK specific functionality (Masternodes, Zerocoin, SwiftX, Budgeting) (0-1, default: %u)"), 0)); #ifdef ENABLE_WALLET strUsage += HelpMessageGroup(_("Staking options:")); @@ -459,14 +478,19 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-masternodeaddr=", strprintf(_("Set external address:port to get to this masternode (example: %s)"), "128.127.106.235:51472")); strUsage += HelpMessageOpt("-budgetvotemode=", _("Change automatic finalized budget voting behavior. mode=auto: Vote for only exact finalized budget match to my generated budget. (string, default: auto)")); - strUsage += HelpMessageGroup(_("Obfuscation options:")); - strUsage += HelpMessageOpt("-enableobfuscation=", strprintf(_("Enable use of automated obfuscation for funds stored in this wallet (0-1, default: %u)"), 0)); - strUsage += HelpMessageOpt("-obfuscationrounds=", strprintf(_("Use N separate masternodes to anonymize funds (2-8, default: %u)"), 2)); - strUsage += HelpMessageOpt("-anonymizebulwarkamount=", strprintf(_("Keep N BWK anonymized (default: %u)"), 0)); - strUsage += HelpMessageOpt("-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)); + strUsage += HelpMessageGroup(_("Zerocoin options:")); + strUsage += HelpMessageOpt("-enablezeromint=", strprintf(_("Enable automatic Zerocoin minting (0-1, default: %u)"), 0)); + strUsage += HelpMessageOpt("-zeromintpercentage=", strprintf(_("Percentage of automatically minted Zerocoin (10-100, default: %u)"), 10)); + strUsage += HelpMessageOpt("-preferredDenom=", strprintf(_("Preferred Denomination for automatically minted Zerocoin (1/5/10/50/100/500/1000), 0 for no preference. default: %u)"), 0)); + strUsage += HelpMessageOpt("-backupzbwk=", strprintf(_("Enable automatic wallet backups triggered after each zBWK minting (0-1, default: %u)"), 1)); + strUsage += HelpMessageOpt("-resetspentzerocoin", strprintf(_("*You can lose zBWK if you run this before the spend is confirmed on the blockchain.* Reset current zBWK spends to match those on the blockchain.%s"), "")); + strUsage += HelpMessageOpt("-resetmintzerocoin", strprintf(_("*You can lose zBWK if you run this before the mint is confirmed on the blockchain.* Reset current zBWK mints to match those on the blockchain.%s"), "")); - strUsage += HelpMessageGroup(_("SwiftTX options:")); - strUsage += HelpMessageOpt("-enableswifttx=", strprintf(_("Enable swifttx, show confirmations for locked transactions (bool, default: %s)"), "true")); +// strUsage += " -anonymizebulwarkamount= " + strprintf(_("Keep N BWK 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)); strUsage += HelpMessageGroup(_("Node relay options:")); @@ -485,6 +509,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-server", _("Accept command line and JSON-RPC commands")); strUsage += HelpMessageOpt("-rest", strprintf(_("Accept public REST requests (default: %u)"), 0)); strUsage += HelpMessageOpt("-rpcbind=", _("Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces)")); + strUsage += HelpMessageOpt("-rpccookiefile=", _("Location of the auth cookie (default: data dir)")); strUsage += HelpMessageOpt("-rpcuser=", _("Username for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcpassword=", _("Password for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Listen for JSON-RPC connections on (default: %u or testnet: %u)"), 52541, 42132)); @@ -785,6 +810,9 @@ bool AppInit2(boost::thread_group& threadGroup) // Check for -tor - as this is a privacy risk to continue, exit here if (GetBoolArg("-tor", false)) return InitError(_("Error: Unsupported argument -tor found, use -onion.")); + // Check level must be 4 for zerocoin checks + if (mapArgs.count("-checklevel")) + return InitError(_("Error: Unsupported argument -checklevel found. Checklevel must be level 4.")); if (GetBoolArg("-benchmark", false)) InitWarning(_("Warning: Unsupported argument -benchmark ignored, use -debug=bench.")); @@ -868,13 +896,14 @@ bool AppInit2(boost::thread_group& threadGroup) } } nTxConfirmTarget = GetArg("-txconfirmtarget", 1); - bSpendZeroConfChange = GetArg("-spendzeroconfchange", true); - fSendFreeTransactions = GetArg("-sendfreetransactions", false); + bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", true); + bdisableSystemnotifications = GetBoolArg("-disablesystemnotifications", false); + fSendFreeTransactions = GetBoolArg("-sendfreetransactions", false); std::string strWalletFile = GetArg("-wallet", "wallet.dat"); #endif // ENABLE_WALLET - fIsBareMultisigStd = GetArg("-permitbaremultisig", true) != 0; + fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", true) != 0; nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS); @@ -1020,6 +1049,41 @@ bool AppInit2(boost::thread_group& threadGroup) } } + if (GetBoolArg("-resync", false)) { + uiInterface.InitMessage(_("Preparing for resync...")); + // Delete the local blockchain folders to force a resync from scratch to get a consitent blockchain-state + filesystem::path blocksDir = GetDataDir() / "blocks"; + filesystem::path chainstateDir = GetDataDir() / "chainstate"; + filesystem::path sporksDir = GetDataDir() / "sporks"; + filesystem::path zerocoinDir = GetDataDir() / "zerocoin"; + + LogPrintf("Deleting blockchain folders blocks, chainstate, sporks and zerocoin\n"); + // We delete in 4 individual steps in case one of the folder is missing already + try { + if (filesystem::exists(blocksDir)){ + boost::filesystem::remove_all(blocksDir); + LogPrintf("-resync: folder deleted: %s\n", blocksDir.string().c_str()); + } + + if (filesystem::exists(chainstateDir)){ + boost::filesystem::remove_all(chainstateDir); + LogPrintf("-resync: folder deleted: %s\n", chainstateDir.string().c_str()); + } + + if (filesystem::exists(sporksDir)){ + boost::filesystem::remove_all(sporksDir); + LogPrintf("-resync: folder deleted: %s\n", sporksDir.string().c_str()); + } + + if (filesystem::exists(zerocoinDir)){ + boost::filesystem::remove_all(zerocoinDir); + LogPrintf("-resync: folder deleted: %s\n", zerocoinDir.string().c_str()); + } + } catch (boost::filesystem::filesystem_error& error) { + LogPrintf("Failed to delete blockchain folders %s\n", error.what()); + } + } + LogPrintf("Using wallet %s\n", strWalletFile); uiInterface.InitMessage(_("Verifying wallet...")); @@ -1092,37 +1156,53 @@ bool AppInit2(boost::thread_group& threadGroup) } } - CService addrProxy; - bool fProxy = false; - if (mapArgs.count("-proxy")) { - addrProxy = CService(mapArgs["-proxy"], 9050); + // Check for host lookup allowed before parsing any network related parameters + fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); + + bool proxyRandomize = GetBoolArg("-proxyrandomize", true); + // -proxy sets a proxy for all outgoing network traffic + // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default + std::string proxyArg = GetArg("-proxy", ""); + if (proxyArg != "" && proxyArg != "0") { + CService proxyAddr; + if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup)) { + return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg)); + } + + proxyType addrProxy = proxyType(proxyAddr, proxyRandomize); if (!addrProxy.IsValid()) - return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"])); + return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg)); SetProxy(NET_IPV4, addrProxy); SetProxy(NET_IPV6, addrProxy); + SetProxy(NET_TOR, addrProxy); SetNameProxy(addrProxy); - fProxy = true; + SetReachable(NET_TOR); // by default, -proxy sets onion as reachable, unless -noonion later } - // -onion can override normal proxy, -noonion disables tor entirely - if (!(mapArgs.count("-onion") && mapArgs["-onion"] == "0") && - (fProxy || mapArgs.count("-onion"))) { - CService addrOnion; - if (!mapArgs.count("-onion")) - addrOnion = addrProxy; - else - addrOnion = CService(mapArgs["-onion"], 9050); - if (!addrOnion.IsValid()) - return InitError(strprintf(_("Invalid -onion address: '%s'"), mapArgs["-onion"])); - SetProxy(NET_TOR, addrOnion); - SetReachable(NET_TOR); + // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses + // -noonion (or -onion=0) disables connecting to .onion entirely + // An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none) + std::string onionArg = GetArg("-onion", ""); + if (onionArg != "") { + if (onionArg == "0") { // Handle -noonion/-onion=0 + SetReachable(NET_TOR, false); // set onions as unreachable + } else { + CService onionProxy; + if (!Lookup(onionArg.c_str(), onionProxy, 9050, fNameLookup)) { + return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg)); + } + proxyType addrOnion = proxyType(onionProxy, proxyRandomize); + if (!addrOnion.IsValid()) + return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg)); + SetProxy(NET_TOR, addrOnion); + SetReachable(NET_TOR); + } } // see Step 2: parameter interactions for more information about these fListen = GetBoolArg("-listen", DEFAULT_LISTEN); fDiscover = GetBoolArg("-discover", true); - fNameLookup = GetBoolArg("-dns", true); bool fBound = false; if (fListen) { @@ -1229,6 +1309,12 @@ bool AppInit2(boost::thread_group& threadGroup) delete pcoinsdbview; delete pcoinscatcher; delete pblocktree; + delete zerocoinDB; + delete pSporkDB; + + //Bulwark specific: zerocoin and spork DB's + zerocoinDB = new CZerocoinDB(0, false, fReindex); + pSporkDB = new CSporkDB(0, false, false); pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); @@ -1238,8 +1324,15 @@ bool AppInit2(boost::thread_group& threadGroup) if (fReindex) pblocktree->WriteReindexing(true); - if (!LoadBlockIndex()) { + // Bulwark: load previous sessions sporks if we have them. + uiInterface.InitMessage(_("Loading sporks...")); + LoadSporksFromDB(); + + uiInterface.InitMessage(_("Loading block index...")); + string strBlockIndexError = ""; + if (!LoadBlockIndex(strBlockIndexError)) { strLoadError = _("Error loading block database"); + strLoadError = strprintf("%s : %s", strLoadError, strBlockIndexError); break; } @@ -1260,18 +1353,60 @@ bool AppInit2(boost::thread_group& threadGroup) break; } + // Recalculate money supply for blocks that are impacted by accounting issue after zerocoin activation + if (GetBoolArg("-reindexmoneysupply", false)) { + int nZerocoinStartHeight = GetZerocoinStartHeight(); + if (nZerocoinStartHeight != 0) { + if (chainActive.Height() > nZerocoinStartHeight) { + RecalculateZBWKMinted(); + RecalculateZBWKSpent(); + } + } + RecalculateBWKSupply(1); + } + + // Force recalculation of accumulators. + if (GetBoolArg("-reindexaccumulators", false)) { + int nZerocoinStartHeight = GetZerocoinStartHeight(); + if (nZerocoinStartHeight != 0) { + CBlockIndex* pindex = chainActive[nZerocoinStartHeight]; + while (pindex->nHeight < chainActive.Height()) { + if (!count(listAccCheckpointsNoDB.begin(), listAccCheckpointsNoDB.end(), pindex->nAccumulatorCheckpoint)) + listAccCheckpointsNoDB.emplace_back(pindex->nAccumulatorCheckpoint); + pindex = chainActive.Next(pindex); + } + } + } + + // Bulwark: recalculate Accumulator Checkpoints that failed to database properly + if (!listAccCheckpointsNoDB.empty()) { + uiInterface.InitMessage(_("Calculating missing accumulators...")); + LogPrintf("%s : finding missing checkpoints\n", __func__); + + string strError; + if (!ReindexAccumulators(listAccCheckpointsNoDB, strError)) + return InitError(strError); + } + uiInterface.InitMessage(_("Verifying blocks...")); - if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 4), - GetArg("-checkblocks", 500))) { + + // Flag sent to validation code to let it know it can skip certain checks + fVerifyingBlocks = true; + + // Zerocoin must check at level 4 + if (!CVerifyDB().VerifyDB(pcoinsdbview, 4, GetArg("-checkblocks", 100))) { strLoadError = _("Corrupted block database detected"); + fVerifyingBlocks = false; break; } } catch (std::exception& e) { if (fDebug) LogPrintf("%s\n", e.what()); strLoadError = _("Error opening block database"); + fVerifyingBlocks = false; break; } + fVerifyingBlocks = false; fLoaded = true; } while (false); @@ -1334,6 +1469,7 @@ bool AppInit2(boost::thread_group& threadGroup) } uiInterface.InitMessage(_("Loading wallet...")); + fVerifyingBlocks = true; nStart = GetTimeMillis(); bool fFirstRun = true; @@ -1429,6 +1565,10 @@ bool AppInit2(boost::thread_group& threadGroup) } } } + fVerifyingBlocks = false; + + bool fEnableZBWKBackups = GetBoolArg("-backupzbwk", true); + pwalletMain->setZBWKAutoBackups(fEnableZBWKBackups); } // (!fDisableWallet) #else // ENABLE_WALLET LogPrintf("No wallet compiled in!\n"); @@ -1514,7 +1654,7 @@ bool AppInit2(boost::thread_group& threadGroup) } if (fMasterNode) { - LogPrintf("IS OBFUSCATION MASTER NODE\n"); + LogPrintf("IS MASTER NODE\n"); strMasterNodeAddr = GetArg("-masternodeaddr", ""); LogPrintf(" addr %s\n", strMasterNodeAddr.c_str()); @@ -1559,22 +1699,32 @@ bool AppInit2(boost::thread_group& threadGroup) } } - fEnableObfuscation = GetBoolArg("-enableobfuscation", false); + fEnableZeromint = GetBoolArg("-enablezeromint", false); - nObfuscationRounds = GetArg("-obfuscationrounds", 2); - if (nObfuscationRounds > 16) nObfuscationRounds = 16; - if (nObfuscationRounds < 1) nObfuscationRounds = 1; + nZeromintPercentage = GetArg("-zeromintpercentage", 10); + if (nZeromintPercentage > 100) nZeromintPercentage = 100; + if (nZeromintPercentage < 10) nZeromintPercentage = 10; - nLiquidityProvider = GetArg("-liquidityprovider", 0); //0-100 - if (nLiquidityProvider != 0) { - obfuScationPool.SetMinBlockSpacing(std::min(nLiquidityProvider, 100) * 15); - fEnableObfuscation = true; - nObfuscationRounds = 99999; + nPreferredDenom = GetArg("-preferredDenom", 0); + if (nPreferredDenom != 0 && nPreferredDenom != 1 && nPreferredDenom != 5 && nPreferredDenom != 10 && nPreferredDenom != 50 && + nPreferredDenom != 100 && nPreferredDenom != 500 && nPreferredDenom != 1000){ + LogPrintf("-preferredDenom: invalid denomination parameter %d. Default value used\n", nPreferredDenom); + nPreferredDenom = 0; } - nAnonymizeBulwarkAmount = GetArg("-anonymizebulwarkamount", 0); - if (nAnonymizeBulwarkAmount > 999999) nAnonymizeBulwarkAmount = 999999; - if (nAnonymizeBulwarkAmount < 2) nAnonymizeBulwarkAmount = 2; +// XX42 Remove/refactor code below. Until then provide safe defaults + nAnonymizeBulwarkAmount = 2; + +// nLiquidityProvider = GetArg("-liquidityprovider", 0); //0-100 +// if (nLiquidityProvider != 0) { +// obfuScationPool.SetMinBlockSpacing(std::min(nLiquidityProvider, 100) * 15); +// fEnableZeromint = true; +// nZeromintPercentage = 99999; +// } +// +// nAnonymizeBulwarkAmount = GetArg("-anonymizebulwarkamount", 0); +// if (nAnonymizeBulwarkAmount > 999999) nAnonymizeBulwarkAmount = 999999; +// if (nAnonymizeBulwarkAmount < 2) nAnonymizeBulwarkAmount = 2; fEnableSwiftTX = GetBoolArg("-enableswifttx", fEnableSwiftTX); nSwiftTXDepth = GetArg("-swifttxdepth", nSwiftTXDepth); @@ -1588,7 +1738,6 @@ bool AppInit2(boost::thread_group& threadGroup) LogPrintf("fLiteMode %d\n", fLiteMode); LogPrintf("nSwiftTXDepth %d\n", nSwiftTXDepth); - LogPrintf("Obfuscation rounds %d\n", nObfuscationRounds); LogPrintf("Anonymize Bulwark Amount %d\n", nAnonymizeBulwarkAmount); LogPrintf("Budget Mode %s\n", strBudgetMode.c_str()); @@ -1644,6 +1793,7 @@ bool AppInit2(boost::thread_group& threadGroup) #endif // ********************************************************* Step 12: finished + SetRPCWarmupFinished(); uiInterface.InitMessage(_("Done loading")); diff --git a/src/json/LICENSE.txt b/src/json/LICENSE.txt deleted file mode 100644 index 797d5363b..000000000 --- a/src/json/LICENSE.txt +++ /dev/null @@ -1,24 +0,0 @@ -The MIT License - -Copyright (c) 2007 - 2009 John W. Wilkinson - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/json/json_spirit.h b/src/json/json_spirit.h deleted file mode 100644 index ac1879d5b..000000000 --- a/src/json/json_spirit.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef JSON_SPIRIT -#define JSON_SPIRIT - -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json_spirit_value.h" -#include "json_spirit_reader.h" -#include "json_spirit_writer.h" -#include "json_spirit_utils.h" - -#endif diff --git a/src/json/json_spirit_error_position.h b/src/json/json_spirit_error_position.h deleted file mode 100644 index 17208507d..000000000 --- a/src/json/json_spirit_error_position.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef JSON_SPIRIT_ERROR_POSITION -#define JSON_SPIRIT_ERROR_POSITION - -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include - -namespace json_spirit -{ - // An Error_position exception is thrown by the "read_or_throw" functions below on finding an error. - // Note the "read_or_throw" functions are around 3 times slower than the standard functions "read" - // functions that return a bool. - // - struct Error_position - { - Error_position(); - Error_position( unsigned int line, unsigned int column, const std::string& reason ); - bool operator==( const Error_position& lhs ) const; - unsigned int line_; - unsigned int column_; - std::string reason_; - }; - - inline Error_position::Error_position() - : line_( 0 ) - , column_( 0 ) - { - } - - inline Error_position::Error_position( unsigned int line, unsigned int column, const std::string& reason ) - : line_( line ) - , column_( column ) - , reason_( reason ) - { - } - - inline bool Error_position::operator==( const Error_position& lhs ) const - { - if( this == &lhs ) return true; - - return ( reason_ == lhs.reason_ ) && - ( line_ == lhs.line_ ) && - ( column_ == lhs.column_ ); -} -} - -#endif diff --git a/src/json/json_spirit_reader.cpp b/src/json/json_spirit_reader.cpp deleted file mode 100644 index aa4f63722..000000000 --- a/src/json/json_spirit_reader.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#include "json_spirit_reader.h" -#include "json_spirit_reader_template.h" - -using namespace json_spirit; - -bool json_spirit::read( const std::string& s, Value& value ) -{ - return read_string( s, value ); -} - -void json_spirit::read_or_throw( const std::string& s, Value& value ) -{ - read_string_or_throw( s, value ); -} - -bool json_spirit::read( std::istream& is, Value& value ) -{ - return read_stream( is, value ); -} - -void json_spirit::read_or_throw( std::istream& is, Value& value ) -{ - read_stream_or_throw( is, value ); -} - -bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) -{ - return read_range( begin, end, value ); -} - -void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ) -{ - begin = read_range_or_throw( begin, end, value ); -} - -#ifndef BOOST_NO_STD_WSTRING - -bool json_spirit::read( const std::wstring& s, wValue& value ) -{ - return read_string( s, value ); -} - -void json_spirit::read_or_throw( const std::wstring& s, wValue& value ) -{ - read_string_or_throw( s, value ); -} - -bool json_spirit::read( std::wistream& is, wValue& value ) -{ - return read_stream( is, value ); -} - -void json_spirit::read_or_throw( std::wistream& is, wValue& value ) -{ - read_stream_or_throw( is, value ); -} - -bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) -{ - return read_range( begin, end, value ); -} - -void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ) -{ - begin = read_range_or_throw( begin, end, value ); -} - -#endif - -bool json_spirit::read( const std::string& s, mValue& value ) -{ - return read_string( s, value ); -} - -void json_spirit::read_or_throw( const std::string& s, mValue& value ) -{ - read_string_or_throw( s, value ); -} - -bool json_spirit::read( std::istream& is, mValue& value ) -{ - return read_stream( is, value ); -} - -void json_spirit::read_or_throw( std::istream& is, mValue& value ) -{ - read_stream_or_throw( is, value ); -} - -bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) -{ - return read_range( begin, end, value ); -} - -void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ) -{ - begin = read_range_or_throw( begin, end, value ); -} - -#ifndef BOOST_NO_STD_WSTRING - -bool json_spirit::read( const std::wstring& s, wmValue& value ) -{ - return read_string( s, value ); -} - -void json_spirit::read_or_throw( const std::wstring& s, wmValue& value ) -{ - read_string_or_throw( s, value ); -} - -bool json_spirit::read( std::wistream& is, wmValue& value ) -{ - return read_stream( is, value ); -} - -void json_spirit::read_or_throw( std::wistream& is, wmValue& value ) -{ - read_stream_or_throw( is, value ); -} - -bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) -{ - return read_range( begin, end, value ); -} - -void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ) -{ - begin = read_range_or_throw( begin, end, value ); -} - -#endif diff --git a/src/json/json_spirit_reader.h b/src/json/json_spirit_reader.h deleted file mode 100644 index 96494a978..000000000 --- a/src/json/json_spirit_reader.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef JSON_SPIRIT_READER -#define JSON_SPIRIT_READER - -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json_spirit_value.h" -#include "json_spirit_error_position.h" -#include - -namespace json_spirit -{ - // functions to reads a JSON values - - bool read( const std::string& s, Value& value ); - bool read( std::istream& is, Value& value ); - bool read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); - - void read_or_throw( const std::string& s, Value& value ); - void read_or_throw( std::istream& is, Value& value ); - void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value ); - -#ifndef BOOST_NO_STD_WSTRING - - bool read( const std::wstring& s, wValue& value ); - bool read( std::wistream& is, wValue& value ); - bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); - - void read_or_throw( const std::wstring& s, wValue& value ); - void read_or_throw( std::wistream& is, wValue& value ); - void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value ); - -#endif - - bool read( const std::string& s, mValue& value ); - bool read( std::istream& is, mValue& value ); - bool read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); - - void read_or_throw( const std::string& s, mValue& value ); - void read_or_throw( std::istream& is, mValue& value ); - void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value ); - -#ifndef BOOST_NO_STD_WSTRING - - bool read( const std::wstring& s, wmValue& value ); - bool read( std::wistream& is, wmValue& value ); - bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); - - void read_or_throw( const std::wstring& s, wmValue& value ); - void read_or_throw( std::wistream& is, wmValue& value ); - void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value ); - -#endif -} - -#endif diff --git a/src/json/json_spirit_reader_template.h b/src/json/json_spirit_reader_template.h deleted file mode 100644 index 47e3c1ca8..000000000 --- a/src/json/json_spirit_reader_template.h +++ /dev/null @@ -1,612 +0,0 @@ -#ifndef JSON_SPIRIT_READER_TEMPLATE -#define JSON_SPIRIT_READER_TEMPLATE - -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#include "json_spirit_value.h" -#include "json_spirit_error_position.h" - -//#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread - -#include -#include -#include - -#if BOOST_VERSION >= 103800 - #include - #include - #include - #include - #include - #define spirit_namespace boost::spirit::classic -#else - #include - #include - #include - #include - #include - #define spirit_namespace boost::spirit -#endif - -namespace json_spirit -{ - const spirit_namespace::int_parser < int64_t > int64_p = spirit_namespace::int_parser < int64_t >(); - const spirit_namespace::uint_parser< uint64_t > uint64_p = spirit_namespace::uint_parser< uint64_t >(); - - template< class Iter_type > - bool is_eq( Iter_type first, Iter_type last, const char* c_str ) - { - for( Iter_type i = first; i != last; ++i, ++c_str ) - { - if( *c_str == 0 ) return false; - - if( *i != *c_str ) return false; - } - - return true; - } - - template< class Char_type > - Char_type hex_to_num( const Char_type c ) - { - if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0'; - if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10; - if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10; - return 0; - } - - template< class Char_type, class Iter_type > - Char_type hex_str_to_char( Iter_type& begin ) - { - const Char_type c1( *( ++begin ) ); - const Char_type c2( *( ++begin ) ); - - return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 ); - } - - template< class Char_type, class Iter_type > - Char_type unicode_str_to_char( Iter_type& begin ) - { - const Char_type c1( *( ++begin ) ); - const Char_type c2( *( ++begin ) ); - const Char_type c3( *( ++begin ) ); - const Char_type c4( *( ++begin ) ); - - return ( hex_to_num( c1 ) << 12 ) + - ( hex_to_num( c2 ) << 8 ) + - ( hex_to_num( c3 ) << 4 ) + - hex_to_num( c4 ); - } - - template< class String_type > - void append_esc_char_and_incr_iter( String_type& s, - typename String_type::const_iterator& begin, - typename String_type::const_iterator end ) - { - typedef typename String_type::value_type Char_type; - - const Char_type c2( *begin ); - - switch( c2 ) - { - case 't': s += '\t'; break; - case 'b': s += '\b'; break; - case 'f': s += '\f'; break; - case 'n': s += '\n'; break; - case 'r': s += '\r'; break; - case '\\': s += '\\'; break; - case '/': s += '/'; break; - case '"': s += '"'; break; - case 'x': - { - if( end - begin >= 3 ) // expecting "xHH..." - { - s += hex_str_to_char< Char_type >( begin ); - } - break; - } - case 'u': - { - if( end - begin >= 5 ) // expecting "uHHHH..." - { - s += unicode_str_to_char< Char_type >( begin ); - } - break; - } - } - } - - template< class String_type > - String_type substitute_esc_chars( typename String_type::const_iterator begin, - typename String_type::const_iterator end ) - { - typedef typename String_type::const_iterator Iter_type; - - if( end - begin < 2 ) return String_type( begin, end ); - - String_type result; - - result.reserve( end - begin ); - - const Iter_type end_minus_1( end - 1 ); - - Iter_type substr_start = begin; - Iter_type i = begin; - - for( ; i < end_minus_1; ++i ) - { - if( *i == '\\' ) - { - result.append( substr_start, i ); - - ++i; // skip the '\' - - append_esc_char_and_incr_iter( result, i, end ); - - substr_start = i + 1; - } - } - - result.append( substr_start, end ); - - return result; - } - - template< class String_type > - String_type get_str_( typename String_type::const_iterator begin, - typename String_type::const_iterator end ) - { - assert( end - begin >= 2 ); - - typedef typename String_type::const_iterator Iter_type; - - Iter_type str_without_quotes( ++begin ); - Iter_type end_without_quotes( --end ); - - return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes ); - } - - inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end ) - { - return get_str_< std::string >( begin, end ); - } - - inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end ) - { - return get_str_< std::wstring >( begin, end ); - } - - template< class String_type, class Iter_type > - String_type get_str( Iter_type begin, Iter_type end ) - { - const String_type tmp( begin, end ); // convert multipass iterators to string iterators - - return get_str( tmp.begin(), tmp.end() ); - } - - // this class's methods get called by the spirit parse resulting - // in the creation of a JSON object or array - // - // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator - // - template< class Value_type, class Iter_type > - class Semantic_actions - { - public: - - typedef typename Value_type::Config_type Config_type; - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename String_type::value_type Char_type; - - Semantic_actions( Value_type& value ) - : value_( value ) - , current_p_( 0 ) - { - } - - void begin_obj( Char_type c ) - { - assert( c == '{' ); - - begin_compound< Object_type >(); - } - - void end_obj( Char_type c ) - { - assert( c == '}' ); - - end_compound(); - } - - void begin_array( Char_type c ) - { - assert( c == '[' ); - - begin_compound< Array_type >(); - } - - void end_array( Char_type c ) - { - assert( c == ']' ); - - end_compound(); - } - - void new_name( Iter_type begin, Iter_type end ) - { - assert( current_p_->type() == obj_type ); - - name_ = get_str< String_type >( begin, end ); - } - - void new_str( Iter_type begin, Iter_type end ) - { - add_to_current( get_str< String_type >( begin, end ) ); - } - - void new_true( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "true" ) ); - - add_to_current( true ); - } - - void new_false( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "false" ) ); - - add_to_current( false ); - } - - void new_null( Iter_type begin, Iter_type end ) - { - assert( is_eq( begin, end, "null" ) ); - - add_to_current( Value_type() ); - } - - void new_int( int64_t i ) - { - add_to_current( i ); - } - - void new_uint64( uint64_t ui ) - { - add_to_current( ui ); - } - - void new_real( double d ) - { - add_to_current( d ); - } - - private: - - Semantic_actions& operator=( const Semantic_actions& ); - // to prevent "assignment operator could not be generated" warning - - Value_type* add_first( const Value_type& value ) - { - assert( current_p_ == 0 ); - - value_ = value; - current_p_ = &value_; - return current_p_; - } - - template< class Array_or_obj > - void begin_compound() - { - if( current_p_ == 0 ) - { - add_first( Array_or_obj() ); - } - else - { - stack_.push_back( current_p_ ); - - Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place - - current_p_ = add_to_current( new_array_or_obj ); - } - } - - void end_compound() - { - if( current_p_ != &value_ ) - { - current_p_ = stack_.back(); - - stack_.pop_back(); - } - } - - Value_type* add_to_current( const Value_type& value ) - { - if( current_p_ == 0 ) - { - return add_first( value ); - } - else if( current_p_->type() == array_type ) - { - current_p_->get_array().push_back( value ); - - return ¤t_p_->get_array().back(); - } - - assert( current_p_->type() == obj_type ); - - return &Config_type::add( current_p_->get_obj(), name_, value ); - } - - Value_type& value_; // this is the object or array that is being created - Value_type* current_p_; // the child object or array that is currently being constructed - - std::vector< Value_type* > stack_; // previous child objects and arrays - - String_type name_; // of current name/value pair - }; - - template< typename Iter_type > - void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason ) - { - throw Error_position( i.get_position().line, i.get_position().column, reason ); - } - - template< typename Iter_type > - void throw_error( Iter_type i, const std::string& reason ) - { - throw reason; - } - - // the spirit grammer - // - template< class Value_type, class Iter_type > - class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > > - { - public: - - typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t; - - Json_grammer( Semantic_actions_t& semantic_actions ) - : actions_( semantic_actions ) - { - } - - static void throw_not_value( Iter_type begin, Iter_type end ) - { - throw_error( begin, "not a value" ); - } - - static void throw_not_array( Iter_type begin, Iter_type end ) - { - throw_error( begin, "not an array" ); - } - - static void throw_not_object( Iter_type begin, Iter_type end ) - { - throw_error( begin, "not an object" ); - } - - static void throw_not_pair( Iter_type begin, Iter_type end ) - { - throw_error( begin, "not a pair" ); - } - - static void throw_not_colon( Iter_type begin, Iter_type end ) - { - throw_error( begin, "no colon in pair" ); - } - - static void throw_not_string( Iter_type begin, Iter_type end ) - { - throw_error( begin, "not a string" ); - } - - template< typename ScannerT > - class definition - { - public: - - definition( const Json_grammer& self ) - { - using namespace spirit_namespace; - - typedef typename Value_type::String_type::value_type Char_type; - - // first we convert the semantic action class methods to functors with the - // parameter signature expected by spirit - - typedef boost::function< void( Char_type ) > Char_action; - typedef boost::function< void( Iter_type, Iter_type ) > Str_action; - typedef boost::function< void( double ) > Real_action; - typedef boost::function< void( int64_t ) > Int_action; - typedef boost::function< void( uint64_t ) > Uint64_action; - - Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) ); - Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) ); - Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) ); - Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) ); - Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) ); - Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) ); - Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) ); - Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) ); - Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) ); - Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) ); - Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) ); - Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) ); - - // actual grammer - - json_ - = value_ | eps_p[ &throw_not_value ] - ; - - value_ - = string_[ new_str ] - | number_ - | object_ - | array_ - | str_p( "true" ) [ new_true ] - | str_p( "false" )[ new_false ] - | str_p( "null" ) [ new_null ] - ; - - object_ - = ch_p('{')[ begin_obj ] - >> !members_ - >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] ) - ; - - members_ - = pair_ >> *( ',' >> pair_ ) - ; - - pair_ - = string_[ new_name ] - >> ( ':' | eps_p[ &throw_not_colon ] ) - >> ( value_ | eps_p[ &throw_not_value ] ) - ; - - array_ - = ch_p('[')[ begin_array ] - >> !elements_ - >> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] ) - ; - - elements_ - = value_ >> *( ',' >> value_ ) - ; - - string_ - = lexeme_d // this causes white space inside a string to be retained - [ - confix_p - ( - '"', - *lex_escape_ch_p, - '"' - ) - ] - ; - - number_ - = strict_real_p[ new_real ] - | int64_p [ new_int ] - | uint64_p [ new_uint64 ] - ; - } - - spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_; - - const spirit_namespace::rule< ScannerT >& start() const { return json_; } - }; - - private: - - Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning - - Semantic_actions_t& actions_; - }; - - template< class Iter_type, class Value_type > - Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) - { - Semantic_actions< Value_type, Iter_type > semantic_actions( value ); - - const spirit_namespace::parse_info< Iter_type > info = - spirit_namespace::parse( begin, end, - Json_grammer< Value_type, Iter_type >( semantic_actions ) >> spirit_namespace::end_p, - spirit_namespace::space_p ); - - if( !info.hit ) - { - throw_error( info.stop, "error" ); - } - - return info.stop; - } - - template< class Iter_type, class Value_type > - void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value ) - { - typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t; - - const Posn_iter_t posn_begin( begin, end ); - const Posn_iter_t posn_end( end, end ); - - read_range_or_throw( posn_begin, posn_end, value ); - } - - template< class Iter_type, class Value_type > - bool read_range( Iter_type& begin, Iter_type end, Value_type& value ) - { - try - { - begin = read_range_or_throw( begin, end, value ); - - return true; - } - catch( ... ) - { - return false; - } - } - - template< class String_type, class Value_type > - void read_string_or_throw( const String_type& s, Value_type& value ) - { - add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value ); - } - - template< class String_type, class Value_type > - bool read_string( const String_type& s, Value_type& value ) - { - typename String_type::const_iterator begin = s.begin(); - - bool success = read_range( begin, s.end(), value ); - return success && begin == s.end(); - } - - template< class Istream_type > - struct Multi_pass_iters - { - typedef typename Istream_type::char_type Char_type; - typedef std::istream_iterator< Char_type, Char_type > istream_iter; - typedef spirit_namespace::multi_pass< istream_iter > Mp_iter; - - Multi_pass_iters( Istream_type& is ) - { - is.unsetf( std::ios::skipws ); - - begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) ); - end_ = spirit_namespace::make_multi_pass( istream_iter() ); - } - - Mp_iter begin_; - Mp_iter end_; - }; - - template< class Istream_type, class Value_type > - bool read_stream( Istream_type& is, Value_type& value ) - { - Multi_pass_iters< Istream_type > mp_iters( is ); - - return read_range( mp_iters.begin_, mp_iters.end_, value ); - } - - template< class Istream_type, class Value_type > - void read_stream_or_throw( Istream_type& is, Value_type& value ) - { - const Multi_pass_iters< Istream_type > mp_iters( is ); - - add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value ); - } -} - -#endif diff --git a/src/json/json_spirit_stream_reader.h b/src/json/json_spirit_stream_reader.h deleted file mode 100644 index 7e59c9adc..000000000 --- a/src/json/json_spirit_stream_reader.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef JSON_SPIRIT_READ_STREAM -#define JSON_SPIRIT_READ_STREAM - -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json_spirit_reader_template.h" - -namespace json_spirit -{ - // these classes allows you to read multiple top level contiguous values from a stream, - // the normal stream read functions have a bug that prevent multiple top level values - // from being read unless they are separated by spaces - - template< class Istream_type, class Value_type > - class Stream_reader - { - public: - - Stream_reader( Istream_type& is ) - : iters_( is ) - { - } - - bool read_next( Value_type& value ) - { - return read_range( iters_.begin_, iters_.end_, value ); - } - - private: - - typedef Multi_pass_iters< Istream_type > Mp_iters; - - Mp_iters iters_; - }; - - template< class Istream_type, class Value_type > - class Stream_reader_thrower - { - public: - - Stream_reader_thrower( Istream_type& is ) - : iters_( is ) - , posn_begin_( iters_.begin_, iters_.end_ ) - , posn_end_( iters_.end_, iters_.end_ ) - { - } - - void read_next( Value_type& value ) - { - posn_begin_ = read_range_or_throw( posn_begin_, posn_end_, value ); - } - - private: - - typedef Multi_pass_iters< Istream_type > Mp_iters; - typedef spirit_namespace::position_iterator< typename Mp_iters::Mp_iter > Posn_iter_t; - - Mp_iters iters_; - Posn_iter_t posn_begin_, posn_end_; - }; -} - -#endif diff --git a/src/json/json_spirit_utils.h b/src/json/json_spirit_utils.h deleted file mode 100644 index 553e3b96a..000000000 --- a/src/json/json_spirit_utils.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef JSON_SPIRIT_UTILS -#define JSON_SPIRIT_UTILS - -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json_spirit_value.h" -#include - -namespace json_spirit -{ - template< class Obj_t, class Map_t > - void obj_to_map( const Obj_t& obj, Map_t& mp_obj ) - { - mp_obj.clear(); - - for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i ) - { - mp_obj[ i->name_ ] = i->value_; - } - } - - template< class Obj_t, class Map_t > - void map_to_obj( const Map_t& mp_obj, Obj_t& obj ) - { - obj.clear(); - - for( typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i ) - { - obj.push_back( typename Obj_t::value_type( i->first, i->second ) ); - } - } - - typedef std::map< std::string, Value > Mapped_obj; - -#ifndef BOOST_NO_STD_WSTRING - typedef std::map< std::wstring, wValue > wMapped_obj; -#endif - - template< class Object_type, class String_type > - const typename Object_type::value_type::Value_type& find_value( const Object_type& obj, const String_type& name ) - { - for( typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i ) - { - if( i->name_ == name ) - { - return i->value_; - } - } - - return Object_type::value_type::Value_type::null; - } -} - -#endif diff --git a/src/json/json_spirit_value.cpp b/src/json/json_spirit_value.cpp deleted file mode 100644 index 44d2f06a0..000000000 --- a/src/json/json_spirit_value.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* Copyright (c) 2007 John W Wilkinson - - This source code can be used for any purpose as long as - this comment is retained. */ - -// json spirit version 2.00 - -#include "json_spirit_value.h" diff --git a/src/json/json_spirit_value.h b/src/json/json_spirit_value.h deleted file mode 100644 index 13cc89210..000000000 --- a/src/json/json_spirit_value.h +++ /dev/null @@ -1,534 +0,0 @@ -#ifndef JSON_SPIRIT_VALUE -#define JSON_SPIRIT_VALUE - -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace json_spirit -{ - enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type }; - static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"}; - - template< class Config > // Config determines whether the value uses std::string or std::wstring and - // whether JSON Objects are represented as vectors or maps - class Value_impl - { - public: - - typedef Config Config_type; - typedef typename Config::String_type String_type; - typedef typename Config::Object_type Object; - typedef typename Config::Array_type Array; - typedef typename String_type::const_pointer Const_str_ptr; // eg const char* - - Value_impl(); // creates null value - Value_impl( Const_str_ptr value ); - Value_impl( const String_type& value ); - Value_impl( const Object& value ); - Value_impl( const Array& value ); - Value_impl( bool value ); - Value_impl( int value ); - Value_impl( int64_t value ); - Value_impl( uint64_t value ); - Value_impl( double value ); - - Value_impl( const Value_impl& other ); - - bool operator==( const Value_impl& lhs ) const; - - Value_impl& operator=( const Value_impl& lhs ); - - Value_type type() const; - - bool is_uint64() const; - bool is_null() const; - - const String_type& get_str() const; - const Object& get_obj() const; - const Array& get_array() const; - bool get_bool() const; - int get_int() const; - int64_t get_int64() const; - uint64_t get_uint64() const; - double get_real() const; - - Object& get_obj(); - Array& get_array(); - - template< typename T > T get_value() const; // example usage: int i = value.get_value< int >(); - // or double d = value.get_value< double >(); - - static const Value_impl null; - - private: - - void check_type( const Value_type vtype ) const; - - typedef boost::variant< String_type, - boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >, - bool, int64_t, double > Variant; - - Value_type type_; - Variant v_; - bool is_uint64_; - }; - - // vector objects - - template< class Config > - struct Pair_impl - { - typedef typename Config::String_type String_type; - typedef typename Config::Value_type Value_type; - - Pair_impl( const String_type& name, const Value_type& value ); - - bool operator==( const Pair_impl& lhs ) const; - - String_type name_; - Value_type value_; - }; - - template< class String > - struct Config_vector - { - typedef String String_type; - typedef Value_impl< Config_vector > Value_type; - typedef Pair_impl < Config_vector > Pair_type; - typedef std::vector< Value_type > Array_type; - typedef std::vector< Pair_type > Object_type; - - static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) - { - obj.push_back( Pair_type( name , value ) ); - - return obj.back().value_; - } - - static String_type get_name( const Pair_type& pair ) - { - return pair.name_; - } - - static Value_type get_value( const Pair_type& pair ) - { - return pair.value_; - } - }; - - // typedefs for ASCII - - typedef Config_vector< std::string > Config; - - typedef Config::Value_type Value; - typedef Config::Pair_type Pair; - typedef Config::Object_type Object; - typedef Config::Array_type Array; - - // typedefs for Unicode - -#ifndef BOOST_NO_STD_WSTRING - - typedef Config_vector< std::wstring > wConfig; - - typedef wConfig::Value_type wValue; - typedef wConfig::Pair_type wPair; - typedef wConfig::Object_type wObject; - typedef wConfig::Array_type wArray; -#endif - - // map objects - - template< class String > - struct Config_map - { - typedef String String_type; - typedef Value_impl< Config_map > Value_type; - typedef std::vector< Value_type > Array_type; - typedef std::map< String_type, Value_type > Object_type; - typedef typename Object_type::value_type Pair_type; - - static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value ) - { - return obj[ name ] = value; - } - - static String_type get_name( const Pair_type& pair ) - { - return pair.first; - } - - static Value_type get_value( const Pair_type& pair ) - { - return pair.second; - } - }; - - // typedefs for ASCII - - typedef Config_map< std::string > mConfig; - - typedef mConfig::Value_type mValue; - typedef mConfig::Object_type mObject; - typedef mConfig::Array_type mArray; - - // typedefs for Unicode - -#ifndef BOOST_NO_STD_WSTRING - - typedef Config_map< std::wstring > wmConfig; - - typedef wmConfig::Value_type wmValue; - typedef wmConfig::Object_type wmObject; - typedef wmConfig::Array_type wmArray; - -#endif - - /////////////////////////////////////////////////////////////////////////////////////////////// - // - // implementation - - template< class Config > - const Value_impl< Config > Value_impl< Config >::null; - - template< class Config > - Value_impl< Config >::Value_impl() - : type_( null_type ) - , is_uint64_( false ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Const_str_ptr value ) - : type_( str_type ) - , v_( String_type( value ) ) - , is_uint64_( false ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const String_type& value ) - : type_( str_type ) - , v_( value ) - , is_uint64_( false ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Object& value ) - : type_( obj_type ) - , v_( value ) - , is_uint64_( false ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Array& value ) - : type_( array_type ) - , v_( value ) - , is_uint64_( false ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( bool value ) - : type_( bool_type ) - , v_( value ) - , is_uint64_( false ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( int value ) - : type_( int_type ) - , v_( static_cast< int64_t >( value ) ) - , is_uint64_( false ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( int64_t value ) - : type_( int_type ) - , v_( value ) - , is_uint64_( false ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( uint64_t value ) - : type_( int_type ) - , v_( static_cast< int64_t >( value ) ) - , is_uint64_( true ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( double value ) - : type_( real_type ) - , v_( value ) - , is_uint64_( false ) - { - } - - template< class Config > - Value_impl< Config >::Value_impl( const Value_impl< Config >& other ) - : type_( other.type() ) - , v_( other.v_ ) - , is_uint64_( other.is_uint64_ ) - { - } - - template< class Config > - Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs ) - { - Value_impl tmp( lhs ); - - std::swap( type_, tmp.type_ ); - std::swap( v_, tmp.v_ ); - std::swap( is_uint64_, tmp.is_uint64_ ); - - return *this; - } - - template< class Config > - bool Value_impl< Config >::operator==( const Value_impl& lhs ) const - { - if( this == &lhs ) return true; - - if( type() != lhs.type() ) return false; - - return v_ == lhs.v_; - } - - template< class Config > - Value_type Value_impl< Config >::type() const - { - return type_; - } - - template< class Config > - bool Value_impl< Config >::is_uint64() const - { - return is_uint64_; - } - - template< class Config > - bool Value_impl< Config >::is_null() const - { - return type() == null_type; - } - - template< class Config > - void Value_impl< Config >::check_type( const Value_type vtype ) const - { - if( type() != vtype ) - { - std::ostringstream os; - - ///// Bitcoin: Tell the types by name instead of by number - os << "value is type " << Value_type_name[type()] << ", expected " << Value_type_name[vtype]; - - throw std::runtime_error( os.str() ); - } - } - - template< class Config > - const typename Config::String_type& Value_impl< Config >::get_str() const - { - check_type( str_type ); - - return *boost::get< String_type >( &v_ ); - } - - template< class Config > - const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const - { - check_type( obj_type ); - - return *boost::get< Object >( &v_ ); - } - - template< class Config > - const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const - { - check_type( array_type ); - - return *boost::get< Array >( &v_ ); - } - - template< class Config > - bool Value_impl< Config >::get_bool() const - { - check_type( bool_type ); - - return boost::get< bool >( v_ ); - } - - template< class Config > - int Value_impl< Config >::get_int() const - { - check_type( int_type ); - - return static_cast< int >( get_int64() ); - } - - template< class Config > - int64_t Value_impl< Config >::get_int64() const - { - check_type( int_type ); - - return boost::get< int64_t >( v_ ); - } - - template< class Config > - uint64_t Value_impl< Config >::get_uint64() const - { - check_type( int_type ); - - return static_cast< uint64_t >( get_int64() ); - } - - template< class Config > - double Value_impl< Config >::get_real() const - { - if( type() == int_type ) - { - return is_uint64() ? static_cast< double >( get_uint64() ) - : static_cast< double >( get_int64() ); - } - - check_type( real_type ); - - return boost::get< double >( v_ ); - } - - template< class Config > - typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() - { - check_type( obj_type ); - - return *boost::get< Object >( &v_ ); - } - - template< class Config > - typename Value_impl< Config >::Array& Value_impl< Config >::get_array() - { - check_type( array_type ); - - return *boost::get< Array >( &v_ ); - } - - template< class Config > - Pair_impl< Config >::Pair_impl( const String_type& name, const Value_type& value ) - : name_( name ) - , value_( value ) - { - } - - template< class Config > - bool Pair_impl< Config >::operator==( const Pair_impl< Config >& lhs ) const - { - if( this == &lhs ) return true; - - return ( name_ == lhs.name_ ) && ( value_ == lhs.value_ ); - } - - // converts a C string, ie. 8 bit char array, to a string object - // - template < class String_type > - String_type to_str( const char* c_str ) - { - String_type result; - - for( const char* p = c_str; *p != 0; ++p ) - { - result += *p; - } - - return result; - } - - // - - namespace internal_ - { - template< typename T > - struct Type_to_type - { - }; - - template< class Value > - int get_value( const Value& value, Type_to_type< int > ) - { - return value.get_int(); - } - - template< class Value > - int64_t get_value( const Value& value, Type_to_type< int64_t > ) - { - return value.get_int64(); - } - - template< class Value > - uint64_t get_value( const Value& value, Type_to_type< uint64_t > ) - { - return value.get_uint64(); - } - - template< class Value > - double get_value( const Value& value, Type_to_type< double > ) - { - return value.get_real(); - } - - template< class Value > - typename Value::String_type get_value( const Value& value, Type_to_type< typename Value::String_type > ) - { - return value.get_str(); - } - - template< class Value > - typename Value::Array get_value( const Value& value, Type_to_type< typename Value::Array > ) - { - return value.get_array(); - } - - template< class Value > - typename Value::Object get_value( const Value& value, Type_to_type< typename Value::Object > ) - { - return value.get_obj(); - } - - template< class Value > - bool get_value( const Value& value, Type_to_type< bool > ) - { - return value.get_bool(); - } - } - - template< class Config > - template< typename T > - T Value_impl< Config >::get_value() const - { - return internal_::get_value( *this, internal_::Type_to_type< T >() ); - } -} - -#endif diff --git a/src/json/json_spirit_writer.cpp b/src/json/json_spirit_writer.cpp deleted file mode 100644 index d24a632cf..000000000 --- a/src/json/json_spirit_writer.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#include "json_spirit_writer.h" -#include "json_spirit_writer_template.h" - -void json_spirit::write( const Value& value, std::ostream& os ) -{ - write_stream( value, os, false ); -} - -void json_spirit::write_formatted( const Value& value, std::ostream& os ) -{ - write_stream( value, os, true ); -} - -std::string json_spirit::write( const Value& value ) -{ - return write_string( value, false ); -} - -std::string json_spirit::write_formatted( const Value& value ) -{ - return write_string( value, true ); -} - -#ifndef BOOST_NO_STD_WSTRING - -void json_spirit::write( const wValue& value, std::wostream& os ) -{ - write_stream( value, os, false ); -} - -void json_spirit::write_formatted( const wValue& value, std::wostream& os ) -{ - write_stream( value, os, true ); -} - -std::wstring json_spirit::write( const wValue& value ) -{ - return write_string( value, false ); -} - -std::wstring json_spirit::write_formatted( const wValue& value ) -{ - return write_string( value, true ); -} - -#endif - -void json_spirit::write( const mValue& value, std::ostream& os ) -{ - write_stream( value, os, false ); -} - -void json_spirit::write_formatted( const mValue& value, std::ostream& os ) -{ - write_stream( value, os, true ); -} - -std::string json_spirit::write( const mValue& value ) -{ - return write_string( value, false ); -} - -std::string json_spirit::write_formatted( const mValue& value ) -{ - return write_string( value, true ); -} - -#ifndef BOOST_NO_STD_WSTRING - -void json_spirit::write( const wmValue& value, std::wostream& os ) -{ - write_stream( value, os, false ); -} - -void json_spirit::write_formatted( const wmValue& value, std::wostream& os ) -{ - write_stream( value, os, true ); -} - -std::wstring json_spirit::write( const wmValue& value ) -{ - return write_string( value, false ); -} - -std::wstring json_spirit::write_formatted( const wmValue& value ) -{ - return write_string( value, true ); -} - -#endif diff --git a/src/json/json_spirit_writer.h b/src/json/json_spirit_writer.h deleted file mode 100644 index 52e14068e..000000000 --- a/src/json/json_spirit_writer.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef JSON_SPIRIT_WRITER -#define JSON_SPIRIT_WRITER - -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include "json_spirit_value.h" -#include - -namespace json_spirit -{ - // functions to convert JSON Values to text, - // the "formatted" versions add whitespace to format the output nicely - - void write ( const Value& value, std::ostream& os ); - void write_formatted( const Value& value, std::ostream& os ); - std::string write ( const Value& value ); - std::string write_formatted( const Value& value ); - -#ifndef BOOST_NO_STD_WSTRING - - void write ( const wValue& value, std::wostream& os ); - void write_formatted( const wValue& value, std::wostream& os ); - std::wstring write ( const wValue& value ); - std::wstring write_formatted( const wValue& value ); - -#endif - - void write ( const mValue& value, std::ostream& os ); - void write_formatted( const mValue& value, std::ostream& os ); - std::string write ( const mValue& value ); - std::string write_formatted( const mValue& value ); - -#ifndef BOOST_NO_STD_WSTRING - - void write ( const wmValue& value, std::wostream& os ); - void write_formatted( const wmValue& value, std::wostream& os ); - std::wstring write ( const wmValue& value ); - std::wstring write_formatted( const wmValue& value ); - -#endif -} - -#endif diff --git a/src/json/json_spirit_writer_template.h b/src/json/json_spirit_writer_template.h deleted file mode 100644 index 6b4978a1f..000000000 --- a/src/json/json_spirit_writer_template.h +++ /dev/null @@ -1,249 +0,0 @@ -#ifndef JSON_SPIRIT_WRITER_TEMPLATE -#define JSON_SPIRIT_WRITER_TEMPLATE - -// Copyright John W. Wilkinson 2007 - 2009. -// Distributed under the MIT License, see accompanying file LICENSE.txt - -// json spirit version 4.03 - -#include "json_spirit_value.h" - -#include -#include -#include - -namespace json_spirit -{ - inline char to_hex_char( unsigned int c ) - { - assert( c <= 0xF ); - - const char ch = static_cast< char >( c ); - - if( ch < 10 ) return '0' + ch; - - return 'A' - 10 + ch; - } - - template< class String_type > - String_type non_printable_to_string( unsigned int c ) - { - // Silence the warning: typedef ‘Char_type’ locally defined but not used [-Wunused-local-typedefs] - // typedef typename String_type::value_type Char_type; - - String_type result( 6, '\\' ); - - result[1] = 'u'; - - result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4; - result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4; - result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4; - result[ 2 ] = to_hex_char( c & 0x000F ); - - return result; - } - - template< typename Char_type, class String_type > - bool add_esc_char( Char_type c, String_type& s ) - { - switch( c ) - { - case '"': s += to_str< String_type >( "\\\"" ); return true; - case '\\': s += to_str< String_type >( "\\\\" ); return true; - case '\b': s += to_str< String_type >( "\\b" ); return true; - case '\f': s += to_str< String_type >( "\\f" ); return true; - case '\n': s += to_str< String_type >( "\\n" ); return true; - case '\r': s += to_str< String_type >( "\\r" ); return true; - case '\t': s += to_str< String_type >( "\\t" ); return true; - } - - return false; - } - - template< class String_type > - String_type add_esc_chars( const String_type& s ) - { - typedef typename String_type::const_iterator Iter_type; - typedef typename String_type::value_type Char_type; - - String_type result; - - const Iter_type end( s.end() ); - - for( Iter_type i = s.begin(); i != end; ++i ) - { - const Char_type c( *i ); - - if( add_esc_char( c, result ) ) continue; - - const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c ); - - if( iswprint( unsigned_c ) ) - { - result += c; - } - else - { - result += non_printable_to_string< String_type >( unsigned_c ); - } - } - - return result; - } - - // this class generates the JSON text, - // it keeps track of the indentation level etc. - // - template< class Value_type, class Ostream_type > - class Generator - { - typedef typename Value_type::Config_type Config_type; - typedef typename Config_type::String_type String_type; - typedef typename Config_type::Object_type Object_type; - typedef typename Config_type::Array_type Array_type; - typedef typename String_type::value_type Char_type; - typedef typename Object_type::value_type Obj_member_type; - - public: - - Generator( const Value_type& value, Ostream_type& os, bool pretty ) - : os_( os ) - , indentation_level_( 0 ) - , pretty_( pretty ) - { - output( value ); - } - - private: - - void output( const Value_type& value ) - { - switch( value.type() ) - { - case obj_type: output( value.get_obj() ); break; - case array_type: output( value.get_array() ); break; - case str_type: output( value.get_str() ); break; - case bool_type: output( value.get_bool() ); break; - case int_type: output_int( value ); break; - - /// Bitcoin: Added std::fixed and changed precision from 16 to 8 - case real_type: os_ << std::showpoint << std::fixed << std::setprecision(8) - << value.get_real(); break; - - case null_type: os_ << "null"; break; - default: assert( false ); - } - } - - void output( const Object_type& obj ) - { - output_array_or_obj( obj, '{', '}' ); - } - - void output( const Array_type& arr ) - { - output_array_or_obj( arr, '[', ']' ); - } - - void output( const Obj_member_type& member ) - { - output( Config_type::get_name( member ) ); space(); - os_ << ':'; space(); - output( Config_type::get_value( member ) ); - } - - void output_int( const Value_type& value ) - { - if( value.is_uint64() ) - { - os_ << value.get_uint64(); - } - else - { - os_ << value.get_int64(); - } - } - - void output( const String_type& s ) - { - os_ << '"' << add_esc_chars( s ) << '"'; - } - - void output( bool b ) - { - os_ << to_str< String_type >( b ? "true" : "false" ); - } - - template< class T > - void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char ) - { - os_ << start_char; new_line(); - - ++indentation_level_; - - for( typename T::const_iterator i = t.begin(); i != t.end(); ++i ) - { - indent(); output( *i ); - - typename T::const_iterator next = i; - - if( ++next != t.end()) - { - os_ << ','; - } - - new_line(); - } - - --indentation_level_; - - indent(); os_ << end_char; - } - - void indent() - { - if( !pretty_ ) return; - - for( int i = 0; i < indentation_level_; ++i ) - { - os_ << " "; - } - } - - void space() - { - if( pretty_ ) os_ << ' '; - } - - void new_line() - { - if( pretty_ ) os_ << '\n'; - } - - Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning - - Ostream_type& os_; - int indentation_level_; - bool pretty_; - }; - - template< class Value_type, class Ostream_type > - void write_stream( const Value_type& value, Ostream_type& os, bool pretty ) - { - Generator< Value_type, Ostream_type >( value, os, pretty ); - } - - template< class Value_type > - typename Value_type::String_type write_string( const Value_type& value, bool pretty ) - { - typedef typename Value_type::String_type::value_type Char_type; - - std::basic_ostringstream< Char_type > os; - - write_stream( value, os, pretty ); - - return os.str(); - } -} - -#endif diff --git a/src/kernel.cpp b/src/kernel.cpp index 1423e22b2..7b3f241f4 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -1,5 +1,6 @@ /* @flow */ // Copyright (c) 2012-2013 The PPCoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -327,8 +328,13 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock blockFrom, const CTra bool fSuccess = false; unsigned int nTryTime = 0; unsigned int i; + int nHeightStart = chainActive.Height(); for (i = 0; i < (nHashDrift); i++) //iterate the hashing { + //new block came in, move on + if (chainActive.Height() != nHeightStart) + break; + //hash this iteration nTryTime = nTimeTx + nHashDrift - i; hashProofOfStake = stakeHash(nTryTime, ss, prevout.n, prevout.hash, nTimeBlockFrom); diff --git a/src/kernel.h b/src/kernel.h index 02d2b0469..32173ff28 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -1,4 +1,5 @@ // Copyright (c) 2012-2013 The PPCoin developers +// Copyright (c) 2015-2017 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_KERNEL_H diff --git a/src/key.h b/src/key.h index 46efc4c9c..9750a4477 100644 --- a/src/key.h +++ b/src/key.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/keystore.h b/src/keystore.h index 2773d9600..ca7a35632 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -45,6 +45,8 @@ class CKeyStore virtual bool RemoveWatchOnly(const CScript& dest) = 0; virtual bool HaveWatchOnly(const CScript& dest) const = 0; virtual bool HaveWatchOnly() const = 0; + + //! Support for MultiSig addresses virtual bool AddMultiSig(const CScript& dest) = 0; virtual bool RemoveMultiSig(const CScript& dest) = 0; virtual bool HaveMultiSig(const CScript& dest) const = 0; @@ -64,7 +66,7 @@ class CBasicKeyStore : public CKeyStore ScriptMap mapScripts; WatchOnlySet setWatchOnly; MultiSigScriptSet setMultiSig; - + public: bool AddKeyPubKey(const CKey& key, const CPubKey& pubkey); bool HaveKey(const CKeyID& address) const @@ -108,7 +110,7 @@ class CBasicKeyStore : public CKeyStore virtual bool RemoveWatchOnly(const CScript& dest); virtual bool HaveWatchOnly(const CScript& dest) const; virtual bool HaveWatchOnly() const; - + virtual bool AddMultiSig(const CScript& dest); virtual bool RemoveMultiSig(const CScript& dest); virtual bool HaveMultiSig(const CScript& dest) const; diff --git a/src/leveldb/db/memtable.cc b/src/leveldb/db/memtable.cc index bfec0a7e7..31ad995d1 100644 --- a/src/leveldb/db/memtable.cc +++ b/src/leveldb/db/memtable.cc @@ -101,7 +101,7 @@ void MemTable::Add(SequenceNumber s, ValueType type, p += 8; p = EncodeVarint32(p, val_size); memcpy(p, value.data(), val_size); - assert((p + val_size) - buf == encoded_len); + assert((p + val_size) - buf == (long)encoded_len); table_.Insert(buf); } diff --git a/src/leveldb/util/bloom.cc b/src/leveldb/util/bloom.cc index a27a2ace2..79276b847 100644 --- a/src/leveldb/util/bloom.cc +++ b/src/leveldb/util/bloom.cc @@ -47,7 +47,7 @@ class BloomFilterPolicy : public FilterPolicy { dst->resize(init_size + bytes, 0); dst->push_back(static_cast(k_)); // Remember # of probes in filter char* array = &(*dst)[init_size]; - for (size_t i = 0; i < n; i++) { + for (size_t i = 0; i < (size_t)n; i++) { // Use double-hashing to generate a sequence of hash values. // See analysis in [Kirsch,Mitzenmacher 2006]. uint32_t h = BloomHash(keys[i]); diff --git a/src/leveldb/util/logging.cc b/src/leveldb/util/logging.cc index ca6b32440..2a1028a2c 100644 --- a/src/leveldb/util/logging.cc +++ b/src/leveldb/util/logging.cc @@ -55,7 +55,7 @@ bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { const int delta = (c - '0'); static const uint64_t kMaxUint64 = ~static_cast(0); if (v > kMaxUint64/10 || - (v == kMaxUint64/10 && delta > kMaxUint64%10)) { + (v == kMaxUint64/10 && (uint64_t)delta > kMaxUint64%10)) { // Overflow return false; } diff --git a/src/libzerocoin/Accumulator.cpp b/src/libzerocoin/Accumulator.cpp new file mode 100644 index 000000000..1bf201a57 --- /dev/null +++ b/src/libzerocoin/Accumulator.cpp @@ -0,0 +1,145 @@ +/** + * @file Accumulator.cpp + * + * @brief Accumulator and AccumulatorWitness classes for the Zerocoin library. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers + +#include +#include +#include "Accumulator.h" +#include "ZerocoinDefines.h" + +namespace libzerocoin { + +//Accumulator class +Accumulator::Accumulator(const AccumulatorAndProofParams* p, const CoinDenomination d): params(p) { + if (!(params->initialized)) { + throw std::runtime_error("Invalid parameters for accumulator"); + } + denomination = d; + this->value = this->params->accumulatorBase; +} + +Accumulator::Accumulator(const ZerocoinParams* p, const CoinDenomination d, const Bignum bnValue) { + this->params = &(p->accumulatorParams); + denomination = d; + + if (!(params->initialized)) { + throw std::runtime_error("Invalid parameters for accumulator"); + } + + if(bnValue != 0) + this->value = bnValue; + else + this->value = this->params->accumulatorBase; +} + +void Accumulator::increment(const CBigNum& bnValue) { + // Compute new accumulator = "old accumulator"^{element} mod N + this->value = this->value.pow_mod(bnValue, this->params->accumulatorModulus); +} + +void Accumulator::accumulate(const PublicCoin& coin) { + // Make sure we're initialized + if(!(this->value)) { + std::cout << "Accumulator is not initialized" << "\n"; + throw std::runtime_error("Accumulator is not initialized"); + } + + if(this->denomination != coin.getDenomination()) { + std::cout << "Wrong denomination for coin. Expected coins of denomination: "; + std::cout << this->denomination; + std::cout << ". Instead, got a coin of denomination: "; + std::cout << coin.getDenomination(); + std::cout << "\n"; + throw std::runtime_error("Wrong denomination for coin"); + } + + if(coin.validate()) { + increment(coin.getValue()); + } else { + std::cout << "Coin not valid\n"; + throw std::runtime_error("Coin is not valid"); + } +} + +CoinDenomination Accumulator::getDenomination() const { + return this->denomination; +} + +const CBigNum& Accumulator::getValue() const { + return this->value; +} + +//Manually set accumulator value +void Accumulator::setValue(CBigNum bnValue) { + this->value = bnValue; +} + +Accumulator& Accumulator::operator += (const PublicCoin& c) { + this->accumulate(c); + return *this; +} + +Accumulator& Accumulator::operator = (Accumulator rhs) { + if (this != &rhs) std::swap(*this, rhs); + return *this; +} + +bool Accumulator::operator == (const Accumulator rhs) const { + return this->value == rhs.value; +} + +//AccumulatorWitness class +AccumulatorWitness::AccumulatorWitness(const ZerocoinParams* p, + const Accumulator& checkpoint, const PublicCoin coin): witness(checkpoint), element(coin) { +} + +void AccumulatorWitness::resetValue(const Accumulator& checkpoint, const PublicCoin coin) { + this->witness.setValue(checkpoint.getValue()); + this->element = coin; +} + +void AccumulatorWitness::AddElement(const PublicCoin& c) { + if(element != c) { + witness += c; + } +} + +//warning check pubcoin value & denom outside of this function! +void AccumulatorWitness::addRawValue(const CBigNum& bnValue) { + witness.increment(bnValue); +} + +const CBigNum& AccumulatorWitness::getValue() const { + return this->witness.getValue(); +} + +bool AccumulatorWitness::VerifyWitness(const Accumulator& a, const PublicCoin &publicCoin) const { + Accumulator temp(witness); + temp += element; + return (temp == a && this->element == publicCoin); +} + +AccumulatorWitness& AccumulatorWitness::operator +=( + const PublicCoin& rhs) { + this->AddElement(rhs); + return *this; +} + +AccumulatorWitness& AccumulatorWitness::operator =(AccumulatorWitness rhs) { + // Not pretty, but seems to work (SPOCK) + if (&witness != &rhs.witness) this->witness = rhs.witness; + if (&element != &rhs.element) std::swap(element, rhs.element); + return *this; +} + +} /* namespace libzerocoin */ diff --git a/src/libzerocoin/Accumulator.h b/src/libzerocoin/Accumulator.h new file mode 100644 index 000000000..2d251e8c1 --- /dev/null +++ b/src/libzerocoin/Accumulator.h @@ -0,0 +1,161 @@ +/** + * @file Accumulator.h + * + * @brief Accumulator and AccumulatorWitness classes for the Zerocoin library. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers +#ifndef ACCUMULATOR_H_ +#define ACCUMULATOR_H_ + +#include "Coin.h" + +namespace libzerocoin { +/** + * \brief Implementation of the RSA-based accumulator. + **/ + +class Accumulator { +public: + + /** + * @brief Construct an Accumulator from a stream. + * @param p An AccumulatorAndProofParams object containing global parameters + * @param d the denomination of coins we are accumulating + * @throw Zerocoin exception in case of invalid parameters + **/ + template + Accumulator(const AccumulatorAndProofParams* p, Stream& strm): params(p) { + strm >> *this; + } + + template + Accumulator(const ZerocoinParams* p, Stream& strm) { + strm >> *this; + this->params = &(p->accumulatorParams); + } + + /** + * @brief Construct an Accumulator from a Params object. + * @param p A Params object containing global parameters + * @param d the denomination of coins we are accumulating + * @throw Zerocoin exception in case of invalid parameters + **/ + Accumulator(const AccumulatorAndProofParams* p, const CoinDenomination d); + + Accumulator(const ZerocoinParams* p, const CoinDenomination d, Bignum bnValue = 0); + + /** + * Accumulate a coin into the accumulator. Validates + * the coin prior to accumulation. + * + * @param coin A PublicCoin to accumulate. + * + * @throw Zerocoin exception if the coin is not valid. + * + **/ + void accumulate(const PublicCoin &coin); + void increment(const CBigNum& bnValue); + + CoinDenomination getDenomination() const; + /** Get the accumulator result + * + * @return a CBigNum containing the result. + */ + const CBigNum& getValue() const; + + void setValue(CBigNum bnValue); + + + // /** + // * Used to set the accumulator value + // * + // * Use this to handle accumulator checkpoints + // * @param b the value to set the accumulator to. + // * @throw A ZerocoinException if the accumulator value is invalid. + // */ + // void setValue(CBigNum &b); // shouldn't this be a constructor? + + /** Used to accumulate a coin + * + * @param c the coin to accumulate + * @return a refrence to the updated accumulator. + */ + Accumulator& operator +=(const PublicCoin& c); + Accumulator& operator =(Accumulator rhs); + bool operator==(const Accumulator rhs) const; + ADD_SERIALIZE_METHODS; + template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(value); + READWRITE(denomination); + } +private: + const AccumulatorAndProofParams* params; + CBigNum value; + CoinDenomination denomination; +}; + +/**A witness that a PublicCoin is in the accumulation of a set of coins + * + */ +class AccumulatorWitness { +public: + template + AccumulatorWitness(const ZerocoinParams* p, Stream& strm) { + strm >> *this; + } + + /** Construct's a witness. You must add all elements after the witness + * @param p pointer to params + * @param checkpoint the last known accumulator value before the element was added + * @param coin the coin we want a witness to + */ + AccumulatorWitness(const ZerocoinParams* p, const Accumulator& checkpoint, const PublicCoin coin); + + /** Adds element to the set whose's accumulation we are proving coin is a member of + * + * @param c the coin to add + */ + void AddElement(const PublicCoin& c); + + /** Adds element to the set whose's accumulation we are proving coin is a member of. No checks performed! + * + * @param bnValue the coin's value to add + */ + void addRawValue(const CBigNum& bnValue); + + /** + * + * @return the value of the witness + */ + const CBigNum& getValue() const; + void resetValue(const Accumulator& checkpoint, const PublicCoin coin); + + /** Checks that this is a witness to the accumulation of coin + * @param a the accumulator we are checking against. + * @param publicCoin the coin we're providing a witness for + * @return True if the witness computation validates + */ + bool VerifyWitness(const Accumulator& a, const PublicCoin &publicCoin) const; + + /** + * Adds rhs to the set whose's accumulation were proving coin is a member of + * @param rhs the PublicCoin to add + * @return + */ + AccumulatorWitness& operator +=(const PublicCoin& rhs); + + AccumulatorWitness& operator =(AccumulatorWitness rhs); +private: + Accumulator witness; + PublicCoin element; // was const but changed to use setting in assignment +}; + +} /* namespace libzerocoin */ +#endif /* ACCUMULATOR_H_ */ diff --git a/src/libzerocoin/AccumulatorProofOfKnowledge.cpp b/src/libzerocoin/AccumulatorProofOfKnowledge.cpp new file mode 100644 index 000000000..b824cb94f --- /dev/null +++ b/src/libzerocoin/AccumulatorProofOfKnowledge.cpp @@ -0,0 +1,148 @@ +/** + * @file AccumulatorProofOfKnowledge.cpp + * + * @brief AccumulatorProofOfKnowledge class for the Zerocoin library. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers +#include "AccumulatorProofOfKnowledge.h" +#include "hash.h" + +namespace libzerocoin { + +AccumulatorProofOfKnowledge::AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p): params(p) {} + +AccumulatorProofOfKnowledge::AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p, + const Commitment& commitmentToCoin, const AccumulatorWitness& witness, + Accumulator& a): params(p) { + + CBigNum sg = params->accumulatorPoKCommitmentGroup.g; + CBigNum sh = params->accumulatorPoKCommitmentGroup.h; + + CBigNum g_n = params->accumulatorQRNCommitmentGroup.g; + CBigNum h_n = params->accumulatorQRNCommitmentGroup.h; + + CBigNum e = commitmentToCoin.getContents(); + CBigNum r = commitmentToCoin.getRandomness(); + + CBigNum aM_4 = params->accumulatorModulus/CBigNum((long)4); + + CBigNum r_1 = CBigNum::randBignum(params->accumulatorModulus/4); + CBigNum r_2 = CBigNum::randBignum(params->accumulatorModulus/4); + CBigNum r_3 = CBigNum::randBignum(params->accumulatorModulus/4); + + this->C_e = g_n.pow_mod(e, params->accumulatorModulus) * h_n.pow_mod(r_1, params->accumulatorModulus); + this->C_u = witness.getValue() * h_n.pow_mod(r_2, params->accumulatorModulus); + this->C_r = g_n.pow_mod(r_2, params->accumulatorModulus) * h_n.pow_mod(r_3, params->accumulatorModulus); + + CBigNum r_alpha = CBigNum::randBignum(params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_alpha = 0-r_alpha; + } + + CBigNum r_gamma = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); + CBigNum r_phi = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); + CBigNum r_psi = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); + CBigNum r_sigma = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); + CBigNum r_xi = CBigNum::randBignum(params->accumulatorPoKCommitmentGroup.modulus); + + CBigNum r_epsilon = CBigNum::randBignum((params->accumulatorModulus/4) * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_epsilon = 0-r_epsilon; + } + CBigNum r_eta = CBigNum::randBignum((params->accumulatorModulus/4) * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_eta = 0-r_eta; + } + CBigNum r_zeta = CBigNum::randBignum((params->accumulatorModulus/4) * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_zeta = 0-r_zeta; + } + + CBigNum r_beta = CBigNum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_beta = 0-r_beta; + } + CBigNum r_delta = CBigNum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * CBigNum(2).pow(params->k_prime + params->k_dprime)); + if(!(CBigNum::randBignum(CBigNum(3)) % 2)) { + r_delta = 0-r_delta; + } + + this->st_1 = (sg.pow_mod(r_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + this->st_2 = (((commitmentToCoin.getCommitmentValue() * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(r_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(r_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + this->st_3 = ((sg * commitmentToCoin.getCommitmentValue()).pow_mod(r_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + + this->t_1 = (h_n.pow_mod(r_zeta, params->accumulatorModulus) * g_n.pow_mod(r_epsilon, params->accumulatorModulus)) % params->accumulatorModulus; + this->t_2 = (h_n.pow_mod(r_eta, params->accumulatorModulus) * g_n.pow_mod(r_alpha, params->accumulatorModulus)) % params->accumulatorModulus; + this->t_3 = (C_u.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus; + this->t_4 = (C_r.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus; + + CHashWriter hasher(0,0); + hasher << *params << sg << sh << g_n << h_n << commitmentToCoin.getCommitmentValue() << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4; + + //According to the proof, this hash should be of length k_prime bits. It is currently greater than that, which should not be a problem, but we should check this. + CBigNum c = CBigNum(hasher.GetHash()); + + this->s_alpha = r_alpha - c*e; + this->s_beta = r_beta - c*r_2*e; + this->s_zeta = r_zeta - c*r_3; + this->s_sigma = r_sigma - c*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); + this->s_eta = r_eta - c*r_1; + this->s_epsilon = r_epsilon - c*r_2; + this->s_delta = r_delta - c*r_3*e; + this->s_xi = r_xi + c*r*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); + this->s_phi = (r_phi - c*r) % params->accumulatorPoKCommitmentGroup.groupOrder; + this->s_gamma = r_gamma - c*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); + this->s_psi = r_psi + c*r*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder)); +} + +/** + * Verifies that a commitment c is accumulated in accumulator a + */ +bool AccumulatorProofOfKnowledge:: Verify(const Accumulator& a, const CBigNum& valueOfCommitmentToCoin) const { + CBigNum sg = params->accumulatorPoKCommitmentGroup.g; + CBigNum sh = params->accumulatorPoKCommitmentGroup.h; + + CBigNum g_n = params->accumulatorQRNCommitmentGroup.g; + CBigNum h_n = params->accumulatorQRNCommitmentGroup.h; + + //According to the proof, this hash should be of length k_prime bits. It is currently greater than that, which should not be a problem, but we should check this. + CHashWriter hasher(0,0); + hasher << *params << sg << sh << g_n << h_n << valueOfCommitmentToCoin << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4; + + CBigNum c = CBigNum(hasher.GetHash()); //this hash should be of length k_prime bits + + CBigNum st_1_prime = (valueOfCommitmentToCoin.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * sg.pow_mod(s_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(s_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + CBigNum st_2_prime = (sg.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * ((valueOfCommitmentToCoin * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(s_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(s_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + CBigNum st_3_prime = (sg.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * (sg * valueOfCommitmentToCoin).pow_mod(s_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(s_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus; + + CBigNum t_1_prime = (C_r.pow_mod(c, params->accumulatorModulus) * h_n.pow_mod(s_zeta, params->accumulatorModulus) * g_n.pow_mod(s_epsilon, params->accumulatorModulus)) % params->accumulatorModulus; + CBigNum t_2_prime = (C_e.pow_mod(c, params->accumulatorModulus) * h_n.pow_mod(s_eta, params->accumulatorModulus) * g_n.pow_mod(s_alpha, params->accumulatorModulus)) % params->accumulatorModulus; + CBigNum t_3_prime = ((a.getValue()).pow_mod(c, params->accumulatorModulus) * C_u.pow_mod(s_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(s_beta, params->accumulatorModulus))) % params->accumulatorModulus; + CBigNum t_4_prime = (C_r.pow_mod(s_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(s_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(s_beta, params->accumulatorModulus))) % params->accumulatorModulus; + + bool result = false; + + bool result_st1 = (st_1 == st_1_prime); + bool result_st2 = (st_2 == st_2_prime); + bool result_st3 = (st_3 == st_3_prime); + + bool result_t1 = (t_1 == t_1_prime); + bool result_t2 = (t_2 == t_2_prime); + bool result_t3 = (t_3 == t_3_prime); + bool result_t4 = (t_4 == t_4_prime); + + bool result_range = ((s_alpha >= -(params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime + 1))) && (s_alpha <= (params->maxCoinValue * CBigNum(2).pow(params->k_prime + params->k_dprime + 1)))); + + result = result_st1 && result_st2 && result_st3 && result_t1 && result_t2 && result_t3 && result_t4 && result_range; + + return result; +} + +} /* namespace libzerocoin */ diff --git a/src/libzerocoin/AccumulatorProofOfKnowledge.h b/src/libzerocoin/AccumulatorProofOfKnowledge.h new file mode 100644 index 000000000..8e632156f --- /dev/null +++ b/src/libzerocoin/AccumulatorProofOfKnowledge.h @@ -0,0 +1,96 @@ +/** + * @file AccumulatorProofOfKnowledge.h + * + * @brief AccumulatorProofOfKnowledge class for the Zerocoin library. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers + +#ifndef ACCUMULATEPROOF_H_ +#define ACCUMULATEPROOF_H_ + +#include "Accumulator.h" +#include "Commitment.h" + +namespace libzerocoin { + +/** + * A prove that a value insde the commitment commitmentToCoin is in an accumulator a. + */ +class AccumulatorProofOfKnowledge { +public: + AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p); + + /** Generates a proof that a commitment to a coin c was accumulated + * @param p Cryptographic parameters + * @param commitmentToCoin commitment containing the coin we want to prove is accumulated + * @param witness The witness to the accumulation of the coin + * @param a + */ + AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p, const Commitment& commitmentToCoin, const AccumulatorWitness& witness, Accumulator& a); + /** Verifies that a commitment c is accumulated in accumulated a + */ + bool Verify(const Accumulator& a,const CBigNum& valueOfCommitmentToCoin) const; + + ADD_SERIALIZE_METHODS; + template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(C_e); + READWRITE(C_u); + READWRITE(C_r); + READWRITE(st_1); + READWRITE(st_2); + READWRITE(st_3); + READWRITE(t_1); + READWRITE(t_2); + READWRITE(t_3); + READWRITE(t_4); + READWRITE(s_alpha); + READWRITE(s_beta); + READWRITE(s_zeta); + READWRITE(s_sigma); + READWRITE(s_eta); + READWRITE(s_epsilon); + READWRITE(s_delta); + READWRITE(s_xi); + READWRITE(s_phi); + READWRITE(s_gamma); + READWRITE(s_psi); + } +private: + const AccumulatorAndProofParams* params; + + /* Return values for proof */ + CBigNum C_e; + CBigNum C_u; + CBigNum C_r; + + CBigNum st_1; + CBigNum st_2; + CBigNum st_3; + + CBigNum t_1; + CBigNum t_2; + CBigNum t_3; + CBigNum t_4; + + CBigNum s_alpha; + CBigNum s_beta; + CBigNum s_zeta; + CBigNum s_sigma; + CBigNum s_eta; + CBigNum s_epsilon; + CBigNum s_delta; + CBigNum s_xi; + CBigNum s_phi; + CBigNum s_gamma; + CBigNum s_psi; +}; + +} /* namespace libzerocoin */ +#endif /* ACCUMULATEPROOF_H_ */ diff --git a/src/libzerocoin/Coin.cpp b/src/libzerocoin/Coin.cpp new file mode 100644 index 000000000..be045383e --- /dev/null +++ b/src/libzerocoin/Coin.cpp @@ -0,0 +1,150 @@ +/** + * @file Coin.cpp + * + * @brief PublicCoin and PrivateCoin classes for the Zerocoin library. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ + +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers +#include +#include +#include "Coin.h" +#include "Commitment.h" +#include "Denominations.h" + +namespace libzerocoin { + +//PublicCoin class +PublicCoin::PublicCoin(const ZerocoinParams* p): + params(p) { + if (this->params->initialized == false) { + throw std::runtime_error("Params are not initialized"); + } + // Assume this will get set by another method later + denomination = ZQ_ERROR; +}; + +PublicCoin::PublicCoin(const ZerocoinParams* p, const CBigNum& coin, const CoinDenomination d): + params(p), value(coin) { + if (this->params->initialized == false) { + throw std::runtime_error("Params are not initialized"); + } + + denomination = d; + /* Do we need this? [oldschool] + for(const CoinDenomination denom : zerocoinDenomList) { + if(denom == d) + denomination = d; + } + */ + if(denomination == 0){ + std::cout << "denom does not exist\n"; + throw std::runtime_error("Denomination does not exist"); + } +}; + +//PrivateCoin class +PrivateCoin::PrivateCoin(const ZerocoinParams* p, const CoinDenomination denomination): params(p), publicCoin(p) { + // Verify that the parameters are valid + if(this->params->initialized == false) { + throw std::runtime_error("Params are not initialized"); + } + +#ifdef ZEROCOIN_FAST_MINT + // Mint a new coin with a random serial number using the fast process. + // This is more vulnerable to timing attacks so don't mint coins when + // somebody could be timing you. + this->mintCoinFast(denomination); +#else + // Mint a new coin with a random serial number using the standard process. + this->mintCoin(denomination); +#endif + +} + +void PrivateCoin::mintCoin(const CoinDenomination denomination) { + // Repeat this process up to MAX_COINMINT_ATTEMPTS times until + // we obtain a prime number + for(uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) { + + // Generate a random serial number in the range 0...{q-1} where + // "q" is the order of the commitment group. + CBigNum s = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder); + + // Generate a Pedersen commitment to the serial number "s" + Commitment coin(¶ms->coinCommitmentGroup, s); + + // Now verify that the commitment is a prime number + // in the appropriate range. If not, we'll throw this coin + // away and generate a new one. + if (coin.getCommitmentValue().isPrime(ZEROCOIN_MINT_PRIME_PARAM) && + coin.getCommitmentValue() >= params->accumulatorParams.minCoinValue && + coin.getCommitmentValue() <= params->accumulatorParams.maxCoinValue) { + // Found a valid coin. Store it. + this->serialNumber = s; + this->randomness = coin.getRandomness(); + this->publicCoin = PublicCoin(params,coin.getCommitmentValue(), denomination); + + // Success! We're done. + return; + } + } + + // We only get here if we did not find a coin within + // MAX_COINMINT_ATTEMPTS. Throw an exception. + throw std::runtime_error("Unable to mint a new Zerocoin (too many attempts)"); +} + +void PrivateCoin::mintCoinFast(const CoinDenomination denomination) { + + // Generate a random serial number in the range 0...{q-1} where + // "q" is the order of the commitment group. + CBigNum s = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder); + + // Generate a random number "r" in the range 0...{q-1} + CBigNum r = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder); + + // Manually compute a Pedersen commitment to the serial number "s" under randomness "r" + // C = g^s * h^r mod p + CBigNum commitmentValue = this->params->coinCommitmentGroup.g.pow_mod(s, this->params->coinCommitmentGroup.modulus).mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus); + + // Repeat this process up to MAX_COINMINT_ATTEMPTS times until + // we obtain a prime number + for (uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) { + // First verify that the commitment is a prime number + // in the appropriate range. If not, we'll throw this coin + // away and generate a new one. + if (commitmentValue.isPrime(ZEROCOIN_MINT_PRIME_PARAM) && + commitmentValue >= params->accumulatorParams.minCoinValue && + commitmentValue <= params->accumulatorParams.maxCoinValue) { + // Found a valid coin. Store it. + this->serialNumber = s; + this->randomness = r; + this->publicCoin = PublicCoin(params, commitmentValue, denomination); + + // Success! We're done. + return; + } + + // Generate a new random "r_delta" in 0...{q-1} + CBigNum r_delta = CBigNum::randBignum(this->params->coinCommitmentGroup.groupOrder); + + // The commitment was not prime. Increment "r" and recalculate "C": + // r = r + r_delta mod q + // C = C * h mod p + r = (r + r_delta) % this->params->coinCommitmentGroup.groupOrder; + commitmentValue = commitmentValue.mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r_delta, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus); + } + + // We only get here if we did not find a coin within + // MAX_COINMINT_ATTEMPTS. Throw an exception. + throw std::runtime_error("Unable to mint a new Zerocoin (too many attempts)"); +} + +} /* namespace libzerocoin */ diff --git a/src/libzerocoin/Coin.h b/src/libzerocoin/Coin.h new file mode 100644 index 000000000..6b7302a56 --- /dev/null +++ b/src/libzerocoin/Coin.h @@ -0,0 +1,150 @@ +/** + * @file Coin.h + * + * @brief PublicCoin and PrivateCoin classes for the Zerocoin library. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2017 The PIVX developers + +#ifndef COIN_H_ +#define COIN_H_ +#include "Denominations.h" +#include "Params.h" +#include "amount.h" +#include "bignum.h" +#include "util.h" +namespace libzerocoin +{ +/** A Public coin is the part of a coin that + * is published to the network and what is handled + * by other clients. It contains only the value + * of commitment to a serial number and the + * denomination of the coin. + */ +class PublicCoin +{ +public: + template + PublicCoin(const ZerocoinParams* p, Stream& strm) : params(p) + { + strm >> *this; + } + + PublicCoin(const ZerocoinParams* p); + + /**Generates a public coin + * + * @param p cryptographic paramters + * @param coin the value of the commitment. + * @param denomination The denomination of the coin. + */ + PublicCoin(const ZerocoinParams* p, const CBigNum& coin, const CoinDenomination d); + const CBigNum& getValue() const { return this->value; } + + CoinDenomination getDenomination() const { return this->denomination; } + bool operator==(const PublicCoin& rhs) const + { + return ((this->value == rhs.value) && (this->params == rhs.params) && (this->denomination == rhs.denomination)); + } + bool operator!=(const PublicCoin& rhs) const { return !(*this == rhs); } + /** Checks that coin is prime and in the appropriate range given the parameters + * @return true if valid + */ + bool validate() const { + return (this->params->accumulatorParams.minCoinValue < value) && (value < this->params->accumulatorParams.maxCoinValue) && value.isPrime(params->zkp_iterations); + } + + ADD_SERIALIZE_METHODS; + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + { + READWRITE(value); + READWRITE(denomination); + } + +private: + const ZerocoinParams* params; + CBigNum value; + CoinDenomination denomination; +}; + +/** + * A private coin. As the name implies, the content + * of this should stay private except PublicCoin. + * + * Contains a coin's serial number, a commitment to it, + * and opening randomness for the commitment. + * + * @warning Failure to keep this secret(or safe), + * @warning will result in the theft of your coins + * @warning and a TOTAL loss of anonymity. + */ +class PrivateCoin +{ +public: + template + PrivateCoin(const ZerocoinParams* p, Stream& strm) : params(p), publicCoin(p) + { + strm >> *this; + } + PrivateCoin(const ZerocoinParams* p, const CoinDenomination denomination); + const PublicCoin& getPublicCoin() const { return this->publicCoin; } + // @return the coins serial number + const CBigNum& getSerialNumber() const { return this->serialNumber; } + const CBigNum& getRandomness() const { return this->randomness; } + + void setPublicCoin(PublicCoin p) { publicCoin = p; } + void setRandomness(Bignum n) { randomness = n; } + void setSerialNumber(Bignum n) { serialNumber = n; } + + ADD_SERIALIZE_METHODS; + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + { + READWRITE(publicCoin); + READWRITE(randomness); + READWRITE(serialNumber); + } + +private: + const ZerocoinParams* params; + PublicCoin publicCoin; + CBigNum randomness; + CBigNum serialNumber; + + /** + * @brief Mint a new coin. + * @param denomination the denomination of the coin to mint + * @throws ZerocoinException if the process takes too long + * + * Generates a new Zerocoin by (a) selecting a random serial + * number, (b) committing to this serial number and repeating until + * the resulting commitment is prime. Stores the + * resulting commitment (coin) and randomness (trapdoor). + **/ + void mintCoin(const CoinDenomination denomination); + + /** + * @brief Mint a new coin using a faster process. + * @param denomination the denomination of the coin to mint + * @throws ZerocoinException if the process takes too long + * + * Generates a new Zerocoin by (a) selecting a random serial + * number, (b) committing to this serial number and repeating until + * the resulting commitment is prime. Stores the + * resulting commitment (coin) and randomness (trapdoor). + * This routine is substantially faster than the + * mintCoin() routine, but could be more vulnerable + * to timing attacks. Don't use it if you think someone + * could be timing your coin minting. + **/ + void mintCoinFast(const CoinDenomination denomination); +}; + +} /* namespace libzerocoin */ +#endif /* COIN_H_ */ diff --git a/src/libzerocoin/CoinSpend.cpp b/src/libzerocoin/CoinSpend.cpp new file mode 100644 index 000000000..8dcebabcf --- /dev/null +++ b/src/libzerocoin/CoinSpend.cpp @@ -0,0 +1,83 @@ +/** + * @file CoinSpend.cpp + * + * @brief CoinSpend class for the Zerocoin library. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2017 The PIVX developers +#include "CoinSpend.h" +#include +namespace libzerocoin +{ +CoinSpend::CoinSpend(const ZerocoinParams* p, const PrivateCoin& coin, Accumulator& a, const uint32_t checksum, const AccumulatorWitness& witness, const uint256& ptxHash) : accChecksum(checksum), + ptxHash(ptxHash), + coinSerialNumber((coin.getSerialNumber())), + accumulatorPoK(&p->accumulatorParams), + serialNumberSoK(p), + commitmentPoK(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup) +{ + denomination = coin.getPublicCoin().getDenomination(); + // Sanity check: let's verify that the Witness is valid with respect to + // the coin and Accumulator provided. + if (!(witness.VerifyWitness(a, coin.getPublicCoin()))) { + std::cout << "CoinSpend: Accumulator witness does not verify\n"; + throw std::runtime_error("Accumulator witness does not verify"); + } + + // 1: Generate two separate commitments to the public coin (C), each under + // a different set of public parameters. We do this because the RSA accumulator + // has specific requirements for the commitment parameters that are not + // compatible with the group we use for the serial number proof. + // Specifically, our serial number proof requires the order of the commitment group + // to be the same as the modulus of the upper group. The Accumulator proof requires a + // group with a significantly larger order. + const Commitment fullCommitmentToCoinUnderSerialParams(&p->serialNumberSoKCommitmentGroup, coin.getPublicCoin().getValue()); + this->serialCommitmentToCoinValue = fullCommitmentToCoinUnderSerialParams.getCommitmentValue(); + + const Commitment fullCommitmentToCoinUnderAccParams(&p->accumulatorParams.accumulatorPoKCommitmentGroup, coin.getPublicCoin().getValue()); + this->accCommitmentToCoinValue = fullCommitmentToCoinUnderAccParams.getCommitmentValue(); + + // 2. Generate a ZK proof that the two commitments contain the same public coin. + this->commitmentPoK = CommitmentProofOfKnowledge(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup, fullCommitmentToCoinUnderSerialParams, fullCommitmentToCoinUnderAccParams); + + // Now generate the two core ZK proofs: + // 3. Proves that the committed public coin is in the Accumulator (PoK of "witness") + this->accumulatorPoK = AccumulatorProofOfKnowledge(&p->accumulatorParams, fullCommitmentToCoinUnderAccParams, witness, a); + + // 4. Proves that the coin is correct w.r.t. serial number and hidden coin secret + // (This proof is bound to the coin 'metadata', i.e., transaction hash) + this->serialNumberSoK = SerialNumberSignatureOfKnowledge(p, coin, fullCommitmentToCoinUnderSerialParams, signatureHash()); +} + +bool CoinSpend::Verify(const Accumulator& a) const +{ + // Verify both of the sub-proofs using the given meta-data + return (a.getDenomination() == this->denomination) && commitmentPoK.Verify(serialCommitmentToCoinValue, accCommitmentToCoinValue) && accumulatorPoK.Verify(a, accCommitmentToCoinValue) && serialNumberSoK.Verify(coinSerialNumber, serialCommitmentToCoinValue, signatureHash()); +} + +const uint256 CoinSpend::signatureHash() const +{ + CHashWriter h(0, 0); + h << serialCommitmentToCoinValue << accCommitmentToCoinValue << commitmentPoK << accumulatorPoK << ptxHash + << coinSerialNumber << accChecksum << denomination; + return h.GetHash(); +} + +bool CoinSpend::HasValidSerial(ZerocoinParams* params) const +{ + return coinSerialNumber > 0 && coinSerialNumber < params->coinCommitmentGroup.groupOrder; +} + +CBigNum CoinSpend::CalculateValidSerial(ZerocoinParams* params) +{ + CBigNum bnSerial = coinSerialNumber; + bnSerial = bnSerial.mul_mod(CBigNum(1),params->coinCommitmentGroup.groupOrder); + return bnSerial; +} + +} /* namespace libzerocoin */ diff --git a/src/libzerocoin/CoinSpend.h b/src/libzerocoin/CoinSpend.h new file mode 100644 index 000000000..7f163732b --- /dev/null +++ b/src/libzerocoin/CoinSpend.h @@ -0,0 +1,133 @@ +/** + * @file CoinSpend.h + * + * @brief CoinSpend class for the Zerocoin library. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers + +#ifndef COINSPEND_H_ +#define COINSPEND_H_ + +#include "Accumulator.h" +#include "AccumulatorProofOfKnowledge.h" +#include "Coin.h" +#include "Commitment.h" +#include "Params.h" +#include "SerialNumberSignatureOfKnowledge.h" +#include "bignum.h" +#include "serialize.h" + +namespace libzerocoin +{ +/** + * The complete proof needed to spend a zerocoin. + * Composes together a proof that a coin is accumulated + * and that it has a given serial number. + */ +class CoinSpend +{ +public: + template + CoinSpend(const ZerocoinParams* p, Stream& strm) : accumulatorPoK(&p->accumulatorParams), + serialNumberSoK(p), + commitmentPoK(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup) + { + strm >> *this; + } + /** + * Generates a proof spending a zerocoin. + * + * To use this, provide an unspent PrivateCoin, the latest Accumulator + * (e.g from the most recent Bitcoin block) containing the public part + * of the coin, a witness to that, and whatever medeta data is needed. + * + * Once constructed, this proof can be serialized and sent. + * It is validated simply be calling validate. + * @warning Validation only checks that the proof is correct + * @warning for the specified values in this class. These values must be validated + * Clients ought to check that + * 1) params is the right params + * 2) the accumulator actually is in some block + * 3) that the serial number is unspent + * 4) that the transaction + * + * @param p cryptographic parameters + * @param coin The coin to be spend + * @param a The current accumulator containing the coin + * @param witness The witness showing that the accumulator contains the coin + * @param a hash of the partial transaction that contains this coin spend + * @throw ZerocoinException if the process fails + */ + CoinSpend(const ZerocoinParams* p, const PrivateCoin& coin, Accumulator& a, const uint32_t checksum, const AccumulatorWitness& witness, const uint256& ptxHash); + + /** + * Returns the serial number of the coin spend by this proof. + * + * @return the coin's serial number + */ + const CBigNum& getCoinSerialNumber() const { return this->coinSerialNumber; } + + /** + * Gets the denomination of the coin spent in this proof. + * + * @return the denomination + */ + CoinDenomination getDenomination() const { return this->denomination; } + + /** + * Gets the checksum of the accumulator used in this proof. + * + * @return the checksum + */ + uint32_t getAccumulatorChecksum() const { return this->accChecksum; } + + /** + * Gets the txout hash used in this proof. + * + * @return the txout hash + */ + uint256 getTxOutHash() const { return ptxHash; } + CBigNum getAccCommitment() const { return accCommitmentToCoinValue; } + CBigNum getSerialComm() const { return serialCommitmentToCoinValue; } + + bool Verify(const Accumulator& a) const; + bool HasValidSerial(ZerocoinParams* params) const; + CBigNum CalculateValidSerial(ZerocoinParams* params); + + ADD_SERIALIZE_METHODS; + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + { + READWRITE(denomination); + READWRITE(ptxHash); + READWRITE(accChecksum); + READWRITE(accCommitmentToCoinValue); + READWRITE(serialCommitmentToCoinValue); + READWRITE(coinSerialNumber); + READWRITE(accumulatorPoK); + READWRITE(serialNumberSoK); + READWRITE(commitmentPoK); + } + +private: + const uint256 signatureHash() const; + CoinDenomination denomination; + uint32_t accChecksum; + uint256 ptxHash; + CBigNum accCommitmentToCoinValue; + CBigNum serialCommitmentToCoinValue; + CBigNum coinSerialNumber; + AccumulatorProofOfKnowledge accumulatorPoK; + SerialNumberSignatureOfKnowledge serialNumberSoK; + CommitmentProofOfKnowledge commitmentPoK; +}; + +} /* namespace libzerocoin */ +#endif /* COINSPEND_H_ */ diff --git a/src/libzerocoin/Commitment.cpp b/src/libzerocoin/Commitment.cpp new file mode 100644 index 000000000..ffe9bafd3 --- /dev/null +++ b/src/libzerocoin/Commitment.cpp @@ -0,0 +1,174 @@ +/** + * @file Commitment.cpp + * + * @brief Commitment and CommitmentProof classes for the Zerocoin library. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2017 The PIVX developers + +#include +#include "Commitment.h" +#include "hash.h" + +namespace libzerocoin { + +//Commitment class +Commitment::Commitment::Commitment(const IntegerGroupParams* p, + const CBigNum& value): params(p), contents(value) { + this->randomness = CBigNum::randBignum(params->groupOrder); + this->commitmentValue = (params->g.pow_mod(this->contents, params->modulus).mul_mod( + params->h.pow_mod(this->randomness, params->modulus), params->modulus)); +} + +const CBigNum& Commitment::getCommitmentValue() const { + return this->commitmentValue; +} + +const CBigNum& Commitment::getRandomness() const { + return this->randomness; +} + +const CBigNum& Commitment::getContents() const { + return this->contents; +} + +//CommitmentProofOfKnowledge class +CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams* ap, const IntegerGroupParams* bp): ap(ap), bp(bp) {} + +// TODO: get parameters from the commitment group +CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, + const IntegerGroupParams* bParams, const Commitment& a, const Commitment& b): + ap(aParams),bp(bParams) +{ + CBigNum r1, r2, r3; + + // First: make sure that the two commitments have the + // same contents. + if (a.getContents() != b.getContents()) { + throw std::runtime_error("Both commitments must contain the same value"); + } + + // Select three random values "r1, r2, r3" in the range 0 to (2^l)-1 where l is: + // length of challenge value + max(modulus 1, modulus 2, order 1, order 2) + margin. + // We set "margin" to be a relatively generous security parameter. + // + // We choose these large values to ensure statistical zero knowledge. + uint32_t randomSize = COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN + + std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()), + std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize())); + CBigNum maxRange = (CBigNum(2).pow(randomSize) - CBigNum(1)); + + r1 = CBigNum::randBignum(maxRange); + r2 = CBigNum::randBignum(maxRange); + r3 = CBigNum::randBignum(maxRange); + + // Generate two random, ephemeral commitments "T1, T2" + // of the form: + // T1 = g1^r1 * h1^r2 mod p1 + // T2 = g2^r1 * h2^r3 mod p2 + // + // Where (g1, h1, p1) are from "aParams" and (g2, h2, p2) are from "bParams". + CBigNum T1 = this->ap->g.pow_mod(r1, this->ap->modulus).mul_mod((this->ap->h.pow_mod(r2, this->ap->modulus)), this->ap->modulus); + CBigNum T2 = this->bp->g.pow_mod(r1, this->bp->modulus).mul_mod((this->bp->h.pow_mod(r3, this->bp->modulus)), this->bp->modulus); + + // Now hash commitment "A" with commitment "B" as well as the + // parameters and the two ephemeral commitments "T1, T2" we just generated + this->challenge = calculateChallenge(a.getCommitmentValue(), b.getCommitmentValue(), T1, T2); + + // Let "m" be the contents of the commitments "A, B". We have: + // A = g1^m * h1^x mod p1 + // B = g2^m * h2^y mod p2 + // T1 = g1^r1 * h1^r2 mod p1 + // T2 = g2^r1 * h2^r3 mod p2 + // + // Now compute: + // S1 = r1 + (m * challenge) -- note, not modular arithmetic + // S2 = r2 + (x * challenge) -- note, not modular arithmetic + // S3 = r3 + (y * challenge) -- note, not modular arithmetic + this->S1 = r1 + (a.getContents() * this->challenge); + this->S2 = r2 + (a.getRandomness() * this->challenge); + this->S3 = r3 + (b.getRandomness() * this->challenge); + + // We're done. The proof is S1, S2, S3 and "challenge", all of which + // are stored in member variables. +} + +bool CommitmentProofOfKnowledge::Verify(const CBigNum& A, const CBigNum& B) const +{ + // Compute the maximum range of S1, S2, S3 and verify that the given values are + // in a correct range. This might be an unnecessary check. + uint32_t maxSize = 64 * (COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN + + std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()), + std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize()))); + + if ((uint32_t)this->S1.bitSize() > maxSize || + (uint32_t)this->S2.bitSize() > maxSize || + (uint32_t)this->S3.bitSize() > maxSize || + this->S1 < CBigNum(0) || + this->S2 < CBigNum(0) || + this->S3 < CBigNum(0) || + this->challenge < CBigNum(0) || + this->challenge > (CBigNum(2).pow(COMMITMENT_EQUALITY_CHALLENGE_SIZE) - CBigNum(1))) { + // Invalid inputs. Reject. + return false; + } + + // Compute T1 = g1^S1 * h1^S2 * inverse(A^{challenge}) mod p1 + CBigNum T1 = A.pow_mod(this->challenge, ap->modulus).inverse(ap->modulus).mul_mod( + (ap->g.pow_mod(S1, ap->modulus).mul_mod(ap->h.pow_mod(S2, ap->modulus), ap->modulus)), + ap->modulus); + + // Compute T2 = g2^S1 * h2^S3 * inverse(B^{challenge}) mod p2 + CBigNum T2 = B.pow_mod(this->challenge, bp->modulus).inverse(bp->modulus).mul_mod( + (bp->g.pow_mod(S1, bp->modulus).mul_mod(bp->h.pow_mod(S3, bp->modulus), bp->modulus)), + bp->modulus); + + // Hash T1 and T2 along with all of the public parameters + CBigNum computedChallenge = calculateChallenge(A, B, T1, T2); + + // Return success if the computed challenge matches the incoming challenge + if(computedChallenge == this->challenge) { + return true; + } + + // Otherwise return failure + return false; +} + +const CBigNum CommitmentProofOfKnowledge::calculateChallenge(const CBigNum& a, const CBigNum& b, const CBigNum &commitOne, const CBigNum &commitTwo) const { + CHashWriter hasher(0,0); + + // Hash together the following elements: + // * A string identifying the proof + // * Commitment A + // * Commitment B + // * Ephemeral commitment T1 + // * Ephemeral commitment T2 + // * A serialized instance of the commitment A parameters + // * A serialized instance of the commitment B parameters + + hasher << std::string(ZEROCOIN_COMMITMENT_EQUALITY_PROOF); + hasher << commitOne; + hasher << std::string("||"); + hasher << commitTwo; + hasher << std::string("||"); + hasher << a; + hasher << std::string("||"); + hasher << b; + hasher << std::string("||"); + hasher << *(this->ap); + hasher << std::string("||"); + hasher << *(this->bp); + + // Convert the SHA256 result into a Bignum + // Note that if we ever change the size of the hash function we will have + // to update COMMITMENT_EQUALITY_CHALLENGE_SIZE appropriately! + return CBigNum(hasher.GetHash()); +} + +} /* namespace libzerocoin */ diff --git a/src/libzerocoin/Commitment.h b/src/libzerocoin/Commitment.h new file mode 100644 index 000000000..3ec2c11ec --- /dev/null +++ b/src/libzerocoin/Commitment.h @@ -0,0 +1,110 @@ +/** + * @file Commitment.h + * + * @brief Commitment and CommitmentProof classes for the Zerocoin library. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers + +#ifndef COMMITMENT_H_ +#define COMMITMENT_H_ + +#include "Params.h" +#include "serialize.h" + +// We use a SHA256 hash for our PoK challenges. Update the following +// if we ever change hash functions. +#define COMMITMENT_EQUALITY_CHALLENGE_SIZE 256 + +// A 512-bit security parameter for the statistical ZK PoK. +#define COMMITMENT_EQUALITY_SECMARGIN 512 + +namespace libzerocoin { + +/** + * A commitment, complete with contents and opening randomness. + * These should remain secret. Publish only the commitment value. + */ +class Commitment { +public: + /**Generates a Pedersen commitment to the given value. + * + * @param p the group parameters for the coin + * @param value the value to commit to + */ + Commitment(const IntegerGroupParams* p, const CBigNum& value); + const CBigNum& getCommitmentValue() const; + const CBigNum& getRandomness() const; + const CBigNum& getContents() const; +private: + const IntegerGroupParams *params; + CBigNum commitmentValue; + CBigNum randomness; + const CBigNum contents; + ADD_SERIALIZE_METHODS; + template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(commitmentValue); + READWRITE(randomness); + READWRITE(contents); + } +}; + +/** + * Proof that two commitments open to the same value. + */ +class CommitmentProofOfKnowledge { +public: + CommitmentProofOfKnowledge(const IntegerGroupParams* ap, const IntegerGroupParams* bp); + /** Generates a proof that two commitments, a and b, open to the same value. + * + * @param ap the IntegerGroup for commitment a + * @param bp the IntegerGroup for commitment b + * @param a the first commitment + * @param b the second commitment + */ + CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, const IntegerGroupParams* bParams, const Commitment& a, const Commitment& b); + //FIXME: is it best practice that this is here? + template + CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, + const IntegerGroupParams* bParams, Stream& strm): ap(aParams), bp(bParams) + { + strm >> *this; + } + + const CBigNum calculateChallenge(const CBigNum& a, const CBigNum& b, const CBigNum &commitOne, const CBigNum &commitTwo) const; + + /** + * Verifies the proof + * + * @return true if the proof is valid. + */ + // ? [oldschool] + /** + * Verifies the proof of equality of the two commitments + * + * @param A value of commitment one + * @param B value of commitment two + * @return + */ + bool Verify(const CBigNum& A, const CBigNum& B) const; + ADD_SERIALIZE_METHODS; + template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(S1); + READWRITE(S2); + READWRITE(S3); + READWRITE(challenge); + } +private: + const IntegerGroupParams *ap, *bp; + + CBigNum S1, S2, S3, challenge; +}; + +} /* namespace libzerocoin */ +#endif /* COMMITMENT_H_ */ diff --git a/src/libzerocoin/Denominations.cpp b/src/libzerocoin/Denominations.cpp new file mode 100644 index 000000000..02e3ac13d --- /dev/null +++ b/src/libzerocoin/Denominations.cpp @@ -0,0 +1,121 @@ +/** + * @file Denominations.cpp + * + * @brief Functions for converting to/from Zerocoin Denominations to other values library. + * + * @copyright Copyright 2017 PIVX Developers + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2018 The Bulwark Core Developers + +#include "Denominations.h" +#include "amount.h" + +namespace libzerocoin { +// All denomination values should only exist in these routines for consistency. +// For serialization/unserialization enums are converted to int (denoted enumvalue in function name) + +CoinDenomination IntToZerocoinDenomination(int64_t amount) +{ + CoinDenomination denomination; + switch (amount) { + case 1: denomination = CoinDenomination::ZQ_ONE; break; + case 5: denomination = CoinDenomination::ZQ_FIVE; break; + case 10: denomination = CoinDenomination::ZQ_TEN; break; + case 50: denomination = CoinDenomination::ZQ_FIFTY; break; + case 100: denomination = CoinDenomination::ZQ_ONE_HUNDRED; break; + case 500: denomination = CoinDenomination::ZQ_FIVE_HUNDRED; break; + case 1000: denomination = CoinDenomination::ZQ_ONE_THOUSAND; break; + default: + //not a valid denomination + denomination = CoinDenomination::ZQ_ERROR; break; + } + + return denomination; +} + +int64_t ZerocoinDenominationToInt(const CoinDenomination& denomination) +{ + int64_t Value = 0; + switch (denomination) { + case CoinDenomination::ZQ_ONE: Value = 1; break; + case CoinDenomination::ZQ_FIVE: Value = 5; break; + case CoinDenomination::ZQ_TEN: Value = 10; break; + case CoinDenomination::ZQ_FIFTY : Value = 50; break; + case CoinDenomination::ZQ_ONE_HUNDRED: Value = 100; break; + case CoinDenomination::ZQ_FIVE_HUNDRED: Value = 500; break; + case CoinDenomination::ZQ_ONE_THOUSAND: Value = 1000; break; + default: + // Error Case + Value = 0; break; + } + return Value; +} + +CoinDenomination AmountToZerocoinDenomination(CAmount amount) +{ + // Check to make sure amount is an exact integer number of COINS + CAmount residual_amount = amount - COIN * (amount / COIN); + if (residual_amount == 0) { + return IntToZerocoinDenomination(amount/COIN); + } else { + return CoinDenomination::ZQ_ERROR; + } +} + +// return the highest denomination that is less than or equal to the amount given +// use case: converting BWK to zBWK without user worrying about denomination math themselves +CoinDenomination AmountToClosestDenomination(CAmount nAmount, CAmount& nRemaining) +{ + if (nAmount < 1 * COIN) + return ZQ_ERROR; + + CAmount nConvert = nAmount / COIN; + CoinDenomination denomination = ZQ_ERROR; + for (unsigned int i = 0; i < zerocoinDenomList.size(); i++) { + denomination = zerocoinDenomList[i]; + + //exact match + if (nConvert == denomination) { + nRemaining = 0; + return denomination; + } + + //we are beyond the value, use previous denomination + if (denomination > nConvert && i) { + CoinDenomination d = zerocoinDenomList[i - 1]; + nRemaining = nConvert - d; + return d; + } + } + //last denomination, the highest value possible + nRemaining = nConvert - denomination; + return denomination; +} + +CAmount ZerocoinDenominationToAmount(const CoinDenomination& denomination) +{ + CAmount nValue = COIN * ZerocoinDenominationToInt(denomination); + return nValue; +} + + +CoinDenomination get_denomination(std::string denomAmount) { + int64_t val = std::stoi(denomAmount); + return IntToZerocoinDenomination(val); +} + + +int64_t get_amount(std::string denomAmount) { + int64_t nAmount = 0; + CoinDenomination denom = get_denomination(denomAmount); + if (denom == ZQ_ERROR) { + // SHOULD WE THROW EXCEPTION or Something? + nAmount = 0; + } else { + nAmount = ZerocoinDenominationToAmount(denom); + } + return nAmount; +} + +} /* namespace libzerocoin */ diff --git a/src/libzerocoin/Denominations.h b/src/libzerocoin/Denominations.h new file mode 100644 index 000000000..bb08af1a2 --- /dev/null +++ b/src/libzerocoin/Denominations.h @@ -0,0 +1,45 @@ +/** + * @file Denominations.h + * + * @brief Denomination info for the Zerocoin library. + * + * @copyright Copyright 2017 PIVX Developers + * @license This project is released under the MIT license. + **/ + +#ifndef DENOMINATIONS_H_ +#define DENOMINATIONS_H_ + +#include +#include +#include + +namespace libzerocoin { + +enum CoinDenomination { + ZQ_ERROR = 0, + ZQ_ONE = 1, + ZQ_FIVE = 5, + ZQ_TEN = 10, + ZQ_FIFTY = 50, + ZQ_ONE_HUNDRED = 100, + ZQ_FIVE_HUNDRED = 500, + ZQ_ONE_THOUSAND = 1000 +}; + +// Order is with the Smallest Denomination first and is important for a particular routine that this order is maintained +const std::vector zerocoinDenomList = {ZQ_ONE, ZQ_FIVE, ZQ_TEN, ZQ_FIFTY, ZQ_ONE_HUNDRED, ZQ_FIVE_HUNDRED, ZQ_ONE_THOUSAND}; +// These are the max number you'd need at any one Denomination before moving to the higher denomination. Last number is 4, since it's the max number of +// possible spends at the moment / +const std::vector maxCoinsAtDenom = {4, 1, 4, 1, 4, 1, 4}; + +int64_t ZerocoinDenominationToInt(const CoinDenomination& denomination); +int64_t ZerocoinDenominationToAmount(const CoinDenomination& denomination); +CoinDenomination IntToZerocoinDenomination(int64_t amount); +CoinDenomination AmountToZerocoinDenomination(int64_t amount); +CoinDenomination AmountToClosestDenomination(int64_t nAmount, int64_t& nRemaining); +CoinDenomination get_denomination(std::string denomAmount); +int64_t get_amount(std::string denomAmount); + +} /* namespace libzerocoin */ +#endif /* DENOMINATIONS_H_ */ diff --git a/src/libzerocoin/LICENSE b/src/libzerocoin/LICENSE new file mode 100644 index 000000000..72dc60d84 --- /dev/null +++ b/src/libzerocoin/LICENSE @@ -0,0 +1,19 @@ +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/libzerocoin/ParamGeneration.cpp b/src/libzerocoin/ParamGeneration.cpp new file mode 100644 index 000000000..37113aa40 --- /dev/null +++ b/src/libzerocoin/ParamGeneration.cpp @@ -0,0 +1,654 @@ +/// \file ParamGeneration.cpp +/// +/// \brief Parameter manipulation routines for the Zerocoin cryptographic +/// components. +/// +/// \author Ian Miers, Christina Garman and Matthew Green +/// \date June 2013 +/// +/// \copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green +/// \license This project is released under the MIT license. +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers +#include "ParamGeneration.h" +#include +#include +#include "hash.h" +#include "uint256.h" + +using namespace std; + +namespace libzerocoin { + +/// \brief Fill in a set of Zerocoin parameters from a modulus "N". +/// \param N A trusted RSA modulus +/// \param aux An optional auxiliary string used in derivation +/// \param securityLevel A security level +/// +/// \throws std::runtime_error if the process fails +/// +/// Fills in a ZC_Params data structure deterministically from +/// a trustworthy RSA modulus "N", which is provided as a CBigNum. +/// +/// Note: this routine makes the fundamental assumption that "N" +/// encodes a valid RSA-style modulus of the form "e1*e2" for some +/// unknown safe primes "e1" and "e2". These factors must not +/// be known to any party, or the security of Zerocoin is +/// compromised. The integer "N" must be a MINIMUM of 1023 +/// in length, and 3072 bits is strongly recommended. +/// + +void +CalculateParams(ZerocoinParams ¶ms, CBigNum N, string aux, uint32_t securityLevel) +{ + params.initialized = false; + params.accumulatorParams.initialized = false; + + // Verify that |N| is > 1023 bits. + uint32_t NLen = N.bitSize(); + if (NLen < 1023) { + throw std::runtime_error("Modulus must be at least 1023 bits"); + } + + // Verify that "securityLevel" is at least 80 bits (minimum). + if (securityLevel < 80) { + throw std::runtime_error("Security level must be at least 80 bits."); + } + + // Set the accumulator modulus to "N". + params.accumulatorParams.accumulatorModulus = N; + + // Calculate the required size of the field "F_p" into which + // we're embedding the coin commitment group. This may throw an + // exception if the securityLevel is too large to be supported + // by the current modulus. + uint32_t pLen = 0; + uint32_t qLen = 0; + calculateGroupParamLengths(NLen - 2, securityLevel, &pLen, &qLen); + + // Calculate candidate parameters ("p", "q") for the coin commitment group + // using a deterministic process based on "N", the "aux" string, and + // the dedicated string "COMMITMENTGROUP". + params.coinCommitmentGroup = deriveIntegerGroupParams(calculateSeed(N, aux, securityLevel, STRING_COMMIT_GROUP), pLen, qLen); + + // Next, we derive parameters for a second Accumulated Value commitment group. + // This is a Schnorr group with the specific property that the order of the group + // must be exactly equal to "q" from the commitment group. We set + // the modulus of the new group equal to "2q+1" and test to see if this is prime. + params.serialNumberSoKCommitmentGroup = deriveIntegerGroupFromOrder(params.coinCommitmentGroup.modulus); + + // Calculate the parameters for the internal commitment + // using the same process. + params.accumulatorParams.accumulatorPoKCommitmentGroup = deriveIntegerGroupParams(calculateSeed(N, aux, securityLevel, STRING_AIC_GROUP), qLen + 300, qLen + 1); + + // Calculate the parameters for the accumulator QRN commitment generators. This isn't really + // a whole group, just a pair of random generators in QR_N. + uint32_t resultCtr; + params.accumulatorParams.accumulatorQRNCommitmentGroup.g = generateIntegerFromSeed(NLen - 1, + calculateSeed(N, aux, securityLevel, STRING_QRNCOMMIT_GROUPG), &resultCtr).pow_mod(CBigNum(2),N); + params.accumulatorParams.accumulatorQRNCommitmentGroup.h = generateIntegerFromSeed(NLen - 1, + calculateSeed(N, aux, securityLevel, STRING_QRNCOMMIT_GROUPH), &resultCtr).pow_mod(CBigNum(2), N); + + // Calculate the accumulator base, which we calculate as "u = C**2 mod N" + // where C is an arbitrary value. In the unlikely case that "u = 1" we increment + // "C" and repeat. + CBigNum constant(ACCUMULATOR_BASE_CONSTANT); + params.accumulatorParams.accumulatorBase = CBigNum(1); + for (uint32_t count = 0; count < MAX_ACCUMGEN_ATTEMPTS && params.accumulatorParams.accumulatorBase.isOne(); count++) { + params.accumulatorParams.accumulatorBase = constant.pow_mod(CBigNum(2), params.accumulatorParams.accumulatorModulus); + } + + // Compute the accumulator range. The upper range is the largest possible coin commitment value. + // The lower range is sqrt(upper range) + 1. Since OpenSSL doesn't have + // a square root function we use a slightly higher approximation. + params.accumulatorParams.maxCoinValue = params.coinCommitmentGroup.modulus; + params.accumulatorParams.minCoinValue = CBigNum(2).pow((params.coinCommitmentGroup.modulus.bitSize() / 2) + 3); + + // If all went well, mark params as successfully initialized. + params.accumulatorParams.initialized = true; + + // If all went well, mark params as successfully initialized. + params.initialized = true; +} + +/// \brief Format a seed string by hashing several values. +/// \param N A CBigNum +/// \param aux An auxiliary string +/// \param securityLevel The security level in bits +/// \param groupName A group description string +/// \throws std::runtime_error if the process fails +/// +/// Returns the hash of the value. + +uint256 +calculateGeneratorSeed(uint256 seed, uint256 pSeed, uint256 qSeed, string label, uint32_t index, uint32_t count) +{ + CHashWriter hasher(0,0); + uint256 hash; + + // Compute the hash of: + // ||||||groupName + hasher << seed; + hasher << string("||"); + hasher << pSeed; + hasher << string("||"); + hasher << qSeed; + hasher << string("||"); + hasher << label; + hasher << string("||"); + hasher << index; + hasher << string("||"); + hasher << count; + + return hasher.GetHash(); +} + +/// \brief Format a seed string by hashing several values. +/// \param N A CBigNum +/// \param aux An auxiliary string +/// \param securityLevel The security level in bits +/// \param groupName A group description string +/// \throws std::runtime_error if the process fails +/// +/// Returns the hash of the value. + +uint256 +calculateSeed(CBigNum modulus, string auxString, uint32_t securityLevel, string groupName) +{ + CHashWriter hasher(0,0); + uint256 hash; + + // Compute the hash of: + // ||||||groupName + hasher << modulus; + hasher << string("||"); + hasher << securityLevel; + hasher << string("||"); + hasher << auxString; + hasher << string("||"); + hasher << groupName; + + return hasher.GetHash(); +} + +uint256 +calculateHash(uint256 input) +{ + CHashWriter hasher(0,0); + + // Compute the hash of "input" + hasher << input; + + return hasher.GetHash(); +} + +/// \brief Calculate field/group parameter sizes based on a security level. +/// \param maxPLen Maximum size of the field (modulus "p") in bits. +/// \param securityLevel Required security level in bits (at least 80) +/// \param pLen Result: length of "p" in bits +/// \param qLen Result: length of "q" in bits +/// \throws std::runtime_error if the process fails +/// +/// Calculates the appropriate sizes of "p" and "q" for a prime-order +/// subgroup of order "q" embedded within a field "F_p". The sizes +/// are based on a 'securityLevel' provided in symmetric-equivalent +/// bits. Our choices slightly exceed the specs in FIPS 186-3: +/// +/// securityLevel = 80: pLen = 1024, qLen = 256 +/// securityLevel = 112: pLen = 2048, qLen = 256 +/// securityLevel = 128: qLen = 3072, qLen = 320 +/// +/// If the length of "p" exceeds the length provided in "maxPLen", or +/// if "securityLevel < 80" this routine throws an exception. + +void +calculateGroupParamLengths(uint32_t maxPLen, uint32_t securityLevel, + uint32_t *pLen, uint32_t *qLen) +{ + *pLen = *qLen = 0; + + if (securityLevel < 80) { + throw std::runtime_error("Security level must be at least 80 bits."); + } else if (securityLevel == 80) { + *qLen = 256; + *pLen = 1024; + } else if (securityLevel <= 112) { + *qLen = 256; + *pLen = 2048; + } else if (securityLevel <= 128) { + *qLen = 320; + *pLen = 3072; + } else { + throw std::runtime_error("Security level not supported."); + } + + if (*pLen > maxPLen) { + throw std::runtime_error("Modulus size is too small for this security level."); + } +} + +/// \brief Deterministically compute a set of group parameters using NIST procedures. +/// \param seedStr A byte string seeding the process. +/// \param pLen The desired length of the modulus "p" in bits +/// \param qLen The desired length of the order "q" in bits +/// \return An IntegerGroupParams object +/// +/// Calculates the description of a group G of prime order "q" embedded within +/// a field "F_p". The input to this routine is in arbitrary seed. It uses the +/// algorithms described in FIPS 186-3 Appendix A.1.2 to calculate +/// primes "p" and "q". It uses the procedure in Appendix A.2.3 to +/// derive two generators "g", "h". + +IntegerGroupParams +deriveIntegerGroupParams(uint256 seed, uint32_t pLen, uint32_t qLen) +{ + IntegerGroupParams result; + CBigNum p; + CBigNum q; + uint256 pSeed, qSeed; + + // Calculate "p" and "q" and "domain_parameter_seed" from the + // "seed" buffer above, using the procedure described in NIST + // FIPS 186-3, Appendix A.1.2. + calculateGroupModulusAndOrder(seed, pLen, qLen, &(result.modulus), + &(result.groupOrder), &pSeed, &qSeed); + + // Calculate the generators "g", "h" using the process described in + // NIST FIPS 186-3, Appendix A.2.3. This algorithm takes ("p", "q", + // "domain_parameter_seed", "index"). We use "index" value 1 + // to generate "g" and "index" value 2 to generate "h". + result.g = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 1); + result.h = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 2); + + // Perform some basic tests to make sure we have good parameters + if ((uint32_t)(result.modulus.bitSize()) < pLen || // modulus is pLen bits long + (uint32_t)(result.groupOrder.bitSize()) < qLen || // order is qLen bits long + !(result.modulus.isPrime()) || // modulus is prime + !(result.groupOrder.isPrime()) || // order is prime + !((result.g.pow_mod(result.groupOrder, result.modulus)).isOne()) || // g^order mod modulus = 1 + !((result.h.pow_mod(result.groupOrder, result.modulus)).isOne()) || // h^order mod modulus = 1 + ((result.g.pow_mod(CBigNum(100), result.modulus)).isOne()) || // g^100 mod modulus != 1 + ((result.h.pow_mod(CBigNum(100), result.modulus)).isOne()) || // h^100 mod modulus != 1 + result.g == result.h || // g != h + result.g.isOne()) { // g != 1 + // If any of the above tests fail, throw an exception + throw std::runtime_error("Group parameters are not valid"); + } + + return result; +} + +/// \brief Deterministically compute a set of group parameters with a specified order. +/// \param groupOrder The order of the group +/// \return An IntegerGroupParams object +/// +/// Given "q" calculates the description of a group G of prime order "q" embedded within +/// a field "F_p". + +IntegerGroupParams +deriveIntegerGroupFromOrder(CBigNum &groupOrder) +{ + IntegerGroupParams result; + + // Set the order to "groupOrder" + result.groupOrder = groupOrder; + + // Try possible values for "modulus" of the form "groupOrder * 2 * i" where + // "p" is prime and i is a counter starting at 1. + for (uint32_t i = 1; i < NUM_SCHNORRGEN_ATTEMPTS; i++) { + // Set modulus equal to "groupOrder * 2 * i" + result.modulus = (result.groupOrder * CBigNum(i*2)) + CBigNum(1); + + // Test the result for primality + // TODO: This is a probabilistic routine and thus not the right choice + if (result.modulus.isPrime(256)) { + + // Success. + // + // Calculate the generators "g", "h" using the process described in + // NIST FIPS 186-3, Appendix A.2.3. This algorithm takes ("p", "q", + // "domain_parameter_seed", "index"). We use "index" value 1 + // to generate "g" and "index" value 2 to generate "h". + uint256 seed = calculateSeed(groupOrder, "", 128, ""); + uint256 pSeed = calculateHash(seed); + uint256 qSeed = calculateHash(pSeed); + result.g = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 1); + result.h = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 2); + + // Perform some basic tests to make sure we have good parameters + if (!(result.modulus.isPrime()) || // modulus is prime + !(result.groupOrder.isPrime()) || // order is prime + !((result.g.pow_mod(result.groupOrder, result.modulus)).isOne()) || // g^order mod modulus = 1 + !((result.h.pow_mod(result.groupOrder, result.modulus)).isOne()) || // h^order mod modulus = 1 + ((result.g.pow_mod(CBigNum(100), result.modulus)).isOne()) || // g^100 mod modulus != 1 + ((result.h.pow_mod(CBigNum(100), result.modulus)).isOne()) || // h^100 mod modulus != 1 + result.g == result.h || // g != h + result.g.isOne()) { // g != 1 + // If any of the above tests fail, throw an exception + throw std::runtime_error("Group parameters are not valid"); + } + + return result; + } + } + + // If we reached this point group generation has failed. Throw an exception. + throw std::runtime_error("Too many attempts to generate Schnorr group."); +} + +/// \brief Deterministically compute a group description using NIST procedures. +/// \param seed A byte string seeding the process. +/// \param pLen The desired length of the modulus "p" in bits +/// \param qLen The desired length of the order "q" in bits +/// \param resultModulus A value "p" describing a finite field "F_p" +/// \param resultGroupOrder A value "q" describing the order of a subgroup +/// \param resultDomainParameterSeed A resulting seed for use in later calculations. +/// +/// Calculates the description of a group G of prime order "q" embedded within +/// a field "F_p". The input to this routine is in arbitrary seed. It uses the +/// algorithms described in FIPS 186-3 Appendix A.1.2 to calculate +/// primes "p" and "q". + +void +calculateGroupModulusAndOrder(uint256 seed, uint32_t pLen, uint32_t qLen, + CBigNum *resultModulus, CBigNum *resultGroupOrder, + uint256 *resultPseed, uint256 *resultQseed) +{ + // Verify that the seed length is >= qLen + if (qLen > (sizeof(seed)) * 8) { + // TODO: The use of 256-bit seeds limits us to 256-bit group orders. We should probably change this. + // throw std::runtime_error("Seed is too short to support the required security level."); + } + +#ifdef ZEROCOIN_DEBUG + cout << "calculateGroupModulusAndOrder: pLen = " << pLen << endl; +#endif + + // Generate a random prime for the group order. + // This may throw an exception, which we'll pass upwards. + // Result is the value "resultGroupOrder", "qseed" and "qgen_counter". + uint256 qseed; + uint32_t qgen_counter; + *resultGroupOrder = generateRandomPrime(qLen, seed, &qseed, &qgen_counter); + + // Using ⎡pLen / 2 + 1⎤ as the length and qseed as the input_seed, use the random prime + // routine to obtain p0 , pseed, and pgen_counter. We pass exceptions upward. + uint32_t p0len = ceil((pLen / 2.0) + 1); + uint256 pseed; + uint32_t pgen_counter; + CBigNum p0 = generateRandomPrime(p0len, qseed, &pseed, &pgen_counter); + + // Set x = 0, old_counter = pgen_counter + uint32_t old_counter = pgen_counter; + + // Generate a random integer "x" of pLen bits + uint32_t iterations; + CBigNum x = generateIntegerFromSeed(pLen, pseed, &iterations); + pseed += (iterations + 1); + + // Set x = 2^{pLen−1} + (x mod 2^{pLen–1}). + CBigNum powerOfTwo = CBigNum(2).pow(pLen-1); + x = powerOfTwo + (x % powerOfTwo); + + // t = ⎡x / (2 * resultGroupOrder * p0)⎤. + // TODO: we don't have a ceiling function + CBigNum t = x / (CBigNum(2) * (*resultGroupOrder) * p0); + + // Now loop until we find a valid prime "p" or we fail due to + // pgen_counter exceeding ((4*pLen) + old_counter). + for ( ; pgen_counter <= ((4*pLen) + old_counter) ; pgen_counter++) { + // If (2 * t * resultGroupOrder * p0 + 1) > 2^{pLen}, then + // t = ⎡2^{pLen−1} / (2 * resultGroupOrder * p0)⎤. + powerOfTwo = CBigNum(2).pow(pLen); + CBigNum prod = (CBigNum(2) * t * (*resultGroupOrder) * p0) + CBigNum(1); + if (prod > powerOfTwo) { + // TODO: implement a ceil function + t = CBigNum(2).pow(pLen-1) / (CBigNum(2) * (*resultGroupOrder) * p0); + } + + // Compute a candidate prime resultModulus = 2tqp0 + 1. + *resultModulus = (CBigNum(2) * t * (*resultGroupOrder) * p0) + CBigNum(1); + + // Verify that resultModulus is prime. First generate a pseudorandom integer "a". + CBigNum a = generateIntegerFromSeed(pLen, pseed, &iterations); + pseed += iterations + 1; + + // Set a = 2 + (a mod (resultModulus–3)). + a = CBigNum(2) + (a % ((*resultModulus) - CBigNum(3))); + + // Set z = a^{2 * t * resultGroupOrder} mod resultModulus + CBigNum z = a.pow_mod(CBigNum(2) * t * (*resultGroupOrder), (*resultModulus)); + + // If GCD(z–1, resultModulus) == 1 AND (z^{p0} mod resultModulus == 1) + // then we have found our result. Return. + if ((resultModulus->gcd(z - CBigNum(1))).isOne() && + (z.pow_mod(p0, (*resultModulus))).isOne()) { + // Success! Return the seeds and primes. + *resultPseed = pseed; + *resultQseed = qseed; + return; + } + + // This prime did not work out. Increment "t" and try again. + t = t + CBigNum(1); + } // loop continues until pgen_counter exceeds a limit + + // We reach this point only if we exceeded our maximum iteration count. + // Throw an exception. + throw std::runtime_error("Unable to generate a prime modulus for the group"); +} + +/// \brief Deterministically compute a generator for a given group. +/// \param seed A first seed for the process. +/// \param pSeed A second seed for the process. +/// \param qSeed A third seed for the process. +/// \param modulus Proposed prime modulus for the field. +/// \param groupOrder Proposed order of the group. +/// \param index Index value, selects which generator you're building. +/// \return The resulting generator. +/// \throws A std::runtime_error if error. +/// +/// Generates a random group generator deterministically as a function of (seed,pSeed,qSeed) +/// Uses the algorithm described in FIPS 186-3 Appendix A.2.3. + +CBigNum +calculateGroupGenerator(uint256 seed, uint256 pSeed, uint256 qSeed, CBigNum modulus, CBigNum groupOrder, uint32_t index) +{ + CBigNum result; + + // Verify that 0 <= index < 256 + if (index > 255) { + throw std::runtime_error("Invalid index for group generation"); + } + + // Compute e = (modulus - 1) / groupOrder + CBigNum e = (modulus - CBigNum(1)) / groupOrder; + + // Loop until we find a generator + for (uint32_t count = 1; count < MAX_GENERATOR_ATTEMPTS; count++) { + // hash = Hash(seed || pSeed || qSeed || “ggen” || index || count + uint256 hash = calculateGeneratorSeed(seed, pSeed, qSeed, "ggen", index, count); + CBigNum W(hash); + + // Compute result = W^e mod p + result = W.pow_mod(e, modulus); + + // If result > 1, we have a generator + if (result > 1) { + return result; + } + } + + // We only get here if we failed to find a generator + throw std::runtime_error("Unable to find a generator, too many attempts"); +} + +/// \brief Deterministically compute a random prime number. +/// \param primeBitLen Desired bit length of the prime. +/// \param in_seed Input seed for the process. +/// \param out_seed Result: output seed from the process. +/// \param prime_gen_counter Result: number of iterations required. +/// \return The resulting prime number. +/// \throws A std::runtime_error if error. +/// +/// Generates a random prime number of primeBitLen bits from a given input +/// seed. Uses the Shawe-Taylor algorithm as described in FIPS 186-3 +/// Appendix C.6. This is a recursive function. + +CBigNum +generateRandomPrime(uint32_t primeBitLen, uint256 in_seed, uint256 *out_seed, + uint32_t *prime_gen_counter) +{ + // Verify that primeBitLen is not too small + if (primeBitLen < 2) { + throw std::runtime_error("Prime length is too short"); + } + + // If primeBitLen < 33 bits, perform the base case. + if (primeBitLen < 33) { + CBigNum result(0); + + // Set prime_seed = in_seed, prime_gen_counter = 0. + uint256 prime_seed = in_seed; + (*prime_gen_counter) = 0; + + // Loop up to "4 * primeBitLen" iterations. + while ((*prime_gen_counter) < (4 * primeBitLen)) { + + // Generate a pseudorandom integer "c" of length primeBitLength bits + uint32_t iteration_count; + CBigNum c = generateIntegerFromSeed(primeBitLen, prime_seed, &iteration_count); +#ifdef ZEROCOIN_DEBUG + cout << "generateRandomPrime: primeBitLen = " << primeBitLen << endl; + cout << "Generated c = " << c << endl; +#endif + + prime_seed += (iteration_count + 1); + (*prime_gen_counter)++; + + // Set "intc" to be the least odd integer >= "c" we just generated + uint32_t intc = c.getulong(); + intc = (2 * floor(intc / 2.0)) + 1; +#ifdef ZEROCOIN_DEBUG + cout << "Should be odd. c = " << intc << endl; + cout << "The big num is: c = " << c << endl; +#endif + + // Perform trial division on this (relatively small) integer to determine if "intc" + // is prime. If so, return success. + if (primalityTestByTrialDivision(intc)) { + // Return "intc" converted back into a CBigNum and "prime_seed". We also updated + // the variable "prime_gen_counter" in previous statements. + result = intc; + *out_seed = prime_seed; + + // Success + return result; + } + } // while() + + // If we reached this point there was an error finding a candidate prime + // so throw an exception. + throw std::runtime_error("Unable to find prime in Shawe-Taylor algorithm"); + + // END OF BASE CASE + } + // If primeBitLen >= 33 bits, perform the recursive case. + else { + // Recurse to find a new random prime of roughly half the size + uint32_t newLength = ceil((double)primeBitLen / 2.0) + 1; + CBigNum c0 = generateRandomPrime(newLength, in_seed, out_seed, prime_gen_counter); + + // Generate a random integer "x" of primeBitLen bits using the output + // of the previous call. + uint32_t numIterations; + CBigNum x = generateIntegerFromSeed(primeBitLen, *out_seed, &numIterations); + (*out_seed) += numIterations + 1; + + // Compute "t" = ⎡x / (2 * c0⎤ + // TODO no Ceiling call + CBigNum t = x / (CBigNum(2) * c0); + + // Repeat the following procedure until we find a prime (or time out) + for (uint32_t testNum = 0; testNum < MAX_PRIMEGEN_ATTEMPTS; testNum++) { + + // If ((2 * t * c0) + 1 > 2^{primeBitLen}), + // then t = ⎡2^{primeBitLen} – 1 / (2 * c0)⎤. + if ((CBigNum(2) * t * c0) > (CBigNum(2).pow(CBigNum(primeBitLen)))) { + t = ((CBigNum(2).pow(CBigNum(primeBitLen))) - CBigNum(1)) / (CBigNum(2) * c0); + } + + // Set c = (2 * t * c0) + 1 + CBigNum c = (CBigNum(2) * t * c0) + CBigNum(1); + + // Increment prime_gen_counter + (*prime_gen_counter)++; + + // Test "c" for primality as follows: + // 1. First pick an integer "a" in between 2 and (c - 2) + CBigNum a = generateIntegerFromSeed(c.bitSize(), (*out_seed), &numIterations); + a = CBigNum(2) + (a % (c - CBigNum(3))); + (*out_seed) += (numIterations + 1); + + // 2. Compute "z" = a^{2*t} mod c + CBigNum z = a.pow_mod(CBigNum(2) * t, c); + + // 3. Check if "c" is prime. + // Specifically, verify that gcd((z-1), c) == 1 AND (z^c0 mod c) == 1 + // If so we return "c" as our result. + if (c.gcd(z - CBigNum(1)).isOne() && z.pow_mod(c0, c).isOne()) { + // Return "c", out_seed and prime_gen_counter + // (the latter two of which were already updated) + return c; + } + + // 4. If the test did not succeed, increment "t" and loop + t = t + CBigNum(1); + } // end of test loop + } + + // We only reach this point if the test loop has iterated MAX_PRIMEGEN_ATTEMPTS + // and failed to identify a valid prime. Throw an exception. + throw std::runtime_error("Unable to generate random prime (too many tests)"); +} + +CBigNum +generateIntegerFromSeed(uint32_t numBits, uint256 seed, uint32_t *numIterations) +{ + CBigNum result(0); + uint32_t iterations = ceil((double)numBits / (double)HASH_OUTPUT_BITS); + +#ifdef ZEROCOIN_DEBUG + cout << "numBits = " << numBits << endl; + cout << "iterations = " << iterations << endl; +#endif + + // Loop "iterations" times filling up the value "result" with random bits + for (uint32_t count = 0; count < iterations; count++) { + // result += ( H(pseed + count) * 2^{count * p0len} ) + result += CBigNum(calculateHash(seed + count)) * CBigNum(2).pow(count * HASH_OUTPUT_BITS); + } + + result = CBigNum(2).pow(numBits - 1) + (result % (CBigNum(2).pow(numBits - 1))); + + // Return the number of iterations and the result + *numIterations = iterations; + return result; +} + +/// \brief Determines whether a uint32_t is a prime through trial division. +/// \param candidate Candidate to test. +/// \return true if the value is prime, false otherwise +/// +/// Performs trial division to determine whether a uint32_t is prime. + +bool +primalityTestByTrialDivision(uint32_t candidate) +{ + // TODO: HACK HACK WRONG WRONG + CBigNum canBignum(candidate); + + return canBignum.isPrime(); +} + +} // namespace libzerocoin diff --git a/src/libzerocoin/ParamGeneration.h b/src/libzerocoin/ParamGeneration.h new file mode 100644 index 000000000..5b8c5b90e --- /dev/null +++ b/src/libzerocoin/ParamGeneration.h @@ -0,0 +1,52 @@ +/// \file ParamGeneration.h +/// +/// \brief Parameter generation routines for Zerocoin. +/// +/// \author Ian Miers, Christina Garman and Matthew Green +/// \date June 2013 +/// +/// \copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green +/// \license This project is released under the MIT license. +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers + +#ifndef PARAMGENERATION_H_ +#define PARAMGENERATION_H_ + +#include "Params.h" + +namespace libzerocoin { + +void CalculateParams(ZerocoinParams ¶ms, CBigNum N, std::string aux, uint32_t securityLevel); +void calculateGroupParamLengths(uint32_t maxPLen, uint32_t securityLevel, + uint32_t *pLen, uint32_t *qLen); + +// Constants +#define STRING_COMMIT_GROUP "COIN_COMMITMENT_GROUP" +#define STRING_AVC_GROUP "ACCUMULATED_VALUE_COMMITMENT_GROUP" +#define STRING_AVC_ORDER "ACCUMULATED_VALUE_COMMITMENT_ORDER" +#define STRING_AIC_GROUP "ACCUMULATOR_INTERNAL_COMMITMENT_GROUP" +#define STRING_QRNCOMMIT_GROUPG "ACCUMULATOR_QRN_COMMITMENT_GROUPG" +#define STRING_QRNCOMMIT_GROUPH "ACCUMULATOR_QRN_COMMITMENT_GROUPH" +#define ACCUMULATOR_BASE_CONSTANT 31 +#define MAX_PRIMEGEN_ATTEMPTS 10000 +#define MAX_ACCUMGEN_ATTEMPTS 10000 +#define MAX_GENERATOR_ATTEMPTS 10000 +#define NUM_SCHNORRGEN_ATTEMPTS 10000 + +// Prototypes +bool primalityTestByTrialDivision(uint32_t candidate); +uint256 calculateSeed(CBigNum modulus, std::string auxString, uint32_t securityLevel, std::string groupName); +uint256 calculateGeneratorSeed(uint256 seed, uint256 pSeed, uint256 qSeed, std::string label, uint32_t index, uint32_t count); +uint256 calculateHash(uint256 input); +IntegerGroupParams deriveIntegerGroupParams(uint256 seed, uint32_t pLen, uint32_t qLen); +IntegerGroupParams deriveIntegerGroupFromOrder(CBigNum &groupOrder); +void calculateGroupModulusAndOrder(uint256 seed, uint32_t pLen, uint32_t qLen, CBigNum *resultModulus, CBigNum *resultGroupOrder, uint256 *resultPseed, uint256 *resultQseed); +CBigNum calculateGroupGenerator(uint256 seed, uint256 pSeed, uint256 qSeed, CBigNum modulus, CBigNum groupOrder, uint32_t index); +CBigNum generateRandomPrime(uint32_t primeBitLen, uint256 in_seed, uint256 *out_seed, uint32_t *prime_gen_counter); +CBigNum generateIntegerFromSeed(uint32_t numBits, uint256 seed, uint32_t *numIterations); +bool primalityTestByTrialDivision(uint32_t candidate); + +}/* namespace libzerocoin */ + +#endif /* PARAMGENERATION_H_ */ diff --git a/src/libzerocoin/Params.cpp b/src/libzerocoin/Params.cpp new file mode 100644 index 000000000..dccdbd150 --- /dev/null +++ b/src/libzerocoin/Params.cpp @@ -0,0 +1,47 @@ +/** +* @file Params.cpp +* +* @brief Parameter class for Zerocoin. +* +* @author Ian Miers, Christina Garman and Matthew Green +* @date June 2013 +* +* @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green +* @license This project is released under the MIT license. +**/ +// Copyright (c) 2017 The PIVX developers +#include "Params.h" +#include "ParamGeneration.h" + +namespace libzerocoin { + +ZerocoinParams::ZerocoinParams(CBigNum N, uint32_t securityLevel) { + this->zkp_hash_len = securityLevel; + this->zkp_iterations = securityLevel; + + this->accumulatorParams.k_prime = ACCPROOF_KPRIME; + this->accumulatorParams.k_dprime = ACCPROOF_KDPRIME; + + // Generate the parameters + CalculateParams(*this, N, ZEROCOIN_PROTOCOL_VERSION, securityLevel); + + this->accumulatorParams.initialized = true; + this->initialized = true; +} + +AccumulatorAndProofParams::AccumulatorAndProofParams() { + this->initialized = false; +} + +IntegerGroupParams::IntegerGroupParams() { + this->initialized = false; +} + +CBigNum IntegerGroupParams::randomElement() const { + // The generator of the group raised + // to a random number less than the order of the group + // provides us with a uniformly distributed random number. + return this->g.pow_mod(CBigNum::randBignum(this->groupOrder),this->modulus); +} + +} /* namespace libzerocoin */ diff --git a/src/libzerocoin/Params.h b/src/libzerocoin/Params.h new file mode 100644 index 000000000..6e51a9ba7 --- /dev/null +++ b/src/libzerocoin/Params.h @@ -0,0 +1,219 @@ +/** +* @file Params.h +* +* @brief Parameter classes for Zerocoin. +* +* @author Ian Miers, Christina Garman and Matthew Green +* @date June 2013 +* +* @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green +* @license This project is released under the MIT license. +**/ +// Copyright (c) 2017 The PIVX developers +#ifndef PARAMS_H_ +#define PARAMS_H_ + +#include "bignum.h" +#include "ZerocoinDefines.h" + +namespace libzerocoin { + +class IntegerGroupParams { +public: + /** @brief Integer group class, default constructor + * + * Allocates an empty (uninitialized) set of parameters. + **/ + IntegerGroupParams(); + + /** + * Generates a random group element + * @return a random element in the group. + */ + CBigNum randomElement() const; + bool initialized; + + /** + * A generator for the group. + */ + CBigNum g; + + /** + * A second generator for the group. + * Note log_g(h) and log_h(g) must + * be unknown. + */ + CBigNum h; + + /** + * The modulus for the group. + */ + CBigNum modulus; + + /** + * The order of the group + */ + CBigNum groupOrder; + + ADD_SERIALIZE_METHODS; + template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(initialized); + READWRITE(g); + READWRITE(h); + READWRITE(modulus); + READWRITE(groupOrder); + } +}; + +class AccumulatorAndProofParams { +public: + /** @brief Construct a set of Zerocoin parameters from a modulus "N". + * @param N A trusted RSA modulus + * @param securityLevel A security level expressed in symmetric bits (default 80) + * + * Allocates and derives a set of Zerocoin parameters from + * a trustworthy RSA modulus "N". This routine calculates all + * of the remaining parameters (group descriptions etc.) from N + * using a verifiable, deterministic procedure. + * + * Note: this constructor makes the fundamental assumption that "N" + * encodes a valid RSA-style modulus of the form "e1 * e2" where + * "e1" and "e2" are safe primes. The factors "e1", "e2" MUST NOT + * be known to any party, or the security of Zerocoin is + * compromised. The integer "N" must be a MINIMUM of 1024 + * in length. 3072 bits is strongly recommended. + **/ + AccumulatorAndProofParams(); + + //AccumulatorAndProofParams(CBigNum accumulatorModulus); + + bool initialized; + + /** + * Modulus used for the accumulator. + * Product of two safe primes who's factorization is unknown. + */ + CBigNum accumulatorModulus; + + /** + * The initial value for the accumulator + * A random Quadratic residue mod n thats not 1 + */ + CBigNum accumulatorBase; + + /** + * Lower bound on the value for committed coin. + * Required by the accumulator proof. + */ + CBigNum minCoinValue; + + /** + * Upper bound on the value for a comitted coin. + * Required by the accumulator proof. + */ + CBigNum maxCoinValue; + + /** + * The second of two groups used to form a commitment to + * a coin (which it self is a commitment to a serial number). + * This one differs from serialNumberSokCommitment due to + * restrictions from Camenisch and Lysyanskaya's paper. + */ + IntegerGroupParams accumulatorPoKCommitmentGroup; + + /** + * Hidden order quadratic residue group mod N. + * Used in the accumulator proof. + */ + IntegerGroupParams accumulatorQRNCommitmentGroup; + + /** + * Security parameter. + * Bit length of the challenges used in the accumulator proof. + */ + uint32_t k_prime; + + /** + * Security parameter. + * The statistical zero-knowledgeness of the accumulator proof. + */ + uint32_t k_dprime; + ADD_SERIALIZE_METHODS; + template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(initialized); + READWRITE(accumulatorModulus); + READWRITE(accumulatorBase); + READWRITE(accumulatorPoKCommitmentGroup); + READWRITE(accumulatorQRNCommitmentGroup); + READWRITE(minCoinValue); + READWRITE(maxCoinValue); + READWRITE(k_prime); + READWRITE(k_dprime); + } +}; + +class ZerocoinParams { +public: + /** @brief Construct a set of Zerocoin parameters from a modulus "N". + * @param N A trusted RSA modulus + * @param securityLevel A security level expressed in symmetric bits (default 80) + * + * Allocates and derives a set of Zerocoin parameters from + * a trustworthy RSA modulus "N". This routine calculates all + * of the remaining parameters (group descriptions etc.) from N + * using a verifiable, deterministic procedure. + * + * Note: this constructor makes the fundamental assumption that "N" + * encodes a valid RSA-style modulus of the form "e1 * e2" where + * "e1" and "e2" are safe primes. The factors "e1", "e2" MUST NOT + * be known to any party, or the security of Zerocoin is + * compromised. The integer "N" must be a MINIMUM of 1024 + * in length. 3072 bits is strongly recommended. + **/ + ZerocoinParams(CBigNum accumulatorModulus, + uint32_t securityLevel = ZEROCOIN_DEFAULT_SECURITYLEVEL); + + bool initialized; + + AccumulatorAndProofParams accumulatorParams; + + /** + * The Quadratic Residue group from which we form + * a coin as a commitment to a serial number. + */ + IntegerGroupParams coinCommitmentGroup; + + /** + * One of two groups used to form a commitment to + * a coin (which it self is a commitment to a serial number). + * This is the one used in the serial number poof. + * It's order must be equal to the modulus of coinCommitmentGroup. + */ + IntegerGroupParams serialNumberSoKCommitmentGroup; + + /** + * The number of iterations to use in the serial + * number proof. + */ + uint32_t zkp_iterations; + + /** + * The amount of the hash function we use for + * proofs. + */ + uint32_t zkp_hash_len; + + ADD_SERIALIZE_METHODS; + template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(initialized); + READWRITE(accumulatorParams); + READWRITE(coinCommitmentGroup); + READWRITE(serialNumberSoKCommitmentGroup); + READWRITE(zkp_iterations); + READWRITE(zkp_hash_len); + } +}; + +} /* namespace libzerocoin */ + +#endif /* PARAMS_H_ */ diff --git a/src/libzerocoin/SerialNumberSignatureOfKnowledge.cpp b/src/libzerocoin/SerialNumberSignatureOfKnowledge.cpp new file mode 100644 index 000000000..4fc204eb4 --- /dev/null +++ b/src/libzerocoin/SerialNumberSignatureOfKnowledge.cpp @@ -0,0 +1,155 @@ +/** +* @file SerialNumberSignatureOfKnowledge.cpp +* +* @brief SerialNumberSignatureOfKnowledge class for the Zerocoin library. +* +* @author Ian Miers, Christina Garman and Matthew Green +* @date June 2013 +* +* @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green +* @license This project is released under the MIT license. +**/ +// Copyright (c) 2017 The PIVX developers +#include +#include "SerialNumberSignatureOfKnowledge.h" + +namespace libzerocoin { + +SerialNumberSignatureOfKnowledge::SerialNumberSignatureOfKnowledge(const ZerocoinParams* p): params(p) { } + +// Use one 256 bit seed and concatenate 4 unique 256 bit hashes to make a 1024 bit hash +CBigNum SeedTo1024(uint256 hashSeed) { + CHashWriter hasher(0,0); + hasher << hashSeed; + + vector vResult; + for (int i = 0; i < 4; i ++) { + vector vHash = CBigNum(hasher.GetHash()).getvch(); + vResult.insert(vResult.end(), vHash.begin(), vHash.end()); + hasher << vResult; + } + + CBigNum bnResult; + bnResult.setvch(vResult); + return bnResult; +} + +SerialNumberSignatureOfKnowledge::SerialNumberSignatureOfKnowledge(const + ZerocoinParams* p, const PrivateCoin& coin, const Commitment& commitmentToCoin, + uint256 msghash):params(p), + s_notprime(p->zkp_iterations), + sprime(p->zkp_iterations) { + + // Sanity check: verify that the order of the "accumulatedValueCommitmentGroup" is + // equal to the modulus of "coinCommitmentGroup". Otherwise we will produce invalid + // proofs. + if (params->coinCommitmentGroup.modulus != params->serialNumberSoKCommitmentGroup.groupOrder) { + throw std::runtime_error("Groups are not structured correctly."); + } + + CBigNum a = params->coinCommitmentGroup.g; + CBigNum b = params->coinCommitmentGroup.h; + CBigNum g = params->serialNumberSoKCommitmentGroup.g; + CBigNum h = params->serialNumberSoKCommitmentGroup.h; + + CHashWriter hasher(0,0); + hasher << *params << commitmentToCoin.getCommitmentValue() << coin.getSerialNumber() << msghash; + + vector r(params->zkp_iterations); + vector v_seed(params->zkp_iterations); + vector v_expanded(params->zkp_iterations); + vector c(params->zkp_iterations); + + for(uint32_t i=0; i < params->zkp_iterations; i++) { + r[i] = CBigNum::randBignum(params->coinCommitmentGroup.groupOrder); + + //use a random 256 bit seed that expands to 1024 bit for v[i] + while (true) { + uint256 hashRand = CBigNum::randBignum(CBigNum(~uint256(0))).getuint256(); + CBigNum bnExpanded = SeedTo1024(hashRand); + + if(bnExpanded > params->serialNumberSoKCommitmentGroup.groupOrder) + continue; + + v_seed[i] = CBigNum(hashRand); + v_expanded[i] = bnExpanded; + break; + } + } + + for(uint32_t i=0; i < params->zkp_iterations; i++) { + // compute g^{ {a^x b^r} h^v} mod p2 + c[i] = challengeCalculation(coin.getSerialNumber(), r[i], v_expanded[i]); + } + + // We can't hash data in parallel either + // because OPENMP cannot not guarantee loops + // execute in order. + for(uint32_t i=0; i < params->zkp_iterations; i++) { + hasher << c[i]; + } + this->hash = hasher.GetHash(); + unsigned char *hashbytes = (unsigned char*) &hash; + + for(uint32_t i = 0; i < params->zkp_iterations; i++) { + int bit = i % 8; + int byte = i / 8; + + bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01); + if (challenge_bit) { + s_notprime[i] = r[i]; + sprime[i] = v_seed[i]; + } else { + s_notprime[i] = r[i] - coin.getRandomness(); + sprime[i] = v_expanded[i] - (commitmentToCoin.getRandomness() * + b.pow_mod(r[i] - coin.getRandomness(), params->serialNumberSoKCommitmentGroup.groupOrder)); + } + } +} + +inline CBigNum SerialNumberSignatureOfKnowledge::challengeCalculation(const CBigNum& a_exp,const CBigNum& b_exp, + const CBigNum& h_exp) const { + + CBigNum a = params->coinCommitmentGroup.g; + CBigNum b = params->coinCommitmentGroup.h; + CBigNum g = params->serialNumberSoKCommitmentGroup.g; + CBigNum h = params->serialNumberSoKCommitmentGroup.h; + + CBigNum exponent = (a.pow_mod(a_exp, params->serialNumberSoKCommitmentGroup.groupOrder) + * b.pow_mod(b_exp, params->serialNumberSoKCommitmentGroup.groupOrder)) % params->serialNumberSoKCommitmentGroup.groupOrder; + + return (g.pow_mod(exponent, params->serialNumberSoKCommitmentGroup.modulus) * h.pow_mod(h_exp, params->serialNumberSoKCommitmentGroup.modulus)) % params->serialNumberSoKCommitmentGroup.modulus; +} + +bool SerialNumberSignatureOfKnowledge::Verify(const CBigNum& coinSerialNumber, const CBigNum& valueOfCommitmentToCoin, + const uint256 msghash) const { + CBigNum a = params->coinCommitmentGroup.g; + CBigNum b = params->coinCommitmentGroup.h; + CBigNum g = params->serialNumberSoKCommitmentGroup.g; + CBigNum h = params->serialNumberSoKCommitmentGroup.h; + CHashWriter hasher(0,0); + hasher << *params << valueOfCommitmentToCoin << coinSerialNumber << msghash; + + vector tprime(params->zkp_iterations); + unsigned char *hashbytes = (unsigned char*) &this->hash; + + for(uint32_t i = 0; i < params->zkp_iterations; i++) { + int bit = i % 8; + int byte = i / 8; + bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01); + if(challenge_bit) { + tprime[i] = challengeCalculation(coinSerialNumber, s_notprime[i], SeedTo1024(sprime[i].getuint256())); + } else { + CBigNum exp = b.pow_mod(s_notprime[i], params->serialNumberSoKCommitmentGroup.groupOrder); + tprime[i] = ((valueOfCommitmentToCoin.pow_mod(exp, params->serialNumberSoKCommitmentGroup.modulus) % params->serialNumberSoKCommitmentGroup.modulus) * + (h.pow_mod(sprime[i], params->serialNumberSoKCommitmentGroup.modulus) % params->serialNumberSoKCommitmentGroup.modulus)) % + params->serialNumberSoKCommitmentGroup.modulus; + } + } + for(uint32_t i = 0; i < params->zkp_iterations; i++) { + hasher << tprime[i]; + } + return hasher.GetHash() == hash; +} + +} /* namespace libzerocoin */ diff --git a/src/libzerocoin/SerialNumberSignatureOfKnowledge.h b/src/libzerocoin/SerialNumberSignatureOfKnowledge.h new file mode 100644 index 000000000..805ccf760 --- /dev/null +++ b/src/libzerocoin/SerialNumberSignatureOfKnowledge.h @@ -0,0 +1,79 @@ +/** +* @file SerialNumberSignatureOfKnowledge.h +* +* @brief SerialNumberSignatureOfKnowledge class for the Zerocoin library. +* +* @author Ian Miers, Christina Garman and Matthew Green +* @date June 2013 +* +* @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green +* @license This project is released under the MIT license. +**/ +// Copyright (c) 2017 The PIVX developers +// Copyright (c) 2018 The Bulwark Core Developers + +#ifndef SERIALNUMBERPROOF_H_ +#define SERIALNUMBERPROOF_H_ + +#include +#include +#include +#include "Params.h" +#include "Coin.h" +#include "Commitment.h" +#include "bignum.h" +#include "serialize.h" +#include "Accumulator.h" +#include "hash.h" + +using namespace std; +namespace libzerocoin { + +/** + * A Signature of knowledge on the hash of metadata attesting that the signer knows the values + * necessary to open a commitment which contains a coin(which it self is of course a commitment) + * with a given serial number. + */ +class SerialNumberSignatureOfKnowledge { +public: + SerialNumberSignatureOfKnowledge(const ZerocoinParams* p); + /** + * Creates a Signature of knowledge object that a commitment to a coin contains a coin with serial number x + * + * @param p params + * @param coin the coin we are going to prove the serial number of. + * @param commitmentToCoin the commitment to the coin + * @param msghash hash of meta data to create a signature of knowledge on. + */ + SerialNumberSignatureOfKnowledge(const ZerocoinParams* p, const PrivateCoin& coin, const Commitment& commitmentToCoin, uint256 msghash); + + /** + * Verifies the Signature of knowledge. + * + * @param msghash hash of meta data to create a signature of knowledge on. + * @return + */ + bool Verify(const CBigNum& coinSerialNumber, const CBigNum& valueOfCommitmentToCoin,const uint256 msghash) const; + ADD_SERIALIZE_METHODS; + template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(s_notprime); + READWRITE(sprime); + READWRITE(hash); + } +private: + const ZerocoinParams* params; + // challenge hash + uint256 hash; //TODO For efficiency, should this be a bitset where Templates define params? + + // challenge response values + // this is s_notprime instead of s + // because the serialization macros + // define something named s and it conflicts + vector s_notprime; + vector sprime; + inline CBigNum challengeCalculation(const CBigNum& a_exp, const CBigNum& b_exp, + const CBigNum& h_exp) const; +}; + +} /* namespace libzerocoin */ +#endif /* SERIALNUMBERPROOF_H_ */ diff --git a/src/libzerocoin/ZerocoinDefines.h b/src/libzerocoin/ZerocoinDefines.h new file mode 100644 index 000000000..9f19a4612 --- /dev/null +++ b/src/libzerocoin/ZerocoinDefines.h @@ -0,0 +1,41 @@ +/** +* @file Zerocoin.h +* +* @brief Exceptions and constants for Zerocoin +* +* @author Ian Miers, Christina Garman and Matthew Green +* @date June 2013 +* +* @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green +* @license This project is released under the MIT license. +**/ +// Copyright (c) 2017 The PIVX developers + +#ifndef ZEROCOIN_DEFINES_H_ +#define ZEROCOIN_DEFINES_H_ + +#include + +#define ZEROCOIN_DEFAULT_SECURITYLEVEL 80 +#define ZEROCOIN_MIN_SECURITY_LEVEL 80 +#define ZEROCOIN_MAX_SECURITY_LEVEL 80 +#define ACCPROOF_KPRIME 160 +#define ACCPROOF_KDPRIME 128 +#define MAX_COINMINT_ATTEMPTS 10000 +#define ZEROCOIN_MINT_PRIME_PARAM 20 +#define ZEROCOIN_VERSION_STRING "0.11" +#define ZEROCOIN_VERSION_INT 11 +#define ZEROCOIN_PROTOCOL_VERSION "1" +#define HASH_OUTPUT_BITS 256 +#define ZEROCOIN_COMMITMENT_EQUALITY_PROOF "COMMITMENT_EQUALITY_PROOF" +#define ZEROCOIN_ACCUMULATOR_PROOF "ACCUMULATOR_PROOF" +#define ZEROCOIN_SERIALNUMBER_PROOF "SERIALNUMBER_PROOF" + +// Activate multithreaded mode for proof verification +#define ZEROCOIN_THREADING 1 + +// Uses a fast technique for coin generation. Could be more vulnerable +// to timing attacks. Turn off if an attacker can measure coin minting time. +#define ZEROCOIN_FAST_MINT 1 + +#endif /* ZEROCOIN_H_ */ diff --git a/src/libzerocoin/bignum.h b/src/libzerocoin/bignum.h new file mode 100755 index 000000000..d05d54210 --- /dev/null +++ b/src/libzerocoin/bignum.h @@ -0,0 +1,790 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2017 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 + +#include +#include +#include +#include "serialize.h" +#include "uint256.h" +#include "version.h" + +/** Errors thrown by the bignum class */ +class bignum_error : public std::runtime_error +{ +public: + explicit bignum_error(const std::string& str) : std::runtime_error(str) {} +}; + + +/** 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) */ +class CBigNum : public BIGNUM +{ +public: + CBigNum() + { + BN_init(this); + } + + // Initialize from a Hex String (for zerocoin modulus) + CBigNum(const std::string& str) { + BN_init(this); + SetHexBool(str); + } + + + CBigNum(const CBigNum& b) + { + BN_init(this); + if (!BN_copy(this, &b)) + { + BN_clear_free(this); + throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed"); + } + } + + CBigNum& operator=(const CBigNum& b) + { + if (!BN_copy(this, &b)) + throw bignum_error("CBigNum::operator= : BN_copy failed"); + return (*this); + } + + ~CBigNum() + { + BN_clear_free(this); + } + + //CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'. + CBigNum(signed char n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(short n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(int n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } + CBigNum(long n) { BN_init(this); if (n >= 0) setulong(n); else setint64(n); } +#ifdef __APPLE__ + CBigNum(int64_t n) { BN_init(this); setint64(n); } +#endif + CBigNum(unsigned char n) { BN_init(this); setulong(n); } + CBigNum(unsigned short n) { BN_init(this); setulong(n); } + CBigNum(unsigned int n) { BN_init(this); setulong(n); } + CBigNum(unsigned long n) { BN_init(this); setulong(n); } + // CBigNum(uint64_t n) { BN_init(this); setuint64(n); } + explicit CBigNum(uint256 n) { BN_init(this); setuint256(n); } + + explicit CBigNum(const std::vector& vch) + { + BN_init(this); + 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) { + CBigNum ret; + if(!BN_rand_range(&ret, &range)){ + 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 + */ + static CBigNum RandKBitBigum(const uint32_t k){ + CBigNum ret; + if(!BN_rand(&ret, 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 bitSize() const{ + return BN_num_bits(this); + } + + void setulong(unsigned long n) + { + if (!BN_set_word(this, n)) + throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed"); + } + + unsigned long getulong() const + { + return BN_get_word(this); + } + + unsigned int getuint() const + { + return BN_get_word(this); + } + + int getint() const + { + unsigned long n = BN_get_word(this); + if (!BN_is_negative(this)) + 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, this); + } + + 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, this); + } + + 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, this); + } + + uint256 getuint256() const + { + unsigned int nSize = BN_bn2mpi(this, NULL); + if (nSize < 4) + return 0; + std::vector vch(nSize); + BN_bn2mpi(this, &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(), this); + } + + std::vector getvch() const + { + unsigned int nSize = BN_bn2mpi(this, NULL); + if (nSize <= 4) + return std::vector(); + std::vector vch(nSize); + BN_bn2mpi(this, &vch[0]); + vch.erase(vch.begin(), vch.begin() + 4); + reverse(vch.begin(), vch.end()); + return vch; + } + + // The "compact" format is a representation of a whole + // number N using an unsigned 32bit number similar to a + // floating point format. + // The most significant 8 bits are the unsigned exponent of base 256. + // This exponent can be thought of as "number of bytes of N". + // The lower 23 bits are the mantissa. + // Bit number 24 (0x800000) represents the sign of N. + // N = (-1^sign) * mantissa * 256^(exponent-3) + // + // Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). + // MPI uses the most significant bit of the first byte as sign. + // Thus 0x1234560000 is compact (0x05123456) + // and 0xc0de000000 is compact (0x0600c0de) + // (0x05c0de00) would be -0x40de000000 + // + // Bitcoin only uses this "compact" format for encoding difficulty + // targets, which are unsigned 256bit quantities. Thus, all the + // complexities of the sign bit and using base 256 are probably an + // implementation accident. + // + // This implementation directly uses shifts instead of going + // through an intermediate MPI representation. + CBigNum& SetCompact(unsigned int nCompact) + { + unsigned int nSize = nCompact >> 24; + bool fNegative =(nCompact & 0x00800000) != 0; + unsigned int nWord = nCompact & 0x007fffff; + if (nSize <= 3) + { + nWord >>= 8*(3-nSize); + BN_set_word(this, nWord); + } + else + { + BN_set_word(this, nWord); + BN_lshift(this, this, 8*(nSize-3)); + } + BN_set_negative(this, fNegative); + return *this; + } + + unsigned int GetCompact() const + { + unsigned int nSize = BN_num_bytes(this); + unsigned int nCompact = 0; + if (nSize <= 3) + nCompact = BN_get_word(this) << 8*(3-nSize); + else + { + CBigNum bn; + BN_rshift(&bn, this, 8*(nSize-3)); + nCompact = BN_get_word(&bn); + } + // The 0x00800000 bit denotes the sign. + // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. + if (nCompact & 0x00800000) + { + nCompact >>= 8; + nSize++; + } + nCompact |= nSize << 24; + nCompact |= (BN_is_negative(this) ? 0x00800000 : 0); + return nCompact; + } + + void SetHex(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; + } + + 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; + std::string str; + CBigNum bn = *this; + BN_set_negative(&bn, false); + CBigNum dv; + CBigNum rem; + if (BN_cmp(&bn, &bn0) == 0) + return "0"; + while (BN_cmp(&bn, &bn0) > 0) + { + if (!BN_div(&dv, &rem, &bn, &bnBase, pctx)) + throw bignum_error("CBigNum::ToString() : BN_div failed"); + bn = dv; + unsigned int c = rem.getulong(); + str += "0123456789abcdef"[c]; + } + if (BN_is_negative(this)) + str += "-"; + reverse(str.begin(), str.end()); + return str; + } + + std::string GetHex() const + { + return ToString(16); + } + + 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 { + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_exp(&ret, this, &e, pctx)) + throw bignum_error("CBigNum::pow : BN_exp failed"); + return ret; + } + + /** + * 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, this, &b, &m, 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 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, &inv, &posE, &m, pctx)) + throw bignum_error("CBigNum::pow_mod: BN_mod_exp failed on negative exponent"); + }else + if (!BN_mod_exp(&ret, this, &e, &m, 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 inverse(const CBigNum& m) const { + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_mod_inverse(&ret, this, &m, 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 + */ + static CBigNum generatePrime(const unsigned int numBits, bool safe = false) { + CBigNum ret; + if(!BN_generate_prime_ex(&ret, 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 gcd( const CBigNum& b) const{ + CAutoBN_CTX pctx; + CBigNum ret; + if (!BN_gcd(&ret, this, &b, 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 isPrime(const int checks=BN_prime_checks) const { + CAutoBN_CTX pctx; + int ret = BN_is_prime(this, checks, NULL, pctx, NULL); + if(ret < 0){ + throw bignum_error("CBigNum::isPrime :BN_is_prime"); + } + return ret; + } + + bool isOne() const { + return BN_is_one(this); + } + + + + bool operator!() const + { + return BN_is_zero(this); + } + + CBigNum& operator+=(const CBigNum& b) + { + if (!BN_add(this, this, &b)) + throw bignum_error("CBigNum::operator+= : BN_add failed"); + return *this; + } + + CBigNum& operator-=(const CBigNum& b) + { + *this = *this - b; + return *this; + } + + CBigNum& operator*=(const CBigNum& b) + { + CAutoBN_CTX pctx; + if (!BN_mul(this, this, &b, 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(this, this, 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, this) > 0) + { + *this = 0; + return *this; + } + + if (!BN_rshift(this, this, shift)) + throw bignum_error("CBigNum:operator>>= : BN_rshift failed"); + return *this; + } + + + CBigNum& operator++() + { + // prefix operator + if (!BN_add(this, this, 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, this, BN_value_one())) + throw bignum_error("CBigNum::operator-- : BN_sub failed"); + *this = r; + 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 bool operator<(const CBigNum& a, const CBigNum& b); + +}; + + + +inline const CBigNum operator+(const CBigNum& a, const CBigNum& b) +{ + CBigNum r; + if (!BN_add(&r, &a, &b)) + throw bignum_error("CBigNum::operator+ : BN_add failed"); + return r; +} + +inline const CBigNum operator-(const CBigNum& a, const CBigNum& b) +{ + CBigNum r; + if (!BN_sub(&r, &a, &b)) + throw bignum_error("CBigNum::operator- : BN_sub failed"); + return r; +} + +inline const CBigNum operator-(const CBigNum& a) +{ + CBigNum r(a); + BN_set_negative(&r, !BN_is_negative(&r)); + return r; +} + +inline const CBigNum operator*(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_mul(&r, &a, &b, pctx)) + throw bignum_error("CBigNum::operator* : BN_mul failed"); + return r; +} + +inline const CBigNum operator/(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_div(&r, NULL, &a, &b, pctx)) + throw bignum_error("CBigNum::operator/ : BN_div failed"); + return r; +} + +inline const CBigNum operator%(const CBigNum& a, const CBigNum& b) +{ + CAutoBN_CTX pctx; + CBigNum r; + if (!BN_nnmod(&r, &a, &b, pctx)) + throw bignum_error("CBigNum::operator% : BN_div failed"); + return r; +} + +inline const CBigNum operator<<(const CBigNum& a, unsigned int shift) +{ + CBigNum r; + if (!BN_lshift(&r, &a, shift)) + throw bignum_error("CBigNum:operator<< : BN_lshift failed"); + return r; +} + +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, &b) == 0); } +inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) != 0); } +inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) <= 0); } +inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) >= 0); } +inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) < 0); } +inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(&a, &b) > 0); } +inline std::ostream& operator<<(std::ostream &strm, const CBigNum &b) { return strm << b.ToString(10); } + +typedef CBigNum Bignum; + +#endif diff --git a/src/libzerocoin/documentation/Doxyfile b/src/libzerocoin/documentation/Doxyfile new file mode 100644 index 000000000..50123473d --- /dev/null +++ b/src/libzerocoin/documentation/Doxyfile @@ -0,0 +1,1870 @@ + +# Doxyfile 1.8.3.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "libzerocoin" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Zerocoin library" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) 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 +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# 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 +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# 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 (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# 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 (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# 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. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +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 +# 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 +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page (index.html). +# This can be useful if you have a project on for instance GitHub and want reuse +# the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# 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. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search engine +# library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. 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 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_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. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/src/libzerocoin/documentation/manual/intro.tex b/src/libzerocoin/documentation/manual/intro.tex new file mode 100644 index 000000000..6c965e5dc --- /dev/null +++ b/src/libzerocoin/documentation/manual/intro.tex @@ -0,0 +1,3 @@ +\section{Introduction} + +This manual describes \textsf{libzerocoin}, an implementation of the cryptographic components of the Zerocoin protocol. \ No newline at end of file diff --git a/src/libzerocoin/documentation/manual/manual.pdf b/src/libzerocoin/documentation/manual/manual.pdf new file mode 100644 index 000000000..106775fcb Binary files /dev/null and b/src/libzerocoin/documentation/manual/manual.pdf differ diff --git a/src/libzerocoin/documentation/manual/manual.tex b/src/libzerocoin/documentation/manual/manual.tex new file mode 100644 index 000000000..e10e03712 --- /dev/null +++ b/src/libzerocoin/documentation/manual/manual.tex @@ -0,0 +1,19 @@ +\documentclass[12pt]{article} +\usepackage{fullpage,pstricks,graphicx,url,mdwlist,ifthen} +\usepackage{epsfig,multirow} +\usepackage{latexsym,amssymb,amsmath} +\usepackage{hyperref} + +\begin{document} + +\newcommand{\libzerocoin}{\textsf{libzerocoin}} + +\title{libzerocoin User Guide} +\author{Ian Miers, Christina Garman and Matthew Green} +\date{} +\maketitle + +\input{intro} +\input{using} + +\end{document} diff --git a/src/libzerocoin/documentation/manual/using.tex b/src/libzerocoin/documentation/manual/using.tex new file mode 100644 index 000000000..72ff20116 --- /dev/null +++ b/src/libzerocoin/documentation/manual/using.tex @@ -0,0 +1,14 @@ +\section{Using libzerocoin} + +The \libzerocoin library is designed to integrate with a Bitcoin/Litecoin style client, and performs the base cryptographic operations necessary to integrate Zerocoin with the client. These operations include generation/verification of coins, as well as generation/verification of spend signatures. Roughly speaking, the use of Zerocoin proceeds according to the following steps: + +\begin{enumerate} +\item {\bf Parameter setup.} All Zerocoin clients in a deployment must share a single parameter $N$ where $N$ is a 2048-3072 bit modulus such that $N = p*q$ where $p$ and $q$ are large safe prime numbers (i.e., $p = 2p'+1$, $q = 2q'+1$ for primes $p', q'$). Once $N$ has been generated, the underlying values $p, q, p', q'$ can and should be destroyed. + +In addition to $N$, all clients must agree on a security level $k$ (an integer $\ge 80$), as well as a canonical value of one zerocoin (measured in the underlying currency). + +\item {\bf Coin generation.} To Mint a zerocoin, a client first generates a new coin $c$ using operations in the \libzerocoin~library. + +Once the coin is Minted, the client must now format and transmit a \textsf{ZEROCOIN\_MINT} transaction to the network, using routines not present in \libzerocoin. This transaction is similar to a normal Bitcoin/Litecoin transaction: it consists of inputs combining to the value of one zerocoin. Unlike a standard transaction, this transaction does not provide any outputs. Instead it simply embeds the Zerocoin value $c$. + +\end{enumerate} \ No newline at end of file diff --git a/src/libzerocoin/paramgen.cpp b/src/libzerocoin/paramgen.cpp new file mode 100644 index 000000000..9ac28a398 --- /dev/null +++ b/src/libzerocoin/paramgen.cpp @@ -0,0 +1,130 @@ +/** + * @file paramgen.cpp + * + * @brief Parameter generation utility for Zerocoin. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ +// Copyright (c) 2017 The PIVX developers + + +#include +#include +#include +//#include +#include +#include "Zerocoin.h" + +#define DEFAULT_MODULUS_SIZE 3072 +#define MIN_MODULUS_SIZE 1026 + +using namespace std; +using namespace libzerocoin; + +void +PrintWarning() +{ + cout << "Zerocoin parameter generation utility" << endl; + cout << "-------------------------------------" << endl << endl; + cout << "This utility generates an l-bit modulus N as the product of" << endl; + cout << "two safe primes p, q. The values p and q are not stored." << endl; + cout << "Call this program with no arguments to see usage options." << endl; + cout << endl; + cout << "SECURITY WARNING: ZEROCOIN PARAMETERS MUST BE GENERATED BY" << endl; + cout << "A TRUSTED PARTY WHO DOES NOT STORE THE FACTORS. WHILE WE MAKE" << endl; + cout << "A BEST EFFORT TO DESTROY THIS INFORMATION WE DO NOT TAKE" << endl; + cout << "SPECIAL PRECAUTIONS TO ENSURE THAT THEY ARE DESTROYED." << endl; + cout << endl; + cout << "USE THIS UTILITY AT YOUR OWN RISK" << endl << endl; +} + +void usage() +{ + printf("Usage:\n"); + printf(" -b \n"); + printf(" -o \n"); + + exit (8); +} + +int main(int argc, char **argv) +{ + static CBigNum resultModulus(0); + uint32_t numBits = DEFAULT_MODULUS_SIZE; + ofstream outfile; + char* outfileName; + bool writeToFile = false; + + while ((argc > 1) && (argv[1][0] == '-')) + { + switch (argv[1][1]) + { + case 'b': + numBits = atoi(argv[2]); + ++argv; + --argc; + break; + + case 'o': + outfileName = argv[2]; + writeToFile = true; + break; + + case 'h': + usage(); + break; + + default: + printf("Wrong Argument: %s\n", argv[1]); + usage(); + break; + } + + ++argv; + --argc; + } + + if (numBits < MIN_MODULUS_SIZE) { + cout << "Modulus is below minimum length (" << MIN_MODULUS_SIZE << ") bits" << endl; + return(0); + } + + PrintWarning(); + + cout << "Modulus size set to " << numBits << " bits." << endl; + cout << "Generating parameters. This may take a few minutes..." << endl; + + // Generate two safe primes "p" and "q" + CBigNum *p, *q; + p = new CBigNum(0); + q = new CBigNum(0); + *p = CBigNum::generatePrime(numBits / 2, true); + *q = CBigNum::generatePrime(numBits / 2, true); + + // Multiply to compute N + resultModulus = (*p) * (*q); + + // Wipe out the factors + delete p; + delete q; + + // Convert to a hexidecimal string + std::string resultHex = resultModulus.ToString(16); + + cout << endl << "N = " << endl << resultHex << endl; + + if (writeToFile) { + try { + outfile.open (outfileName); + outfile << resultHex; + outfile.close(); + cout << endl << "Result has been written to file '" << outfileName << "'." << endl; + } catch (std::runtime_error &e) { + cout << "Unable to write to file:" << e.what() << endl; + } + } +} diff --git a/src/libzerocoin/zerocoin.pc.in b/src/libzerocoin/zerocoin.pc.in new file mode 100644 index 000000000..67834e1fa --- /dev/null +++ b/src/libzerocoin/zerocoin.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: zerocoin +Description: Zerocoin cryptographic routines library +Requires: +Version: @LIBVER@ +Libs: -L${libdir} -lzerocoin -lcrypto +Cflags: -I${includedir} diff --git a/src/main.cpp b/src/main.cpp index 9f39660a6..0fb2ba5ad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,7 @@ #include "main.h" +#include "accumulators.h" #include "addrman.h" #include "alert.h" #include "chainparams.h" @@ -22,6 +23,7 @@ #include "obfuscation.h" #include "pow.h" #include "spork.h" +#include "sporkdb.h" #include "swifttx.h" #include "txdb.h" #include "txmempool.h" @@ -29,6 +31,9 @@ #include "util.h" #include "utilmoneystr.h" +#include "primitives/zerocoin.h" +#include "libzerocoin/Denominations.h" + #include #include @@ -39,11 +44,16 @@ using namespace boost; using namespace std; +using namespace libzerocoin; #if defined(NDEBUG) #error "Bulwark cannot be compiled without assertions." #endif +// 6 comes from OPCODE (1) + vch.size() (1) + BIGNUM size (4) +#define SCRIPT_OFFSET 6 +// For Script size (BIGNUM/Uint256 size) +#define BIGNUM_SIZE 4 /** * Global state */ @@ -65,13 +75,14 @@ bool fReindex = false; bool fTxIndex = true; bool fIsBareMultisigStd = true; bool fCheckBlockIndex = false; +bool fVerifyingBlocks = false; unsigned int nCoinCacheSize = 5000; bool fAlerts = DEFAULT_ALERTS; unsigned int nStakeMinAge = 60 * 60; int64_t nReserveBalance = 0; -/** Fees smaller than this (in duffs) are considered zero fee (for relaying and mining) +/** Fees smaller than this (in uBWK) are considered zero fee (for relaying and mining) * We are ~100 times smaller then bitcoin now (2015-06-23), set minRelayTxFee only 10 times higher * so it's still 10 times lower comparing to bitcoin. */ @@ -585,6 +596,8 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc CCoinsViewCache* pcoinsTip = NULL; CBlockTreeDB* pblocktree = NULL; +CZerocoinDB* zerocoinDB = NULL; +CSporkDB* pSporkDB = NULL; ////////////////////////////////////////////////////////////////////////////// // @@ -701,12 +714,15 @@ bool IsStandardTx(const CTransaction& tx, string& reason) // computing signature hashes is O(ninputs*txsize). Limiting transactions // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); - if (sz >= MAX_STANDARD_TX_SIZE) { + unsigned int nMaxSize = tx.ContainsZerocoins() ? MAX_ZEROCOIN_TX_SIZE : MAX_STANDARD_TX_SIZE; + if (sz >= nMaxSize) { reason = "tx-size"; return false; } - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { + if (txin.scriptSig.IsZerocoinSpend()) + continue; // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed // keys. (remember the 520 byte limit on redeemScript size) That works // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627 @@ -781,8 +797,9 @@ bool IsFinalTx(const CTransaction& tx, int nBlockHeight, int64_t nBlockTime) */ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { - if (tx.IsCoinBase()) - return true; // Coinbases don't use vin normally + if (tx.IsCoinBase() || tx.IsZerocoinSpend()) + return true; // coinbase has no inputs and zerocoinspend has a special input + //todo should there be a check for a 'standard' zerocoinspend here? for (unsigned int i = 0; i < tx.vin.size(); i++) { const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]); @@ -847,7 +864,7 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx) unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs) { - if (tx.IsCoinBase()) + if (tx.IsCoinBase() || tx.IsZerocoinSpend()) return 0; unsigned int nSigOps = 0; @@ -965,10 +982,440 @@ bool GetCoinAge(const CTransaction& tx, const unsigned int nTxTime, uint64_t& nC bool MoneyRange(CAmount nValueOut) { - return nValueOut >= 0 && nValueOut <= Params().MaxMoneyOut(); + return nValueOut >= 0 && nValueOut <= Params().MaxMoneyOut(); +} + +// TODO (ZC): Add this back when we have a hardcoded start height. + +int nZerocoinStartHeight = 0; +int GetZerocoinStartHeight() +{ + if (nZerocoinStartHeight) + return nZerocoinStartHeight; + for (int i = 1; i < chainActive.Height(); i++) { + if (chainActive[i]->nVersion < Params().Zerocoin_HeaderVersion()) + continue; + nZerocoinStartHeight = i; + break; + } + return nZerocoinStartHeight; +} + +void FindMints(vector vMintsToFind, vector& vMintsToUpdate, vector& vMissingMints, bool fExtendedSearch) +{ + // see which mints are in our public zerocoin database. The mint should be here if it exists, unless + // something went wrong + for (CZerocoinMint mint : vMintsToFind) { + uint256 txHash; + if (!zerocoinDB->ReadCoinMint(mint.GetValue(), txHash)) { + vMissingMints.push_back(mint); + continue; + } + + // make sure the txhash and block height meta data are correct for this mint + CTransaction tx; + uint256 hashBlock; + if (!GetTransaction(txHash, tx, hashBlock, true)) { + LogPrintf("%s : cannot find tx %s\n", __func__, txHash.GetHex()); + vMissingMints.push_back(mint); + continue; + } + + if (!mapBlockIndex.count(hashBlock)) { + LogPrintf("%s : cannot find block %s\n", __func__, hashBlock.GetHex()); + vMissingMints.push_back(mint); + continue; + } + + //see if this mint is spent + uint256 hashTxSpend = 0; + zerocoinDB->ReadCoinSpend(mint.GetSerialNumber(), hashTxSpend); + bool fSpent = hashTxSpend != 0; + + //if marked as spent, check that it actually made it into the chain + CTransaction txSpend; + uint256 hashBlockSpend; + if (fSpent && !GetTransaction(hashTxSpend, txSpend, hashBlockSpend, true)) { + LogPrintf("%s : cannot find spend tx %s\n", __func__, hashTxSpend.GetHex()); + zerocoinDB->EraseCoinSpend(mint.GetSerialNumber()); + mint.SetUsed(false); + vMintsToUpdate.push_back(mint); + continue; + } + + //The mint has been incorrectly labelled as spent in zerocoinDB and needs to be undone + int nHeightTx = 0; + if (fSpent && !IsSerialInBlockchain(mint.GetSerialNumber(), nHeightTx)) { + LogPrintf("%s : cannot find block %s. Erasing coinspend from zerocoinDB.\n", __func__, hashBlockSpend.GetHex()); + zerocoinDB->EraseCoinSpend(mint.GetSerialNumber()); + mint.SetUsed(false); + vMintsToUpdate.push_back(mint); + continue; + } + + // if meta data is correct, then no need to update + if (mint.GetTxHash() == txHash && mint.GetHeight() == mapBlockIndex[hashBlock]->nHeight && mint.IsUsed() == fSpent) + continue; + + //mark this mint for update + mint.SetTxHash(txHash); + mint.SetHeight(mapBlockIndex[hashBlock]->nHeight); + mint.SetUsed(fSpent); + + vMintsToUpdate.push_back(mint); + } + + if (fExtendedSearch) + { + // search the blockchain for the meta data on our missing mints + int nZerocoinStartHeight = GetZerocoinStartHeight(); + + for (int i = nZerocoinStartHeight; i < chainActive.Height(); i++) { + + if(i % 1000 == 0) + LogPrintf("%s : scanned %d blocks\n", __func__, i - nZerocoinStartHeight); + + if(chainActive[i]->vMintDenominationsInBlock.empty()) + continue; + + CBlock block; + if(!ReadBlockFromDisk(block, chainActive[i])) + continue; + + list vMints; + if(!BlockToZerocoinMintList(block, vMints)) + continue; + + // search the blocks mints to see if it contains the mint that is requesting meta data updates + for (CZerocoinMint mintBlockChain : vMints) { + for (CZerocoinMint mintMissing : vMissingMints) { + if (mintMissing.GetValue() == mintBlockChain.GetValue()) { + LogPrintf("%s FOUND %s in block %d\n", __func__, mintMissing.GetValue().GetHex(), i); + mintMissing.SetHeight(i); + mintMissing.SetTxHash(mintBlockChain.GetTxHash()); + vMintsToUpdate.push_back(mintMissing); + } + } + } + } + } + + //remove any missing mints that were found + for (CZerocoinMint mintMissing : vMissingMints) { + for (CZerocoinMint mintFound : vMintsToUpdate) { + if (mintMissing.GetValue() == mintFound.GetValue()) + std::remove(vMissingMints.begin(), vMissingMints.end(), mintMissing); + } + } + +} + +bool GetZerocoinMint(const CBigNum& bnPubcoin, uint256& txHash) +{ + txHash = 0; + return zerocoinDB->ReadCoinMint(bnPubcoin, txHash); +} + +bool IsSerialKnown(const CBigNum& bnSerial) +{ + uint256 txHash = 0; + return zerocoinDB->ReadCoinSpend(bnSerial, txHash); +} + +bool IsSerialInBlockchain(const CBigNum& bnSerial, int& nHeightTx) +{ + uint256 txHash = 0; + // if not in zerocoinDB then its not in the blockchain + if (!zerocoinDB->ReadCoinSpend(bnSerial, txHash)) + return false; + + CTransaction tx; + uint256 hashBlock; + if (!GetTransaction(txHash, tx, hashBlock, true)) + return false; + + bool inChain = mapBlockIndex.count(hashBlock) && chainActive.Contains(mapBlockIndex[hashBlock]); + if (inChain) + nHeightTx = mapBlockIndex.at(hashBlock)->nHeight; + + return inChain; +} + +bool RemoveSerialFromDB(const CBigNum& bnSerial) +{ + return zerocoinDB->EraseCoinSpend(bnSerial); +} + +/** zerocoin transaction checks */ +bool RecordMintToDB(PublicCoin publicZerocoin, const uint256& txHash) +{ + //Check the pubCoinValue didn't already store in the zerocoin database. todo: pubcoin memory map? + //write the zerocoinmint to db if we don't already have it + //note that many of the mint parameters are not set here because those params are private to the minter + CZerocoinMint pubCoinTx; + uint256 hashFromDB; + if (zerocoinDB->ReadCoinMint(publicZerocoin.getValue(), hashFromDB)) { + if(hashFromDB == txHash) + return true; + + LogPrintf("RecordMintToDB: failed, we already have this public coin recorded\n"); + return false; + } + + if (!zerocoinDB->WriteCoinMint(publicZerocoin, txHash)) { + LogPrintf("RecordMintToDB: failed to record public coin to DB\n"); + return false; + } + + return true; +} + +bool TxOutToPublicCoin(const CTxOut txout, PublicCoin& pubCoin, CValidationState& state) +{ + CBigNum publicZerocoin; + vector vchZeroMint; + vchZeroMint.insert(vchZeroMint.end(), txout.scriptPubKey.begin() + SCRIPT_OFFSET, + txout.scriptPubKey.begin() + txout.scriptPubKey.size()); + publicZerocoin.setvch(vchZeroMint); + + CoinDenomination denomination = AmountToZerocoinDenomination(txout.nValue); + LogPrint("zero", "%s ZCPRINT denomination %d pubcoin %s\n", __func__, denomination, publicZerocoin.GetHex()); + if (denomination == ZQ_ERROR) + return state.DoS(100, error("TxOutToPublicCoin : txout.nValue is not correct")); + + PublicCoin checkPubCoin(Params().Zerocoin_Params(), publicZerocoin, denomination); + pubCoin = checkPubCoin; + + return true; +} + +bool BlockToPubcoinList(const CBlock& block, list& listPubcoins) +{ + for (const CTransaction tx : block.vtx) { + if(!tx.IsZerocoinMint()) + continue; + + for (unsigned int i = 0; i < tx.vout.size(); i++) { + const CTxOut txOut = tx.vout[i]; + if(!txOut.scriptPubKey.IsZerocoinMint()) + continue; + + CValidationState state; + PublicCoin pubCoin(Params().Zerocoin_Params()); + if(!TxOutToPublicCoin(txOut, pubCoin, state)) + return false; + + listPubcoins.emplace_back(pubCoin); + } + } + + return true; +} + +//return a list of zerocoin mints contained in a specific block +bool BlockToZerocoinMintList(const CBlock& block, std::list& vMints) +{ + for (const CTransaction tx : block.vtx) { + if(!tx.IsZerocoinMint()) + continue; + + for (unsigned int i = 0; i < tx.vout.size(); i++) { + const CTxOut txOut = tx.vout[i]; + if(!txOut.scriptPubKey.IsZerocoinMint()) + continue; + + CValidationState state; + PublicCoin pubCoin(Params().Zerocoin_Params()); + if(!TxOutToPublicCoin(txOut, pubCoin, state)) + return false; + + CZerocoinMint mint = CZerocoinMint(pubCoin.getDenomination(), pubCoin.getValue(), 0, 0, false); + mint.SetTxHash(tx.GetHash()); + vMints.push_back(mint); + } + } + + return true; +} + +bool BlockToMintValueVector(const CBlock& block, const CoinDenomination denom, vector& vValues) +{ + for (const CTransaction tx : block.vtx) { + if(!tx.IsZerocoinMint()) + continue; + + for (const CTxOut txOut : tx.vout) { + if(!txOut.scriptPubKey.IsZerocoinMint()) + continue; + + CValidationState state; + PublicCoin coin(Params().Zerocoin_Params()); + if(!TxOutToPublicCoin(txOut, coin, state)) + return false; + + if (coin.getDenomination() != denom) + continue; + + vValues.push_back(coin.getValue()); + } + } + + return true; +} + +//return a list of zerocoin spends contained in a specific block, list may have many denominations +std::list ZerocoinSpendListFromBlock(const CBlock& block) +{ + std::list vSpends; + for (const CTransaction tx : block.vtx) { + if (!tx.IsZerocoinSpend()) + continue; + + for (const CTxIn txin : tx.vin) { + if (!txin.scriptSig.IsZerocoinSpend()) + continue; + + libzerocoin::CoinDenomination c = libzerocoin::IntToZerocoinDenomination(txin.nSequence); + vSpends.push_back(c); + } + } + return vSpends; +} + +bool CheckZerocoinMint(const uint256& txHash, const CTxOut& txout, CValidationState& state, bool fCheckOnly) +{ + if(!fCheckOnly && GetAdjustedTime() < GetSporkValue(SPORK_21_ENABLE_ZEROCOIN)) + return state.DoS(100, error("CheckZerocoinMint(): Zerocoin transactions are not allowed yet")); + + PublicCoin pubCoin(Params().Zerocoin_Params()); + if(!TxOutToPublicCoin(txout, pubCoin, state)) + return state.DoS(100, error("CheckZerocoinMint(): TxOutToPublicCoin() failed")); + + if (!pubCoin.validate()) + return state.DoS(100, error("CheckZerocoinMint() : PubCoin does not validate")); + + if(!fCheckOnly && !RecordMintToDB(pubCoin, txHash)) + return state.DoS(100, error("CheckZerocoinMint(): RecordMintToDB() failed")); + + return true; +} + +CoinSpend TxInToZerocoinSpend(const CTxIn& txin) +{ + // Deserialize the CoinSpend intro a fresh object + std::vector > dataTxIn; + dataTxIn.insert(dataTxIn.end(), txin.scriptSig.begin() + BIGNUM_SIZE, txin.scriptSig.end()); + + CDataStream serializedCoinSpend(dataTxIn, SER_NETWORK, PROTOCOL_VERSION); + return CoinSpend(Params().Zerocoin_Params(), serializedCoinSpend); +} + +bool IsZerocoinSpendUnknown(CoinSpend coinSpend, uint256 hashTx, CValidationState& state) +{ + uint256 hashTxFromDB; + if(zerocoinDB->ReadCoinSpend(coinSpend.getCoinSerialNumber(), hashTxFromDB)) + return hashTx == hashTxFromDB; + + if(!zerocoinDB->WriteCoinSpend(coinSpend.getCoinSerialNumber(), hashTx)) + return state.DoS(100, error("CheckZerocoinSpend(): Failed to write zerocoin mint to database")); + + return true; +} + +bool CheckZerocoinSpend(const CTransaction tx, bool fVerifySignature, CValidationState& state) +{ + if(GetAdjustedTime() < GetSporkValue(SPORK_21_ENABLE_ZEROCOIN)) + return state.DoS(100, error("CheckZerocoinSpend(): Zerocoin transactions are not allowed yet")); + + //max needed non-mint outputs should be 2 - one for redemption address and a possible 2nd for change + if (tx.vout.size() > 2) { + int outs = 0; + for (const CTxOut out : tx.vout) { + if (out.IsZerocoinMint()) + continue; + outs++; + } + if (outs > 2) + return state.DoS(100, error("CheckZerocoinSpend(): over two non-mint outputs in a zerocoinspend transaction")); + } + + //compute the txout hash that is used for the zerocoinspend signatures + CMutableTransaction txTemp; + for (const CTxOut out : tx.vout) { + txTemp.vout.push_back(out); + } + uint256 hashTxOut = txTemp.GetHash(); + + 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()) + continue; + + CoinSpend newSpend = TxInToZerocoinSpend(txin); + vSpends.push_back(newSpend); + + //check that the denomination is valid + if (newSpend.getDenomination() == ZQ_ERROR) + return state.DoS(100, error("Zerocoinspend does not have the correct denomination")); + + //check that denomination is what it claims to be in nSequence + if (newSpend.getDenomination() != txin.nSequence) + return state.DoS(100, error("Zerocoinspend nSequence denomination does not match CoinSpend")); + + //make sure the txout has not changed + 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)) + return state.DoS(100, error("Zerocoinspend could not find accumulator associated with checksum")); + + Accumulator accumulator(Params().Zerocoin_Params(), newSpend.getDenomination(), bnAccumulatorValue); + + //Check that the coin is on the accumulator + if(!newSpend.Verify(accumulator)) + 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")); + serials.insert(newSpend.getCoinSerialNumber()); + + //make sure that there is no over redemption of coins + nTotalRedeemed += ZerocoinDenominationToAmount(newSpend.getDenomination()); + fValidated = true; + } + + if (nTotalRedeemed < tx.GetValueOut()) { + LogPrintf("redeemed = %s , spend = %s \n", FormatMoney(nTotalRedeemed), FormatMoney(tx.GetValueOut())); + return state.DoS(100, error("Transaction spend more than was redeemed in zerocoins")); + } + + // Send signal to wallet if this is ours + if (pwalletMain) { + CWalletDB walletdb(pwalletMain->strWalletFile); + list listMySerials = walletdb.ListMintedCoinsSerial(); + for (const auto& newSpend : vSpends) { + list::iterator it = find(listMySerials.begin(), listMySerials.end(), newSpend.getCoinSerialNumber()); + if (it != listMySerials.end()) { + LogPrintf("%s: %s detected spent zerocoin mint in transaction %s \n", __func__, it->GetHex(), tx.GetHash().GetHex()); + pwalletMain->NotifyZerocoinChanged(pwalletMain, it->GetHex(), "Used", CT_UPDATED); + } + } + } + + return fValidated; } -bool CheckTransaction(const CTransaction& tx, CValidationState& state) +bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fRejectBadUTXO, CValidationState& state) { // Basic checks that don't depend on any context if (tx.vin.empty()) @@ -977,13 +1424,19 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state) if (tx.vout.empty()) return state.DoS(10, error("CheckTransaction() : vout empty"), REJECT_INVALID, "bad-txns-vout-empty"); + // Size limits - if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + unsigned int nMaxSize = MAX_BLOCK_SIZE_LEGACY; + if(GetAdjustedTime() > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN)) + nMaxSize = MAX_ZEROCOIN_TX_SIZE; + + if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > nMaxSize) return state.DoS(100, error("CheckTransaction() : size limits failed"), REJECT_INVALID, "bad-txns-oversize"); // Check for negative or overflow output values CAmount nValueOut = 0; + int nZCSpendCount = 0; BOOST_FOREACH (const CTxOut& txout, tx.vout) { if (txout.IsEmpty() && !tx.IsCoinBase() && !tx.IsCoinStake()) return state.DoS(100, error("CheckTransaction(): txout empty for user transaction")); @@ -998,25 +1451,56 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state) if (!MoneyRange(nValueOut)) return state.DoS(100, error("CheckTransaction() : txout total out of range"), REJECT_INVALID, "bad-txns-txouttotal-toolarge"); + if (fZerocoinActive && txout.IsZerocoinMint()) { + if(!CheckZerocoinMint(tx.GetHash(), txout, state, false)) + return state.DoS(100, error("CheckTransaction() : invalid zerocoin mint")); + } + if (fZerocoinActive && txout.scriptPubKey.IsZerocoinSpend()) + 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 + for (const CTxIn in : tx.vin) { + if (!in.scriptSig.IsZerocoinSpend()) + return state.DoS(100, + error("CheckTransaction() : zerocoinspend contains inputs that are not zerocoins")); + } + + // Do not require signature verification if this is initial sync and a block over 24 hours old + bool fVerifySignature = !IsInitialBlockDownload() && (GetTime() - chainActive.Tip()->GetBlockTime() < (60*60*24)); + if (!CheckZerocoinSpend(tx, fVerifySignature, state)) + return state.DoS(100, error("CheckTransaction() : invalid zerocoin spend")); + } } // Check for duplicate inputs set vInOutPoints; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + 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"); - vInOutPoints.insert(txin.prevout); + + //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"); + 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 { BOOST_FOREACH (const CTxIn& txin, tx.vin) - if (txin.prevout.IsNull()) + if (txin.prevout.IsNull() && (fZerocoinActive && !txin.scriptSig.IsZerocoinSpend())) return state.DoS(10, error("CheckTransaction() : prevout is null"), REJECT_INVALID, "bad-txns-prevout-null"); } @@ -1078,7 +1562,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF } if (!MoneyRange(nMinFee)) - nMinFee = Params().MaxMoneyOut(); + nMinFee = Params().MaxMoneyOut(); return nMinFee; } @@ -1089,8 +1573,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa if (pfMissingInputs) *pfMissingInputs = false; - if (!CheckTransaction(tx, state)) - return error("AcceptToMemoryPool: : CheckTransaction failed"); + //Temporarily disable zerocoin for maintenance + if (GetAdjustedTime() > GetSporkValue(SPORK_22_ZEROCOIN_MAINTENANCE_MODE) && tx.ContainsZerocoins()) + return state.DoS(10, error("AcceptToMemoryPool : Zerocoin transactions are temporarily disabled for maintenance"), REJECT_INVALID, "bad-tx"); + + if (!CheckTransaction(tx, GetAdjustedTime() > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN), true, state)) + return state.DoS(100, error("AcceptToMemoryPool: : CheckTransaction failed"), REJECT_INVALID, "bad-tx"); // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) @@ -1111,8 +1599,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa // is it already in the memory pool? uint256 hash = tx.GetHash(); - if (pool.exists(hash)) + if (pool.exists(hash)) { + LogPrintf("%s tx already in mempool\n", __func__); return false; + } // ----------- swiftTX transaction scanning ----------- @@ -1127,7 +1617,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa } // Check for conflicts with in-memory transactions - { + if (!tx.IsZerocoinSpend()) { LOCK(pool.cs); // protect pool.mapNextTx for (unsigned int i = 0; i < tx.vin.size(); i++) { COutPoint outpoint = tx.vin[i].prevout; @@ -1144,7 +1634,31 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa CCoinsViewCache view(&dummy); CAmount nValueIn = 0; - { + if(tx.IsZerocoinSpend()){ + nValueIn = tx.GetZerocoinSpent(); + + //Check that txid is not already in the chain + int nHeightTx = 0; + if (IsTransactionInChain(tx.GetHash(), nHeightTx)) + return state.Invalid(error("AcceptToMemoryPool : zBWK spend tx %s already in block %d", tx.GetHash().GetHex(), nHeightTx), + REJECT_DUPLICATE, "bad-txns-inputs-spent"); + + //Check for double spending of serial #'s + for (const CTxIn& txIn : tx.vin) { + if (!txIn.scriptSig.IsZerocoinSpend()) + continue; + CoinSpend spend = TxInToZerocoinSpend(txIn); + int nHeightTx = 0; + if (IsSerialInBlockchain(spend.getCoinSerialNumber(), nHeightTx)) + return state.Invalid(error("%s : zBWK spend with serial %s is already in block %d\n", + __func__, spend.getCoinSerialNumber().GetHex(), nHeightTx)); + + //Is serial in the acceptable range + if (!spend.HasValidSerial(Params().Zerocoin_Params())) + return state.Invalid(error("%s : zBWK spend with serial %s from tx %s is not in valid range\n", + __func__, spend.getCoinSerialNumber().GetHex(), tx.GetHash().GetHex())); + } + } else { LOCK(pool.cs); CCoinsViewMemPool viewMemPool(pcoinsTip, pool); view.SetBackend(viewMemPool); @@ -1156,7 +1670,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa // do all inputs exist? // Note that this does not check for the presence of actual outputs (see the next check for that), // only helps filling in pfMissingInputs (to determine missing vs spent). - BOOST_FOREACH (const CTxIn txin, tx.vin) { + for (const CTxIn txin : tx.vin) { if (!view.HaveCoins(txin.prevout.hash)) { if (pfMissingInputs) *pfMissingInputs = true; @@ -1187,17 +1701,22 @@ 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. - unsigned int nSigOps = GetLegacySigOpCount(tx); - nSigOps += GetP2SHSigOpCount(tx, view); - if (nSigOps > MAX_TX_SIGOPS) - return state.DoS(0, - error("AcceptToMemoryPool : too many sigops %s, %d > %d", - hash.ToString(), nSigOps, MAX_TX_SIGOPS), - REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); + if (!tx.IsZerocoinSpend()) { + unsigned int nSigOps = GetLegacySigOpCount(tx); + unsigned int nMaxSigOps = GetAdjustedTime() > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN) ? MAX_TX_SIGOPS_CURRENT : MAX_TX_SIGOPS_LEGACY; + nSigOps += GetP2SHSigOpCount(tx, view); + if(nSigOps > nMaxSigOps) + return state.DoS(0, + error("AcceptToMemoryPool : too many sigops %s, %d > %d", + hash.ToString(), nSigOps, nMaxSigOps), + REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); + } CAmount nValueOut = tx.GetValueOut(); CAmount nFees = nValueIn - nValueOut; - double dPriority = view.GetPriority(tx, chainActive.Height()); + double dPriority = 0; + if (!tx.IsZerocoinSpend()) + view.GetPriority(tx, chainActive.Height()); CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height()); unsigned int nSize = entry.GetTxSize(); @@ -1208,20 +1727,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) + if (fLimitFree && nFees < txMinFee && !tx.IsZerocoinSpend()) 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 (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { + if (tx.IsZerocoinMint()) { + 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))) { 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)) { + if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.IsZerocoinSpend()) { static CCriticalSection csFreeLimiter; static double dFreeCount; static int64_t nLastTime; @@ -1234,7 +1756,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa nLastTime = nNow; // -limitfreerelay unit is thousand-bytes-per-minute // At default rate it would take over a month to fill 1GB - if (dFreeCount >= GetArg("-limitfreerelay", 15) * 10 * 1000) + if (dFreeCount >= GetArg("-limitfreerelay", 30) * 10 * 1000) return state.DoS(0, error("AcceptToMemoryPool : free transaction rejected by rate limiter"), REJECT_INSUFFICIENTFEE, "rate limited free transaction"); LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount + nSize); @@ -1281,7 +1803,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact if (pfMissingInputs) *pfMissingInputs = false; - if (!CheckTransaction(tx, state)) + if (!CheckTransaction(tx, GetAdjustedTime() > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN), true, state)) return error("AcceptableInputs: : CheckTransaction failed"); // Coinbase is only valid in a block, not as a loose transaction @@ -1315,7 +1837,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact } // Check for conflicts with in-memory transactions - { + if (!tx.IsZerocoinSpend()) { LOCK(pool.cs); // protect pool.mapNextTx for (unsigned int i = 0; i < tx.vin.size(); i++) { COutPoint outpoint = tx.vin[i].prevout; @@ -1344,7 +1866,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact // do all inputs exist? // Note that this does not check for the presence of actual outputs (see the next check for that), // only helps filling in pfMissingInputs (to determine missing vs spent). - BOOST_FOREACH (const CTxIn txin, tx.vin) { + for (const CTxIn txin : tx.vin) { if (!view.HaveCoins(txin.prevout.hash)) { if (pfMissingInputs) *pfMissingInputs = true; @@ -1377,11 +1899,12 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than // merely non-standard transaction. unsigned int nSigOps = GetLegacySigOpCount(tx); + unsigned int nMaxSigOps = GetAdjustedTime() > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN) ? MAX_TX_SIGOPS_CURRENT : MAX_TX_SIGOPS_LEGACY; nSigOps += GetP2SHSigOpCount(tx, view); - if (nSigOps > MAX_TX_SIGOPS) + if (nSigOps > nMaxSigOps) return state.DoS(0, error("AcceptableInputs : too many sigops %s, %d > %d", - hash.ToString(), nSigOps, MAX_TX_SIGOPS), + hash.ToString(), nSigOps, nMaxSigOps), REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); CAmount nValueOut = tx.GetValueOut(); @@ -1397,7 +1920,7 @@ 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) + if (fLimitFree && nFees < txMinFee && !tx.IsZerocoinSpend()) return state.DoS(0, error("AcceptableInputs : not enough fees %s, %d < %d", hash.ToString(), nFees, txMinFee), REJECT_INSUFFICIENTFEE, "insufficient fee"); @@ -1410,7 +1933,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)) { + if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize) && !tx.IsZerocoinSpend()) { static CCriticalSection csFreeLimiter; static double dFreeCount; static int64_t nLastTime; @@ -1423,7 +1946,7 @@ bool AcceptableInputs(CTxMemPool& pool, CValidationState& state, const CTransact nLastTime = nNow; // -limitfreerelay unit is thousand-bytes-per-minute // At default rate it would take over a month to fill 1GB - if (dFreeCount >= GetArg("-limitfreerelay", 15) * 10 * 1000) + if (dFreeCount >= GetArg("-limitfreerelay", 30) * 10 * 1000) return state.DoS(0, error("AcceptableInputs : free transaction rejected by rate limiter"), REJECT_INSUFFICIENTFEE, "rate limited free transaction"); LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount + nSize); @@ -1497,6 +2020,9 @@ bool GetTransaction(const uint256& hash, CTransaction& txOut, uint256& hashBlock return error("%s : txid mismatch", __func__); return true; } + + // transaction not found in the index, nothing more can be done + return false; } if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it @@ -1609,7 +2135,7 @@ double ConvertBitsToDouble(unsigned int nBits) } return dDiff; -} +} int64_t GetBlockValue(int nHeight) { @@ -1974,7 +2500,7 @@ int64_t GetMasternodePayment(int nHeight, int64_t blockValue, int nMasternodeCou bool IsInitialBlockDownload() { LOCK(cs_main); - if (fImporting || fReindex || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate()) + if (fImporting || fReindex || fVerifyingBlocks || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate()) return true; static bool lockIBDState = false; if (lockIBDState) @@ -2116,7 +2642,7 @@ 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()) { + if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { txundo.vprevout.reserve(tx.vin.size()); BOOST_FOREACH (const CTxIn& txin, tx.vin) { txundo.vprevout.push_back(CTxInUndo()); @@ -2140,7 +2666,7 @@ bool CScriptCheck::operator()() bool CheckInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector* pvChecks) { - if (!tx.IsCoinBase()) { + if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { if (pvChecks) pvChecks->reserve(tx.vin.size()); @@ -2240,6 +2766,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState& state, const CCoinsVi bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) { + if (pindex->GetBlockHash() != view.GetBestBlock()) + LogPrintf("%s : pindex=%s view=%s\n", __func__, pindex->GetBlockHash().GetHex(), view.GetBestBlock().GetHex()); assert(pindex->GetBlockHash() == view.GetBestBlock()); if (pfClean) @@ -2260,6 +2788,38 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { const CTransaction& tx = block.vtx[i]; + + /** UNDO ZEROCOIN DATABASING + * note we only undo zerocoin databasing in the following statement, value to and from Bulwark + * addresses should still be handled by the typical bitcoin based undo code + * */ + if (tx.ContainsZerocoins()) { + if (tx.IsZerocoinSpend()) { + //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())) + return error("failed to erase spent zerocoin in block"); + } + } + } + if (tx.IsZerocoinMint()) { + //erase all zerocoinmints in this transaction + for (const CTxOut txout : tx.vout) { + if (txout.scriptPubKey.empty() || !txout.scriptPubKey.IsZerocoinMint()) + continue; + + PublicCoin pubCoin(Params().Zerocoin_Params()); + if (!TxOutToPublicCoin(txout, pubCoin, state)) + return error("DisconnectBlock(): TxOutToPublicCoin() failed"); + + if(!zerocoinDB->EraseCoinMint(pubCoin.getValue())) + return error("DisconnectBlock(): Failed to erase coin mint"); + } + } + } + uint256 hash = tx.GetHash(); // Check that all outputs are available and match the outputs in the block itself @@ -2285,7 +2845,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex } // restore inputs - if (i > 0) { // not coinbases + if (!tx.IsCoinBase() && !tx.IsZerocoinSpend()) { // 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()); @@ -2317,6 +2877,15 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex // move best block pointer to prevout block view.SetBestBlock(pindex->pprev->GetBlockHash()); + if (!fVerifyingBlocks) { + //if block is an accumulator checkpoint block, remove checkpoint and checksums from db + uint256 nCheckpoint = pindex->nAccumulatorCheckpoint; + if(nCheckpoint != pindex->pprev->nAccumulatorCheckpoint) { + if(!EraseAccumulatorValues(nCheckpoint, pindex->pprev->nAccumulatorCheckpoint)) + return error("DisconnectBlock(): failed to erase checkpoint"); + } + } + if (pfClean) { *pfClean = fClean; return true; @@ -2358,17 +2927,192 @@ void ThreadScriptCheck() scriptcheckqueue.Thread(); } +void RecalculateZBWKMinted() +{ + int nZerocoinStartHeight = GetZerocoinStartHeight(); + if (nZerocoinStartHeight == 0) return; + CBlockIndex *pindex = chainActive[nZerocoinStartHeight]; + int nHeightEnd = chainActive.Height(); + while (true) { + if (pindex->nHeight % 1000 == 0) + LogPrintf("%s : block %d...\n", __func__, pindex->nHeight); + + //overwrite possibly wrong vMintsInBlock data + CBlock block; + assert(ReadBlockFromDisk(block, pindex)); + + std::list listMints; + BlockToZerocoinMintList(block, listMints); + + vector vDenomsBefore = pindex->vMintDenominationsInBlock; + pindex->vMintDenominationsInBlock.clear(); + for (auto mint : listMints) + pindex->vMintDenominationsInBlock.emplace_back(mint.GetDenomination()); + + if (pindex->nHeight < nHeightEnd) + pindex = chainActive.Next(pindex); + else + break; + } +} + +void RecalculateZBWKSpent() +{ + int nZerocoinStartHeight = GetZerocoinStartHeight(); + if (nZerocoinStartHeight == 0) return; + CBlockIndex* pindex = chainActive[nZerocoinStartHeight]; + while (true) { + if (pindex->nHeight % 1000 == 0) + LogPrintf("%s : block %d...\n", __func__, pindex->nHeight); + + //Rewrite zBWK supply + CBlock block; + assert(ReadBlockFromDisk(block, pindex)); + + list listDenomsSpent = ZerocoinSpendListFromBlock(block); + + //Reset the supply to previous block + pindex->mapZerocoinSupply = pindex->pprev->mapZerocoinSupply; + + //Add mints to zBWK supply + for (auto denom : libzerocoin::zerocoinDenomList) { + long nDenomAdded = count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), denom); + pindex->mapZerocoinSupply.at(denom) += nDenomAdded; + } + + //Remove spends from zBWK supply + for (auto denom : listDenomsSpent) + pindex->mapZerocoinSupply.at(denom)--; + + //Rewrite money supply + assert(pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))); + + if (pindex->nHeight < chainActive.Height()) + pindex = chainActive.Next(pindex); + else + break; + } +} + +bool RecalculateBWKSupply(int nHeightStart) +{ + if (nHeightStart > chainActive.Height()) + return false; + + CBlockIndex* pindex = chainActive[nHeightStart]; + CAmount nSupplyPrev = pindex->pprev->nMoneySupply; + + while (true) { + if (pindex->nHeight % 1000 == 0) + LogPrintf("%s : block %d...\n", __func__, pindex->nHeight); + + CBlock block; + assert(ReadBlockFromDisk(block, pindex)); + + CAmount nValueIn = 0; + CAmount nValueOut = 0; + for (const CTransaction tx : block.vtx) { + for (unsigned int i = 0; i < tx.vin.size(); i++) { + if (tx.IsCoinBase()) + break; + + if (tx.vin[i].scriptSig.IsZerocoinSpend()) { + nValueIn += tx.vin[i].nSequence * COIN; + continue; + } + + COutPoint prevout = tx.vin[i].prevout; + CTransaction txPrev; + uint256 hashBlock; + assert(GetTransaction(prevout.hash, txPrev, hashBlock, true)); + nValueIn += txPrev.vout[prevout.n].nValue; + } + + for (unsigned int i = 0; i < tx.vout.size(); i++) { + if (i == 0 && tx.IsCoinStake()) + continue; + + nValueOut += tx.vout[i].nValue; + } + } + + // Rewrite money supply + pindex->nMoneySupply = nSupplyPrev + nValueOut - nValueIn; + nSupplyPrev = pindex->nMoneySupply; + + assert(pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))); + + if (pindex->nHeight < chainActive.Height()) + pindex = chainActive.Next(pindex); + else + break; + } + return true; +} + +bool ReindexAccumulators(list& listMissingCheckpoints, string& strError) +{ + int nZerocoinStart = GetZerocoinStartHeight(); + if (nZerocoinStart == 0) return false; + // Bulwark: recalculate Accumulator Checkpoints that failed to database properly + if (!listMissingCheckpoints.empty() && chainActive.Height() >= nZerocoinStart) { + //uiInterface.InitMessage(_("Calculating missing accumulators...")); + LogPrintf("%s : finding missing checkpoints\n", __func__); + + // find each checkpoint that is missing + CBlockIndex* pindex = chainActive[nZerocoinStart]; + while (!listMissingCheckpoints.empty()) { + if (ShutdownRequested()) + return false; + + // find checkpoints by iterating through the blockchain beginning with the first zerocoin block + if (pindex->nAccumulatorCheckpoint != pindex->pprev->nAccumulatorCheckpoint) { + + //double dPercent = (pindex->nHeight - nZerocoinStart) / (double) (chainActive.Height() - nZerocoinStart); + //uiInterface.ShowProgress(_("Calculating missing accumulators..."), (int) (dPercent * 100)); + if (find(listMissingCheckpoints.begin(), listMissingCheckpoints.end(), pindex->nAccumulatorCheckpoint) != listMissingCheckpoints.end()) { + uint256 nCheckpointCalculated = 0; + if (!CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated)) { + // GetCheckpoint could have terminated due to a shutdown request. Check this here. + if (ShutdownRequested()) + break; + strError = _("Failed to calculate accumulator checkpoint"); + return false; + } + + //check that the calculated checkpoint is what is in the index. + if (nCheckpointCalculated != pindex->nAccumulatorCheckpoint) { + LogPrintf("%s : height=%d calculated_checkpoint=%s actual=%s\n", __func__, pindex->nHeight, nCheckpointCalculated.GetHex(), pindex->nAccumulatorCheckpoint.GetHex()); + strError = _("Calculated accumulator checkpoint is not what is recorded by block index"); + return false; + } + + auto it = find(listMissingCheckpoints.begin(), listMissingCheckpoints.end(), pindex->nAccumulatorCheckpoint); + listMissingCheckpoints.erase(it); + } + } + + // if we have iterated to the end of the blockchain, then checkpoints should be in sync + if (pindex->nHeight + 1 <= chainActive.Height()) + pindex = chainActive.Next(pindex); + else + break; + } + } + return true; +} + static int64_t nTimeVerify = 0; static int64_t nTimeConnect = 0; static int64_t nTimeIndex = 0; static int64_t nTimeCallbacks = 0; static int64_t nTimeTotal = 0; -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck, bool fAlreadyChecked) { AssertLockHeld(cs_main); // Check it again in case a previous version let a bad block in - if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) + if (!fAlreadyChecked && !CheckBlock(block, state, !fJustCheck, !fJustCheck)) return false; // verify that the view's current state corresponds to the previous block @@ -2432,7 +3176,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, when 75% of the network has upgraded: if (block.nVersion >= 3 && CBlockIndex::IsSuperMajority(3, pindex->pprev, Params().EnforceBlockUpgradeMajority())) { - flags |= SCRIPT_VERIFY_DERSIG; + flags |= SCRIPT_VERIFY_DERSIG; } CBlockUndo blockundo; @@ -2449,16 +3193,59 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin blockundo.vtxundo.reserve(block.vtx.size() - 1); CAmount nValueOut = 0; CAmount nValueIn = 0; + unsigned int nMaxBlockSigOps = block.nTime > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN) ? MAX_BLOCK_SIGOPS_CURRENT : MAX_BLOCK_SIGOPS_LEGACY; for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction& tx = block.vtx[i]; nInputs += tx.vin.size(); nSigOps += GetLegacySigOpCount(tx); - if (nSigOps > MAX_BLOCK_SIGOPS) + if (nSigOps > nMaxBlockSigOps) return state.DoS(100, error("ConnectBlock() : too many sigops"), REJECT_INVALID, "bad-blk-sigops"); - if (!tx.IsCoinBase()) { + //Temporarily disable zerocoin transactions for maintenance + if (block.nTime > GetSporkValue(SPORK_22_ZEROCOIN_MAINTENANCE_MODE) && !IsInitialBlockDownload() && tx.ContainsZerocoins()) { + return state.DoS(100, error("ConnectBlock() : zerocoin transactions are currently in maintenance mode")); + } + if (tx.IsZerocoinSpend()) { + int nHeightTx = 0; + if (IsTransactionInChain(tx.GetHash(), nHeightTx)) { + //when verifying blocks on init, the blocks are scanned without being disconnected - prevent that from causing an error + if (!fVerifyingBlocks || (fVerifyingBlocks && pindex->nHeight > nHeightTx)) + return state.DoS(100, error("%s : txid %s already exists in block %d , trying to include it again in block %d", __func__, + tx.GetHash().GetHex(), nHeightTx, pindex->nHeight), + REJECT_INVALID, "bad-txns-inputs-missingorspent"); + } + + //Check for double spending of serial #'s + for (const CTxIn& txIn : tx.vin) { + if (!txIn.scriptSig.IsZerocoinSpend()) + continue; + CoinSpend spend = TxInToZerocoinSpend(txIn); + nValueIn += spend.getDenomination() * COIN; + + // Make sure that the serial number is in valid range + if (!spend.HasValidSerial(Params().Zerocoin_Params())) { + string strError = strprintf("%s : txid=%s in block %d contains invalid serial %s\n", __func__, tx.GetHash().GetHex(), pindex->nHeight, spend.getCoinSerialNumber()); + return state.DoS(100, error(strError.c_str())); + } + + //Is the serial already in the blockchain? + uint256 hashTxFromDB; + int nHeightTxSpend = 0; + if (zerocoinDB->ReadCoinSpend(spend.getCoinSerialNumber(), hashTxFromDB)) { + if(IsSerialInBlockchain(spend.getCoinSerialNumber(), nHeightTxSpend)) { + if(!fVerifyingBlocks || (fVerifyingBlocks && pindex->nHeight > nHeightTxSpend)) + return state.DoS(100, error("%s : zBWK with serial %s is already in the block %d\n", + __func__, spend.getCoinSerialNumber().GetHex(), nHeightTxSpend)); + } + } + + //record spend to database + if (!zerocoinDB->WriteCoinSpend(spend.getCoinSerialNumber(), tx.GetHash())) + return error("%s : failed to record coin serial to database"); + } + } else if (!tx.IsCoinBase()) { if (!view.HaveInputs(tx)) return state.DoS(100, error("ConnectBlock() : inputs missing/spent"), REJECT_INVALID, "bad-txns-inputs-missingorspent"); @@ -2468,14 +3255,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // this is to prevent a "rogue miner" from creating // an incredibly-expensive-to-validate block. nSigOps += GetP2SHSigOpCount(tx, view); - if (nSigOps > MAX_BLOCK_SIGOPS) + if (nSigOps > nMaxBlockSigOps) return state.DoS(100, error("ConnectBlock() : too many sigops"), REJECT_INVALID, "bad-blk-sigops"); } if (!tx.IsCoinStake()) - nFees += view.GetValueIn(tx) - tx.GetValueOut(); - + nFees += view.GetValueIn(tx) - tx.GetValueOut(); nValueIn += view.GetValueIn(tx); std::vector vChecks; @@ -2495,10 +3281,49 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); } - // ppcoin: track money supply and mint amount info + std::list listMints; + BlockToZerocoinMintList(block, listMints); + std::list listSpends = ZerocoinSpendListFromBlock(block); + + // Initialize zerocoin supply to the supply from previous block + if (pindex->pprev && pindex->pprev->GetBlockHeader().nVersion > 3) { + for (auto& denom : zerocoinDenomList) { + pindex->mapZerocoinSupply.at(denom) = pindex->pprev->mapZerocoinSupply.at(denom); + } + } + + // Track zerocoin money supply + CAmount nAmountZerocoinSpent = 0; + pindex->vMintDenominationsInBlock.clear(); + if (pindex->pprev) { + for (auto& m : listMints) { + libzerocoin::CoinDenomination denom = m.GetDenomination(); + pindex->vMintDenominationsInBlock.push_back(m.GetDenomination()); + pindex->mapZerocoinSupply.at(denom)++; + } + + for (auto& denom : listSpends) { + pindex->mapZerocoinSupply.at(denom)--; + nAmountZerocoinSpent += libzerocoin::ZerocoinDenominationToAmount(denom); + + // zerocoin failsafe + if (pindex->mapZerocoinSupply.at(denom) < 0) + return state.DoS(100, error("Block contains zerocoins that spend more than are in the available supply to spend")); + } + } + + for (auto& denom : zerocoinDenomList) { + LogPrint("zero" "%s coins for denomination %d pubcoin %s\n", __func__, pindex->mapZerocoinSupply.at(denom), denom); + } + + // track money supply and mint amount info CAmount nMoneySupplyPrev = pindex->pprev ? pindex->pprev->nMoneySupply : 0; pindex->nMoneySupply = nMoneySupplyPrev + nValueOut - nValueIn; - pindex->nMint = pindex->nMoneySupply - nMoneySupplyPrev; + pindex->nMint = pindex->nMoneySupply - nMoneySupplyPrev + nFees; + +// LogPrintf("XX69----------> ConnectBlock(): nValueOut: %s, nValueIn: %s, nFees: %s, nMint: %s zBWKSpent: %s\n", +// FormatMoney(nValueOut), FormatMoney(nValueIn), +// FormatMoney(nFees), FormatMoney(pindex->nMint), FormatMoney(nAmountZerocoinSpent)); if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex))) return error("Connect() : WriteBlockIndex for pindex failed"); @@ -2507,18 +3332,38 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin nTimeConnect += nTime1 - nTimeStart; LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs - 1), nTimeConnect * 0.000001); + //PoW phase redistributed fees to miner. PoS stage destroys fees. CAmount nExpectedMint = GetBlockValue(pindex->pprev->nHeight); if (block.IsProofOfWork()) - nExpectedMint += nFees; + nExpectedMint += nFees; if (!IsBlockValueValid(block, nExpectedMint, pindex->nMint)) { return state.DoS(100, error("ConnectBlock() : reward pays too much (actual=%s vs limit=%s)", - FormatMoney(pindex->nMint), FormatMoney(nExpectedMint)), - + FormatMoney(pindex->nMint), FormatMoney(nExpectedMint)), REJECT_INVALID, "bad-cb-amount"); } + int nZerocoinStart = GetZerocoinStartHeight(); + if (nZerocoinStart != 0) { + // zerocoin accumulator: if a new accumulator checkpoint was generated, check that it is the correct value + if (!fVerifyingBlocks && pindex->nHeight >= nZerocoinStart && pindex->nHeight % 10 == 0) { + uint256 nCheckpointCalculated = 0; + + if (!CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated)) { + return state.DoS(100, error("ConnectBlock() : failed to calculate accumulator checkpoint")); + } + + if (nCheckpointCalculated != block.nAccumulatorCheckpoint) { + LogPrintf("%s: block=%d calculated: %s\n block: %s\n", __func__, pindex->nHeight, nCheckpointCalculated.GetHex(), block.nAccumulatorCheckpoint.GetHex()); + return state.DoS(100, error("ConnectBlock() : accumulator does not match calculated value")); + } + } else if (!fVerifyingBlocks) { + if (block.nAccumulatorCheckpoint != pindex->pprev->nAccumulatorCheckpoint) + return state.DoS(100, error("ConnectBlock() : new accumulator checkpoint generated on a block that is not multiple of 10")); + } + } + if (!control.Wait()) return state.DoS(100, false); int64_t nTime2 = GetTimeMicros(); @@ -2642,6 +3487,10 @@ void static UpdateTip(CBlockIndex* pindexNew) { chainActive.SetTip(pindexNew); + // If turned on AutoZeromint will automatically convert BWK to zBWK + if (pwalletMain->isZeromintEnabled ()) + pwalletMain->AutoZeromint (); + // New best block nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); @@ -2726,12 +3575,15 @@ static int64_t nTimePostConnect = 0; * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. */ -bool static ConnectTip(CValidationState& state, CBlockIndex* pindexNew, CBlock* pblock) +bool static ConnectTip(CValidationState& state, CBlockIndex* pindexNew, CBlock* pblock, bool fAlreadyChecked) { assert(pindexNew->pprev == chainActive.Tip()); mempool.check(pcoinsTip); CCoinsViewCache view(pcoinsTip); + if (pblock == NULL) + fAlreadyChecked = false; + // Read block from disk. int64_t nTime1 = GetTimeMicros(); CBlock block; @@ -2747,7 +3599,7 @@ bool static ConnectTip(CValidationState& state, CBlockIndex* pindexNew, CBlock* LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); { CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); - bool rv = ConnectBlock(*pblock, state, pindexNew, view); + bool rv = ConnectBlock(*pblock, state, pindexNew, view, false, fAlreadyChecked); g_signals.BlockChecked(*pblock, state); if (!rv) { if (state.IsInvalid()) @@ -2814,7 +3666,7 @@ bool DisconnectBlocksAndReprocess(int blocks) /* DisconnectBlockAndInputs - Remove conflicting blocks for successful SwiftTX transaction locks + Remove conflicting blocks for successful SwiftX transaction locks This should be very rare (Probably will never happen) */ // ***TODO*** clean up here @@ -2958,9 +3810,11 @@ static void PruneBlockIndexCandidates() * Try to make some progress towards making pindexMostWork the active block. * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. */ -static bool ActivateBestChainStep(CValidationState& state, CBlockIndex* pindexMostWork, CBlock* pblock) +static bool ActivateBestChainStep(CValidationState& state, CBlockIndex* pindexMostWork, CBlock* pblock, bool fAlreadyChecked) { AssertLockHeld(cs_main); + if (pblock == NULL) + fAlreadyChecked = false; bool fInvalidFound = false; const CBlockIndex* pindexOldTip = chainActive.Tip(); const CBlockIndex* pindexFork = chainActive.FindFork(pindexMostWork); @@ -2990,7 +3844,7 @@ static bool ActivateBestChainStep(CValidationState& state, CBlockIndex* pindexMo // Connect new blocks. BOOST_REVERSE_FOREACH (CBlockIndex* pindexConnect, vpindexToConnect) { - if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { + if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL, fAlreadyChecked)) { if (state.IsInvalid()) { // The block violates a consensus rule. if (!state.CorruptionPossible()) @@ -3028,7 +3882,7 @@ static bool ActivateBestChainStep(CValidationState& state, CBlockIndex* pindexMo * or an activated best chain. pblock is either NULL or a pointer to a block * that is already loaded (to avoid loading it again from disk). */ -bool ActivateBestChain(CValidationState& state, CBlock* pblock) +bool ActivateBestChain(CValidationState& state, CBlock* pblock, bool fAlreadyChecked) { CBlockIndex* pindexNewTip = NULL; CBlockIndex* pindexMostWork = NULL; @@ -3049,7 +3903,7 @@ bool ActivateBestChain(CValidationState& state, CBlock* pblock) if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) return true; - if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) + if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL, fAlreadyChecked)) return false; pindexNewTip = chainActive.Tip(); @@ -3353,6 +4207,17 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f return state.DoS(50, error("CheckBlockHeader() : proof of work failed"), REJECT_INVALID, "high-hash"); + // Version 4 header must be used when SPORK_21_ENABLE_ZEROCOIN is activated. And never before. + if (block.GetBlockTime() > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN)) { + if (block.nVersion < Params().Zerocoin_HeaderVersion()) + return state.DoS(50, error("CheckBlockHeader() : block version must be above 4 after SPORK_21"), + REJECT_INVALID, "block-version"); + } else { + if (block.nVersion >= Params().Zerocoin_HeaderVersion()) + return state.DoS(50, error("CheckBlockHeader() : block version must be below 4 before SPORK_21"), + REJECT_INVALID, "block-version"); + } + return true; } @@ -3394,7 +4259,8 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // because we receive the wrong transactions for it. // Size limits - if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + unsigned int nMaxBlockSize = GetAdjustedTime() > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN) ? MAX_BLOCK_SIZE_CURRENT : MAX_BLOCK_SIZE_LEGACY; + if (block.vtx.empty() || block.vtx.size() > nMaxBlockSize || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > nMaxBlockSize) return state.DoS(100, error("CheckBlock() : size limits failed"), REJECT_INVALID, "bad-blk-length"); @@ -3456,11 +4322,17 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo nHeight = (*mi).second->nHeight + 1; } + // Bulwark + // It is entierly possible that we don't have enough data and this could fail + // (i.e. the block could indeed be valid). Store the block for later consideration + // but issue an initial reject message. + // The case also exists that the sending peer could not have enough data to see + // that this block is invalid, so don't issue an outright ban. if (nHeight != 0 && !IsInitialBlockDownload()) { if (!IsBlockPayeeValid(block, nHeight)) { mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); return state.DoS(0, error("CheckBlock() : Couldn't find masternode/budget payment"), - REJECT_INVALID, "bad-cb-payee"); + REJECT_INVALID, "bad-cb-payee"); } } else { if (fDebug) @@ -3471,15 +4343,33 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // ------------------------------------------- // Check transactions - BOOST_FOREACH (const CTransaction& tx, block.vtx) - if (!CheckTransaction(tx, state)) + bool fZerocoinActive = block.nTime > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN); + vector vBlockSerials; + for (const CTransaction& tx : block.vtx) { + if (!CheckTransaction(tx, fZerocoinActive, true, state)) return error("CheckBlock() : CheckTransaction failed"); + // double check that there are no double spent zBWK spends in this block + if (tx.IsZerocoinSpend()) { + for (const CTxIn txIn : tx.vin) { + if (txIn.scriptSig.IsZerocoinSpend()) { + libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txIn); + if (count(vBlockSerials.begin(), vBlockSerials.end(), spend.getCoinSerialNumber())) + return state.DoS(100, error("%s : Double spending of zBWK serial %s in block\n Block: %s", + __func__, spend.getCoinSerialNumber().GetHex(), block.ToString())); + vBlockSerials.emplace_back(spend.getCoinSerialNumber()); + } + } + } + } + + unsigned int nSigOps = 0; BOOST_FOREACH (const CTransaction& tx, block.vtx) { nSigOps += GetLegacySigOpCount(tx); } - if (nSigOps > MAX_BLOCK_SIGOPS) + unsigned int nMaxBlockSigOps = fZerocoinActive ? MAX_BLOCK_SIGOPS_CURRENT : MAX_BLOCK_SIGOPS_LEGACY; + if (nSigOps > nMaxBlockSigOps) return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"), REJECT_INVALID, "bad-blk-sigops", true); @@ -3493,6 +4383,16 @@ bool CheckWork(const CBlock block, CBlockIndex* const pindexPrev) unsigned int nBitsRequired = GetNextWorkRequired(pindexPrev, &block); + if (block.IsProofOfWork() && (pindexPrev->nHeight + 1 <= 68589)) { + double n1 = ConvertBitsToDouble(block.nBits); + double n2 = ConvertBitsToDouble(nBitsRequired); + + if (abs(n1 - n2) > n1 * 0.5) + return error("%s : incorrect proof of work (DGW pre-fork) - %f %f %f at %d", __func__, abs(n1 - n2), n1, n2, pindexPrev->nHeight + 1); + + return true; + } + if (block.nBits != nBitsRequired) return error("%s : incorrect proof of work at %d", __func__, pindexPrev->nHeight + 1); @@ -3522,8 +4422,9 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta int nHeight = pindexPrev->nHeight + 1; - //If this is a reorg, check that it is not too depp - if (chainActive.Height() - nHeight >= Params().MaxReorganizationDepth()) + //If this is a reorg, check that it is not too deep + int nMaxReorgDepth = GetArg("-maxreorg", Params().MaxReorganizationDepth()); + if (chainActive.Height() - nHeight >= nMaxReorgDepth) return state.DoS(1, error("%s: forked chain older than max reorganization depth (height %d)", __func__, nHeight)); // Check timestamp against prev @@ -3544,7 +4445,8 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta return state.DoS(0, error("%s : forked chain older than last checkpoint (height %d)", __func__, nHeight)); // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: - if (block.nVersion < 2 && CBlockIndex::IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority())) { + if (block.nVersion < 2 && + CBlockIndex::IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority())) { return state.Invalid(error("%s : rejected nVersion=1 block", __func__), REJECT_OBSOLETE, "bad-version"); } @@ -3558,6 +4460,26 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta return true; } +bool IsBlockHashInChain(const uint256& hashBlock) +{ + if (hashBlock == 0 || !mapBlockIndex.count(hashBlock)) + return false; + + return chainActive.Contains(mapBlockIndex[hashBlock]); +} + +bool IsTransactionInChain(uint256 txId, int& nHeightTx) +{ + uint256 hashBlock; + CTransaction tx; + GetTransaction(txId, tx, hashBlock, true); + if (!IsBlockHashInChain(hashBlock)) + return false; + + nHeightTx = mapBlockIndex.at(hashBlock)->nHeight; + return true; +} + bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex* const pindexPrev) { const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; @@ -3614,8 +4536,22 @@ bool AcceptBlockHeader(const CBlock& block, CValidationState& state, CBlockIndex if (mi == mapBlockIndex.end()) return state.DoS(0, error("%s : prev block %s not found", __func__, block.hashPrevBlock.ToString().c_str()), 0, "bad-prevblk"); pindexPrev = (*mi).second; - if (pindexPrev->nStatus & BLOCK_FAILED_MASK) - return state.DoS(100, error("%s : prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); + if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { + //If this "invalid" block is an exact match from the checkpoints, then reconsider it + if (pindex && Checkpoints::CheckBlock(pindex->nHeight - 1, block.hashPrevBlock, true)) { + LogPrintf("%s : Reconsidering block %s height %d\n", __func__, pindexPrev->GetBlockHash().GetHex(), pindexPrev->nHeight); + CValidationState statePrev; + ReconsiderBlock(statePrev, pindexPrev); + if (statePrev.IsValid()) { + ActivateBestChain(statePrev); + return true; + } + } + + return state.DoS(100, error("%s : prev block height=%d hash=%s is invalid, unable to add block %s", __func__, pindexPrev->nHeight, block.hashPrevBlock.GetHex(), block.GetHash().GetHex()), + REJECT_INVALID, "bad-prevblk"); + } + } if (!ContextualCheckBlockHeader(block, state, pindexPrev)) @@ -3630,7 +4566,7 @@ bool AcceptBlockHeader(const CBlock& block, CValidationState& state, CBlockIndex return true; } -bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp) +bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp, bool fAlreadyCheckedBlock) { AssertLockHeld(cs_main); @@ -3643,8 +4579,20 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, if (mi == mapBlockIndex.end()) return state.DoS(0, error("%s : prev block %s not found", __func__, block.hashPrevBlock.ToString().c_str()), 0, "bad-prevblk"); pindexPrev = (*mi).second; - if (pindexPrev->nStatus & BLOCK_FAILED_MASK) - return state.DoS(100, error("%s : prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); + if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { + //If this "invalid" block is an exact match from the checkpoints, then reconsider it + if (Checkpoints::CheckBlock(pindexPrev->nHeight, block.hashPrevBlock, true)) { + LogPrintf("%s : Reconsidering block %s height %d\n", __func__, pindexPrev->GetBlockHash().GetHex(), pindexPrev->nHeight); + CValidationState statePrev; + ReconsiderBlock(statePrev, pindexPrev); + if (statePrev.IsValid()) { + ActivateBestChain(statePrev); + return true; + } + } + return state.DoS(100, error("%s : prev block %s is invalid, unable to add block %s", __func__, block.hashPrevBlock.GetHex(), block.GetHash().GetHex()), + REJECT_INVALID, "bad-prevblk"); + } } if (block.GetHash() != Params().HashGenesisBlock() && !CheckWork(block, pindexPrev)) @@ -3659,7 +4607,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, return true; } - if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) { + if ((!fAlreadyCheckedBlock && !CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) { if (state.IsInvalid() && !state.CorruptionPossible()) { pindex->nStatus |= BLOCK_FAILED_VALID; setDirtyBlockIndex.insert(pindex); @@ -3753,8 +4701,26 @@ void CBlockIndex::BuildSkip() bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDiskBlockPos* dbp) { // Preliminary checks + int64_t nStartTime = GetTimeMillis(); bool checked = CheckBlock(*pblock, state); + int nMints = 0; + int nSpends = 0; + for (const CTransaction tx : pblock->vtx) { + if (tx.ContainsZerocoins()) { + for (const CTxIn in : tx.vin) { + if (in.scriptSig.IsZerocoinSpend()) + nSpends++; + } + for (const CTxOut out : tx.vout) { + if (out.IsZerocoinMint()) + nMints++; + } + } + } + if (nMints || nSpends) + LogPrintf("%s : block contains %d zBWK mints and %d zBWK spends\n", __func__, nMints, nSpends); + // ppcoin: check proof-of-stake // Limited duplicity on stake: prevents block flood attack // Duplicate stake allowed only when there is orphan child block @@ -3774,31 +4740,26 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDis } } - while (true) { - TRY_LOCK(cs_main, lockMain); - if (!lockMain) { - MilliSleep(50); - continue; - } + { + LOCK(cs_main); // Replaces the former TRY_LOCK loop because busy waiting wastes too much resources - MarkBlockAsReceived(pblock->GetHash()); + MarkBlockAsReceived (pblock->GetHash ()); if (!checked) { - return error("%s : CheckBlock FAILED", __func__); + return error ("%s : CheckBlock FAILED for block %s", __func__, pblock->GetHash().GetHex()); } // Store to disk CBlockIndex* pindex = NULL; - bool ret = AcceptBlock(*pblock, state, &pindex, dbp); + bool ret = AcceptBlock (*pblock, state, &pindex, dbp, checked); if (pindex && pfrom) { - mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); + mapBlockSource[pindex->GetBlockHash ()] = pfrom->GetId (); } - CheckBlockIndex(); + CheckBlockIndex (); if (!ret) - return error("%s : AcceptBlock FAILED", __func__); - break; + return error ("%s : AcceptBlock FAILED", __func__); } - if (!ActivateBestChain(state, pblock)) + if (!ActivateBestChain(state, pblock, checked)) return error("%s : ActivateBestChain failed", __func__); if (!fLiteMode) { @@ -3814,12 +4775,13 @@ bool ProcessNewBlock(CValidationState& state, CNode* pfrom, CBlock* pblock, CDis if (pwalletMain->isMultiSendEnabled()) pwalletMain->MultiSend(); - //If turned on Auto Combine will scan wallet for dust to combine + // If turned on Auto Combine will scan wallet for dust to combine if (pwalletMain->fCombineDust) pwalletMain->AutoCombineDust(); } - LogPrintf("%s : ACCEPTED\n", __func__); + LogPrintf("%s : ACCEPTED in %ld milliseconds with size=%d\n", __func__, GetTimeMillis() - nStartTime, + pblock->GetSerializeSize(SER_DISK, CLIENT_VERSION)); return true; } @@ -3840,7 +4802,7 @@ bool TestBlockValidity(CValidationState& state, const CBlock& block, CBlockIndex if (!CheckBlock(block, state, fCheckPOW, fCheckMerkleRoot)) return false; if (!ContextualCheckBlock(block, state, pindexPrev)) - return false; + return false; if (!ConnectBlock(block, state, &indexDummy, viewNew, true)) return false; assert(state.IsValid()); @@ -3934,7 +4896,7 @@ CBlockIndex* InsertBlockIndex(uint256 hash) return pindexNew; } -bool static LoadBlockIndexDB() +bool static LoadBlockIndexDB(string& strError) { if (!pblocktree->LoadBlockIndexGuts()) return false; @@ -3944,7 +4906,7 @@ bool static LoadBlockIndexDB() // Calculate nChainWork vector > vSortedByHeight; vSortedByHeight.reserve(mapBlockIndex.size()); - BOOST_FOREACH (const PAIRTYPE(uint256, CBlockIndex*) & item, mapBlockIndex) { + for (const PAIRTYPE(uint256, CBlockIndex*) & item : mapBlockIndex) { CBlockIndex* pindex = item.second; vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); } @@ -3994,7 +4956,7 @@ bool static LoadBlockIndexDB() // Check presence of blk files LogPrintf("Checking all blk files are present...\n"); set setBlkDataFiles; - BOOST_FOREACH (const PAIRTYPE(uint256, CBlockIndex*) & item, mapBlockIndex) { + for (const PAIRTYPE(uint256, CBlockIndex*) & item : mapBlockIndex) { CBlockIndex* pindex = item.second; if (pindex->nStatus & BLOCK_HAVE_DATA) { setBlkDataFiles.insert(pindex->nFile); @@ -4013,83 +4975,69 @@ bool static LoadBlockIndexDB() LogPrintf("%s: Last shutdown was prepared: %s\n", __func__, fLastShutdownWasPrepared); //Check for inconsistency with block file info and internal state - if (!fLastShutdownWasPrepared && !GetBoolArg("-forcestart", false) && !GetBoolArg("-reindex", false) && (vSortedByHeight.size() != vinfoBlockFile[nLastBlockFile].nHeightLast + 1) && (vinfoBlockFile[nLastBlockFile].nHeightLast != 0)) { - //The database is in a state where a block has been accepted and written to disk, but not - //all of the block has perculated through the code. The block and the index should both be - //intact (although assertions are added if they are not), and the block will be reprocessed - //to ensure all data will be accounted for. - LogPrintf("%s: Inconsistent State Detected mapBlockIndex.size()=%d blockFileBlocks=%d\n", __func__, vSortedByHeight.size(), vinfoBlockFile[nLastBlockFile].nHeightLast + 1); - LogPrintf("%s: lastIndexPos=%d blockFileSize=%d\n", __func__, vSortedByHeight[vSortedByHeight.size() - 1].second->GetBlockPos().nPos, - vinfoBlockFile[nLastBlockFile].nSize); - - //try reading the block from the last index we have - bool isFixed = true; - string strError = ""; - LogPrintf("%s: Attempting to re-add last block that was recorded to disk\n", __func__); - - //get the last block that was properly recorded to the block info file - CBlockIndex* pindexLastMeta = vSortedByHeight[vinfoBlockFile[nLastBlockFile].nHeightLast + 1].second; - - //fix Assertion `hashPrevBlock == view.GetBestBlock()' failed. By adjusting height to the last recorded by coinsview - CBlockIndex* pindexCoinsView = mapBlockIndex[pcoinsTip->GetBestBlock()]; - for(unsigned int i = vinfoBlockFile[nLastBlockFile].nHeightLast + 1; i < vSortedByHeight.size(); i++) - { - pindexLastMeta = vSortedByHeight[i].second; - if(pindexLastMeta->nHeight > pindexCoinsView->nHeight) - break; - } - - LogPrintf("%s: Last block properly recorded: #%d %s\n", __func__, pindexLastMeta->nHeight, pindexLastMeta->GetBlockHash().ToString().c_str()); - - CBlock lastMetaBlock; - if (!ReadBlockFromDisk(lastMetaBlock, pindexLastMeta)) { - isFixed = false; - strError = strprintf("failed to read block %d from disk", pindexLastMeta->nHeight); - } + if (!fLastShutdownWasPrepared && !GetBoolArg("-forcestart", false) && !GetBoolArg("-reindex", false)) { + unsigned int nHeightLastBlockFile = vinfoBlockFile[nLastBlockFile].nHeightLast + 1; + if (vSortedByHeight.size() > nHeightLastBlockFile && pcoinsTip->GetBestBlock() != vSortedByHeight[nHeightLastBlockFile].second->GetBlockHash()) { + //The database is in a state where a block has been accepted and written to disk, but the + //transaction database (pcoinsTip) was not flushed to disk, and is therefore not in sync with + //the block index database. + + if (!mapBlockIndex.count(pcoinsTip->GetBestBlock())) { + strError = "The wallet has been not been closed gracefully, causing the transaction database to be out of sync with the block database"; + return false; + } + LogPrintf("%s : pcoinstip synced to block height %d, block index height %d\n", __func__, + mapBlockIndex[pcoinsTip->GetBestBlock()]->nHeight, vSortedByHeight.size()); + + //get the index associated with the point in the chain that pcoinsTip is synced to + CBlockIndex *pindexLastMeta = vSortedByHeight[vinfoBlockFile[nLastBlockFile].nHeightLast + 1].second; + CBlockIndex *pindex = vSortedByHeight[0].second; + unsigned int nSortedPos = 0; + for (unsigned int i = 0; i < vSortedByHeight.size(); i++) { + nSortedPos = i; + if (vSortedByHeight[i].first == mapBlockIndex[pcoinsTip->GetBestBlock()]->nHeight + 1) { + pindex = vSortedByHeight[i].second; + break; + } + } - //set the chain to the block before lastMeta so that the meta block will be seen as new - chainActive.SetTip(pindexLastMeta->pprev); + // Start at the last block that was successfully added to the txdb (pcoinsTip) and manually add all transactions that occurred for each block up until + // the best known block from the block index db. + CCoinsViewCache view(pcoinsTip); + while (nSortedPos < vSortedByHeight.size()) { + CBlock block; + if (!ReadBlockFromDisk(block, pindex)) { + strError = "The wallet has been not been closed gracefully and has caused corruption of blocks stored to disk. Data directory is in an unusable state"; + return false; + } - //Process the lastMetaBlock again, using the known location on disk - CDiskBlockPos blockPos = pindexLastMeta->GetBlockPos(); - CValidationState state; - ProcessNewBlock(state, NULL, &lastMetaBlock, &blockPos); + vector vtxundo; + vtxundo.reserve(block.vtx.size() - 1); + uint256 hashBlock = block.GetHash(); + for (unsigned int i = 0; i < block.vtx.size(); i++) { + CValidationState state; + CTxUndo undoDummy; + if (i > 0) + vtxundo.push_back(CTxUndo()); + UpdateCoins(block.vtx[i], state, view, i == 0 ? undoDummy : vtxundo.back(), pindex->nHeight); + view.SetBestBlock(hashBlock); + } - //ensure that everything is as it should be - if (pcoinsTip->GetBestBlock() != vSortedByHeight[vSortedByHeight.size() - 1].second->GetBlockHash()) { - isFixed = false; - strError = "pcoinsTip best block is not correct"; - } + if(pindex->nHeight >= pindexLastMeta->nHeight) + break; - //properly account for all of the blocks that were not in the meta data. If this is not done the file - //positioning will be wrong and blocks will be overwritten and later cause serialization errors - CBlockIndex *pindexLast = vSortedByHeight[vSortedByHeight.size() - 1].second; - CBlock lastBlock; - if (!ReadBlockFromDisk(lastBlock, pindexLast)) { - isFixed = false; - strError = strprintf("failed to read block %d from disk", pindexLast->nHeight); - } - vinfoBlockFile[nLastBlockFile].nHeightLast = pindexLast->nHeight; - vinfoBlockFile[nLastBlockFile].nSize = pindexLast->GetBlockPos().nPos + ::GetSerializeSize(lastBlock, SER_DISK, CLIENT_VERSION);; - setDirtyFileInfo.insert(nLastBlockFile); - FlushStateToDisk(state, FLUSH_STATE_ALWAYS); + pindex = vSortedByHeight[++nSortedPos].second; + } - //Print out file info again - pblocktree->ReadLastBlockFile(nLastBlockFile); - vinfoBlockFile.resize(nLastBlockFile + 1); - LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile); - for (int nFile = 0; nFile <= nLastBlockFile; nFile++) { - pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]); - } - LogPrintf("%s: last block file info: %s\n", __func__, vinfoBlockFile[nLastBlockFile].ToString()); + // Save the updates to disk + if (!view.Flush() || !pcoinsTip->Flush()) + LogPrintf("%s : failed to flush view\n", __func__); - if (!isFixed) { - strError = "Failed reading from database. " + strError + ". The block database is in an inconsistent state and may cause issues in the future." - "To force start use -forcestart"; - uiInterface.ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR); - abort(); + LogPrintf("%s: Last block properly recorded: #%d %s\n", __func__, pindexLastMeta->nHeight, + pindexLastMeta->GetBlockHash().ToString().c_str()); + LogPrintf("%s : pcoinstip=%d %s\n", __func__, mapBlockIndex[pcoinsTip->GetBestBlock()]->nHeight, + pcoinsTip->GetBestBlock().GetHex()); } - LogPrintf("Passed corruption fix\n"); } // Check whether we need to continue reindexing @@ -4197,7 +5145,7 @@ bool CVerifyDB::VerifyDB(CCoinsView* coinsview, int nCheckLevel, int nCheckDepth CBlock block; if (!ReadBlockFromDisk(block, pindex)) return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - if (!ConnectBlock(block, state, pindex, coins)) + if (!ConnectBlock(block, state, pindex, coins, false)) return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } } @@ -4215,10 +5163,10 @@ void UnloadBlockIndex() pindexBestInvalid = NULL; } -bool LoadBlockIndex() +bool LoadBlockIndex(string& strError) { // Load block index from databases - if (!fReindex && !LoadBlockIndexDB()) + if (!fReindex && !LoadBlockIndexDB(strError)) return false; return true; } @@ -4273,7 +5221,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp) int nLoaded = 0; try { // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor - CBufferedFile blkdat(fileIn, 2 * MAX_BLOCK_SIZE, MAX_BLOCK_SIZE + 8, SER_DISK, CLIENT_VERSION); + CBufferedFile blkdat(fileIn, 2 * MAX_BLOCK_SIZE_CURRENT, MAX_BLOCK_SIZE_CURRENT + 8, SER_DISK, CLIENT_VERSION); uint64_t nRewind = blkdat.GetPos(); while (!blkdat.eof()) { boost::this_thread::interruption_point(); @@ -4292,7 +5240,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp) continue; // read size blkdat >> nSize; - if (nSize < 80 || nSize > MAX_BLOCK_SIZE) + if (nSize < 80 || nSize > MAX_BLOCK_SIZE_CURRENT) continue; } catch (const std::exception&) { // no valid block header found; don't complain @@ -4519,7 +5467,7 @@ string GetWarnings(string strFor) string strRPC; if (!CLIENT_VERSION_IS_RELEASE) - strStatusBar = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"); + strStatusBar = _("This is a pre-release test build - use at your own risk - do not use for staking or merchant applications!"); if (GetBoolArg("-testsafemode", false)) strStatusBar = strRPC = "testsafemode enabled"; @@ -4664,7 +5612,8 @@ void static ProcessGetData(CNode* pfrom) } } } - if (send) { + // Don't send not-validated blocks + if (send && (mi->second->nStatus & BLOCK_HAVE_DATA)) { // Send block from disk CBlock block; if (!ReadBlockFromDisk(block, (*mi).second)) @@ -4860,6 +5809,7 @@ void static ProcessGetData(CNode* pfrom) } } +bool fRequestedSporksIDB = false; bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) { RandAddSeedPerfmon(); @@ -4878,13 +5828,27 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return false; } + // Bulwark: We use certain sporks during IBD, so check to see if they are + // available. If not, ask the first peer connected for them. + if (!pSporkDB->SporkExists(SPORK_14_NEW_PROTOCOL_ENFORCEMENT) && + !pSporkDB->SporkExists(SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) && + !pSporkDB->SporkExists(SPORK_22_ZEROCOIN_MAINTENANCE_MODE) && + !pSporkDB->SporkExists(SPORK_17_NEW_PROTOCOL_ENFORCEMENT_3) && + !pSporkDB->SporkExists(SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4) && + !pSporkDB->SporkExists(SPORK_20_NEW_PROTOCOL_DYNAMIC) && + !pSporkDB->SporkExists(SPORK_21_ENABLE_ZEROCOIN)) { + LogPrintf("Required sporks not found, asking peer to send them\n"); + pfrom->PushMessage("getsporks"); + fRequestedSporksIDB = true; + } + int64_t nTime; CAddress addrMe; CAddress addrFrom; uint64_t nNonce = 1; vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe; - if (pfrom->DisconnectOldProtocol(ActiveProtocol(), strCommand)) - return false; + if (pfrom->DisconnectOldProtocol(ActiveProtocol(), strCommand)) + return false; if (pfrom->nVersion == 10300) pfrom->nVersion = 300; @@ -5134,7 +6098,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (pindex) pindex = chainActive.Next(pindex); int nLimit = 500; - LogPrintf("getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop == uint256(0) ? "end" : hashStop.ToString(), nLimit, pfrom->id); + LogPrint("net", "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop == uint256(0) ? "end" : hashStop.ToString(), nLimit, pfrom->id); for (; pindex; pindex = chainActive.Next(pindex)) { if (pindex->GetBlockHash() == hashStop) { LogPrint("net", " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); @@ -5247,11 +6211,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LOCK(cs_main); bool fMissingInputs = false; + bool fMissingZerocoinInputs = false; CValidationState state; mapAlreadyAskedFor.erase(inv); - if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, false, ignoreFees)) { + if (!tx.IsZerocoinSpend() && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs, false, ignoreFees)) { mempool.check(pcoinsTip); RelayTransaction(tx); vWorkQueue.push_back(inv.hash); @@ -5263,15 +6228,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Recursively process any orphan transactions that depended on this one set setMisbehaving; - for (unsigned int i = 0; i < vWorkQueue.size(); i++) { + for(unsigned int i = 0; i < vWorkQueue.size(); i++) { map >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); - if (itByPrev == mapOrphanTransactionsByPrev.end()) + if(itByPrev == mapOrphanTransactionsByPrev.end()) continue; - for (set::iterator mi = itByPrev->second.begin(); - mi != itByPrev->second.end(); - ++mi) { - const uint256& orphanHash = *mi; - const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx; + for(set::iterator mi = itByPrev->second.begin(); + mi != itByPrev->second.end(); + ++mi) { + const uint256 &orphanHash = *mi; + const CTransaction &orphanTx = mapOrphanTransactions[orphanHash].tx; NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer; bool fMissingInputs2 = false; // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan @@ -5280,16 +6245,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CValidationState stateDummy; - if (setMisbehaving.count(fromPeer)) + if(setMisbehaving.count(fromPeer)) continue; - if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) { + if(AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) { LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); RelayTransaction(orphanTx); vWorkQueue.push_back(orphanHash); vEraseQueue.push_back(orphanHash); - } else if (!fMissingInputs2) { + } else if(!fMissingInputs2) { int nDos = 0; - if (stateDummy.IsInvalid(nDos) && nDos > 0) { + if(stateDummy.IsInvalid(nDos) && nDos > 0) { // Punish peer that gave us an invalid orphan tx Misbehaving(fromPeer, nDos); setMisbehaving.insert(fromPeer); @@ -5304,8 +6269,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } - BOOST_FOREACH (uint256 hash, vEraseQueue) - EraseOrphanTx(hash); + BOOST_FOREACH (uint256 hash, vEraseQueue)EraseOrphanTx(hash); + } else if (tx.IsZerocoinSpend() && 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); + LogPrint("mempool", "AcceptToMemoryPool: Zerocoinspend peer=%d %s : accepted %s (poolsz %u)\n", + pfrom->id, pfrom->cleanSubVer, + tx.GetHash().ToString(), + mempool.mapTx.size()); } else if (fMissingInputs) { AddOrphanTx(tx, pfrom->GetId()); @@ -5421,16 +6393,22 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->AddInventoryKnown(inv); CValidationState state; - ProcessNewBlock(state, pfrom, &block); - int nDoS; - if (state.IsInvalid(nDoS)) { - pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), - state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); - if (nDoS > 0) { - TRY_LOCK(cs_main, lockMain); - if (lockMain) Misbehaving(pfrom->GetId(), nDoS); + if (!mapBlockIndex.count(block.GetHash())) { + ProcessNewBlock(state, pfrom, &block); + int nDoS; + if(state.IsInvalid(nDoS)) { + pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), + state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); + if(nDoS > 0) { + TRY_LOCK(cs_main, lockMain); + if(lockMain) Misbehaving(pfrom->GetId(), nDoS); + } } - pfrom->DisconnectOldProtocol(ActiveProtocol(), strCommand); + + //disconnect this node if its old protocol version + pfrom->DisconnectOldProtocol(ActiveProtocol(), strCommand); + } else { + LogPrint("net", "%s : Already processed block %s, skipping ProcessNewBlock()\n", __func__, block.GetHash().GetHex()); } } @@ -5667,8 +6645,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Note: whenever a protocol update is needed toggle between both implementations (comment out the formerly active one) // so we can leave the existing clients untouched (old SPORK will stay on so they don't see even older clients). // Those old clients won't react to the changes of the other (new) SPORK because at the time of their implementation -// - +// it was the one which was commented out int ActiveProtocol() { if (IsSporkActive(SPORK_20_NEW_PROTOCOL_DYNAMIC)) diff --git a/src/main.h b/src/main.h index 393366c0a..768307bae 100644 --- a/src/main.h +++ b/src/main.h @@ -21,6 +21,7 @@ #include "pow.h" #include "primitives/block.h" #include "primitives/transaction.h" +#include "primitives/zerocoin.h" #include "script/script.h" #include "script/sigcache.h" #include "script/standard.h" @@ -39,10 +40,14 @@ #include #include +#include "libzerocoin/CoinSpend.h" + #include class CBlockIndex; class CBlockTreeDB; +class CZerocoinDB; +class CSporkDB; class CBloomFilter; class CInv; class CScriptCheck; @@ -61,12 +66,15 @@ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000; static const bool DEFAULT_ALERTS = true; /** The maximum size for transactions we're willing to relay/mine */ static const unsigned int MAX_STANDARD_TX_SIZE = 100000; +static const unsigned int MAX_ZEROCOIN_TX_SIZE = 150000; /** The maximum allowed number of signature check operations in a block (network rule) */ -static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE / 50; +static const unsigned int MAX_BLOCK_SIGOPS_CURRENT = MAX_BLOCK_SIZE_CURRENT / 50; +static const unsigned int MAX_BLOCK_SIGOPS_LEGACY = MAX_BLOCK_SIZE_LEGACY / 50; /** Maximum number of signature check operations in an IsStandard() P2SH script */ static const unsigned int MAX_P2SH_SIGOPS = 15; /** The maximum number of sigops we're willing to relay/mine in a single tx */ -static const unsigned int MAX_TX_SIGOPS = MAX_BLOCK_SIGOPS / 5; +static const unsigned int MAX_TX_SIGOPS_CURRENT = MAX_BLOCK_SIGOPS_CURRENT / 5; +static const unsigned int MAX_TX_SIGOPS_LEGACY = MAX_BLOCK_SIGOPS_LEGACY / 5; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; /** The maximum size of a blk?????.dat file (since 0.8) */ @@ -136,6 +144,7 @@ extern bool fCheckBlockIndex; extern unsigned int nCoinCacheSize; extern CFeeRate minRelayTxFee; extern bool fAlerts; +extern bool fVerifyingBlocks; extern bool fLargeWorkForkFound; extern bool fLargeWorkInvalidChainFound; @@ -147,6 +156,7 @@ extern int64_t nReserveBalance; extern std::map mapRejectedBlocks; extern std::map mapHashedBlocks; +extern std::map mapInvalidSerials; extern std::set > setStakeSeen; /** Best header we've seen so far (used for getheaders queries' starting points). */ @@ -194,7 +204,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos* dbp = NULL); /** Initialize a new block tree database + block data on disk */ bool InitBlockIndex(); /** Load the block tree and coins database from disk */ -bool LoadBlockIndex(); +bool LoadBlockIndex(std::string& strError); /** Unload database information */ void UnloadBlockIndex(); /** See whether the protocol update is enforced for connected nodes */ @@ -230,7 +240,7 @@ double ConvertBitsToDouble(unsigned int nBits); int64_t GetMasternodePayment(int nHeight, int64_t blockValue, int nMasternodeCount = 0); unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader* pblock, bool fProofOfStake); -bool ActivateBestChain(CValidationState& state, CBlock* pblock = NULL); +bool ActivateBestChain(CValidationState& state, CBlock* pblock = NULL, bool fAlreadyChecked = false); CAmount GetBlockValue(int nHeight); /** Create a new block index entry for a given block hash */ @@ -341,7 +351,28 @@ bool CheckInputs(const CTransaction& tx, CValidationState& state, const CCoinsVi void UpdateCoins(const CTransaction& tx, CValidationState& state, CCoinsViewCache& inputs, CTxUndo& txundo, int nHeight); /** Context-independent validity checks */ -bool CheckTransaction(const CTransaction& tx, CValidationState& state); +bool CheckTransaction(const CTransaction& tx, bool fZerocoinActive, bool fRejectBadUTXO, CValidationState& state); +bool CheckZerocoinMint(const uint256& txHash, const CTxOut& txout, CValidationState& state, bool fCheckOnly = false); +bool CheckZerocoinSpend(const CTransaction tx, bool fVerifySignature, CValidationState& state); +libzerocoin::CoinSpend TxInToZerocoinSpend(const CTxIn& txin); +bool TxOutToPublicCoin(const CTxOut txout, libzerocoin::PublicCoin& pubCoin, CValidationState& state); +bool BlockToPubcoinList(const CBlock& block, list& listPubcoins); +bool BlockToZerocoinMintList(const CBlock& block, std::list& vMints); +bool BlockToMintValueVector(const CBlock& block, const libzerocoin::CoinDenomination denom, std::vector& vValues); +std::list ZerocoinSpendListFromBlock(const CBlock& block); +void FindMints(vector vMintsToFind, vector& vMintsToUpdate, vector& vMissingMints, bool fExtendedSearch); +bool GetZerocoinMint(const CBigNum& bnPubcoin, uint256& txHash); +bool IsSerialKnown(const CBigNum& bnSerial); +bool IsSerialInBlockchain(const CBigNum& bnSerial, int& nHeightTx); +bool RemoveSerialFromDB(const CBigNum& bnSerial); +int GetZerocoinStartHeight(); +bool IsTransactionInChain(uint256 txId, int& nHeightTx); +bool IsBlockHashInChain(const uint256& hashBlock); +void RecalculateZBWKSpent(); +void RecalculateZBWKMinted(); +bool RecalculateBWKSupply(int nHeightStart); +bool ReindexAccumulators(list& listMissingCheckpoints, string& strError); + /** * Check if transaction will be final in the next block to be created. @@ -431,7 +462,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex bool DisconnectBlocksAndReprocess(int blocks); /** Apply the effects of this block (with given index) on the UTXO set represented by coins */ -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck, bool fAlreadyChecked = false); /** Context-independent validity checks */ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); @@ -446,7 +477,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn bool TestBlockValidity(CValidationState& state, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); /** Store block on disk. If dbp is provided, the file is known to already reside on disk */ -bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** pindex, CDiskBlockPos* dbp = NULL); +bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** pindex, CDiskBlockPos* dbp = NULL, bool fAlreadyCheckedBlock = false); bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex** ppindex = NULL); @@ -608,6 +639,12 @@ extern CCoinsViewCache* pcoinsTip; /** Global variable that points to the active block tree (protected by cs_main) */ extern CBlockTreeDB* pblocktree; +/** Global variable that points to the zerocoin database (protected by cs_main) */ +extern CZerocoinDB* zerocoinDB; + +/** Global variable that points to the spork database (protected by cs_main) */ +extern CSporkDB* pSporkDB; + struct CBlockTemplate { CBlock block; std::vector vTxFees; diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index 36039ffce..6fd482449 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -41,7 +41,7 @@ bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, s uint256 nBlockHash; if (!GetTransaction(nTxCollateralHash, txCollateral, nBlockHash, true)) { strError = strprintf("Can't find collateral tx %s", txCollateral.ToString()); - LogPrintf("CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); + LogPrint("masternode","CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); return false; } @@ -55,14 +55,14 @@ bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, s BOOST_FOREACH (const CTxOut o, txCollateral.vout) { if (!o.scriptPubKey.IsNormalPaymentScript() && !o.scriptPubKey.IsUnspendable()) { strError = strprintf("Invalid Script %s", txCollateral.ToString()); - LogPrintf("CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); + LogPrint("masternode","CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); return false; } if (o.scriptPubKey == findScript && o.nValue >= PROPOSAL_FEE_TX) foundOpReturn = true; } if (!foundOpReturn) { strError = strprintf("Couldn't find opReturn %s in %s", nExpectedHash.ToString(), txCollateral.ToString()); - LogPrintf("CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); + LogPrint("masternode","CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); return false; } @@ -87,11 +87,11 @@ bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, s nConf = conf; //if we're syncing we won't have swiftTX information, so accept 1 confirmation - if (conf >= BUDGET_FEE_CONFIRMATIONS) { + if (conf >= Params().Budget_Fee_Confirmations()) { return true; } else { - strError = strprintf("Collateral requires at least %d confirmations - %d confirmations", BUDGET_FEE_CONFIRMATIONS, conf); - LogPrintf("CBudgetProposalBroadcast::IsBudgetCollateralValid - %s - %d confirmations\n", strError, conf); + strError = strprintf("Collateral requires at least %d confirmations - %d confirmations", Params().Budget_Fee_Confirmations(), conf); + LogPrint("masternode","CBudgetProposalBroadcast::IsBudgetCollateralValid - %s - %d confirmations\n", strError, conf); return false; } } @@ -105,7 +105,7 @@ void CBudgetManager::CheckOrphanVotes() std::map::iterator it1 = mapOrphanMasternodeBudgetVotes.begin(); while (it1 != mapOrphanMasternodeBudgetVotes.end()) { if (budget.UpdateProposal(((*it1).second), NULL, strError)) { - LogPrintf("CBudgetManager::CheckOrphanVotes - Proposal/Budget is known, activating and removing orphan vote\n"); + LogPrint("masternode","CBudgetManager::CheckOrphanVotes - Proposal/Budget is known, activating and removing orphan vote\n"); mapOrphanMasternodeBudgetVotes.erase(it1++); } else { ++it1; @@ -114,12 +114,13 @@ void CBudgetManager::CheckOrphanVotes() std::map::iterator it2 = mapOrphanFinalizedBudgetVotes.begin(); while (it2 != mapOrphanFinalizedBudgetVotes.end()) { if (budget.UpdateFinalizedBudget(((*it2).second), NULL, strError)) { - LogPrintf("CBudgetManager::CheckOrphanVotes - Proposal/Budget is known, activating and removing orphan vote\n"); + LogPrint("masternode","CBudgetManager::CheckOrphanVotes - Proposal/Budget is known, activating and removing orphan vote\n"); mapOrphanFinalizedBudgetVotes.erase(it2++); } else { ++it2; } } + LogPrint("masternode","CBudgetManager::CheckOrphanVotes - Done\n"); } void CBudgetManager::SubmitFinalBudget() @@ -135,9 +136,20 @@ void CBudgetManager::SubmitFinalBudget() } int nBlockStart = nCurrentHeight - nCurrentHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); - if (nSubmittedHeight >= nBlockStart) return; - //submit final budget 2 days before payment for Mainnet, about 9 minutes for Testnet - if (nBlockStart - nCurrentHeight > ((GetBudgetPaymentCycleBlocks() / 30) * 2)) return; + if (nSubmittedHeight >= nBlockStart){ + LogPrint("masternode","CBudgetManager::SubmitFinalBudget - nSubmittedHeight(=%ld) < nBlockStart(=%ld) condition not fulfilled.\n", nSubmittedHeight, nBlockStart); + return; + } + // Submit final budget during the last 2 days before payment for Mainnet, about 9 minutes for Testnet + int nFinalizationStart = nBlockStart - ((GetBudgetPaymentCycleBlocks() / 30) * 2); + int nOffsetToStart = nFinalizationStart - nCurrentHeight; + + if (nBlockStart - nCurrentHeight > ((GetBudgetPaymentCycleBlocks() / 30) * 2)){ + LogPrint("masternode","CBudgetManager::SubmitFinalBudget - Too early for finalization. Current block is %ld, next Superblock is %ld.\n", nCurrentHeight, nBlockStart); + LogPrint("masternode","CBudgetManager::SubmitFinalBudget - First possible block for finalization: %ld. Last possible block for finalization: %ld. You have to wait for %ld block(s) until Budget finalization will be possible\n", nFinalizationStart, nBlockStart, nOffsetToStart); + + return; + } std::vector vBudgetProposals = budget.GetBudget(); std::string strBudgetName = "main"; @@ -152,13 +164,13 @@ void CBudgetManager::SubmitFinalBudget() } if (vecTxBudgetPayments.size() < 1) { - LogPrintf("CBudgetManager::SubmitFinalBudget - Found No Proposals For Period\n"); + LogPrint("masternode","CBudgetManager::SubmitFinalBudget - Found No Proposals For Period\n"); return; } CFinalizedBudgetBroadcast tempBudget(strBudgetName, nBlockStart, vecTxBudgetPayments, 0); if (mapSeenFinalizedBudgets.count(tempBudget.GetHash())) { - LogPrintf("CBudgetManager::SubmitFinalBudget - Budget already exists - %s\n", tempBudget.GetHash().ToString()); + LogPrint("masternode","CBudgetManager::SubmitFinalBudget - Budget already exists - %s\n", tempBudget.GetHash().ToString()); nSubmittedHeight = nCurrentHeight; return; //already exists } @@ -170,14 +182,14 @@ void CBudgetManager::SubmitFinalBudget() if (!mapCollateralTxids.count(tempBudget.GetHash())) { CWalletTx wtx; if (!pwalletMain->GetBudgetSystemCollateralTX(wtx, tempBudget.GetHash(), false)) { - LogPrintf("CBudgetManager::SubmitFinalBudget - Can't make collateral transaction\n"); + LogPrint("masternode","CBudgetManager::SubmitFinalBudget - Can't make collateral transaction\n"); return; } - // make our change address + // Get our change address CReserveKey reservekey(pwalletMain); - //send the tx to the network - pwalletMain->CommitTransaction(wtx, reservekey, "ix"); + // Send the tx to the network. Do NOT use SwiftTx, locking might need too much time to propagate, especially for testnet + pwalletMain->CommitTransaction(wtx, reservekey, "NO-ix"); tx = (CTransaction)wtx; txidCollateral = tx.GetHash(); mapCollateralTxids.insert(make_pair(tempBudget.GetHash(), txidCollateral)); @@ -190,7 +202,7 @@ void CBudgetManager::SubmitFinalBudget() uint256 nBlockHash; if (!GetTransaction(txidCollateral, txCollateral, nBlockHash, true)) { - LogPrintf("CBudgetManager::SubmitFinalBudget - Can't find collateral tx %s", txidCollateral.ToString()); + LogPrint("masternode","CBudgetManager::SubmitFinalBudget - Can't find collateral tx %s", txidCollateral.ToString()); return; } @@ -208,8 +220,8 @@ void CBudgetManager::SubmitFinalBudget() Wait will we have 1 extra confirmation, otherwise some clients might reject this feeTX -- This function is tied to NewBlock, so we will propagate this budget while the block is also propagating */ - if (conf < BUDGET_FEE_CONFIRMATIONS + 1) { - LogPrintf("CBudgetManager::SubmitFinalBudget - Collateral requires at least %d confirmations - %s - %d confirmations\n", BUDGET_FEE_CONFIRMATIONS + 1, txidCollateral.ToString(), conf); + if (conf < Params().Budget_Fee_Confirmations() + 1) { + LogPrint("masternode","CBudgetManager::SubmitFinalBudget - Collateral requires at least %d confirmations - %s - %d confirmations\n", Params().Budget_Fee_Confirmations() + 1, txidCollateral.ToString(), conf); return; } @@ -218,7 +230,7 @@ void CBudgetManager::SubmitFinalBudget() std::string strError = ""; if (!finalizedBudgetBroadcast.IsValid(strError)) { - LogPrintf("CBudgetManager::SubmitFinalBudget - Invalid finalized budget - %s \n", strError); + LogPrint("masternode","CBudgetManager::SubmitFinalBudget - Invalid finalized budget - %s \n", strError); return; } @@ -227,7 +239,7 @@ void CBudgetManager::SubmitFinalBudget() finalizedBudgetBroadcast.Relay(); budget.AddFinalizedBudget(finalizedBudgetBroadcast); nSubmittedHeight = nCurrentHeight; - LogPrintf("CBudgetManager::SubmitFinalBudget - Done! %s\n", finalizedBudgetBroadcast.GetHash().ToString()); + LogPrint("masternode","CBudgetManager::SubmitFinalBudget - Done! %s\n", finalizedBudgetBroadcast.GetHash().ToString()); } // @@ -268,7 +280,7 @@ bool CBudgetDB::Write(const CBudgetManager& objToSave) } fileout.fclose(); - LogPrintf("Written info to budget.dat %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode","Written info to budget.dat %dms\n", GetTimeMillis() - nStart); return true; } @@ -346,13 +358,13 @@ CBudgetDB::ReadResult CBudgetDB::Read(CBudgetManager& objToLoad, bool fDryRun) return IncorrectFormat; } - LogPrintf("Loaded info from budget.dat %dms\n", GetTimeMillis() - nStart); - LogPrintf(" %s\n", objToLoad.ToString()); + LogPrint("masternode","Loaded info from budget.dat %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode"," %s\n", objToLoad.ToString()); if (!fDryRun) { - LogPrintf("Budget manager - cleaning....\n"); + LogPrint("masternode","Budget manager - cleaning....\n"); objToLoad.CheckAndRemove(); - LogPrintf("Budget manager - result:\n"); - LogPrintf(" %s\n", objToLoad.ToString()); + LogPrint("masternode","Budget manager - result:\n"); + LogPrint("masternode"," %s\n", objToLoad.ToString()); } return Ok; @@ -365,24 +377,24 @@ void DumpBudgets() CBudgetDB budgetdb; CBudgetManager tempBudget; - LogPrintf("Verifying budget.dat format...\n"); + LogPrint("masternode","Verifying budget.dat format...\n"); CBudgetDB::ReadResult readResult = budgetdb.Read(tempBudget, true); // there was an error and it was not an error on file opening => do not proceed if (readResult == CBudgetDB::FileError) - LogPrintf("Missing budgets file - budget.dat, will try to recreate\n"); + LogPrint("masternode","Missing budgets file - budget.dat, will try to recreate\n"); else if (readResult != CBudgetDB::Ok) { - LogPrintf("Error reading budget.dat: "); + LogPrint("masternode","Error reading budget.dat: "); if (readResult == CBudgetDB::IncorrectFormat) - LogPrintf("magic is ok but data has invalid format, will try to recreate\n"); + LogPrint("masternode","magic is ok but data has invalid format, will try to recreate\n"); else { - LogPrintf("file format is unknown or invalid, please fix it manually\n"); + LogPrint("masternode","file format is unknown or invalid, please fix it manually\n"); return; } } - LogPrintf("Writting info to budget.dat...\n"); + LogPrint("masternode","Writting info to budget.dat...\n"); budgetdb.Write(budget); - LogPrintf("Budget dump finished %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode","Budget dump finished %dms\n", GetTimeMillis() - nStart); } bool CBudgetManager::AddFinalizedBudget(CFinalizedBudget& finalizedBudget) @@ -403,7 +415,7 @@ bool CBudgetManager::AddProposal(CBudgetProposal& budgetProposal) LOCK(cs); std::string strError = ""; if (!budgetProposal.IsValid(strError)) { - LogPrintf("CBudgetManager::AddProposal - invalid budget proposal - %s\n", strError); + LogPrint("masternode","CBudgetManager::AddProposal - invalid budget proposal - %s\n", strError); return false; } @@ -412,6 +424,7 @@ bool CBudgetManager::AddProposal(CBudgetProposal& budgetProposal) } mapProposals.insert(make_pair(budgetProposal.GetHash(), budgetProposal)); + LogPrint("masternode","CBudgetManager::AddProposal - proposal %s added\n", budgetProposal.GetName ().c_str ()); return true; } @@ -419,35 +432,60 @@ void CBudgetManager::CheckAndRemove() { LogPrint("mnbudget", "CBudgetManager::CheckAndRemove\n"); + // map tmpMapFinalizedBudgets; + // map tmpMapProposals; + std::string strError = ""; - LogPrint("mnbudget", "CBudgetManager::CheckAndRemove - mapFinalizedBudgets cleanup - size: %d\n", mapFinalizedBudgets.size()); + LogPrint("mnbudget", "CBudgetManager::CheckAndRemove - mapFinalizedBudgets cleanup - size before: %d\n", mapFinalizedBudgets.size()); std::map::iterator it = mapFinalizedBudgets.begin(); while (it != mapFinalizedBudgets.end()) { CFinalizedBudget* pfinalizedBudget = &((*it).second); pfinalizedBudget->fValid = pfinalizedBudget->IsValid(strError); - LogPrintf("CBudgetManager::CheckAndRemove - pfinalizedBudget->IsValid - strError: %s\n", strError); + if (!strError.empty ()) { + LogPrint("masternode","CBudgetManager::CheckAndRemove - Invalid finalized budget: %s\n", strError); + } + else { + LogPrint("masternode","CBudgetManager::CheckAndRemove - Found valid finalized budget: %s %s\n", + pfinalizedBudget->strBudgetName.c_str(), pfinalizedBudget->nFeeTXHash.ToString().c_str()); + } + if (pfinalizedBudget->fValid) { pfinalizedBudget->AutoCheck(); + // tmpMapFinalizedBudgets.insert(make_pair(pfinalizedBudget->GetHash(), *pfinalizedBudget)); } ++it; } - LogPrint("mnbudget", "CBudgetManager::CheckAndRemove - mapProposals cleanup - size: %d\n", mapProposals.size()); + LogPrint("mnbudget", "CBudgetManager::CheckAndRemove - mapProposals cleanup - size before: %d\n", mapProposals.size()); std::map::iterator it2 = mapProposals.begin(); while (it2 != mapProposals.end()) { CBudgetProposal* pbudgetProposal = &((*it2).second); pbudgetProposal->fValid = pbudgetProposal->IsValid(strError); if (!strError.empty ()) { - LogPrintf("CBudgetManager::CheckAndRemove - invalid budget proposal - %s\n", strError); + LogPrint("masternode","CBudgetManager::CheckAndRemove - Invalid budget proposal - %s\n", strError); strError = ""; } + else { + LogPrint("masternode","CBudgetManager::CheckAndRemove - Found valid budget proposal: %s %s\n", + pbudgetProposal->strProposalName.c_str(), pbudgetProposal->nFeeTXHash.ToString().c_str()); + } + if (pbudgetProposal->fValid) { + // tmpMapProposals.insert(make_pair(pbudgetProposal->GetHash(), *pbudgetProposal)); + } + ++it2; } + // Remove invalid entries by overwriting complete map + // mapFinalizedBudgets = tmpMapFinalizedBudgets; + // mapProposals = tmpMapProposals; + + // LogPrint("mnbudget", "CBudgetManager::CheckAndRemove - mapFinalizedBudgets cleanup - size after: %d\n", mapFinalizedBudgets.size()); + // LogPrint("mnbudget", "CBudgetManager::CheckAndRemove - mapProposals cleanup - size after: %d\n", mapProposals.size()); + LogPrint("masternode","CBudgetManager::CheckAndRemove - PASSED\n"); - LogPrintf("CBudgetManager::CheckAndRemove - PASSED\n"); } void CBudgetManager::FillBlockPayee(CMutableTransaction& txNew, CAmount nFees, bool fProofOfStake) @@ -488,6 +526,10 @@ void CBudgetManager::FillBlockPayee(CMutableTransaction& txNew, CAmount nFees, b CTxDestination address1; ExtractDestination(payee, address1); CBitcoinAddress address2(address1); + LogPrint("masternode","CBudgetManager::FillBlockPayee - Budget payment to %s for %lld, nHighestCount = %d\n", address2.ToString(), nAmount, nHighestCount); + } + else { + LogPrint("masternode","CBudgetManager::FillBlockPayee - No Budget payment, nHighestCount = %d\n", nHighestCount); } } else { //miners get the full amount on these blocks @@ -504,7 +546,7 @@ void CBudgetManager::FillBlockPayee(CMutableTransaction& txNew, CAmount nFees, b ExtractDestination(payee, address1); CBitcoinAddress address2(address1); - LogPrintf("CBudgetManager::FillBlockPayee - Budget payment to %s for %lld\n", address2.ToString(), nAmount); + LogPrint("masternode","CBudgetManager::FillBlockPayee - Budget payment to %s for %lld\n", address2.ToString(), nAmount); } } } @@ -551,6 +593,7 @@ CBudgetProposal* CBudgetManager::FindProposal(uint256 nHash) bool CBudgetManager::IsBudgetPaymentBlock(int nBlockHeight) { int nHighestCount = -1; + int nFivePercent = mnodeman.CountEnabled(ActiveProtocol()) / 20; std::map::iterator it = mapFinalizedBudgets.begin(); while (it != mapFinalizedBudgets.end()) { @@ -568,6 +611,8 @@ bool CBudgetManager::IsBudgetPaymentBlock(int nBlockHeight) If budget doesn't have 5% of the network votes, then we should pay a masternode instead */ if (nHighestCount > mnodeman.CountEnabled(ActiveProtocol()) / 20) return true; + LogPrintf("CBudgetManager::IsBudgetPaymentBlock() - nHighestCount: %lli, 5%% of Masternodes: %lli. Number of budgets: %lli\n", + nHighestCount, nFivePercent, mapFinalizedBudgets.size()); return false; } @@ -594,6 +639,7 @@ bool CBudgetManager::IsTransactionValid(const CTransaction& txNew, int nBlockHei LOCK(cs); int nHighestCount = 0; + int nFivePercent = mnodeman.CountEnabled(ActiveProtocol()) / 20; std::vector ret; // ------- Grab The Highest Count @@ -610,6 +656,8 @@ bool CBudgetManager::IsTransactionValid(const CTransaction& txNew, int nBlockHei ++it; } + LogPrint("masternode","CBudgetManager::IsTransactionValid() - nHighestCount: %lli, 5%% of Masternodes: %lli mapFinalizedBudgets.size(): %ld\n", + nHighestCount, nFivePercent, mapFinalizedBudgets.size()); /* If budget doesn't have 5% of the network votes, then we should pay a masternode instead */ @@ -702,19 +750,34 @@ std::vector CBudgetManager::GetBudget() while (it2 != vBudgetPorposalsSort.end()) { CBudgetProposal* pbudgetProposal = (*it2).first; + LogPrint("masternode","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()) { + + LogPrint("masternode","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, + pbudgetProposal->IsEstablished()); + if (pbudgetProposal->GetAmount() + nBudgetAllocated <= nTotalBudget) { pbudgetProposal->SetAllotted(pbudgetProposal->GetAmount()); nBudgetAllocated += pbudgetProposal->GetAmount(); vBudgetProposalsRet.push_back(pbudgetProposal); + LogPrint("masternode","CBudgetManager::GetBudget() - Check 2 passed: Budget added\n"); } else { pbudgetProposal->SetAllotted(0); + LogPrint("masternode","CBudgetManager::GetBudget() - Check 2 failed: no amount allotted\n"); } } + else { + LogPrint("masternode","CBudgetManager::GetBudget() - Check 1 failed: 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, + pbudgetProposal->IsEstablished()); + } ++it2; } @@ -775,7 +838,7 @@ std::string CBudgetManager::GetRequiredPaymentsString(int nBlockHeight) ret += payment.nProposalHash.ToString(); } } else { - LogPrintf("CBudgetManager::GetRequiredPaymentsString - Couldn't find budget payment for block %d\n", nBlockHeight); + LogPrint("masternode","CBudgetManager::GetRequiredPaymentsString - Couldn't find budget payment for block %d\n", nBlockHeight); } } @@ -862,6 +925,7 @@ void CBudgetManager::NewBlock() //this function should be called 1/14 blocks, allowing up to 100 votes per day on all proposals if (chainActive.Height() % 14 != 0) return; + // incremental sync with our peers if (masternodeSync.IsSynced()) { LogPrintf("CBudgetManager::NewBlock - incremental sync started\n"); @@ -883,7 +947,7 @@ void CBudgetManager::NewBlock() //remove invalid votes once in a while (we have to check the signatures and validity of every vote, somewhat CPU intensive) - LogPrintf("CBudgetManager::NewBlock - askedForSourceProposalOrBudget cleanup - size: %d\n", askedForSourceProposalOrBudget.size()); + LogPrint("masternode","CBudgetManager::NewBlock - askedForSourceProposalOrBudget cleanup - size: %d\n", askedForSourceProposalOrBudget.size()); std::map::iterator it = askedForSourceProposalOrBudget.begin(); while (it != askedForSourceProposalOrBudget.end()) { if ((*it).second > GetTime() - (60 * 60 * 24)) { @@ -893,21 +957,21 @@ void CBudgetManager::NewBlock() } } - LogPrintf("CBudgetManager::NewBlock - mapProposals cleanup - size: %d\n", mapProposals.size()); + LogPrint("masternode","CBudgetManager::NewBlock - mapProposals cleanup - size: %d\n", mapProposals.size()); std::map::iterator it2 = mapProposals.begin(); while (it2 != mapProposals.end()) { (*it2).second.CleanAndRemove(false); ++it2; } - LogPrintf("CBudgetManager::NewBlock - mapFinalizedBudgets cleanup - size: %d\n", mapFinalizedBudgets.size()); + LogPrint("masternode","CBudgetManager::NewBlock - mapFinalizedBudgets cleanup - size: %d\n", mapFinalizedBudgets.size()); std::map::iterator it3 = mapFinalizedBudgets.begin(); while (it3 != mapFinalizedBudgets.end()) { (*it3).second.CleanAndRemove(false); ++it3; } - LogPrintf("CBudgetManager::NewBlock - vecImmatureBudgetProposals cleanup - size: %d\n", vecImmatureBudgetProposals.size()); + LogPrint("masternode","CBudgetManager::NewBlock - vecImmatureBudgetProposals cleanup - size: %d\n", vecImmatureBudgetProposals.size()); std::vector::iterator it4 = vecImmatureBudgetProposals.begin(); while (it4 != vecImmatureBudgetProposals.end()) { std::string strError = ""; @@ -918,7 +982,7 @@ void CBudgetManager::NewBlock() } if (!(*it4).IsValid(strError)) { - LogPrintf("mprop (immature) - invalid budget proposal - %s\n", strError); + LogPrint("masternode","mprop (immature) - invalid budget proposal - %s\n", strError); it4 = vecImmatureBudgetProposals.erase(it4); continue; } @@ -928,11 +992,11 @@ void CBudgetManager::NewBlock() (*it4).Relay(); } - LogPrintf("mprop (immature) - new budget - %s\n", (*it4).GetHash().ToString()); + LogPrint("masternode","mprop (immature) - new budget - %s\n", (*it4).GetHash().ToString()); it4 = vecImmatureBudgetProposals.erase(it4); } - LogPrintf("CBudgetManager::NewBlock - vecImmatureFinalizedBudgets cleanup - size: %d\n", vecImmatureFinalizedBudgets.size()); + LogPrint("masternode","CBudgetManager::NewBlock - vecImmatureFinalizedBudgets cleanup - size: %d\n", vecImmatureFinalizedBudgets.size()); std::vector::iterator it5 = vecImmatureFinalizedBudgets.begin(); while (it5 != vecImmatureFinalizedBudgets.end()) { std::string strError = ""; @@ -943,12 +1007,12 @@ void CBudgetManager::NewBlock() } if (!(*it5).IsValid(strError)) { - LogPrintf("fbs (immature) - invalid finalized budget - %s\n", strError); + LogPrint("masternode","fbs (immature) - invalid finalized budget - %s\n", strError); it5 = vecImmatureFinalizedBudgets.erase(it5); continue; } - LogPrintf("fbs (immature) - new finalized budget - %s\n", (*it5).GetHash().ToString()); + LogPrint("masternode","fbs (immature) - new finalized budget - %s\n", (*it5).GetHash().ToString()); CFinalizedBudget finalizedBudget((*it5)); if (AddFinalizedBudget(finalizedBudget)) { @@ -957,7 +1021,7 @@ void CBudgetManager::NewBlock() it5 = vecImmatureFinalizedBudgets.erase(it5); } - LogPrintf("CBudgetManager::NewBlock - PASSED\n"); + LogPrint("masternode","CBudgetManager::NewBlock - PASSED\n"); } void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) @@ -975,7 +1039,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (Params().NetworkID() == CBaseChainParams::MAIN) { if (nProp == 0) { if (pfrom->HasFulfilledRequest("mnvs")) { - LogPrintf("mnvs - peer already asked me for the list\n"); + LogPrint("masternode","mnvs - peer already asked me for the list\n"); Misbehaving(pfrom->GetId(), 20); return; } @@ -984,7 +1048,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData } Sync(pfrom, nProp); - LogPrint("mnbudget", "mnvs - Sent Masternode votes to peer %i\n", pfrom->GetId()); + LogPrint("mnbudget", "mnvs - Sent Masternode votes to peer %i\n", pfrom->GetId()); } if (strCommand == "mprop") { //Masternode Proposal @@ -999,7 +1063,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData std::string strError = ""; int nConf = 0; if (!IsBudgetCollateralValid(budgetProposalBroadcast.nFeeTXHash, budgetProposalBroadcast.GetHash(), strError, budgetProposalBroadcast.nTime, nConf)) { - LogPrintf("Proposal FeeTX is not valid - %s - %s\n", budgetProposalBroadcast.nFeeTXHash.ToString(), strError); + LogPrint("masternode","Proposal FeeTX is not valid - %s - %s\n", budgetProposalBroadcast.nFeeTXHash.ToString(), strError); if (nConf >= 1) vecImmatureBudgetProposals.push_back(budgetProposalBroadcast); return; } @@ -1007,7 +1071,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast)); if (!budgetProposalBroadcast.IsValid(strError)) { - LogPrintf("mprop - invalid budget proposal - %s\n", strError); + LogPrint("masternode","mprop - invalid budget proposal - %s\n", strError); return; } @@ -1017,7 +1081,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData } masternodeSync.AddedBudgetItem(budgetProposalBroadcast.GetHash()); - LogPrintf("mprop - new budget - %s\n", budgetProposalBroadcast.GetHash().ToString()); + LogPrint("masternode","mprop - new budget - %s\n", budgetProposalBroadcast.GetHash().ToString()); //We might have active votes for this proposal that are valid now CheckOrphanVotes(); @@ -1035,7 +1099,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData CMasternode* pmn = mnodeman.Find(vote.vin); if (pmn == NULL) { - LogPrintf("mvote - unknown masternode - vin: %s\n", vote.vin.prevout.hash.ToString()); + LogPrint("masternode","mvote - unknown masternode - vin: %s\n", vote.vin.prevout.hash.ToString()); mnodeman.AskForMN(pfrom, vote.vin); return; } @@ -1043,7 +1107,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); if (!vote.SignatureValid(true)) { - LogPrintf("mvote - signature invalid\n"); + LogPrint("masternode","mvote - signature invalid\n"); if (masternodeSync.IsSynced()) Misbehaving(pfrom->GetId(), 20); // it could just be a non-synced masternode mnodeman.AskForMN(pfrom, vote.vin); @@ -1055,7 +1119,8 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData vote.Relay(); masternodeSync.AddedBudgetItem(vote.GetHash()); } - LogPrint("mnbudget", "mvote - new budget vote - %s\n", vote.GetHash().ToString()); + + LogPrint("masternode","mvote - new budget vote for budget %s - %s\n", vote.nProposalHash.ToString(), vote.GetHash().ToString()); } if (strCommand == "fbs") { //Finalized Budget Suggestion @@ -1070,7 +1135,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData std::string strError = ""; int nConf = 0; if (!IsBudgetCollateralValid(finalizedBudgetBroadcast.nFeeTXHash, finalizedBudgetBroadcast.GetHash(), strError, finalizedBudgetBroadcast.nTime, nConf)) { - LogPrintf("Finalized Budget FeeTX is not valid - %s - %s\n", finalizedBudgetBroadcast.nFeeTXHash.ToString(), strError); + LogPrint("masternode","Finalized Budget FeeTX is not valid - %s - %s\n", finalizedBudgetBroadcast.nFeeTXHash.ToString(), strError); if (nConf >= 1) vecImmatureFinalizedBudgets.push_back(finalizedBudgetBroadcast); return; @@ -1079,11 +1144,11 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData mapSeenFinalizedBudgets.insert(make_pair(finalizedBudgetBroadcast.GetHash(), finalizedBudgetBroadcast)); if (!finalizedBudgetBroadcast.IsValid(strError)) { - LogPrintf("fbs - invalid finalized budget - %s\n", strError); + LogPrint("masternode","fbs - invalid finalized budget - %s\n", strError); return; } - LogPrintf("fbs - new finalized budget - %s\n", finalizedBudgetBroadcast.GetHash().ToString()); + LogPrint("masternode","fbs - new finalized budget - %s\n", finalizedBudgetBroadcast.GetHash().ToString()); CFinalizedBudget finalizedBudget(finalizedBudgetBroadcast); if (AddFinalizedBudget(finalizedBudget)) { @@ -1107,14 +1172,14 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData CMasternode* pmn = mnodeman.Find(vote.vin); if (pmn == NULL) { - LogPrint("mnbudget", "fbvote - unknown masternode - vin: %s\n", vote.vin.prevout.hash.ToString()); + LogPrint("mnbudget", "fbvote - unknown masternode - vin: %s\n", vote.vin.prevout.hash.ToString()); mnodeman.AskForMN(pfrom, vote.vin); return; } mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); if (!vote.SignatureValid(true)) { - LogPrintf("fbvote - signature invalid\n"); + LogPrint("masternode","fbvote - signature invalid\n"); if (masternodeSync.IsSynced()) Misbehaving(pfrom->GetId(), 20); // it could just be a non-synced masternode mnodeman.AskForMN(pfrom, vote.vin); @@ -1126,9 +1191,9 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData vote.Relay(); masternodeSync.AddedBudgetItem(vote.GetHash()); - LogPrintf("fbvote - new finalized budget vote - %s\n", vote.GetHash().ToString()); + LogPrint("masternode","fbvote - new finalized budget vote - %s\n", vote.GetHash().ToString()); } else { - LogPrintf("fbvote - rejected finalized budget vote - %s - %s\n", vote.GetHash().ToString(), strError); + LogPrint("masternode","fbvote - rejected finalized budget vote - %s - %s\n", vote.GetHash().ToString(), strError); } } } @@ -1294,7 +1359,7 @@ bool CBudgetManager::UpdateProposal(CBudgetVote& vote, CNode* pfrom, std::string // otherwise we'll think a full sync succeeded when they return a result if (!masternodeSync.IsSynced()) return false; - LogPrintf("CBudgetManager::UpdateProposal - Unknown proposal %d, asking for source proposal\n", vote.nProposalHash.ToString()); + LogPrint("masternode","CBudgetManager::UpdateProposal - Unknown proposal %d, asking for source proposal\n", vote.nProposalHash.ToString()); mapOrphanMasternodeBudgetVotes[vote.nProposalHash] = vote; if (!askedForSourceProposalOrBudget.count(vote.nProposalHash)) { @@ -1321,7 +1386,7 @@ bool CBudgetManager::UpdateFinalizedBudget(CFinalizedBudgetVote& vote, CNode* pf // otherwise we'll think a full sync succeeded when they return a result if (!masternodeSync.IsSynced()) return false; - LogPrintf("CBudgetManager::UpdateFinalizedBudget - Unknown Finalized Proposal %s, asking for source budget\n", vote.nBudgetHash.ToString()); + LogPrint("masternode","CBudgetManager::UpdateFinalizedBudget - Unknown Finalized Proposal %s, asking for source budget\n", vote.nBudgetHash.ToString()); mapOrphanFinalizedBudgetVotes[vote.nBudgetHash] = vote; if (!askedForSourceProposalOrBudget.count(vote.nBudgetHash)) { @@ -1330,10 +1395,10 @@ bool CBudgetManager::UpdateFinalizedBudget(CFinalizedBudgetVote& vote, CNode* pf } } - strError = "Finalized Budget not found!"; + strError = "Finalized Budget " + vote.nBudgetHash.ToString() + " not found!"; return false; } - + LogPrint("masternode","CBudgetManager::UpdateFinalizedBudget - Finalized Proposal %s added\n", vote.nBudgetHash.ToString()); return mapFinalizedBudgets[vote.nBudgetHash].AddOrUpdateVote(vote, strError); } @@ -1376,7 +1441,7 @@ CBudgetProposal::CBudgetProposal(const CBudgetProposal& other) bool CBudgetProposal::IsValid(std::string& strError, bool fCheckCollateral) { if (GetNays() - GetYeas() > mnodeman.CountEnabled(ActiveProtocol()) / 10) { - strError = "Active removal"; + strError = "Proposal " + strProposalName + ": Active removal"; return false; } @@ -1386,24 +1451,24 @@ bool CBudgetProposal::IsValid(std::string& strError, bool fCheckCollateral) } if (nBlockEnd < nBlockStart) { - strError = "Invalid nBlockEnd (end before start)"; + strError = "Proposal " + strProposalName + ": Invalid nBlockEnd (end before start)"; return false; } if (nAmount < 10 * COIN) { - strError = "Invalid nAmount"; + strError = "Proposal " + strProposalName + ": Invalid nAmount"; return false; } if (address == CScript()) { - strError = "Invalid Payment Address"; + strError = "Proposal " + strProposalName + ": Invalid Payment Address"; return false; } if (fCheckCollateral) { int nConf = 0; if (!IsBudgetCollateralValid(nFeeTXHash, GetHash(), strError, nTime, nConf)) { - strError = "Invalid collateral"; + strError = "Proposal " + strProposalName + ": Invalid collateral"; return false; } } @@ -1412,7 +1477,7 @@ bool CBudgetProposal::IsValid(std::string& strError, bool fCheckCollateral) TODO: There might be an issue with multisig in the coinbase on mainnet, we will add support for it in a future release. */ if (address.IsPayToScriptHash()) { - strError = "Multisig is not currently supported."; + strError = "Proposal " + strProposalName + ": Multisig is not currently supported."; return false; } @@ -1428,18 +1493,22 @@ bool CBudgetProposal::IsValid(std::string& strError, bool fCheckCollateral) //can only pay out 10% of the possible coins (min value of coins) if (nAmount > budget.GetTotalBudget(nBlockStart)) { - strError = "Payment more than max"; + strError = "Proposal " + strProposalName + ": Payment more than max"; return false; } CBlockIndex* pindexPrev = chainActive.Tip(); if (pindexPrev == NULL) { - strError = "Tip is NULL"; + strError = "Proposal " + strProposalName + ": Tip is NULL"; return true; } - if (GetBlockEnd() < pindexPrev->nHeight - GetBudgetPaymentCycleBlocks() / 2) { - strError = "Invalid nBlockEnd (end too early)"; + // Calculate maximum block this proposal will be valid, which is start of proposal + (number of payments * cycle) + int nProposalEnd = GetBlockStart() + (GetBudgetPaymentCycleBlocks() * GetTotalPaymentCount()); + + // if (GetBlockEnd() < pindexPrev->nHeight - GetBudgetPaymentCycleBlocks() / 2) { + if(nProposalEnd < pindexPrev->nHeight){ + strError = "Proposal " + strProposalName + ": Invalid nBlockEnd (" + std::to_string(nProposalEnd) + ") < current height (" + std::to_string(pindexPrev->nHeight) + ")"; return false; } @@ -1448,6 +1517,7 @@ bool CBudgetProposal::IsValid(std::string& strError, bool fCheckCollateral) bool CBudgetProposal::AddOrUpdateVote(CBudgetVote& vote, std::string& strError) { + std::string strAction = "New vote inserted:"; LOCK(cs); uint256 hash = vote.vin.prevout.GetHash(); @@ -1459,10 +1529,11 @@ bool CBudgetProposal::AddOrUpdateVote(CBudgetVote& vote, std::string& strError) return false; } if (vote.nTime - mapVotes[hash].nTime < BUDGET_VOTE_UPDATE_MIN) { - strError = strprintf("time between votes is too soon - %s - %lli\n", vote.GetHash().ToString(), vote.nTime - mapVotes[hash].nTime); + strError = strprintf("time between votes is too soon - %s - %lli sec < %lli sec\n", vote.GetHash().ToString(), vote.nTime - mapVotes[hash].nTime,BUDGET_VOTE_UPDATE_MIN); LogPrint("mnbudget", "CBudgetProposal::AddOrUpdateVote - %s\n", strError); return false; } + strAction = "Existing vote updated:"; } if (vote.nTime > GetTime() + (60 * 60)) { @@ -1472,6 +1543,8 @@ bool CBudgetProposal::AddOrUpdateVote(CBudgetVote& vote, std::string& strError) } mapVotes[hash] = vote; + LogPrint("mnbudget", "CBudgetProposal::AddOrUpdateVote - %s %s\n", strAction.c_str(), vote.GetHash().ToString().c_str()); + return true; } @@ -1562,9 +1635,14 @@ int CBudgetProposal::GetBlockCurrentCycle() int CBudgetProposal::GetBlockEndCycle() { + // XX42: right now single payment proposals have nBlockEnd have a cycle too early! + // switch back if it break something else //end block is half way through the next cycle (so the proposal will be removed much after the payment is sent) + // return nBlockEnd - GetBudgetPaymentCycleBlocks() / 2; + + // End block is half way through the next cycle (so the proposal will be removed much after the payment is sent) + return nBlockEnd; - return nBlockEnd - GetBudgetPaymentCycleBlocks() / 2; } int CBudgetProposal::GetTotalPaymentCount() @@ -1588,8 +1666,14 @@ CBudgetProposalBroadcast::CBudgetProposalBroadcast(std::string strProposalNameIn nBlockStart = nBlockStartIn; int nCycleStart = nBlockStart - nBlockStart % GetBudgetPaymentCycleBlocks(); + + // XX42: right now single payment proposals have nBlockEnd have a cycle too early! + // switch back if it break something else //calculate the end of the cycle for this vote, add half a cycle (vote will be deleted after that block) - nBlockEnd = nCycleStart + GetBudgetPaymentCycleBlocks() * nPaymentCount + GetBudgetPaymentCycleBlocks() / 2; + // nBlockEnd = nCycleStart + GetBudgetPaymentCycleBlocks() * nPaymentCount + GetBudgetPaymentCycleBlocks() / 2; + + // Calculate the end of the cycle for this vote, vote will be deleted after next cycle + nBlockEnd = nCycleStart + (GetBudgetPaymentCycleBlocks() + 1) * nPaymentCount; address = addressIn; nAmount = nAmountIn; @@ -1639,12 +1723,12 @@ bool CBudgetVote::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) std::string strMessage = vin.prevout.ToStringShort() + nProposalHash.ToString() + boost::lexical_cast(nVote) + boost::lexical_cast(nTime); if (!obfuScationSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) { - LogPrintf("CBudgetVote::Sign - Error upon calling SignMessage"); + LogPrint("masternode","CBudgetVote::Sign - Error upon calling SignMessage"); return false; } if (!obfuScationSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) { - LogPrintf("CBudgetVote::Sign - Error upon calling VerifyMessage"); + LogPrint("masternode","CBudgetVote::Sign - Error upon calling VerifyMessage"); return false; } @@ -1659,17 +1743,16 @@ bool CBudgetVote::SignatureValid(bool fSignatureCheck) CMasternode* pmn = mnodeman.Find(vin); if (pmn == NULL) { - if (fDebug) { - LogPrintf("CBudgetVote::SignatureValid() - Unknown Masternode - %s\n", vin.prevout.hash.ToString()); - } - + if (fDebug){ + LogPrint("masternode","CBudgetVote::SignatureValid() - Unknown Masternode - %s\n", vin.prevout.hash.ToString()); + } return false; } if (!fSignatureCheck) return true; if (!obfuScationSigner.VerifyMessage(pmn->pubKeyMasternode, vchSig, strMessage, errorMessage)) { - LogPrintf("CBudgetVote::SignatureValid() - Verify message failed\n"); + LogPrint("masternode","CBudgetVote::SignatureValid() - Verify message failed\n"); return false; } @@ -1705,6 +1788,8 @@ bool CFinalizedBudget::AddOrUpdateVote(CFinalizedBudgetVote& vote, std::string& LOCK(cs); uint256 hash = vote.vin.prevout.GetHash(); + std::string strAction = "New vote inserted:"; + if (mapVotes.count(hash)) { if (mapVotes[hash].nTime > vote.nTime) { strError = strprintf("new vote older than existing vote - %s\n", vote.GetHash().ToString()); @@ -1712,10 +1797,11 @@ bool CFinalizedBudget::AddOrUpdateVote(CFinalizedBudgetVote& vote, std::string& return false; } if (vote.nTime - mapVotes[hash].nTime < BUDGET_VOTE_UPDATE_MIN) { - strError = strprintf("time between votes is too soon - %s - %lli\n", vote.GetHash().ToString(), vote.nTime - mapVotes[hash].nTime); + strError = strprintf("time between votes is too soon - %s - %lli sec < %lli sec\n", vote.GetHash().ToString(), vote.nTime - mapVotes[hash].nTime,BUDGET_VOTE_UPDATE_MIN); LogPrint("mnbudget", "CFinalizedBudget::AddOrUpdateVote - %s\n", strError); return false; } + strAction = "Existing vote updated:"; } if (vote.nTime > GetTime() + (60 * 60)) { @@ -1725,6 +1811,7 @@ bool CFinalizedBudget::AddOrUpdateVote(CFinalizedBudgetVote& vote, std::string& } mapVotes[hash] = vote; + LogPrint("mnbudget", "CFinalizedBudget::AddOrUpdateVote - %s %s\n", strAction.c_str(), vote.GetHash().ToString().c_str()); return true; } @@ -1736,14 +1823,14 @@ void CFinalizedBudget::AutoCheck() CBlockIndex* pindexPrev = chainActive.Tip(); if (!pindexPrev) return; - LogPrintf("CFinalizedBudget::AutoCheck - %lli - %d\n", pindexPrev->nHeight, fAutoChecked); + LogPrint("masternode","CFinalizedBudget::AutoCheck - %lli - %d\n", pindexPrev->nHeight, fAutoChecked); if (!fMasterNode || fAutoChecked) return; //do this 1 in 4 blocks -- spread out the voting activity on mainnet // -- this function is only called every fourteenth block, so this is really 1 in 56 blocks if (Params().NetworkID() == CBaseChainParams::MAIN && rand() % 4 != 0) { - LogPrintf("CFinalizedBudget::AutoCheck - waiting\n"); + LogPrint("masternode","CFinalizedBudget::AutoCheck - waiting\n"); return; } @@ -1756,52 +1843,53 @@ void CFinalizedBudget::AutoCheck() for (unsigned int i = 0; i < vecBudgetPayments.size(); i++) { - LogPrintf("CFinalizedBudget::AutoCheck - nProp %d %s\n", i, vecBudgetPayments[i].nProposalHash.ToString()); - LogPrintf("CFinalizedBudget::AutoCheck - Payee %d %s\n", i, vecBudgetPayments[i].payee.ToString()); - LogPrintf("CFinalizedBudget::AutoCheck - nAmount %d %lli\n", i, vecBudgetPayments[i].nAmount); + LogPrint("masternode","CFinalizedBudget::AutoCheck - nProp %d %s\n", i, vecBudgetPayments[i].nProposalHash.ToString()); + LogPrint("masternode","CFinalizedBudget::AutoCheck - Payee %d %s\n", i, vecBudgetPayments[i].payee.ToString()); + LogPrint("masternode","CFinalizedBudget::AutoCheck - nAmount %d %lli\n", i, vecBudgetPayments[i].nAmount); } for (unsigned int i = 0; i < vBudgetProposals.size(); i++) { - LogPrintf("CFinalizedBudget::AutoCheck - nProp %d %s\n", i, vBudgetProposals[i]->GetHash().ToString()); - LogPrintf("CFinalizedBudget::AutoCheck - Payee %d %s\n", i, vBudgetProposals[i]->GetPayee().ToString()); - LogPrintf("CFinalizedBudget::AutoCheck - nAmount %d %lli\n", i, vBudgetProposals[i]->GetAmount()); + LogPrint("masternode","CFinalizedBudget::AutoCheck - nProp %d %s\n", i, vBudgetProposals[i]->GetHash().ToString()); + LogPrint("masternode","CFinalizedBudget::AutoCheck - Payee %d %s\n", i, vBudgetProposals[i]->GetPayee().ToString()); + LogPrint("masternode","CFinalizedBudget::AutoCheck - nAmount %d %lli\n", i, vBudgetProposals[i]->GetAmount()); } if (vBudgetProposals.size() == 0) { - LogPrintf("CFinalizedBudget::AutoCheck - Can't get Budget, aborting\n"); + LogPrint("masternode","CFinalizedBudget::AutoCheck - Can't get Budget, aborting\n"); return; } if (vBudgetProposals.size() != vecBudgetPayments.size()) { - LogPrintf("CFinalizedBudget::AutoCheck - Budget length doesn't match\n"); + LogPrint("masternode","CFinalizedBudget::AutoCheck - Budget length doesn't match. vBudgetProposals.size()=%ld != vecBudgetPayments.size()=%ld\n", + vBudgetProposals.size(), vecBudgetPayments.size()); return; } for (unsigned int i = 0; i < vecBudgetPayments.size(); i++) { if (i > vBudgetProposals.size() - 1) { - LogPrintf("CFinalizedBudget::AutoCheck - Vector size mismatch, aborting\n"); + LogPrint("masternode","CFinalizedBudget::AutoCheck - Proposal size mismatch, i=%d > (vBudgetProposals.size() - 1)=%d\n", i, vBudgetProposals.size() - 1); return; } if (vecBudgetPayments[i].nProposalHash != vBudgetProposals[i]->GetHash()) { - LogPrintf("CFinalizedBudget::AutoCheck - item #%d doesn't match %s %s\n", i, vecBudgetPayments[i].nProposalHash.ToString(), vBudgetProposals[i]->GetHash().ToString()); + LogPrint("masternode","CFinalizedBudget::AutoCheck - item #%d doesn't match %s %s\n", i, vecBudgetPayments[i].nProposalHash.ToString(), vBudgetProposals[i]->GetHash().ToString()); return; } // if(vecBudgetPayments[i].payee != vBudgetProposals[i]->GetPayee()){ -- triggered with false positive if (vecBudgetPayments[i].payee.ToString() != vBudgetProposals[i]->GetPayee().ToString()) { - LogPrintf("CFinalizedBudget::AutoCheck - item #%d payee doesn't match %s %s\n", i, vecBudgetPayments[i].payee.ToString(), vBudgetProposals[i]->GetPayee().ToString()); + LogPrint("masternode","CFinalizedBudget::AutoCheck - item #%d payee doesn't match %s %s\n", i, vecBudgetPayments[i].payee.ToString(), vBudgetProposals[i]->GetPayee().ToString()); return; } if (vecBudgetPayments[i].nAmount != vBudgetProposals[i]->GetAmount()) { - LogPrintf("CFinalizedBudget::AutoCheck - item #%d payee doesn't match %lli %lli\n", i, vecBudgetPayments[i].nAmount, vBudgetProposals[i]->GetAmount()); + LogPrint("masternode","CFinalizedBudget::AutoCheck - item #%d payee doesn't match %lli %lli\n", i, vecBudgetPayments[i].nAmount, vBudgetProposals[i]->GetAmount()); return; } } - LogPrintf("CFinalizedBudget::AutoCheck - Finalized Budget Matches! Submitting Vote.\n"); + LogPrint("masternode","CFinalizedBudget::AutoCheck - Finalized Budget Matches! Submitting Vote.\n"); SubmitVote(); } } @@ -1856,7 +1944,7 @@ std::string CFinalizedBudget::GetStatus() for (int nBlockHeight = GetBlockStart(); nBlockHeight <= GetBlockEnd(); nBlockHeight++) { CTxBudgetPayment budgetPayment; if (!GetBudgetPaymentByBlock(nBlockHeight, budgetPayment)) { - LogPrintf("CFinalizedBudget::GetStatus - Couldn't find budget payment for block %lld\n", nBlockHeight); + LogPrint("masternode","CFinalizedBudget::GetStatus - Couldn't find budget payment for block %lld\n", nBlockHeight); continue; } @@ -1885,11 +1973,13 @@ std::string CFinalizedBudget::GetStatus() bool CFinalizedBudget::IsValid(std::string& strError, bool fCheckCollateral) { - //must be the correct block for payment to happen (once a month) + // Must be the correct block for payment to happen (once a month) if (nBlockStart % GetBudgetPaymentCycleBlocks() != 0) { strError = "Invalid BlockStart"; return false; } + + // The following 2 checks check the same (basically if vecBudgetPayments.size() > 100) if (GetBlockEnd() - nBlockStart > 100) { strError = "Invalid BlockEnd"; return false; @@ -1903,17 +1993,17 @@ bool CFinalizedBudget::IsValid(std::string& strError, bool fCheckCollateral) return false; } if (nBlockStart == 0) { - strError = "Invalid BlockStart == 0"; + strError = "Budget " + strBudgetName + " Invalid BlockStart == 0"; return false; } if (nFeeTXHash == 0) { - strError = "Invalid FeeTx == 0"; + strError = "Budget " + strBudgetName + " Invalid FeeTx == 0"; return false; } - //can only pay out 10% of the possible coins (min value of coins) + // Can only pay out 10% of the possible coins (min value of coins) if (GetTotalPayout() > budget.GetTotalBudget(nBlockStart)) { - strError = "Invalid Payout (more than max)"; + strError = "Budget " + strBudgetName + " Invalid Payout (more than max)"; return false; } @@ -1922,7 +2012,7 @@ bool CFinalizedBudget::IsValid(std::string& strError, bool fCheckCollateral) int nConf = 0; if (!IsBudgetCollateralValid(nFeeTXHash, GetHash(), strError2, nTime, nConf)) { { - strError = "Invalid Collateral : " + strError2; + strError = "Budget " + strBudgetName + " Invalid Collateral : " + strError2; return false; } } @@ -1933,10 +2023,12 @@ bool CFinalizedBudget::IsValid(std::string& strError, bool fCheckCollateral) CBlockIndex* pindexPrev = chainActive.Tip(); if (pindexPrev == NULL) return true; - if (nBlockStart < pindexPrev->nHeight - 100) { - strError = "Older than current blockHeight"; - return false; - } +// TODO: verify if we can safely remove this +// +// if (nBlockStart < pindexPrev->nHeight - 100) { +// strError = "Budget " + strBudgetName + " Older than current blockHeight" ; +// return false; +// } return true; } @@ -1945,26 +2037,31 @@ bool CFinalizedBudget::IsTransactionValid(const CTransaction& txNew, int nBlockH { int nCurrentBudgetPayment = nBlockHeight - GetBlockStart(); if (nCurrentBudgetPayment < 0) { - LogPrintf("CFinalizedBudget::IsTransactionValid - Invalid block - height: %d start: %d\n", nBlockHeight, GetBlockStart()); + LogPrint("masternode","CFinalizedBudget::IsTransactionValid - Invalid block - height: %d start: %d\n", nBlockHeight, GetBlockStart()); return false; } if (nCurrentBudgetPayment > (int)vecBudgetPayments.size() - 1) { - LogPrintf("CFinalizedBudget::IsTransactionValid - Invalid block - current budget payment: %d of %d\n", nCurrentBudgetPayment + 1, (int)vecBudgetPayments.size()); + LogPrint("masternode","CFinalizedBudget::IsTransactionValid - Invalid block - current budget payment: %d of %d\n", nCurrentBudgetPayment + 1, (int)vecBudgetPayments.size()); return false; } bool found = false; BOOST_FOREACH (CTxOut out, txNew.vout) { - if (vecBudgetPayments[nCurrentBudgetPayment].payee == out.scriptPubKey && vecBudgetPayments[nCurrentBudgetPayment].nAmount == out.nValue) + if (vecBudgetPayments[nCurrentBudgetPayment].payee == out.scriptPubKey && vecBudgetPayments[nCurrentBudgetPayment].nAmount == out.nValue) { found = true; + LogPrint("masternode","CFinalizedBudget::IsTransactionValid - Found valid Budget Payment of %d for %d\n", + vecBudgetPayments[nCurrentBudgetPayment].nAmount, vecBudgetPayments[nCurrentBudgetPayment].nProposalHash.Get32()); + } } + if (!found) { CTxDestination address1; ExtractDestination(vecBudgetPayments[nCurrentBudgetPayment].payee, address1); CBitcoinAddress address2(address1); - LogPrintf("CFinalizedBudget::IsTransactionValid - Missing required payment - %s: %d\n", address2.ToString(), vecBudgetPayments[nCurrentBudgetPayment].nAmount); + LogPrint("masternode","CFinalizedBudget::IsTransactionValid - Missing required payment - %s: %d c: %d\n", + address2.ToString(), vecBudgetPayments[nCurrentBudgetPayment].nAmount, nCurrentBudgetPayment); } return found; @@ -1977,24 +2074,24 @@ void CFinalizedBudget::SubmitVote() std::string errorMessage; if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { - LogPrintf("CFinalizedBudget::SubmitVote - Error upon calling SetKey\n"); + LogPrint("masternode","CFinalizedBudget::SubmitVote - Error upon calling SetKey\n"); return; } CFinalizedBudgetVote vote(activeMasternode.vin, GetHash()); if (!vote.Sign(keyMasternode, pubKeyMasternode)) { - LogPrintf("CFinalizedBudget::SubmitVote - Failure to sign."); + LogPrint("masternode","CFinalizedBudget::SubmitVote - Failure to sign."); return; } std::string strError = ""; if (budget.UpdateFinalizedBudget(vote, NULL, strError)) { - LogPrintf("CFinalizedBudget::SubmitVote - new finalized budget vote - %s\n", vote.GetHash().ToString()); + LogPrint("masternode","CFinalizedBudget::SubmitVote - new finalized budget vote - %s\n", vote.GetHash().ToString()); budget.mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); vote.Relay(); } else { - LogPrintf("CFinalizedBudget::SubmitVote : Error submitting vote - %s\n", strError); + LogPrint("masternode","CFinalizedBudget::SubmitVote : Error submitting vote - %s\n", strError); } } @@ -2070,12 +2167,12 @@ bool CFinalizedBudgetVote::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) std::string strMessage = vin.prevout.ToStringShort() + nBudgetHash.ToString() + boost::lexical_cast(nTime); if (!obfuScationSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) { - LogPrintf("CFinalizedBudgetVote::Sign - Error upon calling SignMessage"); + LogPrint("masternode","CFinalizedBudgetVote::Sign - Error upon calling SignMessage"); return false; } if (!obfuScationSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) { - LogPrintf("CFinalizedBudgetVote::Sign - Error upon calling VerifyMessage"); + LogPrint("masternode","CFinalizedBudgetVote::Sign - Error upon calling VerifyMessage"); return false; } @@ -2091,14 +2188,14 @@ bool CFinalizedBudgetVote::SignatureValid(bool fSignatureCheck) CMasternode* pmn = mnodeman.Find(vin); if (pmn == NULL) { - LogPrintf("CFinalizedBudgetVote::SignatureValid() - Unknown Masternode\n"); + LogPrint("masternode","CFinalizedBudgetVote::SignatureValid() - Unknown Masternode %s\n", strMessage); return false; } if (!fSignatureCheck) return true; if (!obfuScationSigner.VerifyMessage(pmn->pubKeyMasternode, vchSig, strMessage, errorMessage)) { - LogPrintf("CFinalizedBudgetVote::SignatureValid() - Verify message failed\n"); + LogPrint("masternode","CFinalizedBudgetVote::SignatureValid() - Verify message failed %s %s\n", strMessage, errorMessage); return false; } diff --git a/src/masternode-budget.h b/src/masternode-budget.h index 68e3a94ed..31fb6e3a5 100644 --- a/src/masternode-budget.h +++ b/src/masternode-budget.h @@ -4,6 +4,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef MASTERNODE_BUDGET_H #define MASTERNODE_BUDGET_H @@ -491,7 +492,7 @@ class CBudgetProposal bool IsEstablished() { - //Proposals must be at least a day old to make it into a budget + // 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 - 4 hours diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index f16080ae1..d9f00ca3c 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -60,7 +60,7 @@ bool CMasternodePaymentDB::Write(const CMasternodePayments& objToSave) } fileout.fclose(); - LogPrintf("Written info to mnpayments.dat %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode","Written info to mnpayments.dat %dms\n", GetTimeMillis() - nStart); return true; } @@ -135,13 +135,13 @@ CMasternodePaymentDB::ReadResult CMasternodePaymentDB::Read(CMasternodePayments& return IncorrectFormat; } - LogPrintf("Loaded info from mnpayments.dat %dms\n", GetTimeMillis() - nStart); - LogPrintf(" %s\n", objToLoad.ToString()); + LogPrint("masternode","Loaded info from mnpayments.dat %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode"," %s\n", objToLoad.ToString()); if (!fDryRun) { - LogPrintf("Masternode payments manager - cleaning....\n"); + LogPrint("masternode","Masternode payments manager - cleaning....\n"); objToLoad.CleanPaymentList(); - LogPrintf("Masternode payments manager - result:\n"); - LogPrintf(" %s\n", objToLoad.ToString()); + LogPrint("masternode","Masternode payments manager - result:\n"); + LogPrint("masternode"," %s\n", objToLoad.ToString()); } return Ok; @@ -154,24 +154,24 @@ void DumpMasternodePayments() CMasternodePaymentDB paymentdb; CMasternodePayments tempPayments; - LogPrintf("Verifying mnpayments.dat format...\n"); + LogPrint("masternode","Verifying mnpayments.dat format...\n"); CMasternodePaymentDB::ReadResult readResult = paymentdb.Read(tempPayments, true); // there was an error and it was not an error on file opening => do not proceed if (readResult == CMasternodePaymentDB::FileError) - LogPrintf("Missing budgets file - mnpayments.dat, will try to recreate\n"); + LogPrint("masternode","Missing budgets file - mnpayments.dat, will try to recreate\n"); else if (readResult != CMasternodePaymentDB::Ok) { - LogPrintf("Error reading mnpayments.dat: "); + LogPrint("masternode","Error reading mnpayments.dat: "); if (readResult == CMasternodePaymentDB::IncorrectFormat) - LogPrintf("magic is ok but data has invalid format, will try to recreate\n"); + LogPrint("masternode","magic is ok but data has invalid format, will try to recreate\n"); else { - LogPrintf("file format is unknown or invalid, please fix it manually\n"); + LogPrint("masternode","file format is unknown or invalid, please fix it manually\n"); return; } } - LogPrintf("Writting info to mnpayments.dat...\n"); + LogPrint("masternode","Writting info to mnpayments.dat...\n"); paymentdb.Write(masternodePayments); - LogPrintf("Budget dump finished %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode","Budget dump finished %dms\n", GetTimeMillis() - nStart); } bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue, CAmount nMinted) @@ -189,9 +189,11 @@ bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue, CAmount nMin } if (nHeight == 0) { - LogPrintf("IsBlockValueValid() : WARNING: Couldn't find previous block\n"); + LogPrint("masternode","IsBlockValueValid() : WARNING: Couldn't find previous block\n"); } + //LogPrintf("XX69----------> IsBlockValueValid(): nMinted: %d, nExpectedValue: %d\n", FormatMoney(nMinted), FormatMoney(nExpectedValue)); + if (!masternodeSync.IsSynced()) { //there is no budget data to use to check anything //super blocks will always be on these blocks, max 100 per budgeting if (nHeight % GetBudgetPaymentCycleBlocks() < 100) { @@ -240,11 +242,11 @@ bool IsBlockPayeeValid(const CBlock& block, int nBlockHeight) if (budget.IsTransactionValid(txNew, nBlockHeight)) return true; - LogPrintf("Invalid budget payment detected %s\n", txNew.ToString().c_str()); + LogPrint("masternode","Invalid budget payment detected %s\n", txNew.ToString().c_str()); if (IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT)) return false; - LogPrintf("Budget enforcement is disabled, accepting block\n"); + LogPrint("masternode","Budget enforcement is disabled, accepting block\n"); return true; } } @@ -252,11 +254,11 @@ bool IsBlockPayeeValid(const CBlock& block, int nBlockHeight) //check for masternode payee if (masternodePayments.IsTransactionValid(txNew, nBlockHeight)) return true; - LogPrintf("Invalid mn payment detected %s\n", txNew.ToString().c_str()); + LogPrint("masternode","Invalid mn payment detected %s\n", txNew.ToString().c_str()); if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) return false; - LogPrintf("Masternode payment enforcement is disabled, accepting block\n"); + LogPrint("masternode","Masternode payment enforcement is disabled, accepting block\n"); return true; } @@ -296,7 +298,7 @@ void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFe if (winningNode) { payee = GetScriptForDestination(winningNode->pubKeyCollateralAddress.GetID()); } else { - LogPrintf("CreateNewBlock: Failed to detect masternode to pay\n"); + LogPrint("masternode","CreateNewBlock: Failed to detect masternode to pay\n"); hasPayment = false; } } @@ -329,11 +331,11 @@ void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int64_t nFe ExtractDestination(payee, address1); CBitcoinAddress address2(address1); - LogPrintf("Masternode payment of %s to %s\n", FormatMoney(masternodePayment).c_str(), address2.ToString().c_str()); + LogPrint("masternode","Masternode payment of %s to %s\n", FormatMoney(masternodePayment).c_str(), address2.ToString().c_str()); } else { if (!fProofOfStake) txNew.vout[0].nValue = blockValue - masternodePayment; - } + } } int CMasternodePayments::GetMinMasternodePaymentsProto() @@ -359,7 +361,7 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st if (Params().NetworkID() == CBaseChainParams::MAIN) { if (pfrom->HasFulfilledRequest("mnget")) { - LogPrintf("mnget - peer already asked me for the list\n"); + LogPrint("masternode","mnget - peer already asked me for the list\n"); Misbehaving(pfrom->GetId(), 20); return; } @@ -396,17 +398,17 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st std::string strError = ""; if (!winner.IsValid(pfrom, strError)) { - // if(strError != "") LogPrintf("mnw - invalid message - %s\n", strError); + // if(strError != "") LogPrint("masternode","mnw - invalid message - %s\n", strError); return; } if (!masternodePayments.CanVote(winner.vinMasternode.prevout, winner.nBlockHeight)) { - // LogPrintf("mnw - masternode already voted - %s\n", winner.vinMasternode.prevout.ToStringShort()); + // LogPrint("masternode","mnw - masternode already voted - %s\n", winner.vinMasternode.prevout.ToStringShort()); return; } if (!winner.SignatureValid()) { - // LogPrintf("mnw - invalid signature\n"); + // LogPrint("masternode","mnw - invalid signature\n"); if (masternodeSync.IsSynced()) Misbehaving(pfrom->GetId(), 20); // it could just be a non-synced masternode mnodeman.AskForMN(pfrom, winner.vinMasternode); @@ -436,12 +438,12 @@ bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasterno payee.ToString(); if (!obfuScationSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) { - LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str()); + LogPrint("masternode","CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str()); return false; } if (!obfuScationSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) { - LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str()); + LogPrint("masternode","CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str()); return false; } @@ -554,7 +556,7 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) if(out.nValue >= requiredMasternodePayment) found = true; else - LogPrintf("Masternode payment is out of drift range. Paid=%s Min=%s\n", FormatMoney(out.nValue).c_str(), FormatMoney(requiredMasternodePayment).c_str()); + LogPrint("masternode","Masternode payment is out of drift range. Paid=%s Min=%s\n", FormatMoney(out.nValue).c_str(), FormatMoney(requiredMasternodePayment).c_str()); } } @@ -573,7 +575,7 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) } } - LogPrintf("CMasternodePayments::IsTransactionValid - Missing required payment of %s to %s\n", FormatMoney(requiredMasternodePayment).c_str(), strPayeesPossible.c_str()); + LogPrint("masternode","CMasternodePayments::IsTransactionValid - Missing required payment of %s to %s\n", FormatMoney(requiredMasternodePayment).c_str(), strPayeesPossible.c_str()); return false; } @@ -654,15 +656,15 @@ bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError) CMasternode* pmn = mnodeman.Find(vinMasternode); if (!pmn) { - strError = strprintf("Unknown Masternode %s", vinMasternode.prevout.hash.ToString()); - LogPrintf("CMasternodePaymentWinner::IsValid - %s\n", strError); + strError = strprintf("Unknown Masternode %s", vinMasternode.prevout.hash.ToString()); + LogPrint("masternode","CMasternodePaymentWinner::IsValid - %s\n", strError); mnodeman.AskForMN(pnode, vinMasternode); return false; } if (pmn->protocolVersion < ActiveProtocol()) { strError = strprintf("Masternode protocol too old %d - req %d", pmn->protocolVersion, ActiveProtocol()); - LogPrintf("CMasternodePaymentWinner::IsValid - %s\n", strError); + LogPrint("masternode","CMasternodePaymentWinner::IsValid - %s\n", strError); return false; } @@ -672,9 +674,9 @@ bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError) //It's common to have masternodes mistakenly think they are in the top 10 // We don't want to print all of these messages, or punish them unless they're way off if (n > MNPAYMENTS_SIGNATURES_TOTAL * 2) { - strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL * 2, n); - LogPrintf("CMasternodePaymentWinner::IsValid - %s\n", strError); - if (masternodeSync.IsSynced()) Misbehaving(pnode->GetId(), 20); + strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL * 2, n); + LogPrint("masternode","CMasternodePaymentWinner::IsValid - %s\n", strError); + //if (masternodeSync.IsSynced()) Misbehaving(pnode->GetId(), 20); } return false; } @@ -707,13 +709,14 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight) if (budget.IsBudgetPaymentBlock(nBlockHeight)) { //is budget payment block -- handled by the budgeting software } else { - LogPrintf("CMasternodePayments::ProcessBlock() Start nHeight %d - vin %s. \n", nBlockHeight, activeMasternode.vin.prevout.hash.ToString()); + LogPrint("masternode","CMasternodePayments::ProcessBlock() Start nHeight %d - vin %s. \n", nBlockHeight, activeMasternode.vin.prevout.hash.ToString()); + // pay to the oldest MN that still had no payment but its input is old enough and it was active long enough int nCount = 0; CMasternode* pmn = mnodeman.GetNextMasternodeInQueueForPayment(nBlockHeight, true, nCount); if (pmn != NULL) { - LogPrintf("CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n"); + LogPrint("masternode","CMasternodePayments::ProcessBlock() Found by FindOldestNotInVec \n"); newWinner.nBlockHeight = nBlockHeight; @@ -724,9 +727,9 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight) ExtractDestination(payee, address1); CBitcoinAddress address2(address1); - LogPrintf("CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", address2.ToString().c_str(), newWinner.nBlockHeight); + LogPrint("masternode","CMasternodePayments::ProcessBlock() Winner payee %s nHeight %d. \n", address2.ToString().c_str(), newWinner.nBlockHeight); } else { - LogPrintf("CMasternodePayments::ProcessBlock() Failed to find masternode to pay\n"); + LogPrint("masternode","CMasternodePayments::ProcessBlock() Failed to find masternode to pay\n"); } } @@ -735,13 +738,13 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight) CKey keyMasternode; if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { - LogPrintf("CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str()); + LogPrint("masternode","CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str()); return false; } - LogPrintf("CMasternodePayments::ProcessBlock() - Signing Winner\n"); + LogPrint("masternode","CMasternodePayments::ProcessBlock() - Signing Winner\n"); if (newWinner.Sign(keyMasternode, pubKeyMasternode)) { - LogPrintf("CMasternodePayments::ProcessBlock() - AddWinningMasternode\n"); + LogPrint("masternode","CMasternodePayments::ProcessBlock() - AddWinningMasternode\n"); if (AddWinningMasternode(newWinner)) { newWinner.Relay(); diff --git a/src/masternode-payments.h b/src/masternode-payments.h index 12f147a46..4deeccdef 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -1,8 +1,8 @@ - - // Copyright (c) 2014-2015 The Dash developers +// Copyright (c) 2015-2017 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 MASTERNODE_PAYMENTS_H #define MASTERNODE_PAYMENTS_H diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index 70acedda6..9cc7b5535 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -53,7 +53,7 @@ bool CMasternodeSync::IsBlockchainSynced() if (pindex == NULL) return false; - if (pindex->nTime + 60 * 60 < GetTime()) + if ((pindex->nTime + 60 * 60) < GetTime() && Params().NetworkID() != CBaseChainParams::TESTNET) return false; fBlockchainSynced = true; @@ -286,11 +286,12 @@ void CMasternodeSync::Process() //set to synced if (RequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS) { + if (RequestedMasternodeAttempt >= 2) GetNextAsset(); + if (pnode->HasFulfilledRequest("getspork")) continue; pnode->FulfilledRequest("getspork"); pnode->PushMessage("getsporks"); //get current network sporks - if (RequestedMasternodeAttempt >= 2) GetNextAsset(); RequestedMasternodeAttempt++; return; @@ -368,21 +369,16 @@ void CMasternodeSync::Process() if (pnode->nVersion >= ActiveProtocol()) { if (RequestedMasternodeAssets == MASTERNODE_SYNC_BUDGET) { - //we'll start rejecting votes if we accidentally get set as synced too soon - if (lastBudgetItem > 0 && lastBudgetItem < GetTime() - MASTERNODE_SYNC_TIMEOUT * 2 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) { //hasn't received a new item in the last five seconds, so we'll move to the - //LogPrintf("CMasternodeSync::Process - HasNextFinalizedBudget %d nCountFailures %d IsBudgetPropEmpty %d\n", budget.HasNextFinalizedBudget(), nCountFailures, IsBudgetPropEmpty()); - //if(budget.HasNextFinalizedBudget() || nCountFailures >= 2 || IsBudgetPropEmpty()) { + + // We'll start rejecting votes if we accidentally get set as synced too soon + if (lastBudgetItem > 0 && lastBudgetItem < GetTime() - MASTERNODE_SYNC_TIMEOUT * 2 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) { + + // Hasn't received a new item in the last five seconds, so we'll move to the GetNextAsset(); - //try to activate our masternode if possible + // Try to activate our masternode if possible activeMasternode.ManageStatus(); - // } else { //we've failed to sync, this state will reject the next budget block - // LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed, will retry later\n"); - // RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED; - // RequestedMasternodeAttempt = 0; - // lastFailure = GetTime(); - // nCountFailures++; - // } + return; } diff --git a/src/masternode-sync.h b/src/masternode-sync.h index 9392b736c..d341f02d2 100644 --- a/src/masternode-sync.h +++ b/src/masternode-sync.h @@ -4,6 +4,7 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef MASTERNODE_SYNC_H #define MASTERNODE_SYNC_H diff --git a/src/masternode.cpp b/src/masternode.cpp index 5f5e9f496..a7d81519c 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -169,7 +169,7 @@ uint256 CMasternode::CalculateScore(int mod, int64_t nBlockHeight) uint256 aux = vin.prevout.hash + vin.prevout.n; if (!GetBlockHash(hash, nBlockHeight)) { - LogPrintf("CalculateScore ERROR - nHeight %d - Returned 0\n", nBlockHeight); + LogPrint("masternode","CalculateScore ERROR - nHeight %d - Returned 0\n", nBlockHeight); return 0; } @@ -397,19 +397,19 @@ bool CMasternodeBroadcast::Create(std::string strService, std::string strKeyMast //need correct blocks to send ping if (!fOffline && !masternodeSync.IsBlockchainSynced()) { strErrorRet = "Sync in progress. Must wait until sync is complete to start Masternode"; - LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); + LogPrint("masternode","CMasternodeBroadcast::Create -- %s\n", strErrorRet); return false; } if (!obfuScationSigner.GetKeysFromSecret(strKeyMasternode, keyMasternodeNew, pubKeyMasternodeNew)) { strErrorRet = strprintf("Invalid masternode key %s", strKeyMasternode); - LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); + LogPrint("masternode","CMasternodeBroadcast::Create -- %s\n", strErrorRet); return false; } if (!pwalletMain->GetMasternodeVinAndKeys(txin, pubKeyCollateralAddressNew, keyCollateralAddressNew, strTxHash, strOutputIndex)) { strErrorRet = strprintf("Could not allocate txin %s:%s for masternode %s", strTxHash, strOutputIndex, strService); - LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); + LogPrint("masternode","CMasternodeBroadcast::Create -- %s\n", strErrorRet); return false; } @@ -418,12 +418,12 @@ bool CMasternodeBroadcast::Create(std::string strService, std::string strKeyMast if (Params().NetworkID() == CBaseChainParams::MAIN) { if (service.GetPort() != mainnetDefaultPort) { strErrorRet = strprintf("Invalid port %u for masternode %s, only %d is supported on mainnet.", service.GetPort(), strService, mainnetDefaultPort); - LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); + LogPrint("masternode","CMasternodeBroadcast::Create -- %s\n", strErrorRet); return false; } } else if (service.GetPort() == mainnetDefaultPort) { strErrorRet = strprintf("Invalid port %u for masternode %s, %d is the only supported on mainnet.", service.GetPort(), strService, mainnetDefaultPort); - LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); + LogPrint("masternode","CMasternodeBroadcast::Create -- %s\n", strErrorRet); return false; } @@ -442,8 +442,8 @@ bool CMasternodeBroadcast::Create(CTxIn txin, CService service, CKey keyCollater CMasternodePing mnp(txin); if (!mnp.Sign(keyMasternodeNew, pubKeyMasternodeNew)) { - strErrorRet = strprintf("Failed to sign ping, masternode=%s", txin.prevout.hash.ToString()); - LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); + strErrorRet = strprintf("Failed to sign ping, masternode=%s", txin.prevout.hash.ToString()); + LogPrint("masternode","CMasternodeBroadcast::Create -- %s\n", strErrorRet); mnbRet = CMasternodeBroadcast(); return false; } @@ -451,16 +451,16 @@ bool CMasternodeBroadcast::Create(CTxIn txin, CService service, CKey keyCollater mnbRet = CMasternodeBroadcast(service, txin, pubKeyCollateralAddressNew, pubKeyMasternodeNew, PROTOCOL_VERSION); if (!mnbRet.IsValidNetAddr()) { - strErrorRet = strprintf("Invalid IP address %s, masternode=%s", mnbRet.addr.ToStringIP (), txin.prevout.hash.ToString()); - LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); + strErrorRet = strprintf("Invalid IP address %s, masternode=%s", mnbRet.addr.ToStringIP (), txin.prevout.hash.ToString()); + LogPrint("masternode","CMasternodeBroadcast::Create -- %s\n", strErrorRet); mnbRet = CMasternodeBroadcast(); return false; } mnbRet.lastPing = mnp; if (!mnbRet.Sign(keyCollateralAddressNew)) { - strErrorRet = strprintf("Failed to sign broadcast, masternode=%s", txin.prevout.hash.ToString()); - LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorRet); + strErrorRet = strprintf("Failed to sign broadcast, masternode=%s", txin.prevout.hash.ToString()); + LogPrint("masternode","CMasternodeBroadcast::Create -- %s\n", strErrorRet); mnbRet = CMasternodeBroadcast(); return false; } @@ -472,7 +472,7 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) { // make sure signature isn't in the future (past is OK) if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrintf("mnb - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); + LogPrint("masternode","mnb - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); nDos = 1; return false; } @@ -482,7 +482,7 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) std::string strMessage = addr.ToString() + boost::lexical_cast(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast(protocolVersion); if (protocolVersion < masternodePayments.GetMinMasternodePaymentsProto()) { - LogPrintf("mnb - ignoring outdated Masternode %s protocol version %d\n", vin.prevout.hash.ToString(), protocolVersion); + LogPrint("masternode","mnb - ignoring outdated Masternode %s protocol version %d\n", vin.prevout.hash.ToString(), protocolVersion); return false; } @@ -490,7 +490,7 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) pubkeyScript = GetScriptForDestination(pubKeyCollateralAddress.GetID()); if (pubkeyScript.size() != 25) { - LogPrintf("mnb - pubkey the wrong size\n"); + LogPrint("masternode","mnb - pubkey the wrong size\n"); nDos = 100; return false; } @@ -499,19 +499,19 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) pubkeyScript2 = GetScriptForDestination(pubKeyMasternode.GetID()); if (pubkeyScript2.size() != 25) { - LogPrintf("mnb - pubkey2 the wrong size\n"); + LogPrint("masternode","mnb - pubkey2 the wrong size\n"); nDos = 100; return false; } if (!vin.scriptSig.empty()) { - LogPrintf("mnb - Ignore Not Empty ScriptSig %s\n", vin.prevout.hash.ToString()); + LogPrint("masternode","mnb - Ignore Not Empty ScriptSig %s\n", vin.prevout.hash.ToString()); return false; } std::string errorMessage = ""; if (!obfuScationSigner.VerifyMessage(pubKeyCollateralAddress, sig, strMessage, errorMessage)) { - LogPrintf("mnb - Got bad Masternode address signature\n"); + LogPrint("masternode","mnb - Got bad Masternode address signature\n"); nDos = 100; return false; } @@ -530,8 +530,8 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) else { // this broadcast older than we have, it's bad. if (pmn->sigTime > sigTime) { - LogPrintf("mnb - Bad sigTime %d for Masternode %s (existing broadcast is at %d)\n", - sigTime, vin.prevout.hash.ToString(), pmn->sigTime); + LogPrint("masternode","mnb - Bad sigTime %d for Masternode %s (existing broadcast is at %d)\n", + sigTime, vin.prevout.hash.ToString(), pmn->sigTime); return false; } // masternode is not enabled yet/already, nothing to update @@ -542,7 +542,7 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) // after that they just need to match if (pmn->pubKeyCollateralAddress == pubKeyCollateralAddress && !pmn->IsBroadcastedWithin(MASTERNODE_MIN_MNB_SECONDS)) { //take the newest entry - LogPrint("masternode", "mnb - Got updated entry for %s\n", vin.prevout.hash.ToString()); + LogPrint("masternode","mnb - Got updated entry for %s\n", vin.prevout.hash.ToString()); if (pmn->UpdateFromNewBroadcast((*this))) { pmn->Check(); if (pmn->IsEnabled()) Relay(); @@ -596,7 +596,7 @@ bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDoS) LogPrint("masternode", "mnb - Accepted Masternode entry\n"); if (GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS) { - LogPrintf("mnb - Input must have at least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS); + LogPrint("masternode","mnb - Input must have at least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS); // maybe we miss few blocks, let this mnb to be checked again later mnodeman.mapSeenMasternodeBroadcast.erase(GetHash()); masternodeSync.mapSeenSyncMNB.erase(GetHash()); @@ -613,14 +613,13 @@ bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDoS) CBlockIndex* pMNIndex = (*mi).second; // block for 1000 Bulwark tx -> 1 confirmation CBlockIndex* pConfIndex = chainActive[pMNIndex->nHeight + MASTERNODE_MIN_CONFIRMATIONS - 1]; // block where tx got MASTERNODE_MIN_CONFIRMATIONS if (pConfIndex->GetBlockTime() > sigTime) { - LogPrintf("mnb - Bad sigTime %d for Masternode %s (%i conf block is at %d)\n", - sigTime, vin.prevout.hash.ToString(), MASTERNODE_MIN_CONFIRMATIONS, pConfIndex->GetBlockTime()); - + LogPrint("masternode","mnb - Bad sigTime %d for Masternode %s (%i conf block is at %d)\n", + sigTime, vin.prevout.hash.ToString(), MASTERNODE_MIN_CONFIRMATIONS, pConfIndex->GetBlockTime()); return false; } } - LogPrintf("mnb - Got NEW Masternode entry - %s - %lli \n", vin.prevout.hash.ToString(), sigTime); + LogPrint("masternode","mnb - Got NEW Masternode entry - %s - %lli \n", vin.prevout.hash.ToString(), sigTime); CMasternode mn(*this); mnodeman.Add(mn); @@ -655,12 +654,12 @@ bool CMasternodeBroadcast::Sign(CKey& keyCollateralAddress) std::string strMessage = addr.ToString() + boost::lexical_cast(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast(protocolVersion); if (!obfuScationSigner.SignMessage(strMessage, errorMessage, sig, keyCollateralAddress)) { - LogPrintf("CMasternodeBroadcast::Sign() - Error: %s\n", errorMessage); + LogPrint("masternode","CMasternodeBroadcast::Sign() - Error: %s\n", errorMessage); return false; } if (!obfuScationSigner.VerifyMessage(pubKeyCollateralAddress, sig, strMessage, errorMessage)) { - LogPrintf("CMasternodeBroadcast::Sign() - Error: %s\n", errorMessage); + LogPrint("masternode","CMasternodeBroadcast::Sign() - Error: %s\n", errorMessage); return false; } @@ -693,12 +692,12 @@ bool CMasternodePing::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) std::string strMessage = vin.ToString() + blockHash.ToString() + boost::lexical_cast(sigTime); if (!obfuScationSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) { - LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage); + LogPrint("masternode","CMasternodePing::Sign() - Error: %s\n", errorMessage); return false; } if (!obfuScationSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) { - LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage); + LogPrint("masternode","CMasternodePing::Sign() - Error: %s\n", errorMessage); return false; } @@ -708,25 +707,25 @@ bool CMasternodePing::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled) { if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrintf("CMasternodePing::CheckAndUpdate - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); + LogPrint("masternode","CMasternodePing::CheckAndUpdate - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); nDos = 1; return false; } if (sigTime <= GetAdjustedTime() - 60 * 60) { - LogPrintf("CMasternodePing::CheckAndUpdate - Signature rejected, too far into the past %s - %d %d \n", vin.prevout.hash.ToString(), sigTime, GetAdjustedTime()); + LogPrint("masternode","CMasternodePing::CheckAndUpdate - Signature rejected, too far into the past %s - %d %d \n", vin.prevout.hash.ToString(), sigTime, GetAdjustedTime()); nDos = 1; return false; } - LogPrint("masternode", "CMasternodePing::CheckAndUpdate - New Ping - %s - %lli\n", blockHash.ToString(), sigTime); + LogPrint("masternode","CMasternodePing::CheckAndUpdate - New Ping - %s - %lli\n", blockHash.ToString(), sigTime); // see if we have this Masternode CMasternode* pmn = mnodeman.Find(vin); if (pmn != NULL && pmn->protocolVersion >= masternodePayments.GetMinMasternodePaymentsProto()) { if (fRequireEnabled && !pmn->IsEnabled()) return false; - // LogPrintf("mnping - Found corresponding mn for vin: %s\n", vin.ToString()); + // LogPrint("masternode","mnping - Found corresponding mn for vin: %s\n", vin.ToString()); // update only if there is no known ping for this masternode or // last ping was more then MASTERNODE_MIN_MNP_SECONDS-60 ago comparing to this one if (!pmn->IsPingedWithin(MASTERNODE_MIN_MNP_SECONDS - 60, sigTime)) { @@ -734,7 +733,7 @@ bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled) std::string errorMessage = ""; if (!obfuScationSigner.VerifyMessage(pmn->pubKeyMasternode, vchSig, strMessage, errorMessage)) { - LogPrintf("CMasternodePing::CheckAndUpdate - Got bad Masternode address signature %s\n", vin.prevout.hash.ToString()); + LogPrint("masternode","CMasternodePing::CheckAndUpdate - Got bad Masternode address signature %s\n", vin.prevout.hash.ToString()); nDos = 33; return false; } @@ -742,14 +741,14 @@ bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled) BlockMap::iterator mi = mapBlockIndex.find(blockHash); if (mi != mapBlockIndex.end() && (*mi).second) { if ((*mi).second->nHeight < chainActive.Height() - 24) { - LogPrintf("CMasternodePing::CheckAndUpdate - Masternode %s block hash %s is too old\n", vin.prevout.hash.ToString(), blockHash.ToString()); + LogPrint("masternode","CMasternodePing::CheckAndUpdate - Masternode %s block hash %s is too old\n", vin.prevout.hash.ToString(), blockHash.ToString()); // Do nothing here (no Masternode update, no mnping relay) // Let this node to be visible but fail to accept mnping return false; } } else { - if (fDebug) LogPrintf("CMasternodePing::CheckAndUpdate - Masternode %s block hash %s is unknown\n", vin.prevout.hash.ToString(), blockHash.ToString()); + if (fDebug) LogPrint("masternode","CMasternodePing::CheckAndUpdate - Masternode %s block hash %s is unknown\n", vin.prevout.hash.ToString(), blockHash.ToString()); // maybe we stuck so we shouldn't ban this node, just fail to accept it // TODO: or should we also request this block? @@ -773,7 +772,7 @@ bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled) Relay(); return true; } - LogPrint("masternode", "CMasternodePing::CheckAndUpdate - Masternode ping arrived too early, vin: %s\n", vin.prevout.hash.ToString()); + LogPrint("masternode", "CMasternodePing::CheckAndUpdate - Masternode ping arrived too early, vin: %s\n", vin.prevout.hash.ToString()); //nDos = 1; //disable, this is happening frequently and causing banned peers return false; } diff --git a/src/masternode.h b/src/masternode.h index 417121875..7acbf8b76 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -1,8 +1,8 @@ - // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2017 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 MASTERNODE_H #define MASTERNODE_H diff --git a/src/masternodeconfig.cpp b/src/masternodeconfig.cpp index 5b744873b..7a6e8d70a 100644 --- a/src/masternodeconfig.cpp +++ b/src/masternodeconfig.cpp @@ -1,3 +1,8 @@ +// Copyright (c) 2014-2015 The Dash developers +// Copyright (c) 2015-2017 The PIVX developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + // clang-format off #include "net.h" #include "masternodeconfig.h" diff --git a/src/masternodeconfig.h b/src/masternodeconfig.h index 02eb40901..2b0162215 100644 --- a/src/masternodeconfig.h +++ b/src/masternodeconfig.h @@ -1,4 +1,3 @@ - // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2017 The PIVX developers // Copyright (c) 2017-2018 The Bulwark developers diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 5e49902c2..60d5eebe4 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -78,8 +78,8 @@ bool CMasternodeDB::Write(const CMasternodeMan& mnodemanToSave) // FileCommit(fileout); fileout.fclose(); - LogPrintf("Written info to mncache.dat %dms\n", GetTimeMillis() - nStart); - LogPrintf(" %s\n", mnodemanToSave.ToString()); + LogPrint("masternode","Written info to mncache.dat %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode"," %s\n", mnodemanToSave.ToString()); return true; } @@ -153,13 +153,13 @@ CMasternodeDB::ReadResult CMasternodeDB::Read(CMasternodeMan& mnodemanToLoad, bo return IncorrectFormat; } - LogPrintf("Loaded info from mncache.dat %dms\n", GetTimeMillis() - nStart); - LogPrintf(" %s\n", mnodemanToLoad.ToString()); + LogPrint("masternode","Loaded info from mncache.dat %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode"," %s\n", mnodemanToLoad.ToString()); if (!fDryRun) { - LogPrintf("Masternode manager - cleaning....\n"); + LogPrint("masternode","Masternode manager - cleaning....\n"); mnodemanToLoad.CheckAndRemove(true); - LogPrintf("Masternode manager - result:\n"); - LogPrintf(" %s\n", mnodemanToLoad.ToString()); + LogPrint("masternode","Masternode manager - result:\n"); + LogPrint("masternode"," %s\n", mnodemanToLoad.ToString()); } return Ok; @@ -172,24 +172,24 @@ void DumpMasternodes() CMasternodeDB mndb; CMasternodeMan tempMnodeman; - LogPrintf("Verifying mncache.dat format...\n"); + LogPrint("masternode","Verifying mncache.dat format...\n"); CMasternodeDB::ReadResult readResult = mndb.Read(tempMnodeman, true); // there was an error and it was not an error on file opening => do not proceed if (readResult == CMasternodeDB::FileError) - LogPrintf("Missing masternode cache file - mncache.dat, will try to recreate\n"); + LogPrint("masternode","Missing masternode cache file - mncache.dat, will try to recreate\n"); else if (readResult != CMasternodeDB::Ok) { - LogPrintf("Error reading mncache.dat: "); + LogPrint("masternode","Error reading mncache.dat: "); if (readResult == CMasternodeDB::IncorrectFormat) - LogPrintf("magic is ok but data has invalid format, will try to recreate\n"); + LogPrint("masternode","magic is ok but data has invalid format, will try to recreate\n"); else { - LogPrintf("file format is unknown or invalid, please fix it manually\n"); + LogPrint("masternode","file format is unknown or invalid, please fix it manually\n"); return; } } - LogPrintf("Writting info to mncache.dat...\n"); + LogPrint("masternode","Writting info to mncache.dat...\n"); mndb.Write(mnodeman); - LogPrintf("Masternode dump finished %dms\n", GetTimeMillis() - nStart); + LogPrint("masternode","Masternode dump finished %dms\n", GetTimeMillis() - nStart); } CMasternodeMan::CMasternodeMan() @@ -206,7 +206,7 @@ bool CMasternodeMan::Add(CMasternode& mn) CMasternode* pmn = Find(mn.vin); if (pmn == NULL) { - LogPrint("masternode", "CMasternodeMan: Adding new Masternode %s - %i now\n", mn.vin.prevout.hash.ToString(), size() + 1); + LogPrint("masternode", "CMasternodeMan: Adding new Masternode %s - %i now\n", mn.vin.prevout.hash.ToString(), size() + 1); vMasternodes.push_back(mn); return true; } @@ -223,6 +223,7 @@ void CMasternodeMan::AskForMN(CNode* pnode, CTxIn& vin) } // ask for the mnb info once from the node that sent mnp + LogPrint("masternode", "CMasternodeMan::AskForMN - Asking node for missing entry, vin: %s\n", vin.prevout.hash.ToString()); pnode->PushMessage("dseg", vin); int64_t askAgain = GetTime() + MASTERNODE_MIN_MNP_SECONDS; @@ -251,7 +252,7 @@ void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval) (*it).activeState == CMasternode::MASTERNODE_VIN_SPENT || (forceExpiredRemoval && (*it).activeState == CMasternode::MASTERNODE_EXPIRED) || (*it).protocolVersion < masternodePayments.GetMinMasternodePaymentsProto()) { - LogPrint("masternode", "CMasternodeMan: Removing inactive Masternode %s - %i now\n", (*it).vin.prevout.hash.ToString(), size() - 1); + LogPrint("masternode", "CMasternodeMan: Removing inactive Masternode %s - %i now\n", (*it).vin.prevout.hash.ToString(), size() - 1); //erase all of the broadcasts we've seen from this vin // -- if we missed a few pings and the node was removed, this will allow is to get it back without them @@ -353,26 +354,24 @@ int CMasternodeMan::stable_size () int64_t nMasternode_Min_Age = GetSporkValue(SPORK_16_MN_WINNER_MINIMUM_AGE); int64_t nMasternode_Age = 0; - BOOST_FOREACH (CMasternode& mn, vMasternodes) { - if (mn.protocolVersion < nMinProtocol) { - continue; // Skip obsolete versions - } - - if (IsSporkActive (SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { - nMasternode_Age = GetAdjustedTime() - mn.sigTime; - - if ((nMasternode_Age) < nMasternode_Min_Age) { - continue; // Skip masternodes younger than (default) 8000 sec (MUST be > MASTERNODE_REMOVAL_SECONDS) - } - } + BOOST_FOREACH (CMasternode& mn, vMasternodes) { + if (mn.protocolVersion < nMinProtocol) { + continue; // Skip obsolete versions + } + if (IsSporkActive (SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { + nMasternode_Age = GetAdjustedTime() - mn.sigTime; + if ((nMasternode_Age) < nMasternode_Min_Age) { + continue; // Skip masternodes younger than (default) 8000 sec (MUST be > MASTERNODE_REMOVAL_SECONDS) + } + } + mn.Check (); + if (!mn.IsEnabled ()) + continue; // Skip not-enabled masternodes - mn.Check (); - if (!mn.IsEnabled ()) - continue; // Skip not-enabled masternodes + nStable_size++; + } - nStable_size++; - } - return nStable_size; + return nStable_size; } int CMasternodeMan::CountEnabled(int protocolVersion) @@ -423,7 +422,7 @@ void CMasternodeMan::DsegUpdate(CNode* pnode) std::map::iterator it = mWeAskedForMasternodeList.find(pnode->addr); if (it != mWeAskedForMasternodeList.end()) { if (GetTime() < (*it).second) { - LogPrint("masternode", "dseg - we already asked peer %i for the list; skipping...\n", pnode->GetId()); + LogPrint("masternode", "dseg - we already asked peer %i for the list; skipping...\n", pnode->GetId()); return; } } @@ -603,27 +602,23 @@ int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, in // scan for winner BOOST_FOREACH (CMasternode& mn, vMasternodes) { - if (mn.protocolVersion < minProtocol) { - if (fDebug) { - LogPrintf("Skipping Masternode with obsolete version %d\n", mn.protocolVersion); - } - continue; - } - if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { - nMasternode_Age = GetAdjustedTime() - mn.sigTime; - - if ((nMasternode_Age) < nMasternode_Min_Age) { - if (fDebug) { - LogPrintf("Skipping just activated Masternode. Age: %ld\n", nMasternode_Age); - } - continue; - } - } - - if (fOnlyActive) { + if (mn.protocolVersion < minProtocol) { + LogPrint("masternode","Skipping Masternode with obsolete version %d\n", mn.protocolVersion); + continue; // Skip obsolete versions + } + + if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) { + nMasternode_Age = GetAdjustedTime() - mn.sigTime; + if ((nMasternode_Age) < nMasternode_Min_Age) { + if (fDebug){ + LogPrint("masternode","Skipping just activated Masternode. Age: %ld\n", nMasternode_Age); + } + continue; // Skip masternodes younger than (default) 8000 sec + } + } + if (fOnlyActive) { mn.Check(); if (!mn.IsEnabled()) continue; - } uint256 n = mn.CalculateScore(1, nBlockHeight); int64_t n2 = n.GetCompact(false); @@ -658,8 +653,9 @@ std::vector > CMasternodeMan::GetMasternodeRanks(int64_t mn.Check(); if (mn.protocolVersion < minProtocol) continue; + if (!mn.IsEnabled()) { - vecMasternodeScores.push_back(make_pair(9999, mn)); + vecMasternodeScores.push_back(make_pair(9999, mn)); continue; } @@ -720,7 +716,7 @@ void CMasternodeMan::ProcessMasternodeConnections() BOOST_FOREACH (CNode* pnode, vNodes) { if (pnode->fObfuScationMaster) { if (obfuScationPool.pSubmittedToMasternode != NULL && pnode->addr == obfuScationPool.pSubmittedToMasternode->addr) continue; - LogPrintf("Closing Masternode connection peer=%i \n", pnode->GetId()); + LogPrint("masternode","Closing Masternode connection peer=%i \n", pnode->GetId()); pnode->fObfuScationMaster = false; pnode->Release(); } @@ -756,7 +752,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData // make sure the vout that was signed is related to the transaction that spawned the Masternode // - this is expensive, so it's only done once per Masternode if (!obfuScationSigner.IsVinAssociatedWithPubkey(mnb.vin, mnb.pubKeyCollateralAddress)) { - LogPrintf("mnb - Got mismatched pubkey and vin\n"); + LogPrint("masternode","mnb - Got mismatched pubkey and vin\n"); Misbehaving(pfrom->GetId(), 33); return; } @@ -768,7 +764,8 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData addrman.Add(CAddress(mnb.addr), pfrom->addr, 2 * 60 * 60); masternodeSync.AddedMasternodeList(mnb.GetHash()); } else { - LogPrintf("mnb - Rejected Masternode entry %s\n", mnb.vin.prevout.hash.ToString()); + LogPrint("masternode","mnb - Rejected Masternode entry %s\n", mnb.vin.prevout.hash.ToString()); + if (nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); } @@ -777,7 +774,8 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData else if (strCommand == "mnp") { //Masternode Ping CMasternodePing mnp; vRecv >> mnp; - LogPrint("masternode", "mnp - Masternode ping, vin: %s\n", mnp.vin.prevout.hash.ToString()); + + LogPrint("masternode", "mnp - Masternode ping, vin: %s\n", mnp.vin.prevout.hash.ToString()); if (mapSeenMasternodePing.count(mnp.GetHash())) return; //seen mapSeenMasternodePing.insert(make_pair(mnp.GetHash(), mnp)); @@ -814,7 +812,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData int64_t t = (*i).second; if (GetTime() < t) { Misbehaving(pfrom->GetId(), 34); - LogPrintf("dseg - peer already asked me for the list\n"); + LogPrint("masternode","dseg - peer already asked me for the list\n"); return; } } @@ -830,7 +828,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (mn.addr.IsRFC1918()) continue; //local network if (mn.IsEnabled()) { - LogPrint("masternode", "dseg - Sending Masternode entry - %s \n", mn.vin.prevout.hash.ToString()); + LogPrint("masternode", "dseg - Sending Masternode entry - %s \n", mn.vin.prevout.hash.ToString()); if (vin == CTxIn() || vin == mn.vin) { CMasternodeBroadcast mnb = CMasternodeBroadcast(mn); uint256 hash = mnb.GetHash(); @@ -840,7 +838,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (!mapSeenMasternodeBroadcast.count(hash)) mapSeenMasternodeBroadcast.insert(make_pair(hash, mnb)); if (vin == mn.vin) { - LogPrint("masternode", "dseg - Sent 1 Masternode entry to peer %i\n", pfrom->GetId()); + LogPrint("masternode", "dseg - Sent 1 Masternode entry to peer %i\n", pfrom->GetId()); return; } } @@ -849,7 +847,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (vin == CTxIn()) { pfrom->PushMessage("ssc", MASTERNODE_SYNC_LIST, nInvCount); - LogPrintf("dseg - Sent %d Masternode entries to %s\n", nInvCount, pfrom->addr.ToString()); + LogPrint("masternode", "dseg - Sent %d Masternode entries to peer %i\n", nInvCount, pfrom->GetId()); } } /* @@ -880,7 +878,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData // make sure signature isn't in the future (past is OK) if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrintf("dsee - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); + LogPrint("masternode","dsee - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); Misbehaving(pfrom->GetId(), 1); return; } @@ -891,7 +889,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData strMessage = addr.ToString() + boost::lexical_cast(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast(protocolVersion) + donationAddress.ToString() + boost::lexical_cast(donationPercentage); if (protocolVersion < masternodePayments.GetMinMasternodePaymentsProto()) { - LogPrintf("dsee - ignoring outdated Masternode %s protocol version %d < %d\n", vin.prevout.hash.ToString(), protocolVersion, masternodePayments.GetMinMasternodePaymentsProto()); + LogPrint("masternode","dsee - ignoring outdated Masternode %s protocol version %d < %d\n", vin.prevout.hash.ToString(), protocolVersion, masternodePayments.GetMinMasternodePaymentsProto()); Misbehaving(pfrom->GetId(), 1); return; } @@ -900,7 +898,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData pubkeyScript = GetScriptForDestination(pubkey.GetID()); if (pubkeyScript.size() != 25) { - LogPrintf("dsee - pubkey the wrong size\n"); + LogPrint("masternode","dsee - pubkey the wrong size\n"); Misbehaving(pfrom->GetId(), 100); return; } @@ -909,20 +907,20 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData pubkeyScript2 = GetScriptForDestination(pubkey2.GetID()); if (pubkeyScript2.size() != 25) { - LogPrintf("dsee - pubkey2 the wrong size\n"); + LogPrint("masternode","dsee - pubkey2 the wrong size\n"); Misbehaving(pfrom->GetId(), 100); return; } if (!vin.scriptSig.empty()) { - LogPrintf("dsee - Ignore Not Empty ScriptSig %s\n", vin.prevout.hash.ToString()); + LogPrint("masternode","dsee - Ignore Not Empty ScriptSig %s\n", vin.prevout.hash.ToString()); Misbehaving(pfrom->GetId(), 100); return; } std::string errorMessage = ""; if (!obfuScationSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)) { - LogPrintf("dsee - Got bad Masternode address signature\n"); + LogPrint("masternode","dsee - Got bad Masternode address signature\n"); Misbehaving(pfrom->GetId(), 100); return; } @@ -942,7 +940,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (count == -1 && pmn->pubKeyCollateralAddress == pubkey && (GetAdjustedTime() - pmn->nLastDsee > MASTERNODE_MIN_MNB_SECONDS)) { if (pmn->protocolVersion > GETHEADERS_VERSION && sigTime - pmn->lastPing.sigTime < MASTERNODE_MIN_MNB_SECONDS) return; if (pmn->nLastDsee < sigTime) { //take the newest entry - LogPrint("masternode", "dsee - Got updated entry for %s\n", vin.prevout.hash.ToString()); + LogPrint("masternode", "dsee - Got updated entry for %s\n", vin.prevout.hash.ToString()); if (pmn->protocolVersion < GETHEADERS_VERSION) { pmn->pubKeyMasternode = pubkey2; pmn->sigTime = sigTime; @@ -976,12 +974,13 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData // make sure the vout that was signed is related to the transaction that spawned the Masternode // - this is expensive, so it's only done once per Masternode if (!obfuScationSigner.IsVinAssociatedWithPubkey(vin, pubkey)) { - LogPrintf("dsee - Got mismatched pubkey and vin\n"); + LogPrint("masternode","dsee - Got mismatched pubkey and vin\n"); Misbehaving(pfrom->GetId(), 100); return; } - LogPrint("masternode", "dsee - Got NEW OLD Masternode entry %s\n", vin.prevout.hash.ToString()); + + LogPrint("masternode", "dsee - Got NEW OLD Masternode entry %s\n", vin.prevout.hash.ToString()); // make sure it's still unspent // - this is checked later by .check() in many places and by ThreadCheckObfuScationPool() @@ -1001,7 +1000,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (fAcceptable) { if (GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS) { - LogPrintf("dsee - Input must have least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS); + LogPrint("masternode","dsee - Input must have least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS); Misbehaving(pfrom->GetId(), 20); return; } @@ -1016,8 +1015,8 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData CBlockIndex* pMNIndex = (*mi).second; // block for 5000 BWK tx -> 1 confirmation CBlockIndex* pConfIndex = chainActive[pMNIndex->nHeight + MASTERNODE_MIN_CONFIRMATIONS - 1]; // block where tx got MASTERNODE_MIN_CONFIRMATIONS if (pConfIndex->GetBlockTime() > sigTime) { - LogPrintf("mnb - Bad sigTime %d for Masternode %s (%i conf block is at %d)\n", - sigTime, vin.prevout.hash.ToString(), MASTERNODE_MIN_CONFIRMATIONS, pConfIndex->GetBlockTime()); + LogPrint("masternode","mnb - Bad sigTime %d for Masternode %s (%i conf block is at %d)\n", + sigTime, vin.prevout.hash.ToString(), MASTERNODE_MIN_CONFIRMATIONS, pConfIndex->GetBlockTime()); return; } } @@ -1050,12 +1049,12 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData pnode->PushMessage("dsee", vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion, donationAddress, donationPercentage); } } else { - LogPrintf("dsee - Rejected Masternode entry %s\n", vin.prevout.hash.ToString()); + LogPrint("masternode","dsee - Rejected Masternode entry %s\n", vin.prevout.hash.ToString()); int nDoS = 0; if (state.IsInvalid(nDoS)) { - LogPrintf("dsee - %s from %i %s was not accepted into the memory pool\n", tx.GetHash().ToString().c_str(), - pfrom->GetId(), pfrom->cleanSubVer.c_str()); + LogPrint("masternode","dsee - %s from %i %s was not accepted into the memory pool\n", tx.GetHash().ToString().c_str(), + pfrom->GetId(), pfrom->cleanSubVer.c_str()); if (nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); } @@ -1072,16 +1071,16 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData bool stop; vRecv >> vin >> vchSig >> sigTime >> stop; - //LogPrintf("dseep - Received: vin: %s sigTime: %lld stop: %s\n", vin.ToString().c_str(), sigTime, stop ? "true" : "false"); + //LogPrint("masternode","dseep - Received: vin: %s sigTime: %lld stop: %s\n", vin.ToString().c_str(), sigTime, stop ? "true" : "false"); if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrintf("dseep - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); - Misbehaving(pfrom->GetId(), 1); + LogPrint("masternode","dseep - Signature rejected, too far into the future %s\n", vin.prevout.hash.ToString()); + Misbehaving(pfrom->GetId(), 1); return; } if (sigTime <= GetAdjustedTime() - 60 * 60) { - LogPrintf("dseep - Signature rejected, too far into the past %s - %d %d \n", vin.prevout.hash.ToString(), sigTime, GetAdjustedTime()); + LogPrint("masternode","dseep - Signature rejected, too far into the past %s - %d %d \n", vin.prevout.hash.ToString(), sigTime, GetAdjustedTime()); Misbehaving(pfrom->GetId(), 1); return; } @@ -1095,14 +1094,14 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData // see if we have this Masternode CMasternode* pmn = this->Find(vin); if (pmn != NULL && pmn->protocolVersion >= masternodePayments.GetMinMasternodePaymentsProto()) { - // LogPrintf("dseep - Found corresponding mn for vin: %s\n", vin.ToString().c_str()); + // LogPrint("masternode","dseep - Found corresponding mn for vin: %s\n", vin.ToString().c_str()); // take this only if it's newer if (sigTime - pmn->nLastDseep > MASTERNODE_MIN_MNP_SECONDS) { std::string strMessage = pmn->addr.ToString() + boost::lexical_cast(sigTime) + boost::lexical_cast(stop); std::string errorMessage = ""; if (!obfuScationSigner.VerifyMessage(pmn->pubKeyMasternode, vchSig, strMessage, errorMessage)) { - LogPrintf("dseep - Got bad Masternode address signature %s \n", vin.prevout.hash.ToString()); + LogPrint("masternode","dseep - Got bad Masternode address signature %s \n", vin.prevout.hash.ToString()); //Misbehaving(pfrom->GetId(), 100); return; } @@ -1114,7 +1113,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (pmn->IsEnabled()) { TRY_LOCK(cs_vNodes, lockNodes); if (!lockNodes) return; - LogPrint("masternode", "dseep - relaying %s \n", vin.ToString().c_str()); + LogPrint("masternode", "dseep - relaying %s \n", vin.prevout.hash.ToString()); BOOST_FOREACH (CNode* pnode, vNodes) if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) pnode->PushMessage("dseep", vin, vchSig, sigTime, stop); @@ -1123,7 +1122,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData return; } - LogPrint("masternode", "dseep - Couldn't find Masternode entry %s peer=%i\n", vin.prevout.hash.ToString(), pfrom->GetId()); + LogPrint("masternode", "dseep - Couldn't find Masternode entry %s peer=%i\n", vin.prevout.hash.ToString(), pfrom->GetId()); AskForMN(pfrom, vin); } @@ -1140,7 +1139,7 @@ void CMasternodeMan::Remove(CTxIn vin) vector::iterator it = vMasternodes.begin(); while (it != vMasternodes.end()) { if ((*it).vin == vin) { - LogPrint("masternode", "CMasternodeMan: Removing Masternode %s - %i now\n", (*it).vin.prevout.hash.ToString(), size() - 1); + LogPrint("masternode", "CMasternodeMan: Removing Masternode %s - %i now\n", (*it).vin.prevout.hash.ToString(), size() - 1); vMasternodes.erase(it); break; } @@ -1154,7 +1153,7 @@ void CMasternodeMan::UpdateMasternodeList(CMasternodeBroadcast mnb) mapSeenMasternodePing.insert(std::make_pair(mnb.lastPing.GetHash(), mnb.lastPing)); mapSeenMasternodeBroadcast.insert(std::make_pair(mnb.GetHash(), mnb)); - LogPrintf("CMasternodeMan::UpdateMasternodeList -- masternode=%s addr=%s\n", mnb.vin.prevout.ToStringShort(), mnb.addr.ToString()); + LogPrint("masternode","CMasternodeMan::UpdateMasternodeList -- masternode=%s\n", mnb.vin.prevout.ToStringShort()); CMasternode* pmn = Find(mnb.vin); if (pmn == NULL) { diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index b0f0ee314..04ec86723 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -126,7 +127,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector& vMatch) if (nTransactions == 0) return 0; // check for excessively high numbers of transactions - if (nTransactions > MAX_BLOCK_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction + if (nTransactions > MAX_BLOCK_SIZE_CURRENT / 60) // 60 is the lower bound for the size of a serialized CTransaction return 0; // there can never be more hashes provided than one for every txid if (vHash.size() > nTransactions) diff --git a/src/miner.cpp b/src/miner.cpp index 27bdc7d94..16c73ae69 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -23,6 +23,8 @@ #include "wallet.h" #endif #include "masternode-payments.h" +#include "accumulators.h" +#include "spork.h" #include #include @@ -96,7 +98,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, CReserveKey reservekey(pwallet); // Create new block - auto_ptr pblocktemplate(new CBlockTemplate()); + unique_ptr pblocktemplate(new CBlockTemplate()); if (!pblocktemplate.get()) return NULL; CBlock* pblock = &pblocktemplate->block; // pointer for convenience @@ -106,6 +108,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, if (Params().MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); + // Make sure to create the correct block version after zerocoin is enabled + bool fZerocoinActive = GetAdjustedTime() > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN); + if (fZerocoinActive) + pblock->nVersion = 4; + else + pblock->nVersion = 3; + // Create coinbase tx CMutableTransaction txNew; txNew.vin.resize(1); @@ -147,7 +156,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: - nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE - 1000), nBlockMaxSize)); + unsigned int nBlockMaxSizeNetwork = pblock->nTime > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN) ? MAX_BLOCK_SIZE_CURRENT : MAX_BLOCK_SIZE_LEGACY; + nBlockMaxSize = std::max((unsigned int)1000, std::min((nBlockMaxSizeNetwork - 1000), nBlockMaxSize)); // How much of the block should be dedicated to high-priority transactions, // included regardless of the fees they pay @@ -180,14 +190,24 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, for (map::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) { const CTransaction& tx = mi->second.GetTx(); - if (tx.IsCoinBase() || tx.IsCoinStake() || !IsFinalTx(tx, nHeight)) + if (tx.IsCoinBase() || tx.IsCoinStake() || !IsFinalTx(tx, nHeight)){ + continue; + } + if(GetAdjustedTime() > GetSporkValue(SPORK_22_ZEROCOIN_MAINTENANCE_MODE) && tx.ContainsZerocoins()){ continue; + } COrphan* porphan = NULL; double dPriority = 0; CAmount nTotalIn = 0; bool fMissingInputs = false; - BOOST_FOREACH (const CTxIn& txin, tx.vin) { + for (const CTxIn& txin : tx.vin) { + //zerocoinspend has special vin + if (tx.IsZerocoinSpend()) { + nTotalIn = tx.GetZerocoinSpent(); + break; + } + // Read prev transaction if (!view.HaveCoins(txin.prevout.hash)) { // This should never happen; all transactions in the memory @@ -213,6 +233,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue; continue; } + const CCoins* coins = view.AccessCoins(txin.prevout.hash); assert(coins); @@ -250,6 +271,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, TxPriorityCompare comparer(fSortedByFee); std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); + vector vBlockSerials; + vector vTxSerials; while (!vecPriority.empty()) { // Take highest priority transaction off the priority queue: double dPriority = vecPriority.front().get<0>(); @@ -265,8 +288,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, continue; // Legacy limits on sigOps: + unsigned int nMaxBlockSigOps = GetAdjustedTime() > GetSporkValue(SPORK_21_ENABLE_ZEROCOIN) ? MAX_BLOCK_SIGOPS_CURRENT : MAX_BLOCK_SIGOPS_LEGACY; unsigned int nTxSigOps = GetLegacySigOpCount(tx); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + if (nBlockSigOps + nTxSigOps >= nMaxBlockSigOps) continue; // Skip free transactions if we're past the minimum block size: @@ -274,7 +298,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, double dPriorityDelta = 0; CAmount nFeeDelta = 0; mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); - if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) + if (!tx.IsZerocoinSpend() && 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 @@ -289,10 +313,36 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, if (!view.HaveInputs(tx)) continue; + // double check that there are no double spent zBWK spends in this block or tx + if (tx.IsZerocoinSpend()) { + 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); + if (!spend.HasValidSerial(Params().Zerocoin_Params())) + fDoubleSerial = true; + if (count(vBlockSerials.begin(), vBlockSerials.end(), spend.getCoinSerialNumber())) + fDoubleSerial = true; + if (count(vTxSerials.begin(), vTxSerials.end(), spend.getCoinSerialNumber())) + fDoubleSerial = true; + if (fDoubleSerial) + break; + vTxSerials.emplace_back(spend.getCoinSerialNumber()); + } + } + //This zBWK serial has already been included in the block, do not add this tx. + if (fDoubleSerial) + continue; + } + CAmount nTxFees = view.GetValueIn(tx) - tx.GetValueOut(); nTxSigOps += GetP2SHSigOpCount(tx, view); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + if (nBlockSigOps + nTxSigOps >= nMaxBlockSigOps) continue; // Note that flags: we don't want to set mempool/IsStandard() @@ -314,6 +364,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, nBlockSigOps += nTxSigOps; nFees += nTxFees; + for (const CBigNum bnSerial : vTxSerials) + vBlockSerials.emplace_back(bnSerial); + if (fPrintPriority) { LogPrintf("priority %.1f fee %s txid %s\n", dPriority, feeRate.ToString(), tx.GetHash().ToString()); @@ -348,12 +401,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); + // Compute final coinbase transaction. if (!fProofOfStake) { pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; } - pblock->vtx[0].vin[0].scriptSig = CScript() << nHeight << OP_0; + pblock->vtx[0].vin[0].scriptSig = CScript() << nHeight << OP_0; // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); @@ -361,11 +415,17 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, UpdateTime(pblock, pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nNonce = 0; + uint256 nCheckpoint = 0; + if(fZerocoinActive && !CalculateAccumulatorCheckpoint(nHeight, nCheckpoint)){ + LogPrintf("%s: failed to get accumulator checkpoint\n", __func__); + } + pblock->nAccumulatorCheckpoint = nCheckpoint; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); CValidationState state; if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) { LogPrintf("CreateNewBlock() : TestBlockValidity failed\n"); + mempool.clear(); return NULL; } } @@ -435,6 +495,10 @@ bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) if (!ProcessNewBlock(state, NULL, pblock)) return error("BulwarkMiner : ProcessNewBlock, block not accepted"); + for (CNode* node : vNodes) { + node->PushInventory(CInv(MSG_BLOCK, pblock->GetHash())); + } + return true; } @@ -469,7 +533,8 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake) continue; } - while (vNodes.empty() || pwallet->IsLocked() || !fMintableCoins || nReserveBalance >= pwallet->GetBalance() || !masternodeSync.IsSynced()) { + while (chainActive.Tip()->nTime < 1529610000 || vNodes.empty() || pwallet->IsLocked() || !fMintableCoins || + nReserveBalance >= pwallet->GetBalance() || !masternodeSync.IsSynced()) { nLastCoinStakeSearchInterval = 0; MilliSleep(5000); if (!fGenerateBitcoins && !fProofOfStake) @@ -494,7 +559,7 @@ void BitcoinMiner(CWallet* pwallet, bool fProofOfStake) if (!pindexPrev) continue; - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwallet, fProofOfStake)); + unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwallet, fProofOfStake)); if (!pblocktemplate.get()) continue; diff --git a/src/net.cpp b/src/net.cpp index 9ac72aeb3..1b80aa556 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -571,10 +571,29 @@ bool CNode::Unban(const CSubNet& subNet) return false; } -void CNode::GetBanned(banmap_t &banMap) +bool CNode::BannedIsDirty() { LOCK(cs_setBanned); - banMap = setBanned; // thread safe copy + return setBannedIsDirty; +} + +void CNode::GetBanned(banmap_t &banmap) +{ + LOCK(cs_setBanned); + banmap = setBanned; // thread safe copy +} + +void CNode::SetBanned(const banmap_t &banmap) +{ + LOCK(cs_setBanned); + setBanned = banmap; + setBannedIsDirty = true; +} + +void CNode::SetBannedIsDirty(bool dirty) +{ + LOCK(cs_setBanned); + setBannedIsDirty = dirty; } std::vector CNode::vWhitelistedRange; @@ -819,8 +838,13 @@ void ThreadSocketHandler() } } } - if (vNodes.size() != nPrevNodeCount) { - nPrevNodeCount = vNodes.size(); + size_t vNodesSize; + { + LOCK(cs_vNodes); + vNodesSize = vNodes.size(); + } + if(vNodesSize != nPrevNodeCount) { + nPrevNodeCount = vNodesSize; uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount); } @@ -1663,11 +1687,29 @@ void StartNode(boost::thread_group& threadGroup) int64_t nStart = GetTimeMillis(); { CAddrDB adb; - if (!adb.Read(addrman)) + if (!adb.Read(addrman)) { LogPrintf("Invalid or missing peers.dat; recreating\n"); + DumpAddresses(); + } + } + LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman.size(), GetTimeMillis() - nStart); + + uiInterface.InitMessage(_("Loading banlist...")); + // Load addresses from banlist.dat + nStart = GetTimeMillis(); + CBanDB bandb; + banmap_t banmap; + if (bandb.Read(banmap)) { + CNode::SetBanned(banmap); + CNode::SetBannedIsDirty(false); + CNode::SweepBanned(); + + LogPrint("net", "Loaded %i address from banlist.dat %dms\n", banmap.size(), GetTimeMillis() - nStart); + } else { + LogPrintf("Invalid or missing banlist.dat; recreating\n"); + CNode::SetBannedIsDirty(true); + CNode::DumpBanlist(); } - LogPrintf("Loaded %i addresses from peers.dat %dms\n", - addrman.size(), GetTimeMillis() - nStart); fAddressesInitialized = true; if (semOutbound == NULL) { diff --git a/src/net.h b/src/net.h index f5a646e7b..4009e862f 100644 --- a/src/net.h +++ b/src/net.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -641,7 +642,10 @@ class CNode static void DumpBanlist(); static bool Unban(const CNetAddr& ip); static bool Unban(const CSubNet& subNet); - static void GetBanned(banmap_t &banMap); + static bool BannedIsDirty(); + static void GetBanned(banmap_t &banmap); + static void SetBanned(const banmap_t &banmap); + static void SetBannedIsDirty(bool dirty=true); void copyStats(CNodeStats& stats); //!clean unused entries (if bantime has expired) static void SweepBanned(); diff --git a/src/netbase.cpp b/src/netbase.cpp index 53ce1c433..0754ca836 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -12,6 +12,7 @@ #include "hash.h" #include "sync.h" #include "uint256.h" +#include "random.h" #include "util.h" #include "utilstrencodings.h" @@ -38,7 +39,7 @@ using namespace std; // Settings static proxyType proxyInfo[NET_MAX]; -static CService nameProxy; +static proxyType nameProxy; static CCriticalSection cs_proxyInfos; int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; bool fNameLookup = false; @@ -290,18 +291,33 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock return len == 0; } -bool static Socks5(string strDest, int port, SOCKET& hSocket) +struct ProxyCredentials +{ + std::string username; + std::string password; +}; + +/** Connect using SOCKS5 (as described in RFC1928) */ +bool static Socks5(string strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket) { LogPrintf("SOCKS5 connecting %s\n", strDest); if (strDest.size() > 255) { CloseSocket(hSocket); return error("Hostname too long"); } - char pszSocks5Init[] = "\5\1\0"; - ssize_t nSize = sizeof(pszSocks5Init) - 1; - - ssize_t ret = send(hSocket, pszSocks5Init, nSize, MSG_NOSIGNAL); - if (ret != nSize) { + // Accepted authentication methods + std::vector vSocks5Init; + vSocks5Init.push_back(0x05); + if (auth) { + vSocks5Init.push_back(0x02); // # METHODS + vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED + vSocks5Init.push_back(0x02); // X'02' USERNAME/PASSWORD (RFC1929) + } else { + vSocks5Init.push_back(0x01); // # METHODS + vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED + } + ssize_t ret = send(hSocket, (const char*)begin_ptr(vSocks5Init), vSocks5Init.size(), MSG_NOSIGNAL); + if (ret != (ssize_t)vSocks5Init.size()) { CloseSocket(hSocket); return error("Error sending to proxy"); } @@ -310,19 +326,52 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket) CloseSocket(hSocket); return error("Error reading proxy response"); } - if (pchRet1[0] != 0x05 || pchRet1[1] != 0x00) { + if (pchRet1[0] != 0x05) { CloseSocket(hSocket); return error("Proxy failed to initialize"); } - string strSocks5("\5\1"); - strSocks5 += '\000'; - strSocks5 += '\003'; - strSocks5 += static_cast(std::min((int)strDest.size(), 255)); - strSocks5 += strDest; - strSocks5 += static_cast((port >> 8) & 0xFF); - strSocks5 += static_cast((port >> 0) & 0xFF); - ret = send(hSocket, strSocks5.data(), strSocks5.size(), MSG_NOSIGNAL); - if (ret != (ssize_t)strSocks5.size()) { + if (pchRet1[1] == 0x02 && auth) { + // Perform username/password authentication (as described in RFC1929) + std::vector vAuth; + vAuth.push_back(0x01); + if (auth->username.size() > 255 || auth->password.size() > 255) + return error("Proxy username or password too long"); + vAuth.push_back(auth->username.size()); + vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end()); + vAuth.push_back(auth->password.size()); + vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end()); + ret = send(hSocket, (const char*)begin_ptr(vAuth), vAuth.size(), MSG_NOSIGNAL); + if (ret != (ssize_t)vAuth.size()) { + CloseSocket(hSocket); + return error("Error sending authentication to proxy"); + } + LogPrint("proxy", "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password); + char pchRetA[2]; + if (!InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) { + CloseSocket(hSocket); + return error("Error reading proxy authentication response"); + } + if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) { + CloseSocket(hSocket); + return error("Proxy authentication unsuccesful"); + } + } else if (pchRet1[1] == 0x00) { + // Perform no authentication + } else { + CloseSocket(hSocket); + return error("Proxy requested wrong authentication method %02x", pchRet1[1]); + } + std::vector vSocks5; + vSocks5.push_back(0x05); // VER protocol version + vSocks5.push_back(0x01); // CMD CONNECT + vSocks5.push_back(0x00); // RSV Reserved + vSocks5.push_back(0x03); // ATYP DOMAINNAME + vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function + vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end()); + vSocks5.push_back((port >> 8) & 0xFF); + vSocks5.push_back((port >> 0) & 0xFF); + ret = send(hSocket, (const char*)begin_ptr(vSocks5), vSocks5.size(), MSG_NOSIGNAL); + if (ret != (ssize_t)vSocks5.size()) { CloseSocket(hSocket); return error("Error sending to proxy"); } @@ -473,7 +522,7 @@ bool static ConnectSocketDirectly(const CService& addrConnect, SOCKET& hSocketRe return true; } -bool SetProxy(enum Network net, CService addrProxy) +bool SetProxy(enum Network net, const proxyType &addrProxy) { assert(net >= 0 && net < NET_MAX); if (!addrProxy.IsValid()) @@ -493,7 +542,7 @@ bool GetProxy(enum Network net, proxyType& proxyInfoOut) return true; } -bool SetNameProxy(CService addrProxy) +bool SetNameProxy(const proxyType &addrProxy) { if (!addrProxy.IsValid()) return false; @@ -502,7 +551,7 @@ bool SetNameProxy(CService addrProxy) return true; } -bool GetNameProxy(CService& nameProxyOut) +bool GetNameProxy(proxyType &nameProxyOut) { LOCK(cs_proxyInfos); if (!nameProxy.IsValid()) @@ -521,37 +570,49 @@ bool IsProxy(const CNetAddr& addr) { LOCK(cs_proxyInfos); for (int i = 0; i < NET_MAX; i++) { - if (addr == (CNetAddr)proxyInfo[i]) + if (addr == (CNetAddr)proxyInfo[i].proxy) return true; } return false; } -bool ConnectSocket(const CService& addrDest, SOCKET& hSocketRet, int nTimeout, bool* outProxyConnectionFailed) +static bool ConnectThroughProxy(const proxyType &proxy, const std::string strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed) { - proxyType proxy; - if (outProxyConnectionFailed) - *outProxyConnectionFailed = false; - // no proxy needed (none set for target network) - if (!GetProxy(addrDest.GetNetwork(), proxy)) - return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout); - SOCKET hSocket = INVALID_SOCKET; - // first connect to proxy server - if (!ConnectSocketDirectly(proxy, hSocket, nTimeout)) { + if (!ConnectSocketDirectly(proxy.proxy, hSocket, nTimeout)) { if (outProxyConnectionFailed) *outProxyConnectionFailed = true; return false; } // do socks negotiation - if (!Socks5(addrDest.ToStringIP(), addrDest.GetPort(), hSocket)) - return false; + if (proxy.randomize_credentials) { + ProxyCredentials random_auth; + random_auth.username = strprintf("%i", insecure_rand()); + random_auth.password = strprintf("%i", insecure_rand()); + if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket)) + return false; + } else { + if (!Socks5(strDest, (unsigned short)port, 0, hSocket)) + return false; + } hSocketRet = hSocket; return true; } +bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed) +{ + proxyType proxy; + if (outProxyConnectionFailed) + *outProxyConnectionFailed = false; + + if (GetProxy(addrDest.GetNetwork(), proxy)) + return ConnectThroughProxy(proxy, addrDest.ToStringIP(), addrDest.GetPort(), hSocketRet, nTimeout, outProxyConnectionFailed); + else // no proxy needed (none set for target network) + return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout); +} + bool ConnectSocketByName(CService& addr, SOCKET& hSocketRet, const char* pszDest, int portDefault, int nTimeout, bool* outProxyConnectionFailed) { string strDest; @@ -562,9 +623,7 @@ bool ConnectSocketByName(CService& addr, SOCKET& hSocketRet, const char* pszDest SplitHostPort(string(pszDest), port, strDest); - SOCKET hSocket = INVALID_SOCKET; - - CService nameProxy; + proxyType nameProxy; GetNameProxy(nameProxy); CService addrResolved(CNetAddr(strDest, fNameLookup && !HaveNameProxy()), port); @@ -577,18 +636,7 @@ bool ConnectSocketByName(CService& addr, SOCKET& hSocketRet, const char* pszDest if (!HaveNameProxy()) return false; - // first connect to name proxy server - if (!ConnectSocketDirectly(nameProxy, hSocket, nTimeout)) { - if (outProxyConnectionFailed) - *outProxyConnectionFailed = true; - return false; - } - // do socks negotiation - if (!Socks5(strDest, (unsigned short)port, hSocket)) - return false; - - hSocketRet = hSocket; - return true; + return ConnectThroughProxy(nameProxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed); } void CNetAddr::Init() diff --git a/src/netbase.h b/src/netbase.h index 14dbbbc29..1cb536e07 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -21,6 +21,8 @@ extern bool fNameLookup; /** -timeout default */ static const int DEFAULT_CONNECT_TIMEOUT = 5000; +//! -dns default +static const int DEFAULT_NAME_LOOKUP = true; #ifdef WIN32 // In MSVC, this is defined as a macro, undefine it to prevent a compile and link error @@ -182,15 +184,25 @@ class CService : public CNetAddr } }; -typedef CService proxyType; +class proxyType +{ +public: + proxyType(): randomize_credentials(false) {} + proxyType(const CService &proxy, bool randomize_credentials=false): proxy(proxy), randomize_credentials(randomize_credentials) {} + + bool IsValid() const { return proxy.IsValid(); } + + CService proxy; + bool randomize_credentials; +}; enum Network ParseNetwork(std::string net); std::string GetNetworkName(enum Network net); void SplitHostPort(std::string in, int& portOut, std::string& hostOut); -bool SetProxy(enum Network net, CService addrProxy); +bool SetProxy(enum Network net, const proxyType &addrProxy); bool GetProxy(enum Network net, proxyType& proxyInfoOut); bool IsProxy(const CNetAddr& addr); -bool SetNameProxy(CService addrProxy); +bool SetNameProxy(const proxyType &addrProxy); bool HaveNameProxy(); bool LookupHost(const char* pszName, std::vector& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); bool Lookup(const char* pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); diff --git a/src/obfuscation-relay.cpp b/src/obfuscation-relay.cpp index ec7a81e0c..e020d815f 100644 --- a/src/obfuscation-relay.cpp +++ b/src/obfuscation-relay.cpp @@ -1,7 +1,10 @@ +// Copyright (c) 2014-2015 The Dash developers +// Copyright (c) 2015-2017 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 "obfuscation-relay.h" - CObfuScationRelay::CObfuScationRelay() { vinMasternode = CTxIn(); diff --git a/src/obfuscation-relay.h b/src/obfuscation-relay.h index d7b5d60d5..24189eb85 100644 --- a/src/obfuscation-relay.h +++ b/src/obfuscation-relay.h @@ -1,4 +1,3 @@ - // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2017 The PIVX developers // Copyright (c) 2017-2018 The Bulwark developers diff --git a/src/obfuscation.cpp b/src/obfuscation.cpp index 64c2af00c..28d405b3d 100644 --- a/src/obfuscation.cpp +++ b/src/obfuscation.cpp @@ -803,7 +803,7 @@ void CObfuscationPool::ChargeRandomFees() // void CObfuscationPool::CheckTimeout() { - if (!fEnableObfuscation && !fMasterNode) return; + if (!fEnableZeromint && !fMasterNode) return; // catching hanging sessions if (!fMasterNode) { @@ -888,7 +888,7 @@ void CObfuscationPool::CheckTimeout() // void CObfuscationPool::CheckForCompleteQueue() { - if (!fEnableObfuscation && !fMasterNode) return; + if (!fEnableZeromint && !fMasterNode) return; /* Check to see if we're ready for submissions from clients */ // @@ -1147,7 +1147,7 @@ void CObfuscationPool::SendObfuscationDenominate(std::vector& vin, std::v if (!CheckDiskSpace()) { UnlockCoins(); SetNull(); - fEnableObfuscation = false; + fEnableZeromint = false; LogPrintf("CObfuscationPool::SendObfuscationDenominate() - Not enough disk space, disabling Obfuscation.\n"); return; } @@ -1381,7 +1381,9 @@ void CObfuscationPool::ClearLastMessage() // bool CObfuscationPool::DoAutomaticDenominating(bool fDryRun) { - if (!fEnableObfuscation) return false; + 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) { @@ -1451,7 +1453,7 @@ bool CObfuscationPool::DoAutomaticDenominating(bool fDryRun) 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, nObfuscationRounds)) { + if (!pwalletMain->SelectCoinsDark(nValueMin, nBalanceNeedsAnonymized, vCoins, nValueIn, 0, nZeromintPercentage)) { nValueIn = 0; vCoins.clear(); @@ -1556,7 +1558,7 @@ bool CObfuscationPool::DoAutomaticDenominating(bool fDryRun) std::vector vTempCoins; std::vector vTempCoins2; // Try to match their denominations if possible - if (!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nValueMin, nBalanceNeedsAnonymized, vTempCoins, vTempCoins2, nValueIn, 0, nObfuscationRounds)) { + if (!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nValueMin, nBalanceNeedsAnonymized, vTempCoins, vTempCoins2, nValueIn, 0, nZeromintPercentage)) { LogPrintf("DoAutomaticDenominating --- Couldn't match denominations %d\n", dsq.nDenom); continue; } @@ -1649,14 +1651,14 @@ 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 < nObfuscationRounds; i++) { + 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, nObfuscationRounds); + strError = pwalletMain->PrepareObfuscationDenominate(0, nZeromintPercentage); LogPrintf("DoAutomaticDenominating : Running Obfuscation denominate for all rounds. Return '%s'\n", strError); if (strError == "") return true; @@ -1668,8 +1670,8 @@ bool CObfuscationPool::PrepareObfuscationDenominate() bool CObfuscationPool::SendRandomPaymentToSelf() { - CAmount nBalance = pwalletMain->GetBalance(); - CAmount nPayment = (nBalance * 0.35) + (rand() % nBalance); + int64_t nBalance = pwalletMain->GetBalance(); + int64_t nPayment = (nBalance * 0.35) + (rand() % nBalance); if (nPayment > nBalance) nPayment = nBalance - (0.1 * COIN); diff --git a/src/obfuscation.h b/src/obfuscation.h index 9f6db36ed..791268a79 100644 --- a/src/obfuscation.h +++ b/src/obfuscation.h @@ -412,11 +412,11 @@ class CObfuscationPool void UpdateState(unsigned int newState) { if (fMasterNode && (newState == POOL_STATUS_ERROR || newState == POOL_STATUS_SUCCESS)) { - LogPrint("obfuscation", "CObfuscationPool::UpdateState() - Can't set state to ERROR or SUCCESS as a Masternode. \n"); + // LogPrint("obfuscation", "CObfuscationPool::UpdateState() - Can't set state to ERROR or SUCCESS as a Masternode. \n"); return; } - LogPrintf("CObfuscationPool::UpdateState() == %d | %d \n", state, newState); + // LogPrintf("CObfuscationPool::UpdateState() == %d | %d \n", state, newState); if (state != newState) { lastTimeChanged = GetTimeMillis(); if (fMasterNode) { diff --git a/src/pow.cpp b/src/pow.cpp index 957f6ab5a..581438c3f 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index f877920ec..089fcb5e4 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -1,5 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers +// Copyright (c) 2017-2018 The Bulwark developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,13 +12,17 @@ #include "tinyformat.h" #include "script/standard.h" #include "script/sign.h" +#include "tinyformat.h" #include "utilstrencodings.h" #include "crypto/common.h" #include "util.h" uint256 CBlockHeader::GetHash() const { - return Nist5(BEGIN(nVersion), END(nNonce)); + if(nVersion < 4) + return Nist5(BEGIN(nVersion), END(nNonce)); + + return Hash(BEGIN(nVersion), END(nAccumulatorCheckpoint)); } uint256 CBlock::BuildMerkleTree(bool* fMutated) const diff --git a/src/primitives/block.h b/src/primitives/block.h index c45f78fce..8e6332e64 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,7 +13,8 @@ #include "uint256.h" /** The maximum allowed size for a serialized block, in bytes (network rule) */ -static const unsigned int MAX_BLOCK_SIZE = 1000000; +static const unsigned int MAX_BLOCK_SIZE_CURRENT = 2000000; +static const unsigned int MAX_BLOCK_SIZE_LEGACY = 1000000; /** Nodes collect new transactions into a block, hash them into a hash tree, * and scan through nonce values to make the block's hash satisfy proof-of-work @@ -25,13 +27,14 @@ class CBlockHeader { public: // header - static const int32_t CURRENT_VERSION=3; + static const int32_t CURRENT_VERSION=4; int32_t nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; uint32_t nTime; uint32_t nBits; uint32_t nNonce; + uint256 nAccumulatorCheckpoint; CBlockHeader() { @@ -49,6 +52,10 @@ class CBlockHeader READWRITE(nTime); READWRITE(nBits); READWRITE(nNonce); + + //zerocoin active, header changes to include accumulator checksum + if(nVersion > 3) + READWRITE(nAccumulatorCheckpoint); } void SetNull() @@ -59,6 +66,7 @@ class CBlockHeader nTime = 0; nBits = 0; nNonce = 0; + nAccumulatorCheckpoint = 0; } bool IsNull() const @@ -127,6 +135,7 @@ class CBlock : public CBlockHeader block.nTime = nTime; block.nBits = nBits; block.nNonce = nNonce; + block.nAccumulatorCheckpoint = nAccumulatorCheckpoint; return block; } diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 64c5c420a..1eae65fb3 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,6 +12,7 @@ #include "main.h" #include "tinyformat.h" #include "utilstrencodings.h" +#include "transaction.h" #include @@ -51,7 +53,10 @@ std::string CTxIn::ToString() const str += "CTxIn("; str += prevout.ToString(); if (prevout.IsNull()) - str += strprintf(", coinbase %s", HexStr(scriptSig)); + if(scriptSig.IsZerocoinSpend()) + str += strprintf(", zerocoinspend %s", HexStr(scriptSig)); + else + str += strprintf(", coinbase %s", HexStr(scriptSig)); else str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24)); if (nSequence != std::numeric_limits::max()) @@ -147,6 +152,68 @@ CAmount CTransaction::GetValueOut() const return nValueOut; } +CAmount CTransaction::GetZerocoinMinted() const +{ + for (const CTxOut txOut : vout) { + if(!txOut.scriptPubKey.IsZerocoinMint()) + continue; + + return txOut.nValue; + } + + return CAmount(0); +} + +bool CTransaction::UsesUTXO(const COutPoint out) +{ + for (const CTxIn in : vin) { + if (in.prevout == out) + return true; + } + + return false; +} + +std::list CTransaction::GetOutPoints() const +{ + std::list listOutPoints; + uint256 txHash = GetHash(); + for (unsigned int i = 0; i < vout.size(); i++) + listOutPoints.emplace_back(COutPoint(txHash, i)); + return listOutPoints; +} + +CAmount CTransaction::GetZerocoinSpent() const +{ + if(!IsZerocoinSpend()) + return 0; + + CAmount nValueOut = 0; + for (const CTxIn txin : vin) { + if(!txin.scriptSig.IsZerocoinSpend()) + LogPrintf("%s is not zcspend\n", __func__); + + std::vector > dataTxIn; + dataTxIn.insert(dataTxIn.end(), txin.scriptSig.begin() + 4, txin.scriptSig.end()); + + CDataStream serializedCoinSpend(dataTxIn, SER_NETWORK, PROTOCOL_VERSION); + libzerocoin::CoinSpend spend(Params().Zerocoin_Params(), serializedCoinSpend); + nValueOut += libzerocoin::ZerocoinDenominationToAmount(spend.getDenomination()); + } + + return nValueOut; +} + +int CTransaction::GetZerocoinMintCount() const +{ + int nCount = 0; + for (const CTxOut out : vout) { + if (out.scriptPubKey.IsZerocoinMint()) + nCount++; + } + return nCount; +} + double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const { nTxSize = CalculateModifiedSize(nTxSize); diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 9f01a97e3..fe921855b 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,6 +12,8 @@ #include "serialize.h" #include "uint256.h" +#include + class CTransaction; /** An outpoint - a combination of a transaction hash and an index n into its vout */ @@ -157,17 +160,22 @@ class CTxOut bool IsDust(CFeeRate minRelayTxFee) const { - // "Dust" is defined in terms of CTransaction::minRelayTxFee, which has units duffs-per-kilobyte. + // "Dust" is defined in terms of CTransaction::minRelayTxFee, which has units ubwk-per-kilobyte. // If you'd pay more than 1/3 in fees to spend something, then we consider it dust. // A typical txout is 34 bytes big, and will need a CTxIn of at least 148 bytes to spend - // i.e. total is 148 + 32 = 182 bytes. Default -minrelaytxfee is 10000 duffs per kB - // and that means that fee per txout is 182 * 10000 / 1000 = 1820 duffs. - // So dust is a txout less than 1820 *3 = 5460 duffs - // with default -minrelaytxfee = minRelayTxFee = 10000 duffs per kB. + // i.e. total is 148 + 32 = 182 bytes. Default -minrelaytxfee is 10000 ubwk per kB + // and that means that fee per txout is 182 * 10000 / 1000 = 1820 ubwk. + // So dust is a txout less than 1820 *3 = 5460 ubwk + // with default -minrelaytxfee = minRelayTxFee = 10000 ubwk per kB. size_t nSize = GetSerializeSize(SER_DISK,0)+148u; return (nValue < 3*minRelayTxFee.GetFee(nSize)); } + bool IsZerocoinMint() const + { + return !scriptPubKey.empty() && scriptPubKey.IsZerocoinMint(); + } + friend bool operator==(const CTxOut& a, const CTxOut& b) { return (a.nValue == b.nValue && @@ -249,9 +257,35 @@ 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.IsNull() && vin[0].scriptSig[0] == OP_ZEROCOINSPEND); + } + + bool IsZerocoinMint() const + { + for(const CTxOut& txout : vout) { + if (txout.scriptPubKey.IsZerocoinMint()) + return true; + } + return false; + } + + bool ContainsZerocoins() const + { + return IsZerocoinSpend() || IsZerocoinMint(); + } + + CAmount GetZerocoinMinted() const; + CAmount GetZerocoinSpent() const; + int GetZerocoinMintCount() const; + + bool UsesUTXO(const COutPoint out); + std::list GetOutPoints() const; + bool IsCoinBase() const { - return (vin.size() == 1 && vin[0].prevout.IsNull()); + return (vin.size() == 1 && vin[0].prevout.IsNull() && !ContainsZerocoins()); } bool IsCoinStake() const diff --git a/src/primitives/zerocoin.cpp b/src/primitives/zerocoin.cpp new file mode 100644 index 000000000..af57c865b --- /dev/null +++ b/src/primitives/zerocoin.cpp @@ -0,0 +1,37 @@ +// Copyright (c) 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 "primitives/zerocoin.h" + +void CZerocoinSpendReceipt::AddSpend(const CZerocoinSpend& spend) +{ + vSpends.emplace_back(spend); +} + +std::vector CZerocoinSpendReceipt::GetSpends() +{ + return vSpends; +} + +void CZerocoinSpendReceipt::SetStatus(std::string strStatus, int nStatus, int nNeededSpends) +{ + strStatusMessage = strStatus; + this->nStatus = nStatus; + this->nNeededSpends = nNeededSpends; +} + +std::string CZerocoinSpendReceipt::GetStatusMessage() +{ + return strStatusMessage; +} + +int CZerocoinSpendReceipt::GetStatus() +{ + return nStatus; +} + +int CZerocoinSpendReceipt::GetNeededSpends() +{ + return nNeededSpends; +} diff --git a/src/primitives/zerocoin.h b/src/primitives/zerocoin.h new file mode 100644 index 000000000..5671337a3 --- /dev/null +++ b/src/primitives/zerocoin.h @@ -0,0 +1,192 @@ +// Copyright (c) 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 BWK_ZEROCOIN_H +#define BWK_ZEROCOIN_H + +#include +#include +#include "libzerocoin/bignum.h" +#include "libzerocoin/Denominations.h" +#include "serialize.h" + +class CZerocoinMint +{ +private: + libzerocoin::CoinDenomination denomination; + int nHeight; + CBigNum value; + CBigNum randomness; + CBigNum serialNumber; + uint256 txid; + bool isUsed; + +public: + CZerocoinMint() + { + SetNull(); + } + + CZerocoinMint(libzerocoin::CoinDenomination denom, CBigNum value, CBigNum randomness, CBigNum serialNumber, bool isUsed) + { + SetNull(); + this->denomination = denom; + this->value = value; + this->randomness = randomness; + this->serialNumber = serialNumber; + this->isUsed = isUsed; + } + + void SetNull() + { + isUsed = false; + randomness = 0; + value = 0; + denomination = libzerocoin::ZQ_ERROR; + nHeight = 0; + txid = 0; + } + + uint256 GetHash() const; + + CBigNum GetValue() const { return value; } + void SetValue(CBigNum value){ this->value = value; } + libzerocoin::CoinDenomination GetDenomination() const { return denomination; } + int64_t GetDenominationAsAmount() const { return denomination * COIN; } + void SetDenomination(libzerocoin::CoinDenomination denom){ this->denomination = denom; } + int GetHeight() const { return nHeight; } + void SetHeight(int nHeight){ this->nHeight = nHeight; } + bool IsUsed() const { return this->isUsed; } + void SetUsed(bool isUsed){ this->isUsed = isUsed; } + CBigNum GetRandomness() const{ return randomness; } + void SetRandomness(CBigNum rand){ this->randomness = rand; } + CBigNum GetSerialNumber() const { return serialNumber; } + void SetSerialNumber(CBigNum serial){ this->serialNumber = serial; } + uint256 GetTxHash() const { return this->txid; } + void SetTxHash(uint256 txid) { this->txid = txid; } + + inline bool operator <(const CZerocoinMint& a) const { return GetHeight() < a.GetHeight(); } + + CZerocoinMint(const CZerocoinMint& other) { + denomination = other.GetDenomination(); + nHeight = other.GetHeight(); + value = other.GetValue(); + randomness = other.GetRandomness(); + serialNumber = other.GetSerialNumber(); + txid = other.GetTxHash(); + isUsed = other.IsUsed(); + } + + bool operator == (const CZerocoinMint& other) const + { + return this->GetValue() == other.GetValue(); + } + + // Copy another CZerocoinMint + inline CZerocoinMint& operator=(const CZerocoinMint& other) { + denomination = other.GetDenomination(); + nHeight = other.GetHeight(); + value = other.GetValue(); + randomness = other.GetRandomness(); + serialNumber = other.GetSerialNumber(); + txid = other.GetTxHash(); + isUsed = other.IsUsed(); + return *this; + } + + // why 6 below (SPOCK) + inline bool checkUnused(int denom, int Height) const { + if (IsUsed() == false && GetDenomination() == denomination && GetRandomness() != 0 && GetSerialNumber() != 0 && GetHeight() != -1 && GetHeight() != INT_MAX && GetHeight() >= 1 && (GetHeight() + 6 <= Height)) { + return true; + } else { + return false; + } + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(isUsed); + READWRITE(randomness); + READWRITE(serialNumber); + READWRITE(value); + READWRITE(denomination); + READWRITE(nHeight); + READWRITE(txid); + }; +}; + +class CZerocoinSpend +{ +private: + CBigNum coinSerial; + uint256 hashTx; + CBigNum pubCoin; + libzerocoin::CoinDenomination denomination; + unsigned int nAccumulatorChecksum; + int nMintCount; //memory only - the amount of mints that belong to the accumulator this is spent from + +public: + CZerocoinSpend() + { + SetNull(); + } + + CZerocoinSpend(CBigNum coinSerial, uint256 hashTx, CBigNum pubCoin, libzerocoin::CoinDenomination denomination, unsigned int nAccumulatorChecksum) + { + this->coinSerial = coinSerial; + this->hashTx = hashTx; + this->pubCoin = pubCoin; + this->denomination = denomination; + this->nAccumulatorChecksum = nAccumulatorChecksum; + } + + void SetNull() + { + coinSerial = 0; + hashTx = 0; + pubCoin = 0; + denomination = libzerocoin::ZQ_ERROR; + } + + CBigNum GetSerial() const { return coinSerial; } + uint256 GetTxHash() const { return hashTx; } + void SetTxHash(uint256 hash) { this->hashTx = hash; } + CBigNum GetPubCoin() const { return pubCoin; } + libzerocoin::CoinDenomination GetDenomination() const { return denomination; } + unsigned int GetAccumulatorChecksum() const { return this->nAccumulatorChecksum; } + uint256 GetHash() const; + void SetMintCount(int nMintsAdded) { this->nMintCount = nMintsAdded; } + int GetMintCount() const { return nMintCount; } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(coinSerial); + READWRITE(hashTx); + READWRITE(pubCoin); + READWRITE(denomination); + READWRITE(nAccumulatorChecksum); + }; +}; + +class CZerocoinSpendReceipt +{ +private: + std::string strStatusMessage; + int nStatus; + int nNeededSpends; + std::vector vSpends; + +public: + void AddSpend(const CZerocoinSpend& spend); + std::vector GetSpends(); + void SetStatus(std::string strStatus, int nStatus, int nNeededSpends = 0); + std::string GetStatusMessage(); + int GetStatus(); + int GetNeededSpends(); +}; + +#endif //BWK_ZEROCOIN_H diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 14d4bf901..13594f00e 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -18,19 +18,23 @@ const QString AddressTableModel::Send = "S"; const QString AddressTableModel::Receive = "R"; +const QString AddressTableModel::Zerocoin = "X"; struct AddressTableEntry { enum Type { Sending, Receiving, + Zerocoin, Hidden /* QSortFilterProxyModel will filter these out */ }; Type type; QString label; QString address; + QString pubcoin; AddressTableEntry() {} + AddressTableEntry(Type type, const QString &pubcoin): type(type), pubcoin(pubcoin) {} AddressTableEntry(Type type, const QString& label, const QString& address) : type(type), label(label), address(address) {} }; @@ -137,6 +141,43 @@ class AddressTablePriv break; } } + + void updateEntry(const QString &pubCoin, const QString &isUsed, int status) + { + // Find address / label in model + QList::iterator lower = qLowerBound( + cachedAddressTable.begin(), cachedAddressTable.end(), pubCoin, AddressTableEntryLessThan()); + QList::iterator upper = qUpperBound( + cachedAddressTable.begin(), cachedAddressTable.end(), pubCoin, AddressTableEntryLessThan()); + int lowerIndex = (lower - cachedAddressTable.begin()); + bool inModel = (lower != upper); + AddressTableEntry::Type newEntryType = AddressTableEntry::Zerocoin; + + switch(status) + { + case CT_NEW: + if(inModel) + { + qWarning() << "AddressTablePriv_ZC::updateEntry : Warning: Got CT_NEW, but entry is already in model"; + } + parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); + cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, isUsed, pubCoin)); + parent->endInsertRows(); + break; + case CT_UPDATED: + if(!inModel) + { + qWarning() << "AddressTablePriv_ZC::updateEntry : Warning: Got CT_UPDATED, but entry is not in model"; + break; + } + lower->type = newEntryType; + lower->label = isUsed; + parent->emitDataChanged(lowerIndex); + break; + } + + } + int size() { @@ -310,6 +351,15 @@ void AddressTableModel::updateEntry(const QString& address, priv->updateEntry(address, label, isMine, purpose, status); } + +void AddressTableModel::updateEntry(const QString &pubCoin, const QString &isUsed, int status) +{ + // Update stealth address book model from Bitcoin core + priv->updateEntry(pubCoin, isUsed, status); +} + + + QString AddressTableModel::addRow(const QString& type, const QString& label, const QString& address) { std::string strLabel = label.toStdString(); diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 09eda7560..6e384bb7b 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -45,6 +45,7 @@ class AddressTableModel : public QAbstractTableModel static const QString Send; /**< Specifies send address */ static const QString Receive; /**< Specifies receive address */ + static const QString Zerocoin; /**< Specifies stealth address */ /** @name Methods overridden from QAbstractTableModel @{*/ @@ -88,7 +89,7 @@ public slots: /* Update address list from core. */ void updateEntry(const QString& address, const QString& label, bool isMine, const QString& purpose, int status); - + void updateEntry(const QString &pubCoin, const QString &isUsed, int status); friend class AddressTablePriv; }; diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index d8d979db0..3d0f7bab8 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -9,6 +9,7 @@ #include "ui_askpassphrasedialog.h" #include "guiconstants.h" +#include "guiutil.h" #include "walletmodel.h" #include "allocators.h" @@ -25,6 +26,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel fCapsLock(false) { ui->setupUi(this); + this->setStyleSheet(GUIUtil::loadStyleSheet()); ui->passEdit1->setMinimumSize(ui->passEdit1->sizeHint()); ui->passEdit2->setMinimumSize(ui->passEdit2->sizeHint()); diff --git a/src/qt/bip38tooldialog.cpp b/src/qt/bip38tooldialog.cpp index be1babbc2..6aa7a4670 100644 --- a/src/qt/bip38tooldialog.cpp +++ b/src/qt/bip38tooldialog.cpp @@ -153,7 +153,7 @@ void Bip38ToolDialog::on_encryptKeyButton_ENC_clicked() return; } - std::string encryptedKey = BIP38_Encrypt(addr.ToString(), qstrPassphrase.toStdString(), key.GetPrivKey_256()); + std::string encryptedKey = BIP38_Encrypt(addr.ToString(), qstrPassphrase.toStdString(), key.GetPrivKey_256(), key.IsCompressed()); ui->encryptedKeyOut_ENC->setText(QString::fromStdString(encryptedKey)); } diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index 5ac392c5f..d4b95509e 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -6,6 +6,7 @@ #include "bitcoinunits.h" #include "guiconstants.h" +#include "guiutil.h" #include "qvaluecombobox.h" #include @@ -182,7 +183,16 @@ class AmountSpinBox : public QAbstractSpinBox BitcoinAmountField::BitcoinAmountField(QWidget* parent) : QWidget(parent), amount(0) { + this->setObjectName("BitcoinAmountField"); // ID as CSS-reference + // For whatever reasons the Gods of Qt-CSS-manipulation won't let us change this class' stylesheet in the CSS file. + // Workaround for the people after me: + // - name all UI objects, preferably with a unique name + // - address those names globally in the CSS file + amount = new AmountSpinBox(this); + // According to the Qt-CSS specs this should work, but doesn't + amount->setStyleSheet("QSpinBox::up-button:hover { background-color: #f2f2f2; }" + "QSpinBox::down-button:hover { background-color: #f2f2f2; }"); amount->setLocale(QLocale::c()); amount->installEventFilter(this); amount->setMaximumWidth(170); @@ -231,7 +241,9 @@ bool BitcoinAmountField::validate() void BitcoinAmountField::setValid(bool valid) { if (valid) - amount->setStyleSheet(""); + // According to the Qt-CSS specs this should work, but doesn't + amount->setStyleSheet("QSpinBox::up-button:hover { background-color: #f2f2f2 }" + "QSpinBox::down-button:hover { background-color: #f2f2f2 }"); else amount->setStyleSheet(STYLE_INVALID); } diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 62431f194..f6293a505 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1,7 +1,6 @@ // Copyright (c) 2011-2014 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers // Copyright (c) 2015-2017 The PIVX developers -// Copyright (c) 2017-2018 The Bulwark developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -90,9 +89,9 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai signMessageAction(0), verifyMessageAction(0), bip38ToolAction(0), - multisigCreateAction(0), - multisigSpendAction(0), - multisigSignAction(0), + multisigCreateAction(0), + multisigSpendAction(0), + multisigSignAction(0), aboutAction(0), receiveCoinsAction(0), optionsAction(0), @@ -194,8 +193,13 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai frameBlocksLayout->setSpacing(3); unitDisplayControl = new UnitDisplayStatusBarControl(); labelStakingIcon = new QLabel(); - labelEncryptionIcon = new QLabel(); + labelEncryptionIcon = new QPushButton(); + labelEncryptionIcon->setObjectName("labelEncryptionIcon"); + labelEncryptionIcon->setFlat(true); // Make the button look like a label, but clickable + labelEncryptionIcon->setStyleSheet(".QPushButton { background-color: rgba(255, 255, 255, 0);}"); + labelEncryptionIcon->setMaximumSize(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE); labelConnectionsIcon = new QPushButton(); + labelConnectionsIcon->setObjectName("labelConnectionsIcon"); labelConnectionsIcon->setFlat(true); // Make the button look like a label, but clickable labelConnectionsIcon->setStyleSheet(".QPushButton { background-color: rgba(255, 255, 255, 0);}"); labelConnectionsIcon->setMaximumSize(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE); @@ -218,6 +222,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai // Progress bar and label for blocks download progressBarLabel = new QLabel(); progressBarLabel->setVisible(true); + progressBarLabel->setObjectName("progressBarLabel"); progressBar = new GUIUtil::ProgressBar(); progressBar->setAlignment(Qt::AlignCenter); progressBar->setVisible(true); @@ -244,6 +249,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle* networkStyle, QWidget* parent) : QMai connect(openMNConfEditorAction, SIGNAL(triggered()), rpcConsole, SLOT(showMNConfEditor())); connect(showBackupsAction, SIGNAL(triggered()), rpcConsole, SLOT(showBackups())); connect(labelConnectionsIcon, SIGNAL(clicked()), rpcConsole, SLOT(showPeers())); + connect(labelEncryptionIcon, SIGNAL(clicked()), walletFrame, SLOT(toggleLockWallet())); // Get restart command-line parameters and handle restart connect(rpcConsole, SIGNAL(handleRestart(QStringList)), this, SLOT(handleRestart(QStringList))); @@ -327,12 +333,23 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) historyAction->setToolTip(historyAction->statusTip()); historyAction->setCheckable(true); #ifdef Q_OS_MAC - historyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_4)); + historyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_5)); #else - historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4)); + historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); #endif tabGroup->addAction(historyAction); + privacyAction = new QAction(QIcon(":/icons/privacy_m"), tr("&Privacy"), this); + privacyAction->setStatusTip(tr("Privacy Actions for zBWK")); + privacyAction->setToolTip(privacyAction->statusTip()); + privacyAction->setCheckable(true); +#ifdef Q_OS_MAC + privacyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_5)); +#else + privacyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); +#endif + tabGroup->addAction(privacyAction); + #ifdef ENABLE_WALLET QSettings settings; @@ -342,9 +359,9 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) masternodeAction->setToolTip(masternodeAction->statusTip()); masternodeAction->setCheckable(true); #ifdef Q_OS_MAC - masternodeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_5)); + masternodeAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_6)); #else - masternodeAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_5)); + masternodeAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_6)); #endif tabGroup->addAction(masternodeAction); connect(masternodeAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); @@ -359,6 +376,8 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage())); connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage())); + connect(privacyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(privacyAction, SIGNAL(triggered()), this, SLOT(gotoPrivacyPage())); connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); #endif // ENABLE_WALLET @@ -466,9 +485,9 @@ void BitcoinGUI::createActions(const NetworkStyle* networkStyle) connect(usedReceivingAddressesAction, SIGNAL(triggered()), walletFrame, SLOT(usedReceivingAddresses())); connect(openAction, SIGNAL(triggered()), this, SLOT(openClicked())); connect(multiSendAction, SIGNAL(triggered()), this, SLOT(gotoMultiSendDialog())); - connect(multisigCreateAction, SIGNAL(triggered()), this, SLOT(gotoMultisigCreate())); - connect(multisigSpendAction, SIGNAL(triggered()), this, SLOT(gotoMultisigSpend())); - connect(multisigSignAction, SIGNAL(triggered()), this, SLOT(gotoMultisigSign())); + connect(multisigCreateAction, SIGNAL(triggered()), this, SLOT(gotoMultisigCreate())); + connect(multisigSpendAction, SIGNAL(triggered()), this, SLOT(gotoMultisigSpend())); + connect(multisigSignAction, SIGNAL(triggered()), this, SLOT(gotoMultisigSign())); } #endif // ENABLE_WALLET } @@ -494,10 +513,10 @@ void BitcoinGUI::createMenuBar() file->addAction(usedSendingAddressesAction); file->addAction(usedReceivingAddressesAction); file->addSeparator(); - file->addAction(multisigCreateAction); - file->addAction(multisigSpendAction); - file->addAction(multisigSignAction); - file->addSeparator(); + file->addAction(multisigCreateAction); + file->addAction(multisigSpendAction); + file->addAction(multisigSignAction); + file->addSeparator(); } file->addAction(quitAction); @@ -548,7 +567,9 @@ void BitcoinGUI::createToolBars() toolbar->addAction(overviewAction); toolbar->addAction(sendCoinsAction); toolbar->addAction(receiveCoinsAction); + toolbar->addAction(privacyAction); toolbar->addAction(historyAction); + toolbar->addAction(privacyAction); QSettings settings; if (settings.value("fShowMasternodesTab").toBool()) { toolbar->addAction(masternodeAction); @@ -573,7 +594,6 @@ void BitcoinGUI::createToolBars() } } - void BitcoinGUI::setClientModel(ClientModel* clientModel) { this->clientModel = clientModel; @@ -602,6 +622,12 @@ void BitcoinGUI::setClientModel(ClientModel* clientModel) } #endif // ENABLE_WALLET unitDisplayControl->setOptionsModel(clientModel->getOptionsModel()); + + //Show trayIcon + if (trayIcon) + { + trayIcon->show(); + } } else { // Disable possibility to show main window via action toggleHideAction->setEnabled(false); @@ -642,6 +668,7 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) overviewAction->setEnabled(enabled); sendCoinsAction->setEnabled(enabled); receiveCoinsAction->setEnabled(enabled); + privacyAction->setEnabled(enabled); historyAction->setEnabled(enabled); QSettings settings; if (settings.value("fShowMasternodesTab").toBool()) { @@ -668,7 +695,7 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle* networkStyle) QString toolTip = tr("Bulwark Core client") + " " + networkStyle->getTitleAddText(); trayIcon->setToolTip(toolTip); trayIcon->setIcon(networkStyle->getAppIcon()); - trayIcon->show(); + trayIcon->hide(); #endif notificator = new Notificator(QApplication::applicationName(), trayIcon, this); @@ -698,6 +725,7 @@ void BitcoinGUI::createTrayIconMenu() trayIconMenu->addSeparator(); trayIconMenu->addAction(sendCoinsAction); trayIconMenu->addAction(receiveCoinsAction); + trayIconMenu->addAction(privacyAction); trayIconMenu->addSeparator(); trayIconMenu->addAction(signMessageAction); trayIconMenu->addAction(verifyMessageAction); @@ -793,6 +821,12 @@ void BitcoinGUI::gotoReceiveCoinsPage() if (walletFrame) walletFrame->gotoReceiveCoinsPage(); } +void BitcoinGUI::gotoPrivacyPage() +{ + privacyAction->setChecked(true); + if (walletFrame) walletFrame->gotoPrivacyPage(); +} + void BitcoinGUI::gotoSendCoinsPage(QString addr) { sendCoinsAction->setChecked(true); @@ -964,7 +998,7 @@ void BitcoinGUI::setNumBlocks(int count) } progressBarLabel->setVisible(true); - progressBar->setFormat(tr("%1 behind. Scanning block %2").arg(timeBehindText).arg(count)); + progressBar->setFormat(tr("%1 behind. Scanning block %2").arg(timeBehindText).arg(count)); progressBar->setMaximum(1000000000); progressBar->setValue(clientModel->getVerificationProgress() * 1000000000.0 + 0.5); progressBar->setVisible(true); @@ -1085,19 +1119,22 @@ void BitcoinGUI::closeEvent(QCloseEvent* event) #ifdef ENABLE_WALLET void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address) { - // On new transaction, make an info balloon - message((amount) < 0 ? (pwalletMain->fMultiSendNotify == true ? tr("Sent MultiSend transaction") : tr("Sent transaction")) : tr("Incoming transaction"), - tr("Date: %1\n" - "Amount: %2\n" - "Type: %3\n" - "Address: %4\n") - .arg(date) - .arg(BitcoinUnits::formatWithUnit(unit, amount, true)) - .arg(type) - .arg(address), - CClientUIInterface::MSG_INFORMATION); - - pwalletMain->fMultiSendNotify = false; + // Only send notifications when not disabled + if(!bdisableSystemnotifications){ + // On new transaction, make an info balloon + message((amount) < 0 ? (pwalletMain->fMultiSendNotify == true ? tr("Sent MultiSend transaction") : tr("Sent transaction")) : tr("Incoming transaction"), + tr("Date: %1\n" + "Amount: %2\n" + "Type: %3\n" + "Address: %4\n") + .arg(date) + .arg(BitcoinUnits::formatWithUnit(unit, amount, true)) + .arg(type) + .arg(address), + CClientUIInterface::MSG_INFORMATION); + + pwalletMain->fMultiSendNotify = false; + } } #endif // ENABLE_WALLET @@ -1141,7 +1178,7 @@ void BitcoinGUI::setStakingStatus() else tooltip.append("false\n"); tooltip.append("mintablecoins: "); - if (!pwalletMain->MintableCoins()) + if (pwalletMain->MintableCoins()) tooltip.append("true\n"); else tooltip.append("false\n"); @@ -1198,7 +1235,7 @@ void BitcoinGUI::setEncryptionStatus(int status) break; case WalletModel::Unlocked: labelEncryptionIcon->show(); - labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); + labelEncryptionIcon->setIcon(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently unlocked")); encryptWalletAction->setChecked(true); changePassphraseAction->setEnabled(true); @@ -1208,7 +1245,7 @@ void BitcoinGUI::setEncryptionStatus(int status) break; case WalletModel::UnlockedForAnonymizationOnly: labelEncryptionIcon->show(); - labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); + labelEncryptionIcon->setIcon(QIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently unlocked for anonymization and staking only")); encryptWalletAction->setChecked(true); changePassphraseAction->setEnabled(true); @@ -1218,7 +1255,7 @@ void BitcoinGUI::setEncryptionStatus(int status) break; case WalletModel::Locked: labelEncryptionIcon->show(); - labelEncryptionIcon->setPixmap(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); + labelEncryptionIcon->setIcon(QIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); labelEncryptionIcon->setToolTip(tr("Wallet is encrypted and currently locked")); encryptWalletAction->setChecked(true); changePassphraseAction->setEnabled(true); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 89044c924..123cb1140 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -83,7 +83,7 @@ class BitcoinGUI : public QMainWindow UnitDisplayStatusBarControl* unitDisplayControl; QLabel* labelStakingIcon; - QLabel* labelEncryptionIcon; + QPushButton* labelEncryptionIcon; QPushButton* labelConnectionsIcon; QLabel* labelBlocksIcon; QLabel* progressBarLabel; @@ -106,6 +106,7 @@ class BitcoinGUI : public QMainWindow QAction* multisigSignAction; QAction* aboutAction; QAction* receiveCoinsAction; + QAction* privacyAction; QAction* optionsAction; QAction* toggleHideAction; QAction* encryptWalletAction; @@ -204,8 +205,10 @@ private slots: void gotoBlockExplorerPage(); /** Switch to masternode page */ void gotoMasternodePage(); - /** Switch to receive coins page */ + /** Switch to privacy page */ void gotoReceiveCoinsPage(); + /** Switch to receive coins page */ + void gotoPrivacyPage(); /** Switch to send coins page */ void gotoSendCoinsPage(QString addr = ""); diff --git a/src/qt/blockexplorer.cpp b/src/qt/blockexplorer.cpp index b54f926d5..2e67df7fb 100644 --- a/src/qt/blockexplorer.cpp +++ b/src/qt/blockexplorer.cpp @@ -3,6 +3,7 @@ #include "chainparams.h" #include "clientmodel.h" #include "core_io.h" +#include "guiutil.h" #include "main.h" #include "net.h" #include "txdb.h" @@ -433,6 +434,8 @@ BlockExplorer::BlockExplorer(QWidget* parent) : QMainWindow(parent), { ui->setupUi(this); + this->setStyleSheet(GUIUtil::loadStyleSheet()); + connect(ui->pushSearch, SIGNAL(released()), this, SLOT(onSearch())); connect(ui->content, SIGNAL(linkActivated(const QString&)), this, SLOT(goTo(const QString&))); connect(ui->back, SIGNAL(released()), this, SLOT(back())); @@ -547,10 +550,11 @@ void BlockExplorer::setBlock(CBlockIndex* pBlock) } void BlockExplorer::setContent(const std::string& Content) -{ - QString CSS = "body {font-size:12px; background-color: #C8E5E2; color:#444;}\n a, span { font-family: monospace; }\n span.addr {color:#13BE5D; font-weight: bold;}\n table tr td {padding: 3px; border: none; background-color: #A1CDC8;}\n td.d0 {font-weight: bold; color:#f8f8f8;}\n h2, h3 { white-space:nowrap; color:#1B7884;}\n a { text-decoration:none; }\n a.nav {color:green;}\n"; +{ + QString CSS = "body {font-size:12px; color:#f8f6f6; bgcolor:#0091ea;}\n a, span { font-family: monospace; }\n span.addr {color:#0091ea; font-weight: bold;}\n table tr td {padding: 3px; border: 1px solid black; background-color: #0091ea;}\n td.d0 {font-weight: bold; color:#f8f6f6;}\n h2, h3 { white-space:nowrap; color:#0091ea;}\n a { color:#ffffff; text-decoration:none; }\n a:hover { color:#cccccc; }\n a.nav {color:#0091ea;}\n"; QString FullContent = "" + "" + Content.c_str() + ""; // printf(FullContent.toUtf8()); + ui->content->setText(FullContent); } diff --git a/src/qt/bulwark.cpp b/src/qt/bulwark.cpp index 5d6207601..db1e6a53d 100644 --- a/src/qt/bulwark.cpp +++ b/src/qt/bulwark.cpp @@ -574,6 +574,18 @@ int main(int argc, char* argv[]) initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); uiInterface.Translate.connect(Translate); +#ifdef Q_OS_MAC +#if __clang_major__ < 4 + QString s = QSysInfo::kernelVersion(); + std::string ver_info = s.toStdString(); + // ver_info will be like 17.2.0 for High Sierra. Check if true and exit if build via cross-compile + if (ver_info[0] == '1' && ver_info[1] == '7') { + QMessageBox::critical(0, "Unsupported", BitcoinGUI::tr("High Sierra not supported with this build") + QString("\n\n")); + ::exit(1); + } +#endif +#endif + // Show help message immediately after parsing command-line options (for "-lang") and setting locale, // but before showing splash screen. if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) { @@ -598,7 +610,7 @@ int main(int argc, char* argv[]) } catch (std::exception& e) { QMessageBox::critical(0, QObject::tr("Bulwark Core"), QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what())); - return false; + return 0; } /// 7. Determine network (and switch to network specific options) @@ -630,7 +642,7 @@ int main(int argc, char* argv[]) if (!masternodeConfig.read(strErr)) { QMessageBox::critical(0, QObject::tr("Bulwark Core"), QObject::tr("Error reading masternode configuration file: %1").arg(strErr.c_str())); - return false; + return 0; } /// 8. URI IPC sending diff --git a/src/qt/bulwark.qrc b/src/qt/bulwark.qrc index 2d5f5dd88..2ae33fd83 100644 --- a/src/qt/bulwark.qrc +++ b/src/qt/bulwark.qrc @@ -5,8 +5,6 @@ res/icons/receive_m.png res/icons/masternodes_m.png res/icons/overview_m.png - res/icons/lock_open.png - res/icons/lock_closed.png res/icons/open.png res/icons/information.png res/icons/explorer.png @@ -32,6 +30,8 @@ res/icons/eye_plus.png res/icons/configure.png res/icons/receive.png + res/icons/privacy.png + res/icons/privacy_m.png res/icons/editpaste.png res/icons/editcopy.png res/icons/add.png @@ -69,11 +69,13 @@ res/images/about.png res/images/bulwark_logo_horizontal.png - res/images/downArrow.png - res/images/downArrow_small.png - res/images/upArrow_small.png - res/images/leftArrow_small.png - res/images/rightArrow_small.png + res/images/downArrow_dark.png + res/images/downArrow_small_dark.png + res/images/downArrow_small.png + res/images/upArrow_small_dark.png + res/images/upArrow_small.png + res/images/leftArrow_small_dark.png + res/images/rightArrow_small_dark.png res/images/qtreeview_selected.png res/images/walletFrame_bg.png res/images/walletFrame.png @@ -94,4 +96,4 @@ res/fonts/Roboto-Bold.ttf res/fonts/Roboto-Medium.ttf - + \ No newline at end of file diff --git a/src/qt/bulwark_locale.qrc b/src/qt/bulwark_locale.qrc index 6268aacca..1c0297e42 100644 --- a/src/qt/bulwark_locale.qrc +++ b/src/qt/bulwark_locale.qrc @@ -21,6 +21,7 @@ locale/bulwark_ru.qm locale/bulwark_sk.qm locale/bulwark_sv.qm + locale/bulwark_tr.qm locale/bulwark_uk.qm locale/bulwark_zh_CN.qm locale/bulwark_zh_TW.qm diff --git a/src/qt/bulwarkstrings.cpp b/src/qt/bulwarkstrings.cpp index 2bf4e2271..0e98ed854 100644 --- a/src/qt/bulwarkstrings.cpp +++ b/src/qt/bulwarkstrings.cpp @@ -9,6 +9,9 @@ #define UNUSED #endif static const char UNUSED *bulwark_strings[] = { +QT_TRANSLATE_NOOP("bulwark-core", " mints deleted\n"), +QT_TRANSLATE_NOOP("bulwark-core", " mints updated, "), +QT_TRANSLATE_NOOP("bulwark-core", " unconfirmed transactions removed\n"), QT_TRANSLATE_NOOP("bulwark-core", "" "(1 = keep tx meta data e.g. account owner and payment request information, 2 " "= drop tx meta data)"), @@ -30,6 +33,8 @@ QT_TRANSLATE_NOOP("bulwark-core", "" "notation for IPv6. This option can be specified multiple times (default: " "bind to all interfaces)"), QT_TRANSLATE_NOOP("bulwark-core", "" +"Calculated accumulator checkpoint is not what is recorded by block index"), +QT_TRANSLATE_NOOP("bulwark-core", "" "Cannot obtain a lock on data directory %s. Bulwark Core is probably already " "running."), QT_TRANSLATE_NOOP("bulwark-core", "" @@ -45,25 +50,33 @@ QT_TRANSLATE_NOOP("bulwark-core", "" "Delete all wallet transactions and only recover those parts of the " "blockchain through -rescan on startup"), QT_TRANSLATE_NOOP("bulwark-core", "" -"Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftTX, " +"Disable all Bulwark specific functionality (Masternodes, Zerocoin, SwiftX, " "Budgeting) (0-1, default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "" "Distributed under the MIT software license, see the accompanying file " "COPYING or ."), QT_TRANSLATE_NOOP("bulwark-core", "" -"Enable spork administration functionality with the appropriate private key."), -QT_TRANSLATE_NOOP("bulwark-core", "" -"Enable swifttx, show confirmations for locked transactions (bool, default: " -"%s)"), +"Enable SwiftX, show confirmations for locked transactions (bool, default: %s)"), QT_TRANSLATE_NOOP("bulwark-core", "" -"Enable use of automated obfuscation for funds stored in this wallet (0-1, " +"Enable automatic wallet backups triggered after each zBWK minting (0-1, " "default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "" +"Enable spork administration functionality with the appropriate private key."), +QT_TRANSLATE_NOOP("bulwark-core", "" "Enter regression test mode, which uses a special chain in which blocks can " "be solved instantly."), QT_TRANSLATE_NOOP("bulwark-core", "" "Error: Listening for incoming connections failed (listen returned error %s)"), QT_TRANSLATE_NOOP("bulwark-core", "" +"Error: The transaction was rejected! This might happen if some of the coins " +"in your wallet were already spent, such as if you used a copy of wallet.dat " +"and coins were spent in the copy but not marked as spent here."), +QT_TRANSLATE_NOOP("bulwark-core", "" +"Error: This transaction requires a transaction fee of at least %s because of " +"its amount, complexity, or use of recently received funds!"), +QT_TRANSLATE_NOOP("bulwark-core", "" +"Error: Unsupported argument -checklevel found. Checklevel must be level 4."), +QT_TRANSLATE_NOOP("bulwark-core", "" "Error: Unsupported argument -socks found. Setting SOCKS version isn't " "possible anymore, only SOCKS5 proxies are supported."), QT_TRANSLATE_NOOP("bulwark-core", "" @@ -88,14 +101,15 @@ QT_TRANSLATE_NOOP("bulwark-core", "" "Found unconfirmed denominated outputs, will wait till they confirm to " "continue."), QT_TRANSLATE_NOOP("bulwark-core", "" -"How thorough the block verification of -checkblocks is (0-4, default: %u)"), -QT_TRANSLATE_NOOP("bulwark-core", "" "If paytxfee is not set, include enough fee so transactions begin " "confirmation on average within n blocks (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "" "In this mode -genproclimit controls how many blocks are generated " "immediately."), QT_TRANSLATE_NOOP("bulwark-core", "" +"Insufficient or insufficient confirmed funds, you might need to wait a few " +"minutes and try again."), +QT_TRANSLATE_NOOP("bulwark-core", "" "Invalid amount for -maxtxfee=: '%s' (must be at least the minrelay " "fee of %s to prevent stuck transactions)"), QT_TRANSLATE_NOOP("bulwark-core", "" @@ -119,13 +133,15 @@ QT_TRANSLATE_NOOP("bulwark-core", "" QT_TRANSLATE_NOOP("bulwark-core", "" "Output debugging information (default: %u, supplying is optional)"), QT_TRANSLATE_NOOP("bulwark-core", "" -"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)"), +"Preferred Denomination for automatically minted Zerocoin " +"(1/5/10/50/100/500/1000), 0 for no preference. default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "" "Query for peer addresses via DNS lookup, if low on addresses (default: 1 " "unless -connect)"), QT_TRANSLATE_NOOP("bulwark-core", "" +"Randomize credentials for every proxy connection. This enables Tor stream " +"isolation (default: %u)"), +QT_TRANSLATE_NOOP("bulwark-core", "" "Require high priority for relaying free or low-fee transactions (default:%u)"), QT_TRANSLATE_NOOP("bulwark-core", "" "Send trace/debug info to console instead of debug.log file (default: %u)"), @@ -143,8 +159,8 @@ QT_TRANSLATE_NOOP("bulwark-core", "" QT_TRANSLATE_NOOP("bulwark-core", "" "Support filtering of blocks and transaction with bloom filters (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "" -"SwiftTX requires inputs with at least 6 confirmations, you might need to " -"wait a few minutes and try again."), +"SwiftX requires inputs with at least 6 confirmations, you might need to wait " +"a few minutes and try again."), QT_TRANSLATE_NOOP("bulwark-core", "" "This is a pre-release test build - use at your own risk - do not use for " "staking or merchant applications!"), @@ -224,7 +240,9 @@ QT_TRANSLATE_NOOP("bulwark-core", "Already have that input."), QT_TRANSLATE_NOOP("bulwark-core", "Always query for peer addresses via DNS lookup (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Attempt to force blockchain corruption recovery"), QT_TRANSLATE_NOOP("bulwark-core", "Attempt to recover private keys from a corrupt wallet.dat"), +QT_TRANSLATE_NOOP("bulwark-core", "Automatically create Tor hidden service (default: %d)"), QT_TRANSLATE_NOOP("bulwark-core", "Block creation options:"), +QT_TRANSLATE_NOOP("bulwark-core", "Calculating missing accumulators..."), QT_TRANSLATE_NOOP("bulwark-core", "Can't denominate: no compatible inputs left."), QT_TRANSLATE_NOOP("bulwark-core", "Can't find random Masternode."), QT_TRANSLATE_NOOP("bulwark-core", "Can't mix while sync in progress."), @@ -245,6 +263,8 @@ QT_TRANSLATE_NOOP("bulwark-core", "Corrupted block database detected"), QT_TRANSLATE_NOOP("bulwark-core", "Could not parse -rpcbind value %s as network address"), QT_TRANSLATE_NOOP("bulwark-core", "Could not parse masternode.conf"), QT_TRANSLATE_NOOP("bulwark-core", "Debugging/Testing options:"), +QT_TRANSLATE_NOOP("bulwark-core", "Delete blockchain folders and resync from scratch"), +QT_TRANSLATE_NOOP("bulwark-core", "Disable OS notifications for incoming transactions (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Disable safemode, override a real safe mode event (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Discover own IP address (default: 1 when listening and no -externalip)"), QT_TRANSLATE_NOOP("bulwark-core", "Display the stake modifier calculations in the debug.log file."), @@ -252,11 +272,12 @@ QT_TRANSLATE_NOOP("bulwark-core", "Display verbose coin stake messages in the de QT_TRANSLATE_NOOP("bulwark-core", "Do not load the wallet and disable wallet RPC calls"), QT_TRANSLATE_NOOP("bulwark-core", "Do you want to rebuild the block database now?"), QT_TRANSLATE_NOOP("bulwark-core", "Done loading"), +QT_TRANSLATE_NOOP("bulwark-core", "Enable automatic Zerocoin minting (0-1, default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Enable publish hash block in
"), -QT_TRANSLATE_NOOP("bulwark-core", "Enable publish hash transaction (locked via SwiftTX) in
"), +QT_TRANSLATE_NOOP("bulwark-core", "Enable publish hash transaction (locked via SwiftX) in
"), QT_TRANSLATE_NOOP("bulwark-core", "Enable publish hash transaction in
"), QT_TRANSLATE_NOOP("bulwark-core", "Enable publish raw block in
"), -QT_TRANSLATE_NOOP("bulwark-core", "Enable publish raw transaction (locked via SwiftTX) in
"), +QT_TRANSLATE_NOOP("bulwark-core", "Enable publish raw transaction (locked via SwiftX) in
"), QT_TRANSLATE_NOOP("bulwark-core", "Enable publish raw transaction in
"), QT_TRANSLATE_NOOP("bulwark-core", "Enable staking functionality (0-1, default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Enable the client to act as a masternode (0-1, default: %u)"), @@ -278,8 +299,11 @@ QT_TRANSLATE_NOOP("bulwark-core", "Error: Disk space is low!"), QT_TRANSLATE_NOOP("bulwark-core", "Error: Unsupported argument -tor found, use -onion."), QT_TRANSLATE_NOOP("bulwark-core", "Error: Wallet locked, unable to create transaction!"), QT_TRANSLATE_NOOP("bulwark-core", "Error: You already have pending entries in the Obfuscation pool"), +QT_TRANSLATE_NOOP("bulwark-core", "Failed to calculate accumulator checkpoint"), QT_TRANSLATE_NOOP("bulwark-core", "Failed to listen on any port. Use -listen=0 if you want this."), +QT_TRANSLATE_NOOP("bulwark-core", "Failed to read block index"), QT_TRANSLATE_NOOP("bulwark-core", "Failed to read block"), +QT_TRANSLATE_NOOP("bulwark-core", "Failed to write block index"), QT_TRANSLATE_NOOP("bulwark-core", "Fee (in BWK/kB) to add to transactions you send (default: %s)"), QT_TRANSLATE_NOOP("bulwark-core", "Finalizing transaction."), QT_TRANSLATE_NOOP("bulwark-core", "Force safe mode (default: %u)"), @@ -297,21 +321,22 @@ QT_TRANSLATE_NOOP("bulwark-core", "Incorrect or no genesis block found. Wrong da QT_TRANSLATE_NOOP("bulwark-core", "Information"), QT_TRANSLATE_NOOP("bulwark-core", "Initialization sanity check failed. Bulwark Core is shutting down."), QT_TRANSLATE_NOOP("bulwark-core", "Input is not valid."), +QT_TRANSLATE_NOOP("bulwark-core", "Insufficient funds"), QT_TRANSLATE_NOOP("bulwark-core", "Insufficient funds."), -QT_TRANSLATE_NOOP("bulwark-core", "Invalid -onion address: '%s'"), -QT_TRANSLATE_NOOP("bulwark-core", "Invalid -proxy address: '%s'"), +QT_TRANSLATE_NOOP("bulwark-core", "Invalid -onion address or hostname: '%s'"), +QT_TRANSLATE_NOOP("bulwark-core", "Invalid -proxy address or hostname: '%s'"), QT_TRANSLATE_NOOP("bulwark-core", "Invalid amount for -maxtxfee=: '%s'"), QT_TRANSLATE_NOOP("bulwark-core", "Invalid amount for -minrelaytxfee=: '%s'"), QT_TRANSLATE_NOOP("bulwark-core", "Invalid amount for -mintxfee=: '%s'"), QT_TRANSLATE_NOOP("bulwark-core", "Invalid amount for -paytxfee=: '%s' (must be at least %s)"), QT_TRANSLATE_NOOP("bulwark-core", "Invalid amount for -paytxfee=: '%s'"), QT_TRANSLATE_NOOP("bulwark-core", "Invalid amount for -reservebalance="), +QT_TRANSLATE_NOOP("bulwark-core", "Invalid amount"), QT_TRANSLATE_NOOP("bulwark-core", "Invalid masternodeprivkey. Please see documenation."), QT_TRANSLATE_NOOP("bulwark-core", "Invalid netmask specified in -whitelist: '%s'"), QT_TRANSLATE_NOOP("bulwark-core", "Invalid port detected in masternode.conf"), QT_TRANSLATE_NOOP("bulwark-core", "Invalid private key."), QT_TRANSLATE_NOOP("bulwark-core", "Invalid script detected."), -QT_TRANSLATE_NOOP("bulwark-core", "Keep N BWK anonymized (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Keep at most unconnectable transactions in memory (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Last Obfuscation was too recent."), QT_TRANSLATE_NOOP("bulwark-core", "Last successful Obfuscation action was too recent."), @@ -324,6 +349,7 @@ QT_TRANSLATE_NOOP("bulwark-core", "Loading block index..."), QT_TRANSLATE_NOOP("bulwark-core", "Loading budget cache..."), QT_TRANSLATE_NOOP("bulwark-core", "Loading masternode cache..."), QT_TRANSLATE_NOOP("bulwark-core", "Loading masternode payment cache..."), +QT_TRANSLATE_NOOP("bulwark-core", "Loading sporks..."), QT_TRANSLATE_NOOP("bulwark-core", "Loading wallet... (%3.2f %%)"), QT_TRANSLATE_NOOP("bulwark-core", "Loading wallet..."), QT_TRANSLATE_NOOP("bulwark-core", "Lock is already in place."), @@ -348,13 +374,14 @@ QT_TRANSLATE_NOOP("bulwark-core", "Not enough file descriptors available."), QT_TRANSLATE_NOOP("bulwark-core", "Not in the Masternode list."), QT_TRANSLATE_NOOP("bulwark-core", "Number of automatic wallet backups (default: 10)"), QT_TRANSLATE_NOOP("bulwark-core", "Obfuscation is idle."), -QT_TRANSLATE_NOOP("bulwark-core", "Obfuscation options:"), QT_TRANSLATE_NOOP("bulwark-core", "Obfuscation request complete:"), QT_TRANSLATE_NOOP("bulwark-core", "Obfuscation request incomplete:"), QT_TRANSLATE_NOOP("bulwark-core", "Only accept block chain matching built-in checkpoints (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Only connect to nodes in network (ipv4, ipv6 or onion)"), QT_TRANSLATE_NOOP("bulwark-core", "Options:"), QT_TRANSLATE_NOOP("bulwark-core", "Password for JSON-RPC connections"), +QT_TRANSLATE_NOOP("bulwark-core", "Percentage of automatically minted Zerocoin (10-100, default: %u)"), +QT_TRANSLATE_NOOP("bulwark-core", "Preparing for resync..."), QT_TRANSLATE_NOOP("bulwark-core", "Prepend debug output with timestamp (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Print version and exit"), QT_TRANSLATE_NOOP("bulwark-core", "RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)"), @@ -363,11 +390,16 @@ QT_TRANSLATE_NOOP("bulwark-core", "RPC support for HTTP persistent connections ( QT_TRANSLATE_NOOP("bulwark-core", "Randomly drop 1 of every network messages"), QT_TRANSLATE_NOOP("bulwark-core", "Randomly fuzz 1 of every network messages"), QT_TRANSLATE_NOOP("bulwark-core", "Rebuild block chain index from current blk000??.dat files"), +QT_TRANSLATE_NOOP("bulwark-core", "Recalculating coin supply may take 30-60 minutes..."), +QT_TRANSLATE_NOOP("bulwark-core", "Recalculating supply statistics may take 30-60 minutes..."), QT_TRANSLATE_NOOP("bulwark-core", "Receive and display P2P network alerts (default: %u)"), +QT_TRANSLATE_NOOP("bulwark-core", "Reindex the accumulator database"), QT_TRANSLATE_NOOP("bulwark-core", "Relay and mine data carrier transactions (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Relay non-P2SH multisig (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Rescan the block chain for missing wallet transactions"), QT_TRANSLATE_NOOP("bulwark-core", "Rescanning..."), +QT_TRANSLATE_NOOP("bulwark-core", "ResetMintZerocoin finished: "), +QT_TRANSLATE_NOOP("bulwark-core", "ResetSpentZerocoin finished: "), QT_TRANSLATE_NOOP("bulwark-core", "Run a thread to flush wallet periodically (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Run in the background as a daemon and accept commands"), QT_TRANSLATE_NOOP("bulwark-core", "Send transactions as zero-fee transactions if possible (default: %u)"), @@ -380,6 +412,7 @@ QT_TRANSLATE_NOOP("bulwark-core", "Set external address:port to get to this mast QT_TRANSLATE_NOOP("bulwark-core", "Set key pool size to (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Set maximum block size in bytes (default: %d)"), QT_TRANSLATE_NOOP("bulwark-core", "Set minimum block size in bytes (default: %u)"), +QT_TRANSLATE_NOOP("bulwark-core", "Set the Maximum reorg depth (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Set the masternode private key"), QT_TRANSLATE_NOOP("bulwark-core", "Set the number of threads to service RPC calls (default: %d)"), QT_TRANSLATE_NOOP("bulwark-core", "Sets the DB_PRIVATE flag in the wallet db environment (default: %u)"), @@ -401,7 +434,7 @@ QT_TRANSLATE_NOOP("bulwark-core", "Stop running after importing blocks from disk QT_TRANSLATE_NOOP("bulwark-core", "Submitted following entries to masternode: %u / %d"), QT_TRANSLATE_NOOP("bulwark-core", "Submitted to masternode, waiting for more entries ( %u / %d ) %s"), QT_TRANSLATE_NOOP("bulwark-core", "Submitted to masternode, waiting in queue %s"), -QT_TRANSLATE_NOOP("bulwark-core", "SwiftTX options:"), +QT_TRANSLATE_NOOP("bulwark-core", "SwiftX options:"), QT_TRANSLATE_NOOP("bulwark-core", "Synchronization failed"), QT_TRANSLATE_NOOP("bulwark-core", "Synchronization finished"), QT_TRANSLATE_NOOP("bulwark-core", "Synchronization pending..."), @@ -414,6 +447,8 @@ QT_TRANSLATE_NOOP("bulwark-core", "This is experimental software."), QT_TRANSLATE_NOOP("bulwark-core", "This is intended for regression testing tools and app development."), QT_TRANSLATE_NOOP("bulwark-core", "This is not a Masternode."), QT_TRANSLATE_NOOP("bulwark-core", "Threshold for disconnecting misbehaving peers (default: %u)"), +QT_TRANSLATE_NOOP("bulwark-core", "Tor control port password (default: empty)"), +QT_TRANSLATE_NOOP("bulwark-core", "Tor control port to use if onion listening enabled (default: %s)"), QT_TRANSLATE_NOOP("bulwark-core", "Transaction amount too small"), QT_TRANSLATE_NOOP("bulwark-core", "Transaction amounts must be positive"), QT_TRANSLATE_NOOP("bulwark-core", "Transaction created successfully."), @@ -427,10 +462,10 @@ QT_TRANSLATE_NOOP("bulwark-core", "Unable to sign spork message, wrong key?"), QT_TRANSLATE_NOOP("bulwark-core", "Unknown network specified in -onlynet: '%s'"), QT_TRANSLATE_NOOP("bulwark-core", "Unknown state: id = %u"), QT_TRANSLATE_NOOP("bulwark-core", "Upgrade wallet to latest format"), -QT_TRANSLATE_NOOP("bulwark-core", "Use N separate masternodes to anonymize funds (2-8, default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Use OpenSSL (https) for JSON-RPC connections"), QT_TRANSLATE_NOOP("bulwark-core", "Use UPnP to map the listening port (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Use UPnP to map the listening port (default: 1 when listening)"), +QT_TRANSLATE_NOOP("bulwark-core", "Use a custom max chain reorganization depth (default: %u)"), QT_TRANSLATE_NOOP("bulwark-core", "Use the test network"), QT_TRANSLATE_NOOP("bulwark-core", "Username for JSON-RPC connections"), QT_TRANSLATE_NOOP("bulwark-core", "Value more than Obfuscation pool maximum allows."), @@ -451,6 +486,8 @@ QT_TRANSLATE_NOOP("bulwark-core", "Your entries added successfully."), QT_TRANSLATE_NOOP("bulwark-core", "Your transaction was accepted into the pool!"), QT_TRANSLATE_NOOP("bulwark-core", "Zapping all transactions from wallet..."), QT_TRANSLATE_NOOP("bulwark-core", "ZeroMQ notification options:"), +QT_TRANSLATE_NOOP("bulwark-core", "Zerocoin options:"), +QT_TRANSLATE_NOOP("bulwark-core", "failed to validate zerocoin"), QT_TRANSLATE_NOOP("bulwark-core", "on startup"), QT_TRANSLATE_NOOP("bulwark-core", "wallet.dat corrupt, salvage failed"), }; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index f2b2e45b3..277ec837f 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -73,7 +73,11 @@ int ClientModel::getNumConnections(unsigned int flags) const QString ClientModel::getMasternodeCountString() const { - return tr("Total: %1 (OBF compatible: %2 / Enabled: %3)").arg(QString::number((int)mnodeman.size())).arg(QString::number((int)mnodeman.CountEnabled(ActiveProtocol()))).arg(QString::number((int)mnodeman.CountEnabled())); + int ipv4 = 0, ipv6 = 0, onion = 0; + mnodeman.CountNetworks(ActiveProtocol(), ipv4, ipv6, onion); + int nUnknown = mnodeman.size() - ipv4 - ipv6 - onion; + if(nUnknown < 0) nUnknown = 0; + return tr("Total: %1 (IPv4: %2 / IPv6: %3 / Tor: %4 / Unknown: %5)").arg(QString::number((int)mnodeman.size())).arg(QString::number((int)ipv4)).arg(QString::number((int)ipv6)).arg(QString::number((int)onion)).arg(QString::number((int)nUnknown)); } int ClientModel::getNumBlocks() const diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index a3289ae70..8b4a5f4c9 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -40,13 +40,12 @@ int CoinControlDialog::nSplitBlockDummy; CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : QDialog(parent), - ui(new Ui::CoinControlDialog), - model(0) + ui(new Ui::CoinControlDialog), + model(0) { ui->setupUi(this); this->fMultisigEnabled = fMultisigEnabled; - /* Open CSS when configured */ this->setStyleSheet(GUIUtil::loadStyleSheet()); @@ -137,7 +136,6 @@ CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : Q ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100); ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170); ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 190); - ui->treeWidget->setColumnWidth(COLUMN_OBFUSCATION_ROUNDS, 88); ui->treeWidget->setColumnWidth(COLUMN_DATE, 80); ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100); ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100); @@ -176,7 +174,7 @@ void CoinControlDialog::setModel(WalletModel* model) updateView(); updateLabelLocked(); CoinControlDialog::updateLabels(model, this); - updateDialogLabels(); + updateDialogLabels(); } } @@ -192,7 +190,7 @@ QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding) // ok button void CoinControlDialog::selectButtonClicked() { - this->close(); // closes the dialog + this->close(); // closes the dialog } // (un)select all @@ -226,8 +224,8 @@ void CoinControlDialog::buttonToggleLockClicked() for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) { item = ui->treeWidget->topLevelItem(i); - if (item->text(COLUMN_TYPE) == "MultiSig") - continue; + if (item->text(COLUMN_TYPE) == "MultiSig") + continue; COutPoint outpt(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()); if (model->isLockedCoin(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())) { @@ -243,7 +241,7 @@ void CoinControlDialog::buttonToggleLockClicked() } ui->treeWidget->setEnabled(true); CoinControlDialog::updateLabels(model, this); - updateDialogLabels(); + updateDialogLabels(); } else { QMessageBox msgBox; msgBox.setObjectName("lockMessageBox"); @@ -438,23 +436,14 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column) coinControl->UnSelect(outpt); else if (item->isDisabled()) // locked (this happens if "check all" through parent node) item->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); - else { + else coinControl->Select(outpt); - CTxIn vin(outpt); - int rounds = pwalletMain->GetInputObfuscationRounds(vin); - if (coinControl->useObfuScation && rounds < nObfuscationRounds) { - QMessageBox::warning(this, windowTitle(), - tr("Non-anonymized input selected. Obfuscation will be disabled.

If you still want to use Obfuscation, please deselect all non-nonymized inputs first and then check Obfuscation checkbox again."), - QMessageBox::Ok, QMessageBox::Ok); - coinControl->useObfuScation = false; - } - } // selection changed -> update labels if (ui->treeWidget->isEnabled()){ // do not update on every click for (un)select all CoinControlDialog::updateLabels(model, this); - updateDialogLabels(); - } + updateDialogLabels(); + } } // todo: this is a temporary qt5 fix: when clicking a parent node in tree mode, the parent node // including all childs are partially selected. But the parent node should be fully selected @@ -644,11 +633,6 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) if (nPayAmount > 0) { nChange = nAmount - nPayFee - nPayAmount; - // DS Fee = overpay - if (coinControl->useObfuScation && nChange > 0) { - nPayFee += nChange; - nChange = 0; - } // Never create dust outputs; if we would, just add the dust to the fee. if (nChange > 0 && nChange < CENT) { CTxOut txout(nChange, (CScript)vector(24, 0)); @@ -726,7 +710,7 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), payTxFee.GetFeePerK()) / 1000; else dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), mempool.estimateFee(nTxConfirmTarget).GetFeePerK()) / 1000; - QString toolTip4 = tr("Can vary +/- %1 duff(s) per input.").arg(dFeeVary); + QString toolTip4 = tr("Can vary +/- %1 uBWK per input.").arg(dFeeVary); l3->setToolTip(toolTip4); l4->setToolTip(toolTip4); @@ -794,14 +778,12 @@ void CoinControlDialog::updateView() double dPrioritySum = 0; int nChildren = 0; int nInputSum = 0; - for(const COutput& out: coins.second) { - isminetype mine = pwalletMain->IsMine(out.tx->vout[out.i]); - bool fMultiSigUTXO = (mine & ISMINE_MULTISIG); - // when multisig is enabled, it will only display outputs from multisig addresses - if (fMultisigEnabled && !fMultiSigUTXO) - continue; - - + for(const COutput& out: coins.second) { + isminetype mine = pwalletMain->IsMine(out.tx->vout[out.i]); + bool fMultiSigUTXO = (mine & ISMINE_MULTISIG); + // when multisig is enabled, it will only display outputs from multisig addresses + if (fMultisigEnabled && !fMultiSigUTXO) + continue; int nInputSize = 0; nSum += out.tx->vout[out.i].nValue; nChildren++; @@ -870,17 +852,6 @@ void CoinControlDialog::updateView() itemOutput->setToolTip(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime())); itemOutput->setText(COLUMN_DATE_INT64, strPad(QString::number(out.tx->GetTxTime()), 20, " ")); - - // ds+ rounds - CTxIn vin = CTxIn(out.tx->GetHash(), out.i); - int rounds = pwalletMain->GetInputObfuscationRounds(vin); - - if (rounds >= 0) - itemOutput->setText(COLUMN_OBFUSCATION_ROUNDS, strPad(QString::number(rounds), 11, " ")); - else - itemOutput->setText(COLUMN_OBFUSCATION_ROUNDS, strPad(QString(tr("n/a")), 11, " ")); - - // confirmations itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " ")); diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 98f863980..59fe7b399 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -69,8 +69,7 @@ class CoinControlDialog : public QDialog COLUMN_AMOUNT, COLUMN_LABEL, COLUMN_ADDRESS, - COLUMN_TYPE, - COLUMN_OBFUSCATION_ROUNDS, + COLUMN_TYPE, COLUMN_DATE, COLUMN_CONFIRMATIONS, COLUMN_PRIORITY, diff --git a/src/qt/forms/bip38tooldialog.ui b/src/qt/forms/bip38tooldialog.ui index 90e0caaf4..11e57b55d 100644 --- a/src/qt/forms/bip38tooldialog.ui +++ b/src/qt/forms/bip38tooldialog.ui @@ -24,7 +24,7 @@ - &BIP 38 Encrypt + BIP 38 Encrypt @@ -249,7 +249,7 @@ - &BIP 38 Decrypt + BIP 38 Decrypt diff --git a/src/qt/forms/blockexplorer.ui b/src/qt/forms/blockexplorer.ui index 61a3fff36..df2feb1e2 100644 --- a/src/qt/forms/blockexplorer.ui +++ b/src/qt/forms/blockexplorer.ui @@ -13,7 +13,13 @@ Blockchain Explorer + + + + + + @@ -23,11 +29,7 @@ - - - - - :/icons/back:/icons/back + Back false @@ -37,11 +39,7 @@ - - - - - :/icons/forward:/icons/forward + Forward @@ -117,7 +115,7 @@ 0 0 780 - 498 + 489 @@ -155,14 +153,14 @@ 0 0 800 - 25 + 27 - + diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui index fc2bacc87..0c6e800a8 100644 --- a/src/qt/forms/coincontroldialog.ui +++ b/src/qt/forms/coincontroldialog.ui @@ -477,11 +477,11 @@ - DS Rounds + Type - + Date diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui index c1aea3633..53c9781d7 100644 --- a/src/qt/forms/editaddressdialog.ui +++ b/src/qt/forms/editaddressdialog.ui @@ -22,7 +22,7 @@ - &Label + Label labelEdit @@ -39,7 +39,7 @@ - &Address + Address addressEdit diff --git a/src/qt/forms/helpmessagedialog.ui b/src/qt/forms/helpmessagedialog.ui index acd04da32..08e6412b8 100644 --- a/src/qt/forms/helpmessagedialog.ui +++ b/src/qt/forms/helpmessagedialog.ui @@ -7,7 +7,7 @@ 0 0 585 - 225 + 488 @@ -54,8 +54,8 @@ 0 0 - 447 - 68 + 479 + 213 diff --git a/src/qt/forms/masternodelist.ui b/src/qt/forms/masternodelist.ui index 7155862aa..bb33f0866 100644 --- a/src/qt/forms/masternodelist.ui +++ b/src/qt/forms/masternodelist.ui @@ -13,216 +13,267 @@ Form - + - 10 + 9 - 10 + 9 - 10 + 9 - 10 + 9 - - - - My Masternodes - - - - - - 0 - - - - + + + + 0 + + + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + 0 - - - - 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. - - - - - - - - - - 695 - 0 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 85 - 85 - 85 - - - - - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::SingleSelection + + 0 - - QAbstractItemView::SelectRows + + 0 - - true + + 0 - - true - - - QHeaderView::Interactive - - - - Alias - - - - - Address - - - - - Protocol - - - - - Status - - - - - Active - - - - - Last Seen (UTC) - - - - - Pubkey - - - - - - 0 - - - Start alias - - - - - - - Start all - - - - - - - Start MISSING - - - - - - - Update status - - - - - - - Status will be updated automatically in (sec): - - - - - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - + + + 2 - + + + + + 1 + + + + + 0 + + + + + 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. + + + + + + + + + + 695 + 0 + + + + + + + + + 51 + 51 + 51 + + + + + + + + + 51 + 51 + 51 + + + + + + + + + 85 + 85 + 85 + + + + + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + + Alias + + + + + Address + + + + + Protocol + + + + + Status + + + + + Active + + + + + Last Seen (UTC) + + + + + Pubkey + + + + + + + + 0 + + + + + Start alias + + + + + + + Start all + + + + + + + Start MISSING + + + + + + + Update status + + + + + + + Status will be updated automatically in (sec): + + + + + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + - - - - - - + + + + + + + + + + QtMaterialFlatButton + QWidget +
qtmaterialflatbutton.h
+ 1 +
+
diff --git a/src/qt/forms/multisigdialog.ui b/src/qt/forms/multisigdialog.ui index ea56b318d..e3e2b9561 100644 --- a/src/qt/forms/multisigdialog.ui +++ b/src/qt/forms/multisigdialog.ui @@ -29,7 +29,7 @@ QLabel{background-color:#ffffff;} QFrame > QLabel{background-color:#f2f0f0;} - 2 + 0 @@ -39,7 +39,7 @@ QFrame > QLabel{background-color:#f2f0f0;} - Create MultiSignature &Address + Create MultiSignature Address @@ -92,18 +92,18 @@ QFrame > QLabel{background-color:#f2f0f0;} - + Add another address that could sign to verify a transaction from the multisig address. - + Add Address / Key - + :/icons/add:/icons/add - + false @@ -152,8 +152,8 @@ QFrame > QLabel{background-color:#f2f0f0;} 0 0 - 757 - 209 + 759 + 165 @@ -180,7 +180,7 @@ QFrame > QLabel{background-color:#f2f0f0;} - + 0 @@ -193,14 +193,14 @@ QFrame > QLabel{background-color:#f2f0f0;} -3 - + Create - + :/icons/filesave:/icons/filesave - + false @@ -260,17 +260,17 @@ Please be patient after clicking import. - + 0 0 - + Import Redeem - + :/icons/receiving_addresses:/icons/receiving_addresses @@ -292,7 +292,7 @@ Please be patient after clicking import. - &Create MultiSignature Tx + Create MultiSignature Tx @@ -315,14 +315,14 @@ Please be patient after clicking import. - + 0 0 - + Coin Control @@ -363,7 +363,7 @@ Please be patient after clicking import. - + 0 @@ -373,10 +373,10 @@ Please be patient after clicking import. Add an input to fund the outputs - + Add a Raw Input - + :/css/default:/css/default @@ -435,7 +435,7 @@ Please be patient after clicking import. - + 0 @@ -445,10 +445,10 @@ Please be patient after clicking import. Add destinations to send BWK to - + Add Destination - + :/icons/add:/icons/add @@ -513,7 +513,7 @@ Please be patient after clicking import. - + 0 @@ -529,17 +529,17 @@ Please be patient after clicking import. Create a transaction object using the given inputs to the given outputs - + Create - + :/icons/export:/icons/export - + false - + true @@ -581,8 +581,8 @@ Please be patient after clicking import. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Noto Sans'; font-size:9pt;"><br /></p></body></html> +</style></head><body style=" font-family:'Noto Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> @@ -610,7 +610,7 @@ txScrollArea:{ } - &Sign MultiSignature Tx + Sign MultiSignature Tx @@ -638,7 +638,7 @@ txScrollArea:{ - + 0 @@ -654,23 +654,23 @@ txScrollArea:{ Sign the transaction from this wallet or from provided private keys - + Sign - + :/icons/edit:/icons/edit - + false - + true - + false @@ -686,14 +686,14 @@ txScrollArea:{ false - + Commit - + :/icons/send:/icons/send - + true @@ -701,7 +701,7 @@ txScrollArea:{ - + 0 @@ -711,10 +711,10 @@ txScrollArea:{ Add private keys to sign the transaction with - + Add Private Key - + :/icons/add:/icons/add @@ -783,8 +783,8 @@ txScrollArea:{ 0 0 - 753 - 69 + 755 + 68 diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 01777046f..a80c3655c 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -7,7 +7,7 @@ 0 0 576 - 417 + 442 @@ -24,7 +24,7 @@ - &Main + Main @@ -33,7 +33,7 @@ Automatically start Bulwark after logging in to the system. - &Start Bulwark on system login + Start Bulwark on system login @@ -42,7 +42,7 @@ - Size of &database cache + Size of database cache Qt::PlainText @@ -85,7 +85,7 @@ - Number of script &verification threads + Number of script verification threads Qt::PlainText @@ -131,69 +131,66 @@ - + - + - This setting determines the amount of individual masternodes that an input will be anonymized through.<br/>More rounds of anonymization gives a higher degree of privacy, but also costs more in fees. + Percentage of incoming BWK which get automatically converted to zBWK via Zerocoin Protocol - Obfuscation rounds to use + Percentage of autominted zBWK - + - 2 + 0 - 8 - - - 4 + 100 - + + + QLayout::SetFixedSize + - - - This amount acts as a threshold to turn off Obfuscation once it's reached. - - - - - - - - - + + + + 16777215 + 16777215 + - - + + Wait with automatic conversion to Zerocoin until enough BWK for this denomination is available - Amount of Bulwark to keep anonymized + Preferred Automint zBWK Denomination - - - 100 + + + + 16777215 + 27 + - - 100000 + + Wait with automatic conversion to Zerocoin until enough BWK for this denomination is available - - 100 + + 9 - - 1000 + + 9 @@ -203,7 +200,7 @@ - W&allet + Wallet @@ -218,7 +215,7 @@ Whether to show coin control features or not. - Enable coin &control features + Enable coin control features @@ -238,7 +235,7 @@ If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. - &Spend unconfirmed change + Spend unconfirmed change @@ -269,7 +266,7 @@ - &Network + Network @@ -278,7 +275,7 @@ Automatically open the Bulwark client port on the router. This only works when your router supports UPnP and it is enabled. - Map port using &UPnP + Map port using UPnP @@ -298,7 +295,7 @@ Connect to the Bulwark network through a SOCKS5 proxy. - &Connect through SOCKS5 proxy (default proxy): + Connect through SOCKS5 proxy (default proxy): @@ -307,7 +304,7 @@ - Proxy &IP: + Proxy IP: Qt::PlainText @@ -339,7 +336,7 @@ - &Port: + Port: Qt::PlainText @@ -400,7 +397,7 @@ - &Window + Window @@ -409,7 +406,7 @@ Show only a tray icon after minimizing the window. - &Minimize to the tray instead of the taskbar + Minimize to the tray instead of the taskbar @@ -419,7 +416,7 @@ Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - M&inimize on close + Minimize on close @@ -440,7 +437,7 @@ - &Display + Display @@ -448,7 +445,7 @@ - User Interface &language: + User Interface language: Qt::PlainText @@ -522,7 +519,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Unit to show amounts in: + Unit to show amounts in: Qt::PlainText diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 1de512aaf..479183b99 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -1,4 +1,4 @@ - + OverviewPage @@ -6,1399 +6,1183 @@ 0 0 - 960 - 720 + 1078 + 841 - 960 - 0 + 1060 + 682 Form - + + + 9 + - - - false + + + + 960 + 610 + - - background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; + + + 16777215 + 16777215 + - - true + + QFrame::StyledPanel - - 3 + + QFrame::Raised - - - - - - - - 6 - - - - - QFrame::StyledPanel - - - QFrame::Raised - - + + + 0 + + + 0 + + + 0 + + + 6 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + - - - - - - 8 - 75 - false - true - false - PreferDefault - - - - Balances - - - + - - - WhatsThisCursor - - - The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. - - - QLabel { color: red; } - - - (out of sync) - - - - - - - Qt::Horizontal - - - - 30 - 20 - - - - - - - - - - 50 - - - 15 - - - - - Spendable: - - - - - - - - 75 - true - - - - Your current total balance - - - 0.000 000 00 BTC - - - Qt::NoTextInteraction - - - - - - - - 75 - true - - - - Your current spendable balance - - - 0.000 000 00 BTC - - - Qt::NoTextInteraction - - - - - - - false - - - - 50 - false - - - - Unconfirmed transactions to watch-only addresses - - - 0.000 000 00 BTC - - - Qt::NoTextInteraction - - - - - - - - 8 - 75 - true - - - - Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance - - - 0.000 000 00 BTC - - - Qt::NoTextInteraction - - - - - - - false - - - Watch-only: - - - - - - - false - - - - 50 - false - - - - Staked or masternode rewards in watch-only addresses that has not yet matured - - - 0.000 000 00 BTC - - - Qt::NoTextInteraction - - - - - - - true - - - - 0 - 0 - - - + + - 16777215 - 1 + 0 + 0 - - QFrame::Plain - - - Qt::Horizontal - - - - - - - false - - - - 50 - false - - - - Current total balance in watch-only addresses - - - 0.000 000 00 BTC - - - Qt::NoTextInteraction - - - - - - - true - - - - 0 - 0 - - - - - 16777215 - 1 - + + QFrame::StyledPanel - QFrame::Plain - - - Qt::Horizontal - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 30 - 20 - - - - - - - - - 75 - true - - - - Staked or masternode rewards that has not yet matured - - - Qt::LeftToRight - - - 0.000 000 00 BTC - - - Qt::NoTextInteraction - - - - - - - false - - - - 50 - false - - - - Your current balance in watch-only addresses - - - 0.000 000 00 BTC - - - Qt::NoTextInteraction - - - - - - - - 8 - - - - Total: - - - - - - - - 8 - true - - - - Pending: - - - - - - - - 8 - 50 - false - - - - Available: - - - - - - - - 8 - - - - Immature: - + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + 0 + 20 + + + + + 12 + 75 + true + + + + BWK Balances + + + + + + + WhatsThisCursor + + + The displayed information may be out of date. Your wallet automatically synchronizes with the BWK network after a connection is established, but this process has not completed yet. + + + QLabel { color: red; } + + + (out of sync) + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + + + + + 12 + + + + + + 75 + true + + + + IBeamCursor + + + Unconfirmed transactions to watch-only addresses + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + IBeamCursor + + + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + IBeamCursor + + + Staked or masternode rewards in watch-only addresses that has not yet matured + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Total: + + + + + + + + 75 + true + + + + IBeamCursor + + + Staked or masternode rewards that has not yet matured + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Immature: + + + + + + + + 75 + true + + + + IBeamCursor + + + Your current total balance + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + IBeamCursor + + + Current total balance in watch-only addresses + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Watch-only: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Available: + + + + + + + + 75 + true + + + + IBeamCursor + + + Your current spendable balance + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + IBeamCursor + + + Your current balance in watch-only addresses + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Pending: + + + + + + + Spendable: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + 0 + 20 + + + + + 12 + 75 + true + + + + Zerocoin Balance + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + + + + + 12 + + + + + Mature: more than 20 confirmation and more than 1 mint of the same denomination after it was minted. +These zBWK are spendable. + + + Mature: + + + + + + + + 75 + true + + + + IBeamCursor + + + All available zBWK, unconfirmed and immature zBWK included. + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + All available zBWK, unconfirmed and immature zBWK included. + + + Total: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 75 + true + + + + Mature: more than 20 confirmation and more than 1 mint of the same denomination after it was minted. +These zBWK are spendable. + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + Unconfirmed: + + + + + + + + 75 + true + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + Immature: + + + + + + + + 75 + true + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 470 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + 0 + 20 + + + + + 12 + 75 + true + + + + Combined Balances (including unconfirmed and immature coins) + + + <html><head/><body><p>Combined Balances</p></body></html> + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + + + + + 12 + + + + + + 75 + true + + + + IBeamCursor + + + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + IBeamCursor + + + Total Balance, including unconfirmed and immature coins. + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Total: + + + + + + + BWK: + + + + + + + + 75 + true + + + + IBeamCursor + + + Your current spendable balance + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + zBWK: + + + + + + + Current percentage of zBWK. +If AutoMint is enabled this percentage will settle around the configured AutoMint percentage (default = 0%) + + + 0 % + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Locked BWK or Masternode collaterals. These are excluded from zBWK minting. + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Locked BWK or Masternode collaterals. These are excluded from zBWK minting. + + + Locked: + + + + + + + Unlocked BWKs. These can be used for zBWK minting. + + + Unlocked: + + + + + + + Unlocked BWKs. These can be used for zBWK minting. + + + 0.000 000 00 BWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 0 % + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 30 - - - - - - - - - - - - 0 - 350 - - - - Qt::LeftToRight - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 10 - 30 - 441 - 135 - - - - - QFormLayout::AllNonFixedFieldsGrow - - - 115 - - - 12 - - - - - - 50 - false - - - - Status: - - - - - - - - 50 - false - - - - Enabled/Disabled - - - - - - - - 50 - false - - - - Completion: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - true - - - - 154 - 0 - - - - - 220 - 16777215 - - - - - 50 - false - - - - 0 - - - Qt::AlignCenter - - - false - - - - - - - - 50 - false - - - - Obfuscation Balance: - - - - - - - - 75 - true - - - - 0 BWK - - - - - - - - 50 - false - - - - Amount and Rounds: - - - - - - - - 50 - false - - - - 0 BWK / 0 Rounds - - - - - - - - 50 - false - - - - Submitted Denom: - - - - - - - - 50 - false - - - - The denominations you submitted to the Masternode.<br>To mix, other users must submit the exact same denominations. - - - n/a - - - - - - - - - 251 - 17 - 1 - 1 - - - - - - - - - 0 - 0 - 0 - - - - - - - 239 - 238 - 238 - - - - - - - 255 - 255 - 255 - - - - - - - 247 - 246 - 246 - - - - - - - 119 - 119 - 119 - - - - - - - 159 - 159 - 159 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 239 - 238 - 238 - - - - - - - 0 - 0 - 0 - - - - - - - 247 - 246 - 246 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 0 - 0 - 0 - - - - - - - 239 - 238 - 238 - - - - - - - 255 - 255 - 255 - - - - - - - 247 - 246 - 246 - - - - - - - 119 - 119 - 119 - - - - - - - 159 - 159 - 159 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 239 - 238 - 238 - - - - - - - 0 - 0 - 0 - - - - - - - 247 - 246 - 246 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 119 - 119 - 119 - - - - - - - 239 - 238 - 238 - - - - - - - 255 - 255 - 255 - - - - - - - 247 - 246 - 246 - - - - - - - 119 - 119 - 119 - - - - - - - 159 - 159 - 159 - - - - - - - 119 - 119 - 119 - - - - - - - 255 - 255 - 255 - - - - - - - 119 - 119 - 119 - - - - - - - 239 - 238 - 238 - - - - - - - 239 - 238 - 238 - - - - - - - 0 - 0 - 0 - - - - - - - 239 - 238 - 238 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - Qt::NoFocus - - - true - - - - - - true - - - - - - 10 - 270 - 215 - 35 - - - - - 0 - 0 - - - - Start / Stop Obfuscation - - - - - true - - - - 10 - 205 - 441 - 1 - - - - QFrame::Plain - - - Qt::Horizontal - - - - - - 10 - 220 - 441 - 43 - - - - - 288 - 43 - - - - (Last Message) - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - 10 - 315 - 215 - 35 - - - - - 0 - 0 - - - - Try to manually submit a Obfuscation request. - - - Try Mix - - - - - - 230 - 315 - 215 - 35 - - - - - 0 - 0 - - - - Reset the current status of Obfuscation (can interrupt Obfuscation if it's in the process of Mixing, which can cost you money!) - - - false - - - Reset - - - - - - 10 - 180 - 441 - 16 - - - - - 75 - true - - - - Status Messages - - - - - - 230 - 270 - 215 - 35 - - - - - 0 - 0 - - - - Enable Staking - - - - - - 10 - 10 - 451 - 22 - - - - - 5 - - - - - - 8 - 75 - true - - - - Obfuscation - - - - - - - - 50 - false - false - false - - - - The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. - - - QLabel { color: red; } - - - (out of sync) - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 30 - 20 - - - - - - - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - + - - - - 0 - 0 - - - - - 75 - true - - - - Recent transactions - - - - - - - - 0 - 0 - - - - WhatsThisCursor - - - The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. - - - QLabel { color: red; } - - - (out of sync) - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - + + - 30 - 20 + 0 + 0 - + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + 0 + 20 + + + + + 12 + 75 + true + + + + Recent transactions + + + + + + + WhatsThisCursor + + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + + + QLabel { color: red; } + + + (out of sync) + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + + + + + + 100 + 0 + + + + + 500 + 0 + + + + QListView { background: transparent; } + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QAbstractItemView::NoSelection + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 40 + + + + + + + + + 16777215 + 16777215 + + + + background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; + + + + + + true + + + 3 + + + + + - - - - QListView { background: transparent; } - - - QFrame::NoFrame - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - false - - - QAbstractItemView::NoSelection - - - - - - - - + + + + + - - - QtMaterialFlatButton - QWidget -
qtmaterialflatbutton.h
-
-
diff --git a/src/qt/forms/privacydialog.ui b/src/qt/forms/privacydialog.ui new file mode 100644 index 000000000..a63d53ab7 --- /dev/null +++ b/src/qt/forms/privacydialog.ui @@ -0,0 +1,2483 @@ + + + PrivacyDialog + + + true + + + + 0 + 0 + 1078 + 737 + + + + + 0 + 0 + + + + + 1060 + 0 + + + + + + + 0 + + + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 2 + + + + + 6 + + + + + + + + + + + + + + + 12 + 75 + true + + + + Zerocoin Actions: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + + + QLabel { color: red; } + + + (out of sync) + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + QFrame::Sunken + + + Qt::Horizontal + + + + + + + + + + 131 + 0 + + + + Enter an amount of BWK to convert to zBWK + + + Mint Zerocoin + + + + + + + + 60 + 0 + + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + zBWK + + + + + + + Available for minting are coins which are confirmed and not locked or Masternode collaterals. + + + Mintable: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 75 + true + + + + Enter an amount of BWK to convert to zBWK + + + 0.000 000 00 BWK + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 131 + 27 + + + + + 131 + 16777215 + + + + + + + Coin Control... + + + false + + + + + + + + + + 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 BWK + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 8 + + + + Status and/or Mesages from the last Mint Action. + + + QFrame::Panel + + + QFrame::Sunken + + + 2 + + + 2 + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOff + + + true + + + + + + true + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + + + + + 0 + + + 0 + + + + + zBWK Control + + + + + + + zBWK Selected: + + + + + + + 0 + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + Quantity Selected: + + + + + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 131 + 0 + + + + Spend Zerocoin. Without 'Pay To:' address creates payments to yourself. + + + Spend Zerocoin + + + + + + + Available (mature and spendable) zBWK for spending + + + Available Balance: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 75 + true + + + + Available (mature and spendable) zBWK for spending + +zBWK are mature when they have more than 20 confirmations AND more than 1 mint of the same denomination after them were minted + + + 0 zBWK + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Security Level for Zerocoin Transactions. More is better, but needs more time and resources. + + + QFrame::Box + + + Security Level: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 0 + 0 + + + + Security Level 1 - 100 (default: 42) + + + QAbstractSpinBox::PlusMinus + + + true + + + QAbstractSpinBox::CorrectToNearestValue + + + 1 + + + 100 + + + 42 + + + + + + + + + + + + + + 80 + 0 + + + + Pay To: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + payTo + + + + + + + 0 + + + + + true + + + + 0 + 31 + + + + The Bulwark address to send the payment to. Creates local payment to yourself when empty. + + + + + + + Choose previously used address + + + + + + + :/icons/address-book:/icons/address-book + + + Alt+A + + + + + + + Paste address from clipboard + + + + + + + :/icons/editpaste:/icons/editpaste + + + Alt+P + + + + + + + + + + + + + + 80 + 0 + + + + Label: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + addAsLabel + + + + + + + Enter a label for this address to add it to the list of used addresses + + + + + + + + + + + + 80 + 0 + + + + Amount: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + zBWKpayAmount + + + + + + + + + + + 55 + 0 + + + + zBWK + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Qt::LeftToRight + + + Convert Change to Zerocoin (might cost additional fees) + + + + + + + If checked, the wallet tries to minimize the returning change instead of minimizing the number of spent denominations. + + + Minimize Change + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + 75 + true + + + + Information about the available Zerocoin funds. + + + Zerocoin Stats: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + + + + + Qt::Vertical + + + QSizePolicy::Maximum + + + + 20 + 10 + + + + + + + + + + + 75 + true + + + + Total Balance including unconfirmed and immature zBWK + + + Total Zerocoin Balance: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 40 + 0 + + + + + 75 + true + + + + Total Balance including unconfirmed and immature zBWK + + + 0 zBWK + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Denominations with value 1: + + + Denom. with value 1: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 40 + 0 + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + 0 x + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Denominations with value 5: + + + Denom. with value 5: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 40 + 0 + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + 0 x + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Denominations with value 10: + + + Denom. with value 10: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 40 + 0 + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + 0 x + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Denominations with value 50: + + + Denom. with value 50: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 40 + 0 + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + 0 x + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Denominations with value 100: + + + Denom. with value 100: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 40 + 0 + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + 0 x + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Denominations with value 500: + + + Denom. with value 500: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 40 + 0 + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + 0 x + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Denominations with value 1000: + + + Denom. with value 1000: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 40 + 0 + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + 0 x + + + Qt::RichText + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + + + + + + + Show the current status of automatic zBWK minting. + +To change the status (restart required): +- enable: add 'enablezeromint=1' to bulwark.conf +- disable: add 'enablezeromint=0' to bulwark.conf + +To change the percentage (no restart required): +- menu Settings->Options->Percentage of autominted zBWK + + + + + AutoMint Status + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + + + + + + + + 75 + true + + + + Global Supply: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 75 + true + + + + 0 zBWK + + + + + + + + + + + Denom. 1: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 zBWK + + + + + + + + + + + Denom. 5: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 zBWK + + + + + + + + + + + Denom. 10: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 zBWK + + + + + + + + + + + Denom. 50: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 zBWK + + + + + + + + + + + Denom. 100: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 zBWK + + + + + + + + + + + Denom. 500: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 zBWK + + + + + + + + + + + Denom. 1000: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 zBWK + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + 100 + 22 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 10 + + + 14 + + + 10 + + + 4 + + + 6 + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + false + + + + 0 + 0 + + + + + 111 + 12 + + + + + 111 + 12 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.000 000 00 BWK + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + false + + + + 75 + true + + + + Priority: + + + + + + + + + TextLabel + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + false + + + + 75 + true + + + + Fee: + + + 0 + + + + + + + false + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BWK + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + false + + + + 75 + true + + + + Dust: + + + + + + + false + + + IBeamCursor + + + Qt::ActionsContextMenu + + + no + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + false + + + + 75 + true + + + + Bytes: + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + 0 + + + 0 + + + + + + + false + + + + 0 + 0 + + + + + 75 + true + + + + color:red;font-weight:bold; + + + Insufficient funds! + + + 5 + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + false + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + 3 + + + + + + + false + + + + 0 + 0 + + + + + 0 + 0 + + + + + 240 + 16777215 + + + + Coins automatically selected + + + 5 + + + + + + + false + + + + 0 + 0 + + + + + 111 + 0 + + + + + 111 + 16777215 + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.000 000 00 BWK + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + false + + + IBeamCursor + + + Qt::ActionsContextMenu + + + medium + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 10 + + + 10 + + + + + 15 + + + + + false + + + + 0 + 0 + + + + + 75 + true + + + + font-weight:bold; + + + Coin Control Features + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + 0 + + + 10 + + + + + + + + + + 12 + + + QLayout::SetDefaultConstraint + + + 5 + + + 5 + + + + + false + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + + + Custom change address + + + + + + + false + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + 3 + + + + + + + + + Qt::Vertical + + + + 800 + 1 + + + + + + + + + + + + + false + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 75 + true + + + + Amount After Fee: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 0 + + + + + + + false + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 75 + true + + + + Change: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + + QtMaterialFlatButton + QWidget +
qtmaterialflatbutton.h
+ 1 +
+ + QValidatedLineEdit + QLineEdit +
qvalidatedlineedit.h
+
+
+ + + + +
diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index ed469671f..d4e0b641e 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -6,346 +6,371 @@ 0 0 - 776 - 364 + 962 + 616 - + - - - - 0 - 0 - + + + 0 - - QFrame::StyledPanel - - - QFrame::Sunken - - - - - - - - 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. - - - R&euse an existing receiving address (not recommended) - - - - - - - - - - - - - - An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bulwark network. - - - &Message: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - reqMessage - - - - - - - An optional label to associate with the new receiving address. - - - - - - - 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 Bulwark network. - - - - - - - Use this form to request payments. All fields are <b>optional</b>. - - - - - - - An optional label to associate with the new receiving address. - - - &Label: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - reqLabel - - - - - - - An optional amount to request. Leave this empty or zero to not request a specific amount. - - - &Amount: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - reqAmount - - - - - - - - 80 - 0 - - - - An optional amount to request. Leave this empty or zero to not request a specific amount. - - - - - - - - - - 150 - 0 - - - - Generate Address - - - - :/icons/receiving_addresses:/icons/receiving_addresses - - - - - - - - 0 - 0 - - - - Clear all fields of the form. - - - Clear - - - - :/icons/remove:/icons/remove - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 10 - - - - - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - 75 - true - - - - Requested payments history - - - - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 51 - 51 - 51 - - - - - - - - - 85 - 85 - 85 - - - - - + + + + + 6 - - Qt::CustomContextMenu + + 6 - - false + + 6 - - true + + 6 - - - - - - - false - - - Show the selected request (does the same as double clicking an entry) - - - Show - - - - :/icons/edit:/icons/edit - - - false - + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + + + 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 an existing receiving address (not recommended) + + + + + + + + + + + + + + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bulwark network. + + + Message: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + reqMessage + + + + + + + An optional label to associate with the new receiving address. + + + + + + + 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 Bulwark network. + + + + + + + Use this form to request payments. All fields are <b>optional</b>. + + + + + + + An optional label to associate with the new receiving address. + + + Label: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + reqLabel + + + + + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + + + Amount: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + reqAmount + + + + + + + + 80 + 0 + + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + + + + + + + + + + + + + + + + + 150 + 0 + + + + Request payment + + + + :/icons/receiving_addresses:/icons/receiving_addresses + + + + + + + + 0 + 0 + + + + Clear all fields of the form. + + + Clear + + + + :/icons/remove:/icons/remove + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + - - - false - - - Remove the selected entries from the list - - - Remove - - - - :/icons/remove:/icons/remove - - - false - + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 75 + true + + + + Requested payments history + + + + + + + + + + + + 51 + 51 + 51 + + + + + + + + + 51 + 51 + 51 + + + + + + + + + 85 + 85 + 85 + + + + + + + + Qt::CustomContextMenu + + + false + + + true + + + + + + + + + false + + + Show the selected request (does the same as double clicking an entry) + + + Show + + + + :/icons/edit:/icons/edit + + + false + + + + + + + false + + + Remove the selected entries from the list + + + Remove + + + + :/icons/remove:/icons/remove + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - + + + diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index 4c7cbf7c8..100b59677 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -21,7 +21,7 @@ - &Information + Information @@ -252,9 +252,18 @@ + + IBeamCursor + N/A + + Qt::PlainText + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + @@ -359,7 +368,7 @@ - &Console + Console @@ -396,19 +405,15 @@ - 24 + 68 24 - + Clear console - - - - - :/icons/remove:/icons/remove + Clear Ctrl+L @@ -424,7 +429,7 @@ - &Network Traffic + Network Traffic @@ -677,7 +682,7 @@ - &Peers + Peers @@ -1133,12 +1138,25 @@ - &Wallet Repair + Wallet Repair - + 12 + + + + + 100 + 23 + + + + Delete local Blockchain Folders + + + @@ -1384,7 +1402,7 @@ - + Qt::Vertical @@ -1397,6 +1415,23 @@ + + + + -resync: + + + + + + + Deletes all local blockchain folders so the wallet synchronizes from scratch. + + + true + + + diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index 06ef96a6a..53bc5e870 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -2,180 +2,104 @@ SendCoinsDialog + + true + 0 0 - 850 - 610 + 978 + 693 Send Coins - + - 8 + 9 - - - - 0 - 0 - + + + 0 + + + 0 - - - 16777215 - 16777215 - + + 0 - - QFrame::StyledPanel + + 0 - - QFrame::Sunken + + 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 6 - - - - + + + + + 0 + + + 0 + + + 0 + + 0 + + + + + + + + 0 + 0 + + + - 10 + 6 - 10 + 6 + + + 6 + + + 0 - - - 15 - - - - - - 0 - 0 - - - - - 75 - true - - - - font-weight:bold; - - - Coin Control Features - - - - - - - - - 8 - - - 10 - - - - - - - - Inputs... - - - false - - - - - - - automatically selected - - - 5 - - - - - - - - 75 - true - - - - color:red;font-weight:bold; - - - Insufficient funds! - - - 5 - - - - - - - Qt::Horizontal - - - - 40 - 1 - - - - - - - - + - + 0 0 - + - 0 - 0 + 16777215 + 16777215 - - + + QFrame::StyledPanel + + + QFrame::Sunken - + + + 0 + 0 @@ -189,1261 +113,1557 @@ 0 - - - 20 - - - 0 - - - 10 - - - - - 10 - - - 14 - - - 10 - - - 4 - - - 6 - - - - - - 75 - true - - - - Quantity: - - - 0 - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0 - - - 0 - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 75 - true - - - - Bytes: - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0 - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - 10 - - - 14 - - - 6 - - - 4 - - - 6 - - - - - - 75 - true - - - - Amount: - - - 0 - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0.00 BWK - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 75 - true - - - - Priority: - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - medium - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - 10 - - - 14 - - - 6 - - - 4 - - - 6 - - - - - - 75 - true - - - - Fee: - - - 0 - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0.00 BWK - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 75 - true - - - - Dust: - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - no - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - 10 - - - 14 - - - 6 - - - 4 - - - 6 - - - - - - 75 - true - - - - After Fee: - - - 0 - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0.00 BWK - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 75 - true - - - - Change: - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0.00 BWK - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - - - - - - 12 - - - QLayout::SetDefaultConstraint - - - 5 - - - 5 - - - - - If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. - - - Custom change address - - - - - - - false - - - - 0 - 0 - - - - - - - - Split UTXO - - - - - - - - 50 - 0 - - - - # of outputs - - - - - - - UTXO Size: - - - - - - - 0 BWK - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - - - 3 - - - - - - - - - Qt::Vertical - - - - 800 - 1 - - - - - - - - - - - - - true - - - - - 0 - 0 - 830 - 161 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 6 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - QFrame::StyledPanel - - - QFrame::Sunken - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - 10 - - - 0 - - - - - 0 - - - - - 0 - - - - - Qt::Vertical - - - QSizePolicy::Fixed + + + + 1 - - - 1 - 4 - + + 10 - - - - - + 10 - - - - 0 - 0 - - - - - 75 - true - - - - font-weight:bold; + + + 15 - - Transaction Fee: - - + + + + 6 + + + + + + 0 + 0 + + + + + 0 + 20 + + + + + 12 + 75 + true + + + + font-weight:bold; + + + Coin Control Features + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + + + + - - - + + + 8 - - - - - - Choose... + + 10 - + + + + + + + Open Coin Control... + + + false + + + + + + + Coins automatically selected + + + 5 + + + + + + + + 75 + true + + + + color:red;font-weight:bold; + + + Insufficient funds! + + + 5 + + + + + + + Qt::Horizontal + + + + 40 + 1 + + + + + - - - collapse fee-settings + + + + 0 + 0 + - - Minimize + + + 0 + 0 + - - - - - - - - Qt::Vertical - - - - 1 - 1 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 10 - - - 4 - - - 10 - - - 4 - - - - - 6 - - - - - - - If the custom fee is set to 1000 uBWKs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 uBWKs in fee,<br />while "at least" pays 1000 uBWKs. For transactions bigger than a kilobyte both pay by kilobyte. - - - per kilobyte - - - true - - - groupCustomFee - - - - - - - If the custom fee is set to 1000 uBWKs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 uBWKs in fee,<br />while "total at least" pays 1000 uBWKs. For transactions bigger than a kilobyte both pay by kilobyte. - - - total at least - - - groupCustomFee - - - - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - - - - - Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks.<br />But be aware that this can end up in a never confirming transaction once there is more demand for Bulwark transactions than the network can process. - - - - - - + + + + + + 0 + + + 0 + + + 0 + + + 0 + - - - true - - - Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks.<br />But be aware that this can end up in a never confirming transaction once there is more demand for Bulwark transactions than the network can process. - - - (read the tooltip) + + + 20 - - 5 + + 0 - - - - - - Qt::Horizontal - - - - 1 - 1 - + + 10 - + + + + 10 + + + 14 + + + 10 + + + 4 + + + 6 + + + + + + 75 + true + + + + Quantity: + + + 0 + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + Bytes: + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0 + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + + 75 + true + + + + Amount: + + + 0 + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BWK + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + Priority: + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + medium + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + + 75 + true + + + + Fee: + + + 0 + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BWK + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + Dust: + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + no + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + 10 + + + 14 + + + 6 + + + 4 + + + 6 + + + + + + 75 + true + + + + After Fee: + + + 0 + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BWK + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 75 + true + + + + Change: + + + + + + + IBeamCursor + + + Qt::ActionsContextMenu + + + 0.00 BWK + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + - - - - - - - - - Qt::Vertical - - - - 1 - 1 - - - - - - - - - - - - - - - groupFee - - - - - - - Qt::Vertical - - - - 1 - 1 - - - - - - - - - - 6 - - - 2 + + + + + + 12 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + + + Custom change address + + + + + + + false + + + + 0 + 0 + + + + + 300 + 0 + + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + + + 3 + + + + + + + + + 12 + + + 0 + + + + + + 0 + 0 + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + Split UTXO + + + + + + + + 50 + 0 + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + # of outputs + + + + + + + 0 BWK + + + + + + + UTXO Size: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 800 + 1 + + + + + + + + + + + + + + true + + + + + 0 + 0 + 944 + 136 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 6 + + + 0 + + + 6 + + + + + 0 - + + + 0 + - + - Qt::Horizontal + Qt::Vertical + + + QSizePolicy::Fixed 1 - 1 + 4 - - - - - + + + 10 + - - - Confirmation time: + + + + 0 + 0 + + + + + 75 + true + + + + font-weight:bold; - - 2 + + Transaction Fee: - - - Qt::Vertical - - - - 1 - 1 - + + + - + - - - - - - 30 - - - - 0 - - - 24 - - - 1 - - - 0 - - - Qt::Horizontal - - - false - - - false - - - QSlider::NoTicks + + + Choose... - - - - - normal - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - fast - - - - + + + collapse fee-settings + + + Minimize + + + + + + Qt::Vertical + + + + 1 + 1 + + + + - + - Qt::Vertical + Qt::Horizontal - 1 - 1 + 40 + 20 - - - - Recommended - - - - - - - - - - true - - - groupFee - + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 10 + + + 4 + + + 10 + + + 4 + + + + + + + Qt::Vertical + + + + 1 + 1 + + + + + + + + + + + + + + + groupFee + + + + + + + Qt::Vertical + + + + 1 + 1 + + + + + + + + + + Custom: + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + + + + + 6 + + + + + + + If the custom fee is set to 1000 uBWKs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 uBWKs in fee,<br />while "at least" pays 1000 uBWKs. For transactions bigger than a kilobyte both pay by kilobyte. + + + per kilobyte + + + true + + + groupCustomFee + + + + + + + If the custom fee is set to 1000 uBWKs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 uBWKs in fee,<br />while "total at least" pays 1000 uBWKs. For transactions bigger than a kilobyte both pay by kilobyte. + + + total at least + + + groupCustomFee + + + + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + + + + + Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks.<br />But be aware that this can end up in a never confirming transaction once there is more demand for Bulwark transactions than the network can process. + + + + + + + + + + true + + + Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks.<br />But be aware that this can end up in a never confirming transaction once there is more demand for Bulwark transactions than the network can process. + + + (read the tooltip) + + + 5 + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + + + + + Recommended + + + + + + + 6 + + + 2 + + + 20 + + + + + + + Confirmation time: + + + 2 + + + + + + + normal + + + 2 + + + + + + + + 0 + 24 + + + + 0 + + + 24 + + + 1 + + + 0 + + + Qt::Horizontal + + + false + + + false + + + QSlider::NoTicks + + + + + + + fast + + + + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 2 + + + + + + + (Smart fee not initialized yet. This usually takes a few blocks...) + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + 2 + + + -1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + Qt::Horizontal + + + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + + + Qt::Vertical + + + + 1 + 1 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + 2 + + + + + + + + + + true + + + groupFee + + + + + + + + + 8 + + + 4 + + + + + Send as zero-fee transaction if possible + + + + + + + (confirmation may take longer) + + + 5 + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + + + Qt::Vertical + + + + 1 + 1 + + + + + - - - - Custom: + + + + Qt::Vertical - - Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + 800 + 1 + - + - - - - - - - 2 + + + + + + + + + + 0 + + + + + + 150 + 0 + + + + Confirm the send action + + + Send + + + + :/icons/send:/icons/send + + + false + + + true + + + + + + + + 0 + 0 + + + + Clear all fields of the form. + + + Clear All + + + + :/icons/remove:/icons/remove + + + false + + + + + + + Send to multiple recipients at once + + + Add Recipient + + + + :/icons/add:/icons/add + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 3 + + + + + false - - - - - + Anonymized BWK - - - - (Smart fee not initialized yet. This usually takes a few blocks...) - - - Qt::AlignHCenter - - + + + true - - 2 + + + 85 + 0 + - - - - - - - - 8 - - - 4 - - - - Send as zero-fee transaction if possible + SwiftTX - + - (confirmation may take longer) - - - 5 + Balance: - - - Qt::Horizontal + + + + 0 + 0 + - - - 1 - 1 - + + IBeamCursor - + + 123.456 BWK + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + - - - - Qt::Vertical - - - - 1 - 1 - - - - - - - - Qt::Vertical - - - - 800 - 1 - - - - - - - - - - - - - - - 150 - 0 - - - - Confirm the send action - - - Send - - - - :/icons/send:/icons/send - - - false - - - true - - - - - - - - 0 - 0 - - - - Clear all fields of the form. - - - Clear All - - - - :/icons/remove:/icons/remove - - - false - - - - - - - Send to multiple recipients at once - - - Add Recipient - - - - :/icons/add:/icons/add - - - false - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 3 - - - - - - 95 - 0 - - - - Obfuscation - - - false - - - - - - - true - - - - 85 - 0 - - - - SwiftTX - - - - - - - Balance: - - - - - - - - 0 - 0 - - - - IBeamCursor - - - 123.456 BWK - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - @@ -1453,6 +1673,7 @@ QtMaterialFlatButton QWidget
qtmaterialflatbutton.h
+ 1 QValidatedLineEdit diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui index ebf155331..a46e50bf8 100644 --- a/src/qt/forms/sendcoinsentry.ui +++ b/src/qt/forms/sendcoinsentry.ui @@ -49,7 +49,7 @@ - Pay &To: + Pay To: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -62,7 +62,7 @@ - A&mount: + Amount: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -75,7 +75,7 @@ - &Label: + Label: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -724,7 +724,7 @@ - A&mount: + Amount: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -1260,7 +1260,7 @@ - A&mount: + Amount: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui index 0f333383e..69a9515a5 100644 --- a/src/qt/forms/signverifymessagedialog.ui +++ b/src/qt/forms/signverifymessagedialog.ui @@ -24,7 +24,7 @@ - &Sign Message + Sign Message @@ -231,7 +231,7 @@ - &Verify Message + Verify Message diff --git a/src/qt/forms/zbwkcontroldialog.ui b/src/qt/forms/zbwkcontroldialog.ui new file mode 100644 index 000000000..7d8bd9be2 --- /dev/null +++ b/src/qt/forms/zbwkcontroldialog.ui @@ -0,0 +1,170 @@ + + + ZBwkControlDialog + + + + 0 + 0 + 681 + 384 + + + + + 681 + 384 + + + + Select zBWK to Spend + + + + + + QLayout::SetDefaultConstraint + + + + + Quantity + + + + + + + 0 + + + + + + + zBWK + + + + + + + 0 + + + + + + + Select/Deselect All + + + + + + + + + + + + 0 + 250 + + + + true + + + true + + + 5 + + + 100 + + + + Select + + + + + Denomination + + + + + zBWK Public ID + + + + + Confirmations + + + + + Is Spendable + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + QtMaterialFlatButton + QWidget +
qtmaterialflatbutton.h
+
+
+ + + + buttonBox + accepted() + ZBwkControlDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ZBwkControlDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 526416dfb..7dca56f90 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -23,9 +23,9 @@ static const bool DEFAULT_SPLASHSCREEN = true; #define STYLE_INVALID "background:#FF8080" /* Transaction list -- unconfirmed transaction */ -#define COLOR_UNCONFIRMED QColor(128, 128, 128) +#define COLOR_UNCONFIRMED QColor(135, 214, 48) /* Transaction list -- negative amount */ -#define COLOR_NEGATIVE QColor(255, 0, 0) +#define COLOR_NEGATIVE QColor(206, 0, 188) /* Transaction list -- bare address (without label) */ #define COLOR_BAREADDRESS QColor(140, 140, 140) /* Transaction list -- TX status decoration - open until date */ @@ -34,6 +34,8 @@ static const bool DEFAULT_SPLASHSCREEN = true; #define COLOR_TX_STATUS_OFFLINE QColor(192, 192, 192) /* Transaction list -- TX status decoration - default color */ #define COLOR_BLACK QColor(51, 51, 51) +/* Transaction list -- TX status decoration - conflicted */ +#define COLOR_CONFLICTED QColor(255, 0, 0) /* Tooltips longer than this (in characters) are converted into rich text, so that they can be word-wrapped. diff --git a/src/qt/locale/bulwark_bg.ts b/src/qt/locale/bulwark_bg.ts index 8b6244ee8..14a836600 100644 --- a/src/qt/locale/bulwark_bg.ts +++ b/src/qt/locale/bulwark_bg.ts @@ -10,36 +10,36 @@ Създайте нов адрес - &New - &Нов + New + Нов Copy the currently selected address to the system clipboard Копиране на избраните адреси в системния буфер - &Copy - &Копирай + Copy + Копирай Delete the currently selected address from the list Изтриване на избраните адреси от списъка - &Delete - &Изтрии + Delete + Изтрии Export the data in the current tab to a file Експортиране информацията от сегашния таб във файл - &Export - &Експортиране + Export + Експортиране - C&lose - &Затвори + Close + Затвори Choose the address to send coins to @@ -50,8 +50,8 @@ Изберете адрес, в който да получавате монети - C&hoose - Из&бери + Choose + Избери Sending addresses @@ -70,16 +70,16 @@ Това са вашите Bulwark адреси за получаване на плащания. Препоръчително е да използвате нови адреси за получаване за всяка транзакция. - &Copy Address - &Копиране на адреса + Copy Address + Копиране на адреса - Copy &Label - Копиране на &Етикета + Copy Label + Копиране на Етикета - &Edit - &Редактиране + Edit + Редактиране Export Address List @@ -227,8 +227,8 @@ BIP 38 инструменти - &BIP 38 Encrypt - &BIP 38 криптиране + BIP 38 Encrypt + BIP 38 криптиране Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -275,7 +275,7 @@ Подпишете съобщението, за да докажете, че притежавате този Bulwark адрес - Encrypt &Key + Encrypt Key Криптиращ ключ @@ -283,7 +283,7 @@ BitcoinGUI Unlock wallet - Отключи портфейла + Отключване на портфейла @@ -347,6 +347,25 @@ PeerTableModel + + PrivacyDialog + + Choose previously used address + Изберете предишноизползван адрес + + + Alt+A + Алт+А + + + Paste address from clipboard + Постави адреса от буфера + + + Alt+P + Алт+П + + QObject @@ -491,14 +510,17 @@ WalletView - &Export - &Експортиране + Export + Експортиране Export the data in the current tab to a file Експортиране информацията от сегашния таб във файл + + ZBwkControlDialog + bulwark-core diff --git a/src/qt/locale/bulwark_ca.ts b/src/qt/locale/bulwark_ca.ts index 399e5c0dc..c61a495d9 100644 --- a/src/qt/locale/bulwark_ca.ts +++ b/src/qt/locale/bulwark_ca.ts @@ -10,36 +10,36 @@ Crea una nova adreça - &New - &Nou + New + Nou Copy the currently selected address to the system clipboard Copia l'adreça seleccionada al porta-retalls del sistema - &Copy - &Copia + Copy + Copia Delete the currently selected address from the list Elimina l'adreça seleccionada de la llista - &Delete - &Elimina + Delete + Elimina Export the data in the current tab to a file Exporta les dades de la pestanya actual a un fitxer - &Export - &Exporta + Export + Exporta - C&lose - &Tanca + Close + Tanca Choose the address to send coins to @@ -50,8 +50,8 @@ Tria l'adreça on rebre les monedes - C&hoose - &Tria + Choose + Tria Sending addresses @@ -62,16 +62,16 @@ Adreces de recepció - &Copy Address - &Copia adreça + Copy Address + Copia adreça - Copy &Label - Copia l'eti&queta + Copy Label + Copia l'etiqueta - &Edit - &Edita + Edit + Edita Export Address List @@ -234,144 +234,144 @@ Node - &Send - &Envia + Send + Envia - &Receive - &Rep + Receive + Rep - &Transactions - &Transaccions + Transactions + Transaccions Browse transaction history Mostra històric de transaccions - E&xit - &Surt + Exit + Surt Quit application Surt de l'aplicació - About &Qt - Sobre &Qt + About Qt + Sobre Qt Show information about Qt Mostra informació sobre el Qt - &Options... - &Opcions... + Options... + Opcions... Show or hide the main Window Mostra o oculta la Finestra principal - &Encrypt Wallet... - &Encripta el moneder... + Encrypt Wallet... + Encripta el moneder... - &Backup Wallet... - Realitza una &còpia de seguretat del moneder... + Backup Wallet... + Realitza una còpia de seguretat del moneder... - &Unlock Wallet... - &Desbloqueja el moneder... + Unlock Wallet... + Desbloqueja el moneder... Unlock wallet Desbloqueja el moneder - &Lock Wallet - B&loqueja el moneder + Lock Wallet + Bloqueja el moneder - Sign &message... - Signar &missatge... + Sign message... + Signar missatge... - &Verify message... - &Verifica el missatge... + Verify message... + Verifica el missatge... - &Information - &Informació + Information + Informació - &Debug console - Consola de &Depuració + Debug console + Consola de Depuració - &Network Monitor - Monitor de &Xarxa + Network Monitor + Monitor de Xarxa Show network monitor Mostra el monitor de xarxa - Wallet &Repair - &Repara el moneder + Wallet Repair + Repara el moneder Open configuration file Obre el fitxer de configuració - &Sending addresses... - Adreces d'&enviament... + Sending addresses... + Adreces d'enviament... - &Receiving addresses... - Adreces de &recepció... + Receiving addresses... + Adreces de recepció... - Open &URI... - Obre l'&URI... + Open URI... + Obre l'URI... - &File - &Fitxer + File + Fitxer - &Settings - &Configuració + Settings + Configuració - &Tools - &Eines + Tools + Eines - &Help - A&juda + Help + Ajuda Bulwark Core Bulwark Core - &About Bulwark Core - &Sobre Bulwark Core + About Bulwark Core + Sobre Bulwark Core - &BIP38 tool - Eina &BIP38 + BIP38 tool + Eina BIP38 - Open Wallet &Configuration File - Obre el fitxer de &configuració del moneder + Open Wallet Configuration File + Obre el fitxer de configuració del moneder - Open &Masternode Configuration File - Obre el fitxer de &configuració del Node Mestre + Open Masternode Configuration File + Obre el fitxer de configuració del Node Mestre Open Masternode configuration file @@ -518,8 +518,8 @@ Edita l'adreça - &Address - &Adreça + Address + Adreça New receiving address @@ -694,20 +694,20 @@ Expert - &Port: - &Port: + Port: + Port: User Interface Theme: Tema de la interfície d'usuari: - &Reset Options - &Restableix les opcions + Reset Options + Restableix les opcions - &Cancel - &Cancel·la + Cancel + Cancel·la @@ -729,52 +729,71 @@ Total: - Status: - Estat: + Recent transactions + Transaccions recents + + + PaymentServer + + + PeerTableModel - Obfuscation - Ofuscació + Version + Versió - Recent transactions - Transaccions recents + Ping Time + Temps de Ping + + + PrivacyDialog Reset Restableix - Disabled - Desactivat + Quantity: + Quantitat: - Start Obfuscation - Inicia ofuscació + Amount: + Import: - Stop Obfuscation - Atura ofuscació + Alt+A + Alt+A - Enabled - Activat + Alt+P + Alt+P - - - PaymentServer - - - PeerTableModel - Version - Versió + Priority: + Prioritat: - Ping Time - Temps de Ping + no + no - + + Bytes: + Bytes: + + + Change: + Canvi: + + + Copy quantity + Copia la quantitat + + + Copy amount + Copia l'import + + QObject @@ -809,8 +828,8 @@ QRImageWidget - &Copy Image - &Copia la imatge + Copy Image + Copia la imatge @@ -820,8 +839,8 @@ Finestra d'eines - &Information - &Informació + Information + Informació General @@ -836,8 +855,8 @@ Nombre de connexions - &Open - &Obre + Open + Obre Network @@ -848,8 +867,8 @@ Data de compilació - &Console - &Consola + Console + Consola Totals @@ -915,8 +934,8 @@ ReceiveCoinsDialog - &Message: - &Missatge: + Message: + Missatge: Remove @@ -942,8 +961,8 @@ Codi QR - Copy &Address - Copia l'&adreça + Copy Address + Copia l'adreça URI @@ -1019,10 +1038,6 @@ Minimize Minimitzar - - Obfuscation - Ofuscació - Confirmation time: Temps de Confirmació: @@ -1085,8 +1100,8 @@ Signatures - Signa / Verifica un Missatge - &Sign Message - &Signa el missatge + Sign Message + Signa el missatge Alt+A @@ -1101,16 +1116,16 @@ Signatura - Sign &Message - Signa el &missatge + Sign Message + Signa el missatge - &Verify Message - &Verifica el missatge + Verify Message + Verifica el missatge - Verify &Message - Verifica el &missatge + Verify Message + Verifica el missatge The entered address is invalid. @@ -1283,14 +1298,17 @@ WalletView - &Export - &Exporta + Export + Exporta Export the data in the current tab to a file Exporta les dades de la pestanya actual a un fitxer + + ZBwkControlDialog + bulwark-core @@ -1301,10 +1319,6 @@ Information Informació - - Obfuscation options: - Opcions d'ofuscació: - Options: Opcions: diff --git a/src/qt/locale/bulwark_cs.ts b/src/qt/locale/bulwark_cs.ts index e437e4f4f..d070ec16e 100644 --- a/src/qt/locale/bulwark_cs.ts +++ b/src/qt/locale/bulwark_cs.ts @@ -10,36 +10,36 @@ Vytvořit novou adresu - &New - &Nová + New + Nová Copy the currently selected address to the system clipboard Kopírovat vybranou adresu do mezipaměti - &Copy - &Kopírovat + Copy + Kopírovat Delete the currently selected address from the list Smazat aktuálně vybranou adresu ze seznamu - &Delete - &Smazat + Delete + Smazat Export the data in the current tab to a file Exportovat data z aktulní záložky do souboru - &Export - &Exportovat + Export + Exportovat - C&lose - Z&avřít + Close + Zavřít Choose the address to send coins to @@ -50,8 +50,8 @@ Vybrat adresu pro přijetí peněz - C&hoose - V&ybrat + Choose + Vybrat Sending addresses @@ -70,16 +70,16 @@ Toto jsou Vaše Bulwark adresy pro přijetí plateb. Je doporučeno použít novou adresu pro každou novou transakci. - &Copy Address - &Kopírovat Adresu + Copy Address + Kopírovat Adresu - Copy &Label - Kopírovat &Popis + Copy Label + Kopírovat Popis - &Edit - &Upravit + Edit + Upravit Export Address List @@ -235,8 +235,8 @@ BIP 38 Nástroj - &BIP 38 Encrypt - &BIP 38 Šifrovat + BIP 38 Encrypt + BIP 38 Šifrovat Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -283,20 +283,20 @@ Podepsat zprávu k prokázání, že vlastníte tuto Bulwark adresu - Encrypt &Key - Šifrovat &Klíč + Encrypt Key + Šifrovat Klíč Reset all sign message fields Resetovat všechny položky podepsání zprávy - Clear &All - Smazat &Vše + Clear All + Smazat Vše - &BIP 38 Decrypt - &BIP 38 Dešifrování + BIP 38 Decrypt + BIP 38 Dešifrování Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. @@ -311,8 +311,8 @@ Verifikujte zprávu pro ujištění, že byla podepsána zmíněnou Bulwark adresou - Decrypt &Key - Dešifrovat &Klíč + Decrypt Key + Dešifrovat Klíč Reset all verify message fields @@ -402,136 +402,136 @@ Uzel - &Overview - &Přehled + Overview + Přehled Show general overview of wallet Ukaž celkový přehled peněženky - &Send - &Odeslat + Send + Odeslat - &Receive - &Přijmout + Receive + Přijmout - &Transactions - &Transakce + Transactions + Transakce Browse transaction history Procházet historii transakcí - E&xit - E&xit + Exit + Exit Quit application Zavřít aplikaci - About &Qt - O &Qt + About Qt + O Qt Show information about Qt Ukaž informace o Qt - &Options... - &Možnosti... + Options... + Možnosti... - &Show / Hide - &Zobrazit / Schovat + Show / Hide + Zobrazit / Schovat Show or hide the main Window Zobrazit nebo schovat hlavní okno - &Encrypt Wallet... - &Šifrovat Peněženku... + Encrypt Wallet... + Šifrovat Peněženku... Encrypt the private keys that belong to your wallet Šifrovat privátní klíče náležící Vaší peněžence - &Backup Wallet... - &Zálohovat peněženku... + Backup Wallet... + Zálohovat peněženku... Backup wallet to another location Zálohovat peněženku na jiné místo - &Change Passphrase... - &Změnit frázové heslo... + Change Passphrase... + Změnit frázové heslo... Change the passphrase used for wallet encryption Změnit frázové heslo pro šifrování peněženky - &Unlock Wallet... - &Odemknout peněženku... + Unlock Wallet... + Odemknout peněženku... Unlock wallet Odemknout peněženku - &Lock Wallet - &Zamknout Peněženku + Lock Wallet + Zamknout Peněženku - Sign &message... - Podepsat &zprávu... + Sign message... + Podepsat zprávu... - &Verify message... - &Verifikovat zprávu... + Verify message... + Verifikovat zprávu... - &Information - &Informace + Information + Informace Show diagnostic information Zobrazit diagnostická data - &Debug console - &Ladící konzolce + Debug console + Ladící konzolce Open debugging console Otevřít ladící konzoli - &Network Monitor - &Monitorování sítě + Network Monitor + Monitorování sítě Show network monitor Zobrazit monitorování sítě - &Peers list - &Seznam peerů + Peers list + Seznam peerů Show peers info Zobrazit info peerů - Wallet &Repair - &Oprava Peněženky + Wallet Repair + Oprava Peněženky Show wallet repair options @@ -542,35 +542,35 @@ Otevřít konfigurační soubor - Show Automatic &Backups - Zobrazit Automatické &Zálohy + Show Automatic Backups + Zobrazit Automatické Zálohy Show automatically created wallet backups Zobrazit automaticky vytvořené zálohy peněženky - &Sending addresses... - &Odesílací adresy... + Sending addresses... + Odesílací adresy... Show the list of used sending addresses and labels Zobrazit seznam použitých adres a popisků pro odedslání platby - &Receiving addresses... - &Příjimací adresy... + Receiving addresses... + Příjimací adresy... Show the list of used receiving addresses and labels Zobrazit seznam použitých adres a popisků pro přijetí plateb - Open &URI... - Otevřít &URI... + Open URI... + Otevřít URI... - &Command-line options + Command-line options Možnosti příkazové řádky @@ -578,20 +578,20 @@ Synchronizuji přídavná data: %p% - &File - &Soubor + File + Soubor - &Settings - &Nastavení + Settings + Nastavení - &Tools - &Nástroje + Tools + Nástroje - &Help - &Pomoc + Help + Pomoc Tabs toolbar @@ -610,16 +610,16 @@ Vyžádat platbu (generování QK kódu a bulwark: URIs) - &Masternodes - &Masternody + Masternodes + Masternody Browse masternodes Procházet masternody - &About Bulwark Core - &O Bulwark Core + About Bulwark Core + O Bulwark Core Show information about Bulwark Core @@ -638,28 +638,28 @@ Ověřit zprávy k zajištění, že bylypodepsány vybranými Bulwark adresami - &BIP38 tool - &BIP38 nástroj + BIP38 tool + BIP38 nástroj Encrypt and decrypt private keys using a passphrase Šifrovat a dešivraovat klíče s použitím frázového hesla - &MultiSend - &MultiSend + MultiSend + MultiSend MultiSend Settings Nastavení MultiSendu - Open Wallet &Configuration File - Otevřít Pěněženkový &Konfigurační soubor + Open Wallet Configuration File + Otevřít Pěněženkový Konfigurační soubor - Open &Masternode Configuration File - Otevřít &Masternodový Konfigurační Soubor + Open Masternode Configuration File + Otevřít Masternodový Konfigurační Soubor Open Masternode configuration file @@ -670,8 +670,8 @@ Otevřít Bulwark: URI nebo platební žádost - &Blockchain explorer - &Blockchanový průzkumník + Blockchain explorer + Blockchanový průzkumník Block explorer window @@ -962,10 +962,6 @@ MultiSend: %1 medium-high středně vysoký - - n/a - n/a - medium střední @@ -1046,12 +1042,12 @@ MultiSend: %1 Upravit adresu - &Label - &Popis + Label + Popis - &Address - &Adresy + Address + Adresy New receiving address @@ -1230,20 +1226,20 @@ MultiSend: %1 Veřejný klíč - S&tart alias - S&pustit alias + Start alias + Spustit alias - Start &all - Spustit &vše + Start all + Spustit vše - Start &MISSING - Spustit &CHYBĚJÍCÍ + Start MISSING + Spustit CHYBĚJÍCÍ - &Update status - &Update stavu + Update status + Update stavu Status will be updated automatically in (sec): @@ -1492,24 +1488,24 @@ Prosím zkontrolujte adresu a zkuste to znovu. Možnosti - &Main - &Hlavní + Main + Hlavní - Size of &database cache - Velikost &databatové cahce + Size of database cache + Velikost databatové cahce MB MB - Number of script &verification threads - Počet skriptových &ověřovacích vláken + Number of script verification threads + Počet skriptových ověřovacích vláken - W&allet - P&eněženka + Wallet + Peněženka Accept connections from outside @@ -1528,8 +1524,8 @@ Prosím zkontrolujte adresu a zkuste to znovu. Automaticky spustit Bulwark po přihlášení do systému - &Start Bulwark on system login - &Spusti Bulwark při přihlášení do systému + Start Bulwark on system login + Spusti Bulwark při přihlášení do systému Amount of Bulwark to keep anonymized @@ -1540,52 +1536,52 @@ Prosím zkontrolujte adresu a zkuste to znovu. Zobrazit záložku Masternodů - &Network - &Síť + Network + Síť - Proxy &IP: - Proxy &IP + Proxy IP: + Proxy IP IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) IP adresa proxy (například IPv4: 127.0.0.1 / IPv6: ::1) - &Port: - &Port + Port: + Port Port of the proxy (e.g. 9050) Port proxy (například 9050) - &Window - &Okno + Window + Okno - M&inimize on close + Minimize on close Při zavření minimalizovat - &Display - &Zobrazit + Display + Zobrazit Reset all client options to default. Resetovat všechny klintské volby na defaultní hodnoty. - &Reset Options - &Resetovat Volby + Reset Options + Resetovat Volby - &OK - &OK + OK + OK - &Cancel - &Zrušit + Cancel + Zrušit none @@ -1614,10 +1610,6 @@ Prosím zkontrolujte adresu a zkuste to znovu. Pending: Zpracovávané: - - Balances - Balance - Total: Celkem: @@ -1630,93 +1622,104 @@ Prosím zkontrolujte adresu a zkuste to znovu. Spendable: Disponibilní: + + + PaymentServer - Status: - Stav: + Invalid payment address %1 + Nevalidní adresa pro platbu %1 + + + PeerTableModel - Obfuscation Balance: - Obfuskační Balance: + Version + Verze - 0 BWK / 0 Rounds - 0 BWK / 0 Kol + Ping Time + Čas pingnutí + + + PrivacyDialog - Enabled/Disabled - Zapnuté/Vypnuté + 0 + 0 - Obfuscation - Obfuskace + Reset + Reset - n/a - n/a + Quantity: + Množství: - Start/Stop Mixing - Spustit/Zastavit Míchání + Amount: + Hodnota: - Reset - Reset + Choose previously used address + Vyberte již dříve použitou adresu - Disabled - Vypnuto + Alt+A + Alt+A - No inputs detected - Nedetekovány žádné vstupy + Paste address from clipboard + Vložit adresu z mezipamětí - Overall progress - Celkový postup + Alt+P + Alt+P - Anonymized - Anonymizováno + Label: + Popis - Obfuscation was successfully reset. - Obfuskace byla úspěšně resetována + Amount: + Hodnota: - Start Obfuscation - Spustit Obfuskaci + Priority: + Priorita: - Stop Obfuscation - Zastavit Obfuskaci + Fee: + Poplatek: - Enabled - Zapnuto + no + ne - N/A - N/A + Bytes: + Byty: - - - PaymentServer - Invalid payment address %1 - Nevalidní adresa pro platbu %1 + Insufficient funds! + Nedostatek prostředků! - - - PeerTableModel - Version - Verze + medium + střední - Ping Time - Čas pingnutí + Change: + Změna: - + + Copy quantity + Kopíroat množstí + + + Copy amount + Kopírovat hodnotu + + QObject @@ -1747,15 +1750,15 @@ Prosím zkontrolujte adresu a zkuste to znovu. QRImageWidget - &Save Image... - &Uložit Obrázek... + Save Image... + Uložit Obrázek... RPCConsole - &Information - &Informace + Information + Informace General @@ -1778,8 +1781,8 @@ Prosím zkontrolujte adresu a zkuste to znovu. Počet spojení - &Open - &Otevřít + Open + Otevřít Network @@ -1814,7 +1817,7 @@ Prosím zkontrolujte adresu a zkuste to znovu. Počet Masternodů - &Console + Console Konzole @@ -1822,8 +1825,8 @@ Prosím zkontrolujte adresu a zkuste to znovu. Vymazat konzoli - &Clear - &Vymazat + Clear + Vymazat Totals @@ -1838,8 +1841,8 @@ Prosím zkontrolujte adresu a zkuste to znovu. Odesláno - &Peers - &Peerů + Peers + Peerů Direction @@ -1878,8 +1881,8 @@ Prosím zkontrolujte adresu a zkuste to znovu. Čas pingnutí - &Wallet Repair - &Oprava Peněženky + Wallet Repair + Oprava Peněženky Rescan blockchain files @@ -1917,16 +1920,16 @@ Prosím zkontrolujte adresu a zkuste to znovu. ReceiveCoinsDialog - &Label: - &Popis + Label: + Popis - &Amount: - &Hodnota + Amount: + Hodnota - &Request payment - &Vyžádat platbu + Request payment + Vyžádat platbu Clear @@ -1960,16 +1963,16 @@ Prosím zkontrolujte adresu a zkuste to znovu. QR kód - Copy &URI - Kopírovat &URI + Copy URI + Kopírovat URI - Copy &Address - Kopírovat &Adresu + Copy Address + Kopírovat Adresu - &Save Image... - &Uložit Obrázek... + Save Image... + Uložit Obrázek... URI @@ -2017,14 +2020,6 @@ Prosím zkontrolujte adresu a zkuste to znovu. SendCoinsDialog - - Inputs... - Vstupy... - - - automatically selected - automaticky vybráno - Insufficient funds! Nedostatek prostředků! @@ -2081,10 +2076,6 @@ Prosím zkontrolujte adresu a zkuste to znovu. Minimize Minimalizovat - - Obfuscation - Obfuskace - per kilobyte za kilobyte @@ -2102,20 +2093,20 @@ Prosím zkontrolujte adresu a zkuste to znovu. Doporučeno - S&end - O&deslat + Send + Odeslat - Clear &All - Smazat &Vše + Clear All + Smazat Vše - Add &Recipient - Přidat &Příjemce + Add Recipient + Přidat Příjemce - SwiftTX - SwiftTX + SwiftX + SwiftX Balance: @@ -2177,12 +2168,12 @@ Prosím zkontrolujte adresu a zkuste to znovu. Alt+P - &Label: - &Popis + Label: + Popis - A&mount: - H&odnota: + Amount: + Hodnota: Message: @@ -2239,16 +2230,16 @@ Prosím zkontrolujte adresu a zkuste to znovu. Verifikujte zprávu pro ujištění, že byla podepsána zmíněnou Bulwark adresou - Sign &Message - Podepsat &Zprávu + Sign Message + Podepsat Zprávu Reset all sign message fields Resetovat všechny položky podepsání zprávy - Clear &All - Smazat &Vše + Clear All + Smazat Vše Reset all verify message fields @@ -2373,14 +2364,21 @@ Prosím zkontrolujte adresu a zkuste to znovu. WalletView - &Export - &Exportovat + Export + Exportovat Export the data in the current tab to a file Exportovat data z aktulní záložky do souboru + + ZBwkControlDialog + + 0 + 0 + + bulwark-core @@ -2392,8 +2390,8 @@ Prosím zkontrolujte adresu a zkuste to znovu. Informace - SwiftTX options: - SwiftTx možnosti: + SwiftX options: + SwiftX možnosti: Synchronization failed diff --git a/src/qt/locale/bulwark_da.ts b/src/qt/locale/bulwark_da.ts index 48c2c5a2e..d4d68fc22 100644 --- a/src/qt/locale/bulwark_da.ts +++ b/src/qt/locale/bulwark_da.ts @@ -7,39 +7,39 @@ Create a new address - Ny adresse + opret ny adresse - &New - &Ny + New + Ny Copy the currently selected address to the system clipboard Kopier til udklipsholder - &Copy - &Kopier + Copy + Kopier Delete the currently selected address from the list Slet den valgte adresse fra listen - &Delete - &Slet + Delete + Slet Export the data in the current tab to a file Eksporter aktuelle tekst til en fil - &Export - E&ksporter + Export + Eksporter - C&lose - L&uk + Close + Luk Choose the address to send coins to @@ -50,8 +50,8 @@ Vælg egen modtageradresse - C&hoose - V&ælg + Choose + Vælg Sending addresses @@ -70,15 +70,15 @@ Dette er dine modtager adresser. Det anbefales at anvende en ny adresse til hver transaktion - &Copy Address + Copy Address Kopier adresse - Copy &Label + Copy Label Kopier tekst - &Edit + Edit Ret @@ -235,7 +235,7 @@ BIP 38 værktøj - &BIP 38 Encrypt + BIP 38 Encrypt BIP 38 kryptografering @@ -283,7 +283,7 @@ Underskriv beskeden for at bevise, at De ejer denne Bulwark adresse. - Encrypt &Key + Encrypt Key Krypter og underskriv @@ -291,11 +291,11 @@ Nulstil alle underskriftsfelter - Clear &All + Clear All Nulstil alt - &BIP 38 Decrypt + BIP 38 Decrypt BIP 38 dekryptér. @@ -311,7 +311,7 @@ verificer beskeden for at sikre, at den blev underskrevet med den rigtige Bulwark adresse. - Decrypt &Key + Decrypt Key Dekrypteringsnøgle @@ -402,7 +402,7 @@ Node - &Overview + Overview Overblik @@ -410,128 +410,128 @@ Vis et generelt overblik over tegnebogen - &Send - &Send + Send + Send - &Receive - &Modtag + Receive + Modtag - &Transactions - &Transaktioner + Transactions + Transaktioner Browse transaction history Vis transaktionshistorik - E&xit - E&xit + Exit + Exit Quit application Afslut applikationen - About &Qt - Om&Qt + About Qt + OmQt Show information about Qt Information om Qt - &Options... - &Indstillinger + Options... + Indstillinger - &Show / Hide - &Vis / skjul + Show / Hide + Vis / skjul Show or hide the main Window Vis eller skjul hovedvinduet. - &Encrypt Wallet... - &Kryptografer tegnebog + Encrypt Wallet... + Kryptografer tegnebog Encrypt the private keys that belong to your wallet Krypter den private nøgle som hører til tegnebogen. - &Backup Wallet... - &Sikkerhedskopier tegnebog + Backup Wallet... + Sikkerhedskopier tegnebog Backup wallet to another location Sikkerhedskopier og gem et andet sted - &Change Passphrase... - &Skift kodeord + Change Passphrase... + Skift kodeord Change the passphrase used for wallet encryption Skift kodeordet til kryptografering af tegnebog - &Unlock Wallet... - &Lås tegnebogen op + Unlock Wallet... + Lås tegnebogen op Unlock wallet Lås tegnebogen op - &Lock Wallet - &Lås tegnebogen + Lock Wallet + Lås tegnebogen - Sign &message... - Underskriv & besked + Sign message... + Underskriv besked - &Verify message... - &verificer besked + Verify message... + verificer besked - &Information - &information + Information + information Show diagnostic information Vis diagnosticeringsinformation - &Debug console - &Debugpanel + Debug console + Debugpanel Open debugging console Åben debugpanel - &Network Monitor - &Netværksmonitering + Network Monitor + Netværksmonitering Show network monitor Vis netværksmonitor - &Peers list - &Peersliste + Peers list + Peersliste Show peers info Vis information om PEERS - Wallet &Repair - Tegnebog &Reparer + Wallet Repair + Tegnebog Reparer Show wallet repair options @@ -542,56 +542,56 @@ Åbn konfigurationsfil - Show Automatic &Backups - Vis &sikkerhedskopier, der er taget automatisk + Show Automatic Backups + Vis sikkerhedskopier, der er taget automatisk Show automatically created wallet backups Vis sikkerhedskopier, der er taget automatisk - &Sending addresses... - &Afsenderadresser + Sending addresses... + Afsenderadresser Show the list of used sending addresses and labels Vis listen over brugte afsenderadresse med tilhørende tekst. - &Receiving addresses... - &Modtageradresse + Receiving addresses... + Modtageradresse Show the list of used receiving addresses and labels Vis listen over brugte modtageradresser og tekst - Open &URI... - Åbn &URL + Open URI... + Åbn URL - &Command-line options - &Kommandolinieparametre + Command-line options + Kommandolinieparametre Synchronizing additional data: %p% Synkroniserer yderligere data %p% - &File - &Fil + File + Fil - &Settings - &indstillinger + Settings + indstillinger - &Tools - &værktøj + Tools + værktøj - &Help - &hjælp + Help + hjælp Tabs toolbar @@ -610,16 +610,16 @@ Anmod om betaling (genrerer QR kode og Bulwark URL) - &Masternodes - &Masternoder + Masternodes + Masternoder Browse masternodes Vis masternoder - &About Bulwark Core - &Om Bulwark kerne + About Bulwark Core + Om Bulwark kerne Show information about Bulwark Core @@ -638,28 +638,28 @@ Verificer besked for at sikre, at den er underskrevet med den opgivne Bulwark adresse - &BIP38 tool - &BIP 38 værktøj + BIP38 tool + BIP 38 værktøj Encrypt and decrypt private keys using a passphrase Krypter og dekrypter private nøgler ved hjælp af et kodeord - &MultiSend - &Massesending + MultiSend + Massesending MultiSend Settings Massesending, indstillinger - Open Wallet &Configuration File - Åbn tegnebog &konfigurationsfil + Open Wallet Configuration File + Åbn tegnebog konfigurationsfil - Open &Masternode Configuration File - Åbn &Masternode konfigurationsfil + Open Masternode Configuration File + Åbn Masternode konfigurationsfil Open Masternode configuration file @@ -670,8 +670,8 @@ Åbn en Bulwark URl eller betalingsanmodning - &Blockchain explorer - &blockchain explorer + Blockchain explorer + blockchain explorer Block explorer window @@ -898,10 +898,6 @@ Adresse: %4 Received with address Modtaget med adresse - - DS Rounds - DS gennemløb - Date Dato @@ -974,10 +970,6 @@ Adresse: %4 Please switch to "List mode" to use this function. Skift til "listeformat" for at benytte denne funktion - - Non-anonymized input selected. <b>Obfuscation will be disabled.</b><br><br>If you still want to use Obfuscation, please deselect all non-nonymized inputs first and then check Obfuscation checkbox again. - Ikke anonymiseret indhold valgt.<b>tilsløring vil være slået fra.</b><br><br>Hvis De ønsker at anvende tilsløring skal De fravælge alt ikke anonymiseret indhold først, derefter afmærke boksen for tilsløring igen. - highest højeste @@ -998,10 +990,6 @@ Adresse: %4 Can vary +/- %1 duff(s) per input. kan variere +/- %1 duff(s) pr. input - - n/a - Ikke tilgængelig - medium Middel @@ -1082,16 +1070,16 @@ Adresse: %4 Ret adresse - &Label - &tekstmarkør + Label + tekstmarkør The label associated with this address list entry Denne tekstmarkør e forbundet med denne adresse i listen. - &Address - &adresse + Address + adresse The address associated with this address list entry. This can only be modified for sending addresses. @@ -1298,20 +1286,20 @@ Adresse: %4 Offentlig nøgle - S&tart alias - S&tart alias + Start alias + Start alias - Start &all - Start &all + Start all + Start all - Start &MISSING - Start &MANGLER + Start MISSING + Start MANGLER - &Update status - &opdateringsstatus + Update status + opdateringsstatus Status will be updated automatically in (sec): @@ -1594,28 +1582,28 @@ Kontroller adressen og prøv igen. Muligheder - &Main - &hoved + Main + hoved - Size of &database cache - Størrelse på &databasecache + Size of database cache + Størrelse på databasecache MB MB - Number of script &verification threads - antal af script &verifikationstråde + Number of script verification threads + antal af script verifikationstråde (0 = auto, <0 = leave that many cores free) (0=auto, >0 efterlad så mange tråde fri) - W&allet - T&egnebog + Wallet + Tegnebog If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. @@ -1634,8 +1622,8 @@ Kontroller adressen og prøv igen. Tillad indkomne forbindelser - &Connect through SOCKS5 proxy (default proxy): - &forbind gennem SOCJS5 proxy (standardproxy): + Connect through SOCKS5 proxy (default proxy): + forbind gennem SOCJS5 proxy (standardproxy): Expert @@ -1646,32 +1634,16 @@ Kontroller adressen og prøv igen. Start Bulwark automatisk, når der logges på systemet - &Start Bulwark on system login - &start Bulwark når der logges på systemet - - - This setting determines the amount of individual masternodes that an input will be anonymized through.<br/>More rounds of anonymization gives a higher degree of privacy, but also costs more in fees. - Denne indstilling bestemmer antallet af individuelle masternoder hvorgennem der tilsløres et input. <br/>Jo flere gennemløb der udføres, jo højere grad af tilsløring, og jo højere gebyrer. - - - Obfuscation rounds to use - Antal gennemløb der skal benyttes - - - This amount acts as a threshold to turn off Obfuscation once it's reached. - når dette antal er nået slås tilsløringsfunktonen fra. - - - Amount of Bulwark to keep anonymized - Antallet af Bulwark som skal holdes tilslørede + Start Bulwark on system login + start Bulwark når der logges på systemet Whether to show coin control features or not. Vis eller skjul møntkontrolfeatures - Enable coin &control features - Aktiver mønt &kontrolfeatures + Enable coin control features + Aktiver mønt kontrolfeatures Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. @@ -1682,12 +1654,12 @@ Kontroller adressen og prøv igen. Vis fane med masternoder - &Spend unconfirmed change - &brug ikke bekræftede "penge tilbage" + Spend unconfirmed change + brug ikke bekræftede "penge tilbage" - &Network - &netværk + Network + netværk The user interface language can be set here. This setting will take effect after restarting Bulwark. @@ -1700,7 +1672,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations https://www.transifex.com/bulwark-project/bulwark-project-translations - Map port using &UPnP + Map port using UPnP MAP port ved hjælp af UPnP @@ -1708,56 +1680,56 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsTilslut Bulwark netværket gennem en SOCKS5 PROXY - Proxy &IP: - Proxy &IP + Proxy IP: + Proxy IP IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) IP adresse til proxyserveren (For eksempel IPV4: 127.0.0.1/IPv6: ::1) - &Port: - &port + Port: + port Port of the proxy (e.g. 9050) Proxyport (f.eks 9050) - &Window - &vindue + Window + vindue Show only a tray icon after minimizing the window. Vis kun ikonet efter minimering af vinduet - &Minimize to the tray instead of the taskbar - &Minimer til bakken i stedet for til proceslinien + Minimize to the tray instead of the taskbar + Minimer til bakken i stedet for til proceslinien Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. Minimer i stedet for at afslutte applikationen når vinduet lukkes. Når dette er valgt er det kun muligt at lukke ned via filmenuen og afslut - M&inimize on close - M&inimer og luk + Minimize on close + Minimer og luk - &Display - &Vis + Display + Vis - User Interface &language: - Brugerinterface &sprog: + User Interface language: + Brugerinterface sprog: User Interface Theme: Brugers tema: - &Unit to show amounts in: - &Enhed som beløb vises i + Unit to show amounts in: + Enhed som beløb vises i Choose the default subdivision unit to show in the interface and when sending coins. @@ -1784,16 +1756,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsNulstil alle klientoptioner til standard - &Reset Options - &nulstil optioner + Reset Options + nulstil optioner - &OK - &Ok + OK + Ok - &Cancel - &Annuller + Cancel + Annuller default @@ -1854,10 +1826,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsStaked or masternode rewards that has not yet matured Indskyder- eller masternodebelønning er stadig under behandling - - Balances - Saldi - The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. De viste informationer kan være uddaterede. Deres tegnebog synkronisere automatism med Bulwark netværket så snart en forbindelse er etalbleret, men denne proces er ikke færdiggjort endnu. @@ -1894,147 +1862,14 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSpendable: Brugbare: - - Status: - Status - - - Obfuscation Balance: - Sløret beløb - - - 0 BWK / 0 Rounds - 0 BWK / 0 gennemløb - - - Enabled/Disabled - Startet/Stoppet - - - Try to manually submit a Obfuscation request. - Prøv at send en manuel tilsløringsanmodning. - - - Reset the current status of Obfuscation (can interrupt Obfuscation if it's in the process of Mixing, which can cost you money!) - Nulstil den aktuelle status for tilsløringsfunktionen. (Kan forstyrre processen, hvilket kan koste mønter). - - - Obfuscation - Tilsløring - - - Completion: - Færdiggørelse: - - - Amount and Rounds: - Beløb og gennemløb - - - Submitted Denom: - Afsendte midler - - - n/a - Ikke tilgængelig - Recent transactions Nylige transaktioner - - Start/Stop Mixing - Start/Stop tilsløring - - - The denominations you submitted to the Masternode.<br>To mix, other users must submit the exact same denominations. - Designerede midler afsendt til masternoden. <br>For at gennemføre tilsløringen må andre brugere afsende tilsvarende designerede midler. - - - (Last Message) - (seneste besked) - - - Try Mix - Prøv at usynliggøre - - - Reset - Nulstil - out of sync Ude af synk - - Disabled - slået fra - - - No inputs detected - Ingen inputs valgt - - - Not enough compatible inputs to anonymize <span style='color:red;'>%1</span>,<br>will anonymize <span style='color:red;'>%2</span> instead - Der er ikke tilstrækkelige kompatible inputs tilgængelige for tilsløring <span style='color:red;'>%1</span>,<br>vil tilsløre <span style='color:red;'>%2</span> i stedet - - - Overall progress - Samlet status - - - Denominated - Designerede - - - Anonymized - Tilsløret - - - Last Obfuscation message: - - Seneste besked fra tilsløringsprocessen - - - Obfuscation was successfully reset. - Tilsløringsfunktionen blev nulstillet - - - If you don't want to see internal Obfuscation fees/transactions select "Most Common" as Type on the "Transactions" tab. - Hvis de ikke ønsker at se de interne tilsløringsgebyrer og transaktioner, skal De vælge "Mest fremherskende" som type i transaktionsmenuen. - - - Obfuscation requires at least %1 to use. - Tilsløring kræver mindst %1 for at kunne anvendes - - - Wallet is locked and user declined to unlock. Disabling Obfuscation. - Tegnebogen er låst, brugeren har afvist at låse den op. Tilsløring slås fra. - - - Found enough compatible inputs to anonymize %1 - Der er fundet nok kompatible inputs for tilsløring af %1 - - - Start Obfuscation - Start tilsløring - - - Stop Obfuscation - stop tilsløring - - - Mixed - Tilsløret - - - Enabled - Slået til - - - N/A - Ikke tilgængelig - PaymentServer @@ -2142,6 +1977,121 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsPingtidPingtid + + PrivacyDialog + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + De viste informationer kan være uddaterede. Deres tegnebog synkronisere automatism med Bulwark netværket så snart en forbindelse er etalbleret, men denne proces er ikke færdiggjort endnu. + + + 0 + 0 + + + Reset + Nulstil + + + Quantity: + Antal: + + + Amount: + Beløb + + + Pay To: + Betal Til + + + Choose previously used address + Benyt en tidligere anvendt adresse. + + + Alt+A + Alt+A + + + Paste address from clipboard + Indsæt adresse fra udklipsholderen. + + + Alt+P + Alt+P + + + Label: + Mærkning + + + Enter a label for this address to add it to the list of used addresses + Indtast et mærke til denne adresse for at tilføje den til listen over brugte adresser + + + Amount: + Amount + + + Priority: + Prioritet: + + + Fee: + Gebyr: + + + Dust: + Affald: + + + no + nej + + + Bytes: + Bytes: + + + Insufficient funds! + Saldo for lille! + + + medium + Middel + + + Coin Control Features + Møntkontrol, features + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + Hvis denne er aktiveret, men tilbagebetalingsadressen er tom, eller ugyldig, overskydende beløb vil blive fremsendt til en nyoprettet adresse + + + Custom change address + Brugerdefineret tilbagebetalingsadresse + + + Change: + Penge tilbage: + + + out of sync + Ude af synk + + + Copy quantity + Kopiér antal + + + Copy amount + Kopiér beløb + + + Confirm send coins + Bekræft at De vil sende mønter + + QObject @@ -2192,12 +2142,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations QRImageWidget - &Save Image... - &Gem billede + Save Image... + Gem billede - &Copy Image - &Kopier billede + Copy Image + Kopier billede Save QR Code @@ -2215,8 +2165,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsVærktøjskasse - &Information - &information + Information + information General @@ -2239,8 +2189,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsAntal forbindelser - &Open - &Åben + Open + Åben Startup time @@ -2291,20 +2241,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsAntal masternoder - &Console - &konsol + Console + konsol Clear console Clear konsollet - &Network Traffic - &Netværkstrafik + Network Traffic + Netværkstrafik - &Clear - &clear + Clear + clear Totals @@ -2319,8 +2269,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSendt - &Peers - &Peers + Peers + Peers Select a peer to view detailed information. @@ -2379,8 +2329,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsPingtidPingtid - &Wallet Repair - &Tegnebog Reparer + Wallet Repair + Tegnebog Reparer Wallet In Use: @@ -2510,12 +2460,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsGenbrug en af de tidligere benyttede modtageradresser. <br> Genbrug af adresser kan kompromittere anonymiteten og sikkerheden. <br> Anbefales ikke, med mindre der blot er tale om genudsendelse af en tidligere genereret adresse. - R&euse an existing receiving address (not recommended) - G&enbrug en eksisterendemodageradresse (ikke anbefalet) + Reuse an existing receiving address (not recommended) + Genbrug en eksisterendemodageradresse (ikke anbefalet) - &Message: - &Besked + Message: + Besked An optional label to associate with the new receiving address. @@ -2534,20 +2484,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsAnvend denne formular for at anmode om betalinger. Alle felter er <b>valgfri</b> - &Label: - &Mærkning + Label: + Mærkning An optional amount to request. Leave this empty or zero to not request a specific amount. Beløbsfeltet er valgfrit. Efterlad det tomt, eller med værdien 0 for at anmode om et beløb, som afsenderen bestemmer. - &Amount: - &Beløb + Amount: + Beløb - &Request payment - &Anmod om betaling + Request payment + Anmod om betaling Clear all fields of the form. @@ -2555,7 +2505,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Clear - &clear + clear Requested payments history @@ -2597,16 +2547,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsQR kode - Copy &URI - Kopier &URl + Copy URI + Kopier URl - Copy &Address - Kopier &Adresse + Copy Address + Kopier Adresse - &Save Image... - &Gem billede + Save Image... + Gem billede Request payment to %1 @@ -2686,14 +2636,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsCoin Control Features Møntkontrol, features - - Inputs... - Inputs... - - - automatically selected - Automatisk valgte - Insufficient funds! Saldo for lille! @@ -2778,10 +2720,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsMinimize Minimer - - Obfuscation - Tilsløring - per kilobyte pr. kilobyte @@ -2843,15 +2781,15 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsBekræft og send - S&end - S&end + Send + Send Clear all fields of the form. Tøm alle felter i formularen - Clear &All + Clear All Nulstil alt @@ -2859,12 +2797,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSend til flere modtagere på én gang - Add &Recipient - Tilføj &Modtager + Add Recipient + Tilføj Modtager - SwiftTX - SwiftTX + SwiftX + SwiftX Balance: @@ -2927,8 +2865,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsAlle tilgængelige saldi (anbefales ikke) - and SwiftTX - og SwiftTX + and SwiftX + og SwiftX %1 to %2 @@ -2954,18 +2892,10 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsA fee %1 times higher than %2 per kB is considered an insanely high fee. Et gebyr %1 gange højere end %2 pr. kilobyte er vanvittigt højt. - - Estimated to begin confirmation within %n block(s). - Forventer bekræftelse indenfor %n blokkeForventer bekræftelse indenfor %n blokke - The recipient address is not valid, please recheck. Modtageradressen er ikke gyldig. Kontroller igen - - (obfuscation requires this amount to be rounded up to the nearest %1). - (Tilsløring kræver at dette beløb rundes op til nærmeste %1) - split into %1 outputs using the UTXO splitter. Split i %1 outputs ved hjælp af UTXO splitteren. @@ -3022,8 +2952,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsDette er en almindelig betaling - Pay &To: - Betal &Til + Pay To: + Betal Til The Bulwark address to send the payment to @@ -3050,16 +2980,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsFjern denne postering - &Label: - &Mærkning + Label: + Mærkning Enter a label for this address to add it to the list of used addresses Indtast et mærke til denne adresse for at tilføje den til listen over brugte adresser - A&mount: - A&mount + Amount: + Amount Message: @@ -3108,8 +3038,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsUnderskrifter - Underskriv / verificer en besked - &Sign Message - &Underskriv besked + Sign Message + Underskriv besked You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. @@ -3160,28 +3090,28 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsverificer beskeden for at sikre, at den blev underskrevet med den rigtige Bulwark adresse. - Sign &Message - Underskriv &Besked + Sign Message + Underskriv Besked Reset all sign message fields Nulstil alle underskriftsfelter - Clear &All + Clear All Nulstil alt - &Verify Message - &verificer besked + Verify Message + verificer besked Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Skriv den adresse der skal bruges til at underskrive med. (Vær sikker på at få det hele med, herunder alle linjerne, mellemrum, tabuleringer o.l. præcist) og signer nedenfor for at verificere beskeden. Vær forsigtig med ikke at læse mere ind i underskriften end den underskrevne besked for at undgå snyd fra et "man-in-the-middle" angreb. - Verify &Message - Verificer &Beske + Verify Message + Verificer Beske Reset all verify message fields @@ -3285,15 +3215,15 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsKonflikt! - %1/offline (verified via swifttx) + %1/offline (verified via SwiftX) %1/offline (verified via svifttx) - %1/confirmed (verified via swifttx) + %1/confirmed (verified via SwiftX) %1/bekræftet (verified via svifttx) - %1 confirmations (verified via swifttx) + %1 confirmations (verified via SwiftX) %1/bekræftelser (verified via svifttx) @@ -3309,23 +3239,23 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations%1/bekræftelser - %1/offline (SwiftTX verification in progress - %2 of %3 signatures) + %1/offline (SwiftX verification in progress - %2 of %3 signatures) %1/offline (SwifTX verificering i gang - %2 af %3 signaturer) - %1/confirmed (SwiftTX verification in progress - %2 of %3 signatures ) + %1/confirmed (SwiftX verification in progress - %2 of %3 signatures ) %1/bekræftet(SwifTX verificering i gang - %2 af %3 signaturer) - %1 confirmations (SwiftTX verification in progress - %2 of %3 signatures) + %1 confirmations (SwiftX verification in progress - %2 of %3 signatures) %1/bekræftelser (SwifTX verificering i gang - %2 af %3 signaturer) - %1/offline (SwiftTX verification failed) + %1/offline (SwiftX verification failed) %1/offline (SwifTX verificering mislykkedes) - %1/confirmed (SwiftTX verification failed) + %1/confirmed (SwiftX verification failed) %1/bekræftet (SwifTX verificering mislykkedes) @@ -3791,15 +3721,15 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSend mønter - SwiftTX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. - SwiftTx understøtter ikke afsendelse af så store beløb endnu. Transaktioner er for tiden begrænsede til %1BWK. + SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. + SwiftX understøtter ikke afsendelse af så store beløb endnu. Transaktioner er for tiden begrænsede til %1BWK. WalletView - &Export - E&ksporter + Export + Eksporter Export the data in the current tab to a file @@ -3834,6 +3764,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsTegnebogens data blev gemt i %1 + + ZBwkControlDialog + + 0 + 0 + + bulwark-core @@ -3881,8 +3818,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSlet alle tegnebogens transaktioner og genskab kun fra blokkæden ved at tilføje -rescan i forbindes med opstart. - Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftTX, Budgeting) (0-1, default: %u) - Slå alle Bulwark funktioner fra (Masternoder, Tilsløring, SwiftTX, Budgetting)(0-1,default:%u) + Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftX, Budgeting) (0-1, default: %u) + Slå alle Bulwark funktioner fra (Masternoder, Tilsløring, SwiftX, Budgetting)(0-1,default:%u) Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. @@ -3894,12 +3831,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSlå spork administrationsfunktionen til med den rette private nøgle - Enable swifttx, show confirmations for locked transactions (bool, default: %s) - Aktiver swifttx, vis bekræftelser for låste transaktioner (bool, default: %s) - - - Enable use of automated obfuscation for funds stored in this wallet (0-1, default: %u) - Slå automatisk tilsløring til for alle midler i denne tegebog (0-1, default: %u) + Enable SwiftX, show confirmations for locked transactions (bool, default: %s) + Aktiver SwiftX, vis bekræftelser for låste transaktioner (bool, default: %s) Enter regression test mode, which uses a special chain in which blocks can be solved instantly. @@ -3989,10 +3922,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsOutput debugging information (default: %u, supplying <category> is optional) Output debug information (default: %u, supplying <category> er valgfri) - - 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) - Tilfør tilsløring likviditet ved at tilføje flere Bulwark løbende (0-100, default:%u, 1=meget hyppigt, høje gebyrer, 100=sjældent, lave gebyrer) - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Forespørg peer adresser via DNS opslag, hvis antallet af adresser er laft (default: 1 med mindre -connect) @@ -4026,8 +3955,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsUnderstøt filtrering af blokke og transaktioner med bloom filters (default: %u) - SwiftTX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. - SwiftTX kræver mindst 6 bekræftelser. Vent nogle minutter og prøv igen. + SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. + SwiftX kræver mindst 6 bekræftelser. Vent nogle minutter og prøv igen. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. @@ -4497,10 +4426,6 @@ For eksempel: alertnotify=Echo %% | mail - s "Bulwark ALARM!" e-mail@administrat Attempt to force blockchain corruption recovery Forsøg at gennemtvinge reparation af korrumperet blokkæde - - Keep N BWK anonymized (default: %u) - Behold N BWK anonymiserede (default: %u) - Keep at most <n> unconnectable transactions in memory (default: %u) Behold højest <n> transaktioner i hukommelsen, der ikke kan forbindes (default: %u) @@ -4645,10 +4570,6 @@ For eksempel: alertnotify=Echo %% | mail - s "Bulwark ALARM!" e-mail@administrat Obfuscation is idle. Tilsløringssystem ledigt - - Obfuscation options: - Tilsløringsmuligheder - Obfuscation request complete: Tilsløring færdig. @@ -4850,8 +4771,8 @@ For eksempel: alertnotify=Echo %% | mail - s "Bulwark ALARM!" e-mail@administrat Afsendt til masternode, venter i kø %s - SwiftTX options: - SwiftTX optioner: + SwiftX options: + SwiftX optioner: Synchronization failed @@ -4953,10 +4874,6 @@ For eksempel: alertnotify=Echo %% | mail - s "Bulwark ALARM!" e-mail@administrat Upgrade wallet to latest format Opdater tegnebogen til det nyeste format - - Use N separate masternodes to anonymize funds (2-8, default: %u) - Brug N forskellige masternoder for at anonymisere saldi (2-8, default: %u) - Use OpenSSL (https) for JSON-RPC connections Brug OpenSSL (https) til JSON-RPC forbindelser diff --git a/src/qt/locale/bulwark_de.ts b/src/qt/locale/bulwark_de.ts index 32f27a167..4f03cb6ba 100644 --- a/src/qt/locale/bulwark_de.ts +++ b/src/qt/locale/bulwark_de.ts @@ -10,36 +10,36 @@ Eine neue Adresse erstellen - &New - &Neu + New + Neu Copy the currently selected address to the system clipboard Ausgewählte Adresse in die Zwischenablage kopieren - &Copy - &Kopieren + Copy + Kopieren Delete the currently selected address from the list Ausgewählte Adresse aus der Liste entfernen - &Delete - &Löschen + Delete + Löschen Export the data in the current tab to a file Daten der aktuellen Ansicht in eine Datei exportieren - &Export - &Exportieren + Export + Exportieren - C&lose - &Schließen + Close + Schließen Choose the address to send coins to @@ -50,8 +50,8 @@ Wählen Sie die Adresse aus, über die Sie Bulwark empfangen wollen - C&hoose - &Auswählen + Choose + Auswählen Sending addresses @@ -70,16 +70,16 @@ Dies sind ihre Bulwark-Adressen zum Empfangen von Zahlungen. Es wird empfohlen für jede Transaktion eine neue Empfangsadresse zu verwenden. - &Copy Address - &Adresse kopieren + Copy Address + Adresse kopieren - Copy &Label - &Bezeichnung kopieren + Copy Label + Bezeichnung kopieren - &Edit - &Editieren + Edit + Editieren Export Address List @@ -235,8 +235,8 @@ BIP 38 Tool - &BIP 38 Encrypt - &BIP 38 Verschlüsselung + BIP 38 Encrypt + BIP 38 Verschlüsselung Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -283,20 +283,20 @@ Signiere die Nachricht um zu Beweisen, dass du diese Bulwark Adresse besitzt - Encrypt &Key - Verschlüsselt &Schlüssel + Encrypt Key + Verschlüsselt Schlüssel Reset all sign message fields Setze alle signierten Nachrichten Felder zurück - Clear &All - &Alles zurücksetzen + Clear All + Alles zurücksetzen - &BIP 38 Decrypt - &BIP 38 Entschlüsseln + BIP 38 Decrypt + BIP 38 Entschlüsseln Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. @@ -311,8 +311,8 @@ Überprüfen Sie die Nachricht, um sicherzustellen, dass sie mit der angegebenen Bulwark-Adresse signiert wurde. - Decrypt &Key - Entschlüsseln &Schlüssel + Decrypt Key + Entschlüsseln Schlüssel Reset all verify message fields @@ -402,136 +402,136 @@ Knoten - &Overview - &Übersicht + Overview + Übersicht Show general overview of wallet Allgemeine Wallet-Übersicht anzeigen - &Send - &Überweisen + Send + Überweisen - &Receive - &Empfangen + Receive + Empfangen - &Transactions - &Transaktionen + Transactions + Transaktionen Browse transaction history Transaktionsverlauf durchsehen - E&xit - &Beenden + Exit + Beenden Quit application Anwendung beenden - About &Qt - Über &Qt + About Qt + Über Qt Show information about Qt Informationen über Qt anzeigen - &Options... - &Konfiguration... + Options... + Konfiguration... - &Show / Hide - &Anzeigen / Verstecken + Show / Hide + Anzeigen / Verstecken Show or hide the main Window Das Hauptfenster anzeigen oder verstecken - &Encrypt Wallet... - Wallet &verschlüsseln... + Encrypt Wallet... + Wallet verschlüsseln... Encrypt the private keys that belong to your wallet Verschlüsselt die zu ihrer Wallet gehörenden privaten Schlüssel - &Backup Wallet... - Wallet &sichern... + Backup Wallet... + Wallet sichern... Backup wallet to another location Eine Wallet-Sicherungskopie erstellen und abspeichern - &Change Passphrase... - Passphrase &ändern... + Change Passphrase... + Passphrase ändern... Change the passphrase used for wallet encryption Ändert die Passphrase, die für die Wallet-Verschlüsselung benutzt wird - &Unlock Wallet... - Wallet &entsperren + Unlock Wallet... + Wallet entsperren Unlock wallet Wallet entsperren - &Lock Wallet - Wallet &sperren + Lock Wallet + Wallet sperren - Sign &message... - Nachricht s&ignieren... + Sign message... + Nachricht signieren... - &Verify message... + Verify message... Nachricht prüfen... - &Information - &Information + Information + Information Show diagnostic information Diagnoseinformation anzeigen - &Debug console - &Debugkonsole + Debug console + Debugkonsole Open debugging console Debugkonsole öffnen - &Network Monitor - &Netzwerkmonitor + Network Monitor + Netzwerkmonitor Show network monitor Netzwerkmonitor anzeigen - &Peers list - &Gegenstellen-Liste + Peers list + Gegenstellen-Liste Show peers info Informationen zu Gegenstellen anzeigen - Wallet &Repair - Wallet-&Reparatur + Wallet Repair + Wallet-Reparatur Show wallet repair options @@ -542,60 +542,60 @@ Konfigurationsdatei öffnen - Show Automatic &Backups - Automatische &Sicherheitskopien anzeigen + Show Automatic Backups + Automatische Sicherheitskopien anzeigen Show automatically created wallet backups Automatisch erzeugte Wallet-Sicherheitskopien anzeigen - &Sending addresses... - &Zahlungsadressen... + Sending addresses... + Zahlungsadressen... Show the list of used sending addresses and labels Liste verwendeter Zahlungsadressen und Bezeichnungen anzeigen - &Receiving addresses... - &Empfangsadressen... + Receiving addresses... + Empfangsadressen... Show the list of used receiving addresses and labels Liste verwendeter Empfangsadressen und Bezeichnungen anzeigen - Open &URI... - &URI öffnen... + Open URI... + URI öffnen... - &Command-line options - &Kommandozeilenoptionen + Command-line options + Kommandozeilenoptionen Processed %n blocks of transaction history. - Verarbeitet %n Blöcke der Transaktionsgeschichte.Verarbeitet %n Blöcke der Transaktionsgeschichte. + %n Block des Transaktionsverlaufs verarbeitet.%n Blöcke des Transaktionsverlaufs verarbeitet. Synchronizing additional data: %p% Synchronisiere zusätzliche Daten: %p% - &File - &Datei + File + Datei - &Settings - &Einstellungen + Settings + Einstellungen - &Tools - &Werkzeuge + Tools + Werkzeuge - &Help - &Hilfe + Help + Hilfe Tabs toolbar @@ -614,15 +614,23 @@ Zahlung anfordern (QR-Code Generierung und bulwark: URIs) - &Masternodes - &Masternodes + Privacy + Privatsphäre + + + Privacy Action for zBWK and Obfuscation + Privatsphäre Aktion für zBWK und Verschleierung + + + Masternodes + Masternodes Browse masternodes Masternodes durchsuchen - &About Bulwark Core + About Bulwark Core Über.Bulwark Core @@ -642,24 +650,24 @@ Überprüft eine Nachricht um zu prüfen ob diese mit einer bestimmten Bulwark-Adresse signiert wurde - &BIP38 tool - &BIP38 Hilfsprogramm + BIP38 tool + BIP38 Hilfsprogramm - &MultiSend - &MultiSend + MultiSend + MultiSend MultiSend Settings MultiSend Einstellungen - Open Wallet &Configuration File - Öffne Wallet &Einstellungsdatei + Open Wallet Configuration File + Öffne Wallet Einstellungsdatei - Open &Masternode Configuration File - Öffne &Masternode Einstellungsdatei + Open Masternode Configuration File + Öffne Masternode Einstellungsdatei Open Masternode configuration file @@ -670,8 +678,8 @@ Öffne eine Bulwark: URI or Zahlungsanfrage - &Blockchain explorer - &Blockchain Betrachter + Blockchain explorer + Blockchain Betrachter Block explorer window @@ -685,6 +693,10 @@ Bulwark Core client Bulwark Core Client + + %n active connection(s) to Bulwark network + %n aktive Verbindung zum Bulwark Netzwerk%n aktive Verbindungen zum Bulwark Netzwerk + Synchronizing with network... Synchronisiere mit Netzwerk... @@ -705,10 +717,26 @@ Up to date Auf aktuellem Stand + + %n hour(s) + %n Stunde%n Stunden + + + %n day(s) + %n Tag%n Tage + + + %n week(s) + %n Woche%n Wochen + %1 and %2 %1 und %2 + + %n year(s) + %n Jahr%n Jahre + %1 behind %1 im Rückstand @@ -799,6 +827,14 @@ Adresse: %4 Blockchain Explorer Blockchain Explorer + + Back + Zurück + + + Forward + Vor + Address / Block / Transaction Addrese / Block / Tansaktion @@ -973,10 +1009,6 @@ Adresse: %4 Please switch to "List mode" to use this function. Bitte wechsle zur "Listenansicht" um diese Funktion zu verwenden. - - Non-anonymized input selected. <b>Obfuscation will be disabled.</b><br><br>If you still want to use Obfuscation, please deselect all non-nonymized inputs first and then check Obfuscation checkbox again. - Nicht anonymisierter Eingang ausgewählt. <b></b>Verschleierung wird deaktiviert. <br><br>Wenn Sie immer noch verschleiern möchten, bitte deaktivieren Sie zuerst alle nicht-anonymisierten Eingang und überprüfen Sie dann das Verschleierungskontrollkästchen erneut. - highest höchste @@ -997,10 +1029,6 @@ Adresse: %4 Can vary +/- %1 duff(s) per input. Kann um +/- %1 Abzug(s) pro Eingang variieren. - - n/a - k.A. - medium mittel @@ -1081,16 +1109,16 @@ Adresse: %4 Adresse bearbeiten - &Label - &Bezeichnung + Label + Bezeichnung The label associated with this address list entry Bezeichnung, die dem Adresslisteneintrag zugeordnet ist - &Address - &Adresse + Address + Adresse The address associated with this address list entry. This can only be modified for sending addresses. @@ -1297,20 +1325,20 @@ Adresse: %4 Öffentlicher Schlüssel - S&tart alias - S&tarten + Start alias + Starten - Start &all - &Alle starten + Start all + Alle starten - Start &MISSING - Starte nur &MISSING + Start MISSING + Starte nur MISSING - &Update status - Stat&us aktualisieren + Update status + Status aktualisieren Status will be updated automatically in (sec): @@ -1445,33 +1473,181 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.View MultiSend Zeige MultiSend + + Send For Stakes + For Staker versenden + + + Send For Masternode Rewards + Für Masternode Rewards versenden + The entered address: Die eingegebene Adresse: + + + + is invalid. +Please check the address and try again. + ist ungültig. +Bitte Adresse überprüfen und nochmals versuchen. + + + The total amount of your MultiSend vector is over 100% of your stake reward + + Die Gesamtzahl des MultiSend Vektors ist über 100% des Stake Rewards + + + + Please Enter 1 - 100 for percent. + Bitte eine Zahl zwischen 1-100 in Prozent eingeben. + + + MultiSend Vector + + MultiSend Vektor Removed Gelöscht - + + Could not locate address + + Konnte Adresse nicht ermitteln + + + ObfuscationConfig - + + Configure Obfuscation + Verschleierung konfigurieren + + + Basic Privacy + Wenig Privatsphäre + + + High Privacy + Hohe Privatsphäre + + + Maximum Privacy + Maximale Privatsphäre + + + Please select a privacy level. + Bitte den gewünschten Privatsphäre Level auswählen. + + + Use 2 separate masternodes to mix funds up to 10000 BWK + 2 separate Masternodes verwenden um bis zu 10000 BWK zu mixen + + + Use 8 separate masternodes to mix funds up to 10000 BWK + 8 separate Masternodes verwenden um bis zu 10000 BWK zu mixen + + + Use 16 separate masternodes + 16 separate Masternodes verwenden + + + This option is the quickest and will cost about ~0.025 BWK to anonymize 10000 BWK + Diese Option ist die schnellst und kostet ungefähr ~0.025 BWK um 10000 BWK zu anonymisieren + + + This option is moderately fast and will cost about 0.05 BWK to anonymize 10000 BWK + Diese Option ist angemessen schnell und kostet ungefähr 0.05 BWK um 10000 BWK zu anonymisieren + + + This is the slowest and most secure option. Using maximum anonymity will cost + Diese Option ist die langsamste und sicherste Option. Die Verwendung maximaler Anonymisierung kostet + + + 0.1 BWK per 10000 BWK you anonymize. + 0.1 BWK per 10000 BWK die anonymisiert werden. + + + Obfuscation Configuration + Verschleierungskonfiguration + + + Obfuscation was successfully set to basic (%1 and 2 rounds). You can change this at any time by opening Bulwark's configuration screen. + Verschleierung erfolgreich auf normal gesetzt (%1 und 2 Runden). Sie können dies jederzeit in den Bulwarks Konfigurationen ändern. + + + Obfuscation was successfully set to high (%1 and 8 rounds). You can change this at any time by opening Bulwark's configuration screen. + Verschleierung erfolgreich auf hohen gesetzt (%1 und 8 Runden). Sie können dies jederzeit in den Bulwarks Konfigurationen ändern. + + + Obfuscation was successfully set to maximum (%1 and 16 rounds). You can change this at any time by opening Bulwark's configuration screen. + Verschleierung erfolgreich auf maximal gesetzt (%1 und 16 Runden). Sie können dies jederzeit in den Bulwarks Konfigurationen ändern. + + OpenURIDialog Open URI URI öffnen - + + Open payment request from URI or file + Zahlungsanfrage von URI oder Datei öffnen + + + URI: + URI: + + + Select payment request file + Datei für Zahlungsanfrage auswählen + + + Select payment request file to open + Datei für Zahlungsanfrage öffnen + + OptionsDialog + + Options + Optionen + + + Main + Main + + + Size of database cache + Größe Datenbank Cache + MB MB + + Number of script verification threads + Anzahl der Skript Verifikation Threads + + + (0 = auto, <0 = leave that many cores free) + (0 = auto, <0 = leave that many cores free) + + + Wallet + Wallet + + + If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. + Wenn Sie das Ausgeben von unbestätigten Wechselgeld deaktivieren, so kann das Wechselgeld von einer Transaktion <br/>nicht verwendet werden, bis mindestens eine Bestätigung vorliegt.<br/>Dies hat auch Auswirkungen auf ihre Bilanzberechnung. + + + Automatically open the Bulwark client port on the router. This only works when your router supports UPnP and it is enabled. + Automatisches öffnen des Bulwark-Client-Port im Router. Dies funktioniert nur, wenn ihr Router UPnP unterstützt und es eingeschaltet ist. + Accept connections from outside Verbindungen von Aussen zulassen @@ -1481,12 +1657,170 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Eingehende Verbindungen erlauben - &Network - &Netzwerk + Connect through SOCKS5 proxy (default proxy): + Verbindung durch SOCKS5 proxy (default proxy): + + + Expert + Experte + + + Automatically start Bulwark after logging in to the system. + Bulwark automatisch nach dem Login starten. + + + Start Bulwark on system login + Bulwark automatisch beim System Login starten. + + + Whether to show coin control features or not. + Coin control Funktionen anzeigen oder nicht + + + Enable coin control features + Coin control Funktionen aktivieren + + + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. + Zeige zusätzlichen Tab, der alle ihre Masternodes anzeigt, im ersten Untertab<br/>und alle Masternodes im Netzwerk im zweiten Untertab. + + + Show Masternodes Tab + Masternodes Tab anzeigen + + + Spend unconfirmed change + Sende unbestätigtes Wechselgeld + + + Network + Netzwerk + + + The user interface language can be set here. This setting will take effect after restarting Bulwark. + Die Sprache der Benutzeroberflächekann hier gesetzt werden. Diese Einstellung wird nach einem Neustart realisiert. + + + Language missing or translation incomplete? Help contributing translations here: +https://www.transifex.com/pivx-project/pivx-project-translations + Sprache fehlt oder ist unvollständig? Helfe mit und trage zur Übersetzung hier bei: +https://www.transifex.com/pivx-project/pivx-project-translations + + + Map port using UPnP + Port mit UPnP mappen + + + Percentage of incoming BWK which get automatically converted to zBWK via Zerocoin Protocol + Anteil des einkommenden BWK, welcher automatisch zu zBWK via Zerocoin Protokoll konvertiert wird + + + Percentage of autominted zBWK + Prozentsatz der automatisierten zBWK + + + Wait with automatic conversion to Zerocoin until enough BWK for this denomination is available + Warte mit automatischer Konvertierung zu Zerocoin, bis genügend BWK für diese Stückelung verfügbar ist + + + Preferred Automint zBWK Denomination + Bevorzugte automatisierte zBWK Stückelung + + + Connect to the Bulwark network through a SOCKS5 proxy. + Durch einen SOCKS5 Proxy mit dem Bulwark Netzwerk verbinden. + + + Proxy IP: + Proxy IP: + + + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) + IP Adresse des PROXY (z.B. IPv4: 127.0.0.1 / IPv6: ::1) + + + Port: + Port: + + + Port of the proxy (e.g. 9050) + Port des Proxies (z.B. 9050) + + + Window + Fenster + + + Show only a tray icon after minimizing the window. + Zeige nur ein Symbolkachel nach der Fensterminimierung. + + + Minimize to the tray instead of the taskbar + Minimierung zur Kachel anstelle auf der Taskbar + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. + Minimierung anstelle vom Schließen der Anwendung, wenn das Fenster geschlossen wird. Wenn diese Option aktiviert ist, wird die Anwendung nur geschlossen, wenn im Menü Beenden gewählt wird. + + + Minimize on close + Beim Schließen minimieren + + + Display + Display + + + User Interface language: + Benutzeroberfläche Sprache + + + User Interface Theme: + Benutzeroberfläche Motiv: + + + Unit to show amounts in: + Einheit des Betrags anzeigen in: + + + Choose the default subdivision unit to show in the interface and when sending coins. + Wähle die Standardunterteilungseinheit, um sie auf der Oberfläche anzuzeigen und wenn Coins gesendet werden. + + + Decimal digits + Dezimalstellen + + + 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 |. + Drittpartei URLs (z.B. Blockexplorer) die auf der Registerkarte Transaktionen als Kontextmenü erscheinen.. %s in der URL wird durch den Transaktionshash ersetzt. Mehrere URLs sind durch vertikale Balken | getrennt. + + + Third party transaction URLs + Drittanbieter Transaktions URLs + + + Active command-line options that override above options: + Aktive Befehlszeilenoptionen, die über Optionen hinausgehen: + + + Reset all client options to default. + Alle Client Optionen auf den Standard zurücksetzen + + + Reset Options + Optionen Zurücksetzen + + + OK + OK + + + Cancel + Abbrechen - &Window - &Fenster + I don't care + Mir egal default @@ -1496,13 +1830,37 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.none keine - + + Confirm options reset + Zurücksetzen der Optionen bestätigen + + + Client restart required to activate changes. + Client Neustart erforderlich, um Änderungen zu aktivieren. + + + Client will be shutdown, do you want to proceed? + Der Client wird heruntergefahren, wollen Sie fortfahren? + + + This change would require a client restart. + Diese Änderung würde einen Neustart des Clients erfordern. + + + The supplied proxy address is invalid. + Die eingegeben PROXY-Adresse ist ungültig. + + OverviewPage Form Formular + + BWK Balances + BWK Bilanzen + Available: Verfügbar: @@ -1528,8 +1886,8 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Erarbeiteter Betrag der noch nicht gereift ist - Balances - Kontostände + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + Die angezeigte Information ist möglicherweise nicht mehr aktuell. Ihre Wallet synchronisiert sich automatisch mit dem Bulwark-Netzwerk, nachdem eine Verbindung hergestellt wurde. Aber dieser Vorgang ist noch nicht abgeschlossen. Unconfirmed transactions to watch-only addresses @@ -1564,125 +1922,125 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Verfügbar: - Status: - Status: + Combined Balances (including immature coins) + Kombinierte Bilanz (einschließlich unreifer Coins) - Obfuscation Balance: - Verschleierter Betrag: + BWK: + BWK: - 0 BWK / 0 Rounds - 0 BWK / 0 Runden + zBWK: + zBWK: - Enabled/Disabled - Aktiviert/Deaktiviert + 0 % + 0 % - Obfuscation - Verschleierung + Zerocoin Balance + Zerocoin Bilanz - Completion: - Vollendet: + Recent transactions + Letzte Transaktionen - Amount and Rounds: - Betrag und Runden: + out of sync + nicht synchron + + + PaymentServer - Submitted Denom: - Stückelung des Betrages: + Payment request error + Zahlungsauftragsfehler - n/a - k.A. + URI handling + URI Behandlung - Recent transactions - Letzte Transaktionen + Payment request fetch URL is invalid: %1 + Zahlungsauftragsabruf URL ist ungültig: %1 - Start/Stop Mixing - Starte/Stoppe das Mixen + Payment request file handling + Zahlungsauftragsdatei Behandlung - The denominations you submitted to the Masternode.<br>To mix, other users must submit the exact same denominations. - Die gestückelten Beträge, die Sie zu dem Masternode gesendet haben.<br> Zum Erfolgreichen Mixen müssen andere Benutzer exakt gleich gestückelte Beträge senden. + Invalid payment address %1 + Zahlungsaufforderungadresse %1 - (Last Message) - (Letzte Nachricht) + Cannot start Bulwark: click-to-pay handler + Kann Bulwark nicht starten: click-to-pay Handler - Try Mix - Versuche zu Mixen + URI cannot be parsed! This can be caused by an invalid Bulwark address or malformed URI parameters. + URI kann nicht analysiert werden! Dies kann durch eine ungültige Bulwark-Adresse oder fehlerhafte URI-Parameter verursacht sein. - Reset - Zurücksetzen + Payment request file cannot be read! This can be caused by an invalid payment request file. + Zahlungsauftragsdatei kann nicht gelesen werden! Dies kann durch eine ungültige Zahlungsauftragsdatei verursacht werden. - out of sync - nicht synchron + Payment request rejected + Zahlungsauftrag abgelehnt - Disabled - Deaktiviert + Payment request network doesn't match client network. + Das Zahlungsauftragsnetzwerk stimmt nicht mit dem Clientnetzwerk überein. - No inputs detected - Keine Inputs gefunden + Payment request has expired. + Zahlungsauftrag ist abgelaufen. - Not enough compatible inputs to anonymize <span style='color:red;'>%1</span>,<br>will anonymize <span style='color:red;'>%2</span> instead - Nicht genug kompatible Inputs zum Anonymisieren von <span style='color:red;'>%1</span> gefunden,<br/><span style='color:red;'>%2</span> wird stattdessen anonymisiert + Payment request is not initialized. + Zahlungsauftrag ist nicht initialisiert. - Overall progress - Fortschritt + Unverified payment requests to custom payment scripts are unsupported. + Nicht verifizierte Zahlungsaufträge an benutzerdefinierte Zahlungsskripts werden nicht unterstützt. - Denominated - Gestückelt + Requested payment amount of %1 is too small (considered dust). + Der angeforderte Zahlungsbetrag von %1 ist zu klein (betrachtet als Staub). - Anonymized - Anonymisiert + Refund from %1 + Rückerstattung von %1 - Wallet is locked and user declined to unlock. Disabling Obfuscation. - Wallet ist gesperrt und der Benutzer verweigert die Entsperrung. Verschleierung deaktiviert. + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + Zahlungsauftrag %1 ist zu groß (%2 Bytes, erlaubt %3 Bytes). - Found enough compatible inputs to anonymize %1 - Genug kompatible Inputs zum Anonymisieren von %1 gefunden + Payment request DoS protection + Zahlungsauftrag DoS Schutz - Start Obfuscation - Verschleierung starten + Error communicating with %1: %2 + Fehler beim kommunizieren mit %1: %2 - Stop Obfuscation - Verschleierung stoppen + Payment request cannot be parsed! + Zahlungsauftrag kann nicht analysiert werden! - Mixed - Gemixt + Bad response from server %1 + Schlechte Antwort vom Server %1 - Enabled - Aktiviert + Network request error + Netzwerkanfragefehler - N/A - k.A. + Payment acknowledged + Zahlung anerkannt - - PaymentServer - PeerTableModel @@ -1699,80 +2057,665 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben. - QObject + PrivacyDialog - Amount - Betrag + BWK which were anonymized via Zerocin Protocol + BWK, die über das Zerocin-Protokoll anonymisiert wurden - Enter a Bulwark address (e.g. %1) - Bulwark-Adresse eingeben (z.B. %1) + Zerocoin BWK (zBWK) + Zerocoin BWK (zBWK) - %1 d - %1 T + Zerocoin Actions: + Zerocoin Handlungen: - %1 h - %1 St. + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + Die angezeigte Information ist möglicherweise nicht mehr aktuell. Ihre Wallet synchronisiert sich automatisch mit dem Bulwark-Netzwerk, nachdem eine Verbindung hergestellt wurde. Aber dieser Vorgang ist noch nicht abgeschlossen. - %1 m - %1 Min. + Enter an amount of BWK to convert to zBWK + Eingabe des BWK-Betrags, um in zBWK umzuwandeln - %1 s - %1 S + Mint Zerocoin + Präge Zerocoin - NETWORK - NETZWERK + 0 + 0 - UNKNOWN - UNBEKANNT + zBWK + zBWK - None - Keine + Mintable: + Verfügbar für Prägung: - N/A - k.A. + 0.000 000 00 BWK + 0.000 000 00 BWK - %1 ms - %1 Ms + Reset Zerocoin Wallet DB. Deletes transactions that did not make it into the blockchain. + Zurücksetzen der Zerocoin-Wallet-DB. Löscht Transaktionen, die es nicht in die Blockchain geschafft haben. - + + Reset + Zurücksetzen + + + Coin Control... + Coin-Kontrolle... + + + Quantity: + Anzahl: + + + Amount: + Betrag: + + + Rescan the complete blockchain for Zerocoin mints and their meta-data. Needs a very long time, please be patient. + Nachscannen der komplette Blockchain für Zerocoin-Prägungen und ihre Metadaten. Braucht eine sehr lange Zeit. Bitte seien Sie geduldig. + + + ReScan + NachScannen + + + Status and/or Mesages from the last Mint Action. + Status und/oder Mitteilungen aus der letzten Präge-Action + + + zBWK Control + zBWK Kontrolle + + + zBWK Selected: + zBWK Ausgewählt: + + + Quantity Selected: + Menge ausgewählt: + + + Spend Zerocoin. Without 'Pay To:' address creates payments to yourself. + Ausgebene Zerocoin. Ohne 'Pay To:'-Adresse erstellte Zahlungen an Sie selbst. + + + Spend Zerocoin + Ausgebene Zerocoin. + + + Available Balance: + Verfügbare Bilanz: + + + 0 zBWK + 0 zBWK + + + Security Level for Zerocoin Transactions. More is better, but needs more time and resources. + Sicherheitsstufe für Zerocoin-Transaktionen. Mehr ist besser, braucht aber mehr Zeit und Ressourcen. + + + Security Level: + Sicherheitsstufe: + + + Security Level 1 - 100 (default: 42) + Sicherheitsstufe 1 - 100 (Voreinstellung: 42) + + + Pay To: + Empfänger: + + + The Bulwark address to send the payment to. Creates local payment to yourself when empty. + Die Bulwark-Adresse, an die die Zahlung gesenden wird. Erstelle Sie eine lokale Zahlung an sich selbst, wenn sie leer ist. + + + Choose previously used address + Bereits verwendete Adresse auswählen + + + Alt+A + Alt+A + + + Paste address from clipboard + Adresse aus der Zwischenablage einfügen + + + Alt+P + Alt+P + + + Label: + Bezeichnung: + + + Enter a label for this address to add it to the list of used addresses + Adressbezeichnung eingeben, um diese in der Liste der bereits verwendeten Adressen zu speichern + + + Amount: + Betrag: + + + Convert Change to Zerocoin (might cost additional fees) + Wandle Wechselgeld in Zerocoin um (kann zusätzliche Gebühren kosten) + + + If checked, the wallet tries to minimize the returning change instead of minimizing the number of spent denominations. + Wenn überprüft wird, versucht die Wallet, das zurückkehrende Wechselgeld zu minimieren, anstatt die Anzahl der verbrauchten Stückelungen zu minimieren. + + + Minimize Change + Minimiert Wechselgeld + + + Information about the available Zerocoin funds. + Informationen über die verfügbaren Zerocoin-Mittel. + + + Zerocoin Stats: + Zerocoin Statistiken: + + + Available Funds + Verfügbare Mittel + + + Available Zerocoin Balance: + Verfügbare Zerocoin Bilanz: + + + Denominations with value 1: + Stückelungen mit Wert 1: + + + Denom. with value 1: + Stücke mit Wert 1: + + + 0 x + 0 x + + + Denominations with value 5: + Stückelungen mit Wert 5: + + + Denom. with value 5: + Stücke mit Wert 5: + + + Denominations with value 10: + Stückelungen mit Wert 10: + + + Denom. with value 10: + Stücke mit Wert 10: + + + Denominations with value 50: + Stückelungen mit Wert 50: + + + Denom. with value 50: + Stücke mit Wert 50: + + + Denominations with value 100: + Stückelungen mit Wert 100: + + + Denom. with value 100: + Stücke mit Wert 100: + + + Denominations with value 500: + Stückelungen mit Wert 500: + + + Denom. with value 500: + Stücke mit Wert 500: + + + Denominations with value 1000: + Stückelungen mit Wert 1000: + + + Denom. with value 1000: + Stücke mit Wert 1000: + + + Denominations with value 5000: + Stückelungen mit Wert 5000: + + + Denom. with value 5000: + Stücke mit Wert 5000: + + + Note: This hidden objects are used for communication between the 'Coin Control' dialog and its parent objects. We don't want to change/reimplement the existing Coin Control, so this objects must be here, even when we don't use them. No, we don't like this approach, either. + Hinweis: Diese verborgenen Objekte werden für die Kommunikation zwischen dem Dialog "Coin Kontrolle" und den übergeordneten Objekten verwendet. Wir wollen die bestehende Coin Kontrolle nicht ändern / reimplementieren. Also müssen diese Objekte hier sein, auch wenn wir sie nicht benutzen. Nein, das gefällt uns auch nicht. + + + Priority: + Priorität: + + + Fee: + Gebühr: + + + Dust: + Abzug: + + + no + nein + + + Bytes: + Byte: + + + Insufficient funds! + Unzureichender Kontostand! + + + Coins automatically selected + Coins automatisch ausgewählt + + + medium + mittel + + + Coin Control Features + "Coin Control"-Funktionen + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + Wenn dies aktivert, und die Wechselgeld-Adresse leer oder ungültig ist, wird das Wechselgeld einer neu erzeugten Adresse gutgeschrieben. + + + Custom change address + Benutzerdefinierte Wechselgeld-Adresse + + + Amount After Fee: + Betrag nach Gebühr: + + + Change: + Wechselgeld: + + + out of sync + nicht synchron + + + Mint Status: Okay + Prägestatus: Okay + + + Copy quantity + Kopiere Anzahl + + + Copy amount + Betrag kopieren + + + Error: your wallet is locked. Please enter the wallet passphrase first. + Fehler: Ihre Brieftasche ist gesperrt. Bitte geben Sie zuerst die Passphrase der Wallet ein. + + + Message: Enter an amount > 0. + Nachricht: Geben Sie einen Betrag > 0 ein. + + + Minting + Prägung + + + Successfully minted + Erfolgreich geprägt + + + zBWK in + zBWK in + + + sec. Used denominations: + + ausg. Verwendete Stückelungen: + + + + Starting ResetMintZerocoin: rescanning the complete blockchain, this will need up to 30 minutes depending on your hardware.<br /><br /> + Starten von ResetMintZerocoin: Nachscannung der kompletten Blockchain. Das benötigt bis zu 30 Minuten je nach Hardware.<br /><br /> + + + You won't be able to do anything else during that time!<br /> + Sie können während dieser Zeit nichts anderes machen!<br /> + + + Confirm Rescan + Nachscannen bestätigen + + + ResetMintZerocoin: action canceled by user + ResetMintZerocoin: Aktion vom Benutzer abgebrochen + + + Starting ResetMintZerocoin: rescanning complete blockchain, this will need up to 30 minutes depending on your hardware. +Please be patient... + Starten von ResetMintZerocoin: Nachscannen der kompletten Blockchain. Das benötigt bis zu 30 Minuten je nach Hardware. +Bitte haben Sie Geduld... + + + Duration: + Dauer: + + + sec. + + ausg. + + + + Starting ResetSpentZerocoin: + Starte ResetSpentZerocoin: + + + No 'Pay To' address provided, creating local payment + Keine "Pay To"-Adresse zur Verfügung. Erstelle lokale Zahlung + + + Invalid Bulwark Address + Ungültige Bulwark-Adresse + + + Invalid Send Amount + Ungültiger Sendebetrag. + + + Confirm additional Fees + Zusätzliche Gebühren bestätigen + + + Are you sure you want to send?<br /><br /> + Sind Sie sicher, dass Sie senden möchten?<br /><br /> + + + to address + an Adresse + + + to a newly generated (unused and therefor anonymous) local address <br /> + zu einer neu erzeugten (unbenutzten und damit anonymen) lokalen Adresse <br /> + + + with Security Level + mit Sicherheitsstufe + + + Confirm send coins + Sende Coins bestätigen + + + Spending Zerocoin. +Computationally expensive, might need several minutes depending on the selected Security Level and your hardware. +Please be patient... + Zerocoin ausgeben. +Rechnerisch aufwändig. Kann je nach ausgewähltem Sicherheitsstufe und Ihrer Hardware mehrere Minuten benötigen +Bitte haben Sie Geduld... + + + Spend Zerocoin failed with status = + Ausgeben Zerocoin fehlgeschlagen mit Status = + + + zBWK Spend #: + zBWK Ausgeben #: + + + denomination: + Stückelung: + + + serial: + seriell: + + + Spend is 1 of : + Spend ist 1 von : + + + value out: + Betrag out: + + + address: + Adresse: + + + zBWK Mint + zBWK Prägen + + + Sending successful, return code: + Senden erfolgreich, Rückgabecode: + + + txid: + txid: + + + fee: + Gebühr: + + + + QObject + + Amount + Betrag + + + Enter a Bulwark address (e.g. %1) + Bulwark-Adresse eingeben (z.B. %1) + + + %1 d + %1 T + + + %1 h + %1 St. + + + %1 m + %1 Min. + + + %1 s + %1 S + + + NETWORK + NETZWERK + + + BLOOM + BLOOM + + + UNKNOWN + UNBEKANNT + + + None + Keine + + + N/A + k.A. + + + %1 ms + %1 Ms + + QRImageWidget - &Save Image... - Grafik &speichern... + Save Image... + Grafik speichern... + + + Copy Image + Grafik kopieren + + + Save QR Code + QR-Code speichern + + + PNG Image (*.png) + PNG-Grafik (*.png) + + + + RPCConsole + + Tools window + Werkzeugfenster + + + Information + Information + + + General + Allgemein + + + Name + Name + + + Client name + Client Name + + + N/A + k.A. + + + Number of connections + Anzahl der Verbindungen + + + Open + Offen + + + Startup time + Startzeit - &Copy Image - Grafik &kopieren + Network + Netzwerk - Save QR Code - QR-Code speichern + Last block time + Letzte Blockzeit - PNG Image (*.png) - PNG-Grafik (*.png) + Debug log file + Debug-Protokolldatei - - - RPCConsole - &Information - &Information + Using OpenSSL version + Verwendete OpenSSL Version - N/A - k.A. + Build date + Build Datum + + + Current number of blocks + Aktuelle Blockanzahl + + + Client version + Client Version + + + Using BerkeleyDB version + Verwendete BerkeleyDB Version + + + Block chain + Block chain + + + Open the Bulwark debug log file from the current data directory. This can take a few seconds for large log files. + Öffne Bulwark-Debug-Protokolldatei aus dem aktuellen Datenverzeichnis. Dies kann für einige Protokolldateien einige Sekunden dauern. + + + Number of Masternodes + Anzahl der Masternodes + + + Console + Konsole + + + Clear console + Leere Konsole + + + Network Traffic + Netzwerk Traffic + + + Clear + Clear + + + Totals + Gesamtbetrag + + + Received + Empfangen + + + Sent + Gesendet + + + Peers + Peers + + + Select a peer to view detailed information. + Wähle ein Peer, um detaillierte Informationen zu sehen. + + + Direction + Richtung Protocol @@ -1782,10 +2725,130 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Version Programmversion + + Services + Dienstleistung + + + Starting Height + Starthöhe + + + Sync Height + Sync Höhe + + + Ban Score + Ban Score + + + Connection Time + Verbindungszeit + + + Last Send + Letztes Senden + + + Last Receive + Letzter Empfang + + + Bytes Sent + Bytes gesendet + + + Bytes Received + Bytes empfangen + Ping Time Latenz (Ping) + + Wallet Repair + Wallet Reparieren + + + Wallet In Use: + Wallet In Benutzung: + + + Salvage wallet + Wallet Rettung + + + Attempt to recover private keys from a corrupt wallet.dat. + Versuche, private Schlüssel aus einer beschädigten wallet.dat zurückzugewinnen. + + + Rescan blockchain files + Nachscannen der Bockchain Dateien + + + Rescan the block chain for missing wallet transactions. + Nachscannen der Bockchain nach verschollen Wallet Transaktionen + + + Recover transactions 1 + Wiederherstellung von Transaktionen 1 + + + Recover transactions from blockchain (keep meta-data, e.g. account owner). + Wiederherstellung von Transaktionen von Blockchain (behalte Meta-Daten, zB. Kontoinhaber) + + + Recover transactions 2 + Wiederherstellung von Transaktionen 2 + + + Recover transactions from blockchain (drop meta-data). + Wiederherstellung von Transaktionen von Blockchain (verwerfe Meta-Daten) + + + Upgrade wallet format + Upgrade Wallet Format + + + Rebuild block chain index from current blk000??.dat files. + Umbau des Blockchain Index vom aktuellen blk000??.dat Datei. + + + The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockhain files or missing/obsolete transactions. + Die unten aufgeführten Schaltflächen starten die Wallet mit Befehlszeilenoptionen, um die Wallet zu reparieren. Problemebehebung mit beschädigten Blockhain-Dateien oder fehlenden/veralteten Transaktionen. + + + Wallet repair options. + Wallet-Reparatur-Optionen + + + Upgrade wallet to latest format on startup. (Note: this is NOT an update of the wallet itself!) + Upgrade Wallet auf neueste Format beim Start. (Anmerkung: Dies ist NICHT ein Update der Wallet selbst!) + + + Rebuild index + Unbau-Index + + + In: + In: + + + Out: + Out: + + + Welcome to the Bulwark RPC console. + Willkommen in der Bulwark RPC Konsole. + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + Nutze Pfeiltasten hoch und runter um alt Konsolenbefehle hervor zu holen, und <b>Ctrl-L</b> um die Konsole zu reinigen. + + + Type <b>help</b> for an overview of available commands. + Gebe <b>help</b> ein, um eine Übersicht der verfügbaren Befehle zu erhalten. + %1 B %1 Byte @@ -1802,37 +2865,113 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.%1 GB %1 GB + + via %1 + via %1 + never nie + + Inbound + Eingehend + + + Outbound + Ausgehend + Unknown Unbekannt - + + Fetching... + Holen... + + ReceiveCoinsDialog - &Message: + 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. + Wiederverwendung eines der zuvor verwendeten Empfangsadressen.<br>Wiederverwendung-Adressen haben Sicherheits- und Datenschutzprobleme.<br>Verwenden Sie diese nicht, es sei denn, dass Sie zuvor eine Zahlungsanforderung generieren. + + + Reuse an existing receiving address (not recommended) + Wiederverwendung einer vorhandenen Empfangsadresse (nicht empfohlen) + + + Message: Nachricht: - &Label: - &Bezeichnung: + An optional label to associate with the new receiving address. + Ein optionales Etikett, das mit der neuen Empfangsadresse verknüpft werden soll. + + + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bulwark network. + Eine optionale Nachricht anhängen an die Zahlungsaufforderung, die bei der Eröffnung der Anforderung angezeigt wird. Hinweis: Die Nachricht wird nicht mit der Zahlung über das Bulwark-Netzwerk gesendet. + + + 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 Bulwark network. + Eine optionale Nachricht anhängen an die Zahlungsaufforderung, die bei der Eröffnung der Anforderung angezeigt wird.<br>Hinweis: Die Nachricht wird nicht mit der Zahlung über das Bulwark-Netzwerk gesendet. + + + Use this form to request payments. All fields are <b>optional</b>. + Verwenden Sie dieses Formular, um Zahlungen anzufordern. Alle Felder sind <b>optional</b>. + + + Label: + Bezeichnung: + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + Einen optionalen Betrag anfordern. Lassen Sie diesen leer oder Null, um nicht einen bestimmten Betrag anzufordern. + + + Amount: + Betrag: - &Request payment - Zahlung anfo&rdern + Request payment + Zahlung anfordern Clear all fields of the form. Alle Formularfelder zurücksetzen. + + Clear + Clear + + + Requested payments history + Verlauf der Angeforderten Zahlungen + + + Show the selected request (does the same as double clicking an entry) + Zeige die ausgewählte Anfrage an (entspricht dem Doppelklick auf einen Eintrag) + + + Show + Anzeigen + + + Remove the selected entries from the list + Entferne die ausgewählten Einträge aus der Liste + + + Remove + Entfernen + Copy label Bezeichnung kopieren + + Copy message + Kopiere Nachricht + Copy amount Betrag kopieren @@ -1845,8 +2984,28 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.QR Code - &Save Image... - Grafik &speichern... + Copy URI + Kopiere URI + + + Copy Address + Kopiere Adresse + + + Save Image... + Grafik speichern... + + + Request payment to %1 + Zahlung anfordern %1 + + + Payment information + Zahlungsinformationen + + + URI + URI Address @@ -1864,7 +3023,15 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Message Nachricht - + + Resulting URI too long, try to reduce the text for label / message. + Resultierende URI zu lange. Versuchen sie den Text für Label / Nachricht zu reduzieren. + + + Error encoding URI into QR Code. + Fehler, Codierung URI in QR-Code + + RecentRequestsTableModel @@ -1887,7 +3054,15 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.(no label) (keine Bezeichnung) - + + (no message) + (keine Nachricht) + + + (no amount) + (kein Betrag) + + SendCoinsDialog @@ -1898,10 +3073,6 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Coin Control Features "Coin Control"-Funktionen - - automatically selected - automatisch ausgewählt - Insufficient funds! Unzureichender Kontostand! @@ -1932,7 +3103,7 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben. Dust: - "Dust": + Abzug: no @@ -1986,10 +3157,6 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Minimize Minimieren - - Obfuscation - Verschleierung - per kilobyte pro Kilobyte @@ -2014,6 +3181,26 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Confirmation time: Bestätigungszeit: + + Open Coin Control... + Öffne Coin Kontrolle... + + + Coins automatically selected + Coins automatisch ausgewählt + + + If the custom fee is set to 1000 uBWKs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 uBWKs in fee,<br />while "at least" pays 1000 uBWKs. For transactions bigger than a kilobyte both pay by kilobyte. + Wenn die kundenspezifische Gebühr auf 1000 uBWKs eingestellt ist und die Transaktion nur 250 Bytes beträgt, dann zahlt man "pro Kilobyte" nur 250 uBWKs an Gebühr,<br />während man "mindestens" 1000 uBWKs bezahlt. Für Transaktionen, die größer sind als ein Kilobyte, bezahlen sie mit Kilobyte. + + + If the custom fee is set to 1000 uBWKs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 uBWKs in fee,<br />while "total at least" pays 1000 uBWKs. For transactions bigger than a kilobyte both pay by kilobyte. + Wenn die kundenspezifische Gebühr auf 1000 uBWKs eingestellt ist und die Transaktion nur 250 Bytes beträgt, dann zahlt man "pro Kilobyte" nur 250 uBWKs an Gebühr,<br />während man "insgesamt mindestens" 1000 uBWKs bezahlt. Für Transaktionen, die größer sind als ein Kilobyte, bezahlen sie mit Kilobyte. + + + Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks.<br />But be aware that this can end up in a never confirming transaction once there is more demand for Bulwark transactions than the network can process. + Nur die minimale Gebühr zu zahlen ist nur gut, solange es weniger Transaktionsvolumen als Platz in den Blocken ist.<br />Aber sein Sie sich bewusst, dass dies am Ende in einer niemals bestätigende Transaktion endet, sobald es mehr Nachfrage nach Bulwark-Transaktionen gibt, als das Netzwerk verarbeiten kann. + normal normal @@ -2027,28 +3214,44 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Empfohlen - S&end - Üb&erweisen + Send as zero-fee transaction if possible + Sende als Null-Gebühr Transaction, wenn möglich + + + (confirmation may take longer) + (Bestätigung kann länger dauern) + + + Confirm the send action + Bestätige die Sendeaktion + + + Send + Überweisen Clear all fields of the form. Alle Formularfelder zurücksetzen. - Clear &All - &Alles zurücksetzen + Clear All + Alles zurücksetzen Send to multiple recipients at once An mehrere Empfänger auf einmal überweisen - Add &Recipient - Empfänge&r hinzufügen + Add Recipient + Empfänger hinzufügen - SwiftTX - SwiftTX + Anonymized BWK + Anonymisierte BWK + + + SwiftX + SwiftX Balance: @@ -2084,7 +3287,111 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben. Copy change - Kopiere Änderung + Kopiere Wechselgeld + + + The split block tool does not work when sending to outside addresses. Try again. + Das Split-Block-Tool funktioniert nicht beim Senden an externe Adressen. Versuch es noch einmal. + + + The split block tool does not work with multiple addresses. Try again. + Das Split-Block-Tool funktioniert nicht mit mehreren Adressen. Versuch es noch einmal. + + + using + benutzend + + + anonymous funds + anonyme Mittel + + + Warning: Invalid Bulwark address + Warnung: Ungültige Bulwark-Adresse + + + any available funds (not recommended) + verfügbare Mittel (nicht empfohlen) + + + and SwiftX + und SwiftX + + + %1 to %2 + %1 zu %2 + + + Are you sure you want to send? + Sind Sie sicher, dass Sie senden möchten? + + + are added as transaction fee + werden als Transaktionsgebühr hinzugefügt + + + Total Amount = <b>%1</b><br />= %2 + GesamtBetrag = <b>%1</b><br />= %2 + + + Confirm send coins + Sende Coins bestätigen + + + A fee %1 times higher than %2 per kB is considered an insanely high fee. + Eine Gebühr %1 mal höher als %2 pro kB gilt als eine wahnsinnig hohe Gebühr. + + + Estimated to begin confirmation within %n block(s). + Geschätzt beginnt die Betätigung in %n Blöcken.Geschätzt beginnt die Betätigung in %n Blöcken. + + + The recipient address is not valid, please recheck. + Die Adresse des Empfängers ist nicht gültig, bitte erneut prüfen. + + + split into %1 outputs using the UTXO splitter. + In %1 Ausgänge mit dem UTXO-Splitter aufgeteilt. + + + <b>(%1 of %2 entries displayed)</b> + <b>(%1 von %2 Einträge angezeigt)</b> + + + The amount to pay must be larger than 0. + Der zu zahlende Betrag muss größer als 0 sein. + + + The amount exceeds your balance. + Der Betrag übersteigt ihre Bilanz. + + + The total exceeds your balance when the %1 transaction fee is included. + Die Gesamtsumme überschreitet Ihre Bilanz, wenn die Transaktionsgebühr von %1 enthalten ist. + + + Duplicate address found, can only send to each address once per send operation. + Doppelte Adresse gefunden. Es kann nur an jede Adresse einmal pro Sendeoperation gesenden werden. + + + Transaction creation failed! + Transaktionserstellung fehlgeschlagen! + + + The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Die Transaktion wurde abgelehnt! Dies könnte passieren, wenn einige der Coins in deiner Wallet schon ausgegeben wurden, wie wenn du eine Kopie der wallet.dat benutzt hättetst und Coins wurden in der Kopie verbracht. Aber sie sind hier nicht als verbracht markiert. + + + Error: The wallet was unlocked only to anonymize coins. + Fehler: Die Wallet wurde nur zum Anonymisieren von Coins freigeschaltet. + + + Error: The wallet was unlocked only to anonymize coins. Unlock canceled. + Fehler: Die Wallet wurde nur zum Anonymisieren von Coins freigeschaltet. Freischalten aufgehoben. + + + Pay only the minimum fee of %1 + Zahle nur die Mindestgebühr von %1 Warning: Unknown change address @@ -2102,8 +3409,8 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Dies ist eine normale Überweisung. - Pay &To: - E&mpfänger: + Pay To: + Empfänger: The Bulwark address to send the payment to @@ -2130,16 +3437,16 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Diesen Eintrag entfernen - &Label: - &Bezeichnung: + Label: + Bezeichnung: Enter a label for this address to add it to the list of used addresses Adressbezeichnung eingeben, um diese in der Liste der bereits verwendeten Adressen zu speichern - A&mount: - Betra&g: + Amount: + Betrag: Message: @@ -2184,8 +3491,16 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben. SignVerifyMessageDialog - &Sign Message - Nachricht &signieren + Signatures - Sign / Verify a Message + Signaturen - Signieren / Überprüfen einer Nachricht + + + Sign Message + Nachricht signieren + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + Sie können Nachrichten mit Ihren Adressen signieren, um zu beweisen, dass Sie sie besitzen. Sein Sie vorsichtig nichts nebulöses zu unterschreiben, da Phishing-Angriffe versuchen können, Sie dazu zu bringen, Ihre Identität zu denen zu untergeben. Unterschreiben Sie nur ganz detaillierte Aussagen, denen Sie zustimmen. The Bulwark address to sign the message with @@ -2211,13 +3526,25 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Enter the message you want to sign here Gehen Sie hier die Nachricht ein, die Sie digital unterschreiben möchten + + Signature + Signatur + Copy the current signature to the system clipboard Kopiert die aktuelle Signatur in den Zwischenspeicher - Sign the message to prove you own this Bulwark address - Signiere die Nachricht um zu Beweisen, dass du diese Bulwark Adresse besitzt + Sign the message to prove you own this Bulwark address + Signiere die Nachricht um zu Beweisen, dass du diese Bulwark Adresse besitzt + + + The Bulwark address the message was signed with + Die Bulwark Adresse mit welcher die Nachricht signiert wurde. + + + Verify the message to ensure it was signed with the specified Bulwark address + Überprüfen Sie die Nachricht, um sicherzustellen, dass sie mit der angegebenen Bulwark-Adresse signiert wurde. The Bulwark address the message was signed with @@ -2227,18 +3554,38 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Verify the message to ensure it was signed with the specified Bulwark address Überprüfen Sie die Nachricht, um sicherzustellen, dass sie mit der angegebenen Bulwark-Adresse signiert wurde. + + Sign Message + Signiere Nachricht + Reset all sign message fields Setze alle signierten Nachrichten Felder zurück - Clear &All - &Alles zurücksetzen + Clear All + Alles zurücksetzen + + + Verify Message + Verifiziere Nachricht + + + Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. + Geben Sie die signierte Adresse, die Nachricht (stellen Sie sicher, dass Zeilenumbrüche, Leerzeichen, Tabs usw. genau kopieren) und Signatur unten ein, um die Nachricht zu überprüfen. Seien Sie vorsichtig, nicht mehr in die Signatur zu lesen, als was in der signierten Nachricht selbst ist, um zu vermeiden, von einem Mann-in-der-Mitte Angriff getroffen zu werden. + + + Verify Message + Verifiziere Nachricht Reset all verify message fields Zurücksetzen aller überprüften Felder. + + Click "Sign Message" to generate signature + Klicken Sie auf "signiere Nachricht", um Signatur zu generieren + The entered address is invalid. Die eingegebene Adresse ist falsch @@ -2259,7 +3606,35 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Private key for the entered address is not available. Privater Schlüssel für die eingegebene Adresse ist nicht verfügbar - + + Message signing failed. + Nachricht Signierung fehlgeschlagen. + + + Message signed. + Nachricht signiert. + + + The signature could not be decoded. + Die Signatur konnte nicht dekodiert werden. + + + Please check the signature and try again. + Bitte überprüfen Sie die Signatur und versuchen Sie es erneut. + + + The signature did not match the message digest. + Die Signatur stimmt nicht mit der Nachricht überein. + + + Message verification failed. + Nachrichtenüberprüfung fehlgeschlagen. + + + Message verified. + Nachricht überprüft. + + SplashScreen @@ -2296,6 +3671,10 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben. TransactionDesc + + Open for %n more block(s) + Offen für %n weitere BlockOffen für %n weitere Blocks + Open until %1 Offen bis %1 @@ -2305,16 +3684,16 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.in Konflikt stehend - %1/offline (verified via swifttx) - %1/offline (Überprüft durch SwiftTX) + %1/offline (verified via SwiftX) + %1/offline (Überprüft durch SwiftX) - %1/confirmed (verified via swifttx) - %1/bestätigt (Überprüft durch SwiftTX) + %1/confirmed (verified via SwiftX) + %1/bestätigt (Überprüft durch SwiftX) - %1 confirmations (verified via swifttx) - %1 Bestätigungen (Überprüft durch SwiftTX) + %1 confirmations (verified via SwiftX) + %1 Bestätigungen (Überprüft durch SwiftX) %1/offline @@ -2329,24 +3708,24 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.%1 Bestätigungen - %1/offline (SwiftTX verification in progress - %2 of %3 signatures) - %1/offline (Überprüfung durch SwiftTX - %2 von %3 Signaturen) + %1/offline (SwiftX verification in progress - %2 of %3 signatures) + %1/offline (Überprüfung durch SwiftX - %2 von %3 Signaturen) - %1/confirmed (SwiftTX verification in progress - %2 of %3 signatures ) - %1/bestätigt (Überprüfung durch SwiftTX - %2 von %3 Signaturen) + %1/confirmed (SwiftX verification in progress - %2 of %3 signatures ) + %1/bestätigt (Überprüfung durch SwiftX - %2 von %3 Signaturen) - %1 confirmations (SwiftTX verification in progress - %2 of %3 signatures) - %1 Bestätigungen (Überprüfung durch SwiftTX - %2 von %3 Signaturen) + %1 confirmations (SwiftX verification in progress - %2 of %3 signatures) + %1 Bestätigungen (Überprüfung durch SwiftX - %2 von %3 Signaturen) - %1/offline (SwiftTX verification failed) - %1/offline (Überprüfung durch SwiftTX fehlgeschlagen) + %1/offline (SwiftX verification failed) + %1/offline (Überprüfung durch SwiftX fehlgeschlagen) - %1/confirmed (SwiftTX verification failed) - %1/bestätigt (Überprüfung durch SwiftTX fehlgeschlagen) + %1/confirmed (SwiftX verification failed) + %1/bestätigt (Überprüfung durch SwiftX fehlgeschlagen) Status @@ -2356,6 +3735,10 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben., has not been successfully broadcast yet , wurde noch nicht erfolgreich übertragen + + , broadcast through %n node(s) + , Broadcast durch %n Node, Broadcast durch %n Nodes + Date Datum @@ -2396,6 +3779,10 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Credit Gutschrift + + matures in %n more block(s) + gereift in %n weiteren Blockgereift in %n weiteren Blocks + not accepted nicht angenommen @@ -2432,6 +3819,10 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Transaction ID Transaktions-ID + + Output index + Output Index + Merchant Händler @@ -2490,6 +3881,10 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Address Adresse + + Open for %n more block(s) + Offen für %n weitere BlockOffen für %n weitere Blocks + Open until %1 Offen bis %1 @@ -2558,6 +3953,10 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Sent to Überwiesen an + + Orphan Block - Generated but not accepted. This does not impact your holdings. + Verwaister Block - Generiert, aber nicht akzeptiert. Dies wirkt sich nicht auf Ihre Bestände aus. + Payment to yourself Eigenüberweisung @@ -2574,10 +3973,34 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Obfuscated Verschleiert + + Converted BWK to zBWK + Umgewandeltes BWK zu zBWK + + + Spent zBWK + Ausgeben zBWK + + + Received BWK from zBWK + Empfangene BWK von zBWK + + + Minted Change as zBWK from zBWK Spend + Geprägtes Wechselgeld als zBWK von zBWK Ausgabe + + + Converted zBWK to BWK + Umgewandeltes zBWK zu BWK + watch-only nur beobachtet + + zBWK Accumulator + zBWK Speicher + (n/a) (k.A.) @@ -2685,6 +4108,26 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Masternode Reward Masternode Vergütung + + Received BWK from zBWK + Empfangen BWK von zBWK + + + Zerocoin Mint + Zerocoin Prägung + + + Zerocoin Spend + Zerocoin Ausgabe + + + Zerocoin Spend, Change in zBWK + Zerocoin Ausgabe, Wechselgeld in zBWK + + + Zerocoin Spend to Self + Zerocoin Ausgabe an sich Selbst + Other Andere @@ -2803,15 +4246,15 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.BWKs überweisen - SwiftTX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. - SwiftTX unterstützt das Versenden von Beträgen dieser Höhe noch nicht. Transaktionen sind zur Zeit auf maximal %1 BWK begrenzt. + SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. + SwiftX unterstützt das Versenden von Beträgen dieser Höhe noch nicht. Transaktionen sind zur Zeit auf maximal %1 BWK begrenzt. WalletView - &Export - &Exportieren + Export + Exportieren Export the data in the current tab to a file @@ -2846,16 +4289,371 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Speichern der Wallet-Daten nach %1 war erfolgreich. + + ZBwkControlDialog + + Select zBWK to Spend + Auswahl zBWK als Ausgabe + + + Quantity + Menge + + + 0 + 0 + + + zBWK + zBWK + + + Select/Deselect All + Markiere/Demarkiere Alle + + + Is Spendable + ist aufwendbar + + bulwark-core + + (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) + (1 = behalte Tx-Meta-Daten z.B. Betrag, Besitzer und Zahlungsanforderungsinformationen, 2 = verwerfe Tx-Meta-Daten) + + + Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times + Erlaubt JSON-RPC Verbindungen von der angegebenen Quelle. Valide für <ip> sein eine einzelne IP (z.B. 1.2.3.4), ein Netzwerk/Netzwerkmaske (z.B. 1.2.3.4/255.255.255.0) oder ein Netzwerk/CIDR (z.B. 1.2.3.4/24). Diese Option kann mehrfach angegeben werden + + + An error occurred while setting up the RPC address %s port %u for listening: %s + Fehler aufgetreten beim Einrichten der RPC-Adresse %s Port %u für horchen: %s + + + Calculated accumulator checkpoint is not what is recorded by block index + Der berechnete Akkumulator-Checkpoint ist nicht das, was vom Blockindex aufgezeichnet wurde + + + Cannot obtain a lock on data directory %s. Bulwark Core is probably already running. + Kann keine Sperre für das Datenverzeichnis %s erhalten. Bulwark Core läuft wahrscheinlich bereits. + + + Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality) + Erstelle neue Dateien mit Systemstandardberechtigungen anstelle von umask 077 (nur wirksam mit deaktivierter Wallet-Funktionalität) + + + Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup + Lösche alle Wallet-Transaktionen und stelle nur diese Teile der Blockchain wieder her durch -neuscan beim Start + + + Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftX, Budgeting) (0-1, default: %u) + Deaktiviere alle Bulwark-spezifischen Funktionen (Masternodes, Verschleierung, SwiftX, Budgetplanung) (0-1, default: %u) + + + Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. + Veröffentlicht unter der MIT-Software-Lizenz, siehe die beigelegte Datei COPYING oder <http://www.opensource.org/licenses/mit-license.php>. + + + Enable spork administration functionality with the appropriate private key. + Aktiviere die Funktionalität der Spork-Administration mit dem entsprechenden privaten Schlüssel. + + + Enable SwiftX, show confirmations for locked transactions (bool, default: %s) + SwiftX aktivieren, Bestätigungen für gesperrte Transaktionen anzeigen (bool, default: %s) + + + Enter regression test mode, which uses a special chain in which blocks can be solved instantly. + Gebe den Regressions-Testmodus ein, der eine spezielle Kette verwendet, in der Blöcke sofort gelöst werden können. + + + Error: Listening for incoming connections failed (listen returned error %s) + Fehler: Horchen von eingehenden Verbindungen fehlgeschlagen (listen return error %s) + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Fehler: Die Transaktion wurde abgelehnt! Dies könnte passieren, wenn einige Coins in deiner Wallet schon ausgegeben wurden, als wenn du eine Kopie von der wallet.dat benutzt hättest. Coins wurden in der Kopie verbracht, aber hier nicht als verbracht markiert. + + + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! + Fehler: Diese Transaktion erfordert eine Transaktionsgebühr von mindestens %s wegen ihrer Menge, Komplexität oder Verwendung von kürzlich erhaltenen Mitteln! + + + Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) + Befehl ausführen, wenn eine relevante Warnung empfangen wird oder wir einen wirklich langen Fork sehen (%s in cmd wird durch Benachrichtigungen ersetzt) + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Befehl ausführen, wenn eine Wallet-Transaktion geändert wird (%s in cmd wird durch TxID ersetzt) + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Befehl ausführen, wenn sich der beste Block ändert (%s in cmd wird durch Blockhash ersetzt) + + + Fees (in BWK/Kb) smaller than this are considered zero fee for relaying (default: %s) + Gebühren (in BWK/kB) kleiner als diese gelten als Null-Gebühr für die Weiterleitung (default: %s) + + + Fees (in BWK/Kb) smaller than this are considered zero fee for transaction creation (default: %s) + Gebühren (in BWK/kB) kleiner als diese werden als Null-Gebühr für die Transaktionserstellung betrachtet (default: %s) + + + Flush database activity from memory pool to disk log every <n> megabytes (default: %u) + Flusht die Datenbankaktivität vom Speicherpool auf das Festplattenprotokoll alle <n> Megabytes (default: %u) + + + Found unconfirmed denominated outputs, will wait till they confirm to continue. + Gefundene unbestätigte benannte Outputs werden warten bis sie bestätigen sind, um fortzufahren. + + + How thorough the block verification of -checkblocks is (0-4, default: %u) + Wie gründlich die Blockprüfung von -checkblocks ist (0-4, default: %u) + + + If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) + Wenn paytxfee nicht gesetzt ist, gebe genügend Gebühr an, sodass die Transaktionsbestätigungen im Durchschnitt innerhalb von n Blöcken beginnen (default: %u) + + + In this mode -genproclimit controls how many blocks are generated immediately. + In diesem Modus -genproclimit steuern, wie viele Blöcke sofort erzeugt werden. + + + Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Ungültiger Betrag für -maxtxfee=<amount>: '%s' (muss mindestens das minrelay Gebühr von %s sein, um Transaktionsstau zu vermeiden) + + + Keep the specified amount available for spending at all times (default: 0) + Behalte jeder Zeit den angegebenen Betrag für die Ausgaben (default: 0) + + + Log transaction priority and fee per kB when mining blocks (default: %u) + Priorität der Protokolltransaktion und Gebühr pro kB wenn Mining-Blocke (default: %u) + + + Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u) + Pflege einen vollständigen Transaktionsindex, der von der getrawtransaction rpc call verwendet wird. (default: %u) + + + Maximum size of data in data carrier transactions we relay and mine (default: %u) + Maximale Größe der Daten in Datenträgertransaktionen, die wir weiterleiten und abbilden (default: %u) + + + Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s) + Maximale Gesamtgebühren für die Verwendung in einer einzigen Wallet-Transaktion. Zu niedrige Einstellung kann große Transaktionen abbrechen (default: %s) + + + Number of seconds to keep misbehaving peers from reconnecting (default: %u) + Sekundenanzahl, um fehlerhafte Peers zu halten von der Wiederverbindung (default: %u) + + + (default: %s) + (default: %s) + + + (default: 1) + (default: 1) + + + Connection options: + Verbindungsoptionen: + + + Copyright (C) 2009-%i The Bitcoin Core Developers + Copyright (C) 2009-%i The Bitcoin Core Developers + + + Copyright (C) 2014-%i The Dash Core Developers + Copyright (C) 2014-%i The Dash Core Developers + + + Copyright (C) 2015-%i The PIVX Core Developers + Copyright (C) 2015-%i The PIVX Core Developers + Error Fehler + + Generate coins (default: %u) + Generiere Coins (default: %u) + + + How many blocks to check at startup (default: %u, 0 = all) + Zu überprüfende Blöcke beim Start (default: %u, 0 = all) + + + Importing... + Importiere... + + + Incompatible mode. + Inkompatibler Modus. + + + Incompatible version. + Inkompatible Version. + + + Incorrect or no genesis block found. Wrong datadir for network? + Falscher oder kein Genesis-Block gefunden. Falsches Datenverzeichnis für das Netzwerk? + Information Hinweis + + Initialization sanity check failed. Bulwark Core is shutting down. + Initialisierung Sanity-Check fehlgeschlagen. Bulwark Core schaltet ab. + + + Input is not valid. + Input ist nicht gültig. + + + Insufficient funds + Unzureichende Mittel + + + Insufficient funds. + Unzureichende Mittel. + + + Invalid -onion address: '%s' + Ungültige -onion Adresse: '%s' + + + Invalid -proxy address: '%s' + Ungültige -proxy Adresse: '%s' + + + Invalid amount for -maxtxfee=<amount>: '%s' + Ungültiger Betrag für -maxtxfee=<amount>: '%s' + + + Invalid amount for -minrelaytxfee=<amount>: '%s' + Ungültiger Betrag für -minrelaytxfee=<amount>: '%s' + + + Invalid amount for -mintxfee=<amount>: '%s' + Ungültiger Betrag für -mintxfee=<amount>: '%s' + + + Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) + Ungültiger Betrag für -paytxfee=<amount>: '%s' (muss mindestens %s sein) + + + Invalid amount for -paytxfee=<amount>: '%s' + Ungültiger Betrag für -paytxfee=<amount>: '%s' + + + Invalid amount for -reservebalance=<amount> + Ungültiger Betrag für -reservebalance=<amount> + + + Invalid amount + Ungültiger Betrag + + + Enable staking functionality (0-1, default: %u) + Aktiviere Staking-Funktionalität (0-1, default: %u) + + + Loading wallet... (%3.2f %%) + Lade Wallet... (%3.2f %%) + + + Loading wallet... + Lade Wallet... + + + Masternode options: + Masternode-Optionen: + + + Masternode queue is full. + Masternode-Schlange ist voll. + + + Masternode: + Masternode: + + + Only connect to nodes in network <net> (ipv4, ipv6 or onion) + Nur Verbindung zu Knoten im Netzwerk <net> (ipv4, ipv6 oder onion) + + + Options: + Optionen: + + + RPC server options: + RPC Serveroptionen: + + + Rescan the block chain for missing wallet transactions + Neuscannen der Blockchain nach fehlenden Wallet-Transaktionen + + + Rescanning... + Neuscannen... + + + ResetMintZerocoin finished: + ResetMintZerocoin abgeschlossen: + + + ResetSpentZerocoin finished: + ResetSpentZerocoin abgeschlossen: + + + Show all debugging options (usage: --help -help-debug) + Zeige alle debugging Optionen (verwende: --help -help-debug) + + + Specify data directory + Bezeichne Datenverzeichnis + + + Specify masternode configuration file (default: %s) + Bezeichne Masternode-Konfigurationsdatei (default: %s) + + + Specify pid file (default: %s) + Bezeichne pid-Datei (default: %s) + + + Specify wallet file (within data directory) + Bezeichne Wallet-Datei (im Datenverzeichnis) + + + Specify your own public address + Bezeichnen Sie ihre eigene öffentliche Adresse + + + Staking options: + Staking-Optionen: + + + Stop running after importing blocks from disk (default: %u) + Stoppt den Lauf nach dem Importieren von Blöcken von der Festplatte (default: %u) + + + Submitted following entries to masternode: %u / %d + Folgende Einträge zum Masternode eingereicht: %u / %d + + + Submitted to masternode, waiting for more entries ( %u / %d ) %s + Eingereicht zum Masternode, wartet auf mehr Einträge ( %u / %d ) %s + + + Submitted to masternode, waiting in queue %s + Eingereicht zum Masternode, wartet in der Schlange %s + + + SwiftX options: + SwiftX Optionen: + Synchronization failed Synchronisierung fehlgeschlagen @@ -3016,6 +4814,30 @@ MultiSend wird nicht aktiviert bis Sie auf Aktivieren geklickt haben.Warning: This version is obsolete, upgrade required! Warnung: Diese Version is veraltet, Aktualisierung erforderlich! + + Will retry... + Wird wiederholt... + + + Your entries added successfully. + Ihre Eingaben wurden erfolgreich hinzugefügt. + + + Your transaction was accepted into the pool! + Ihre Transaktion wurde in den Pool aufgenommen! + + + ZeroMQ notification options: + ZeroMQ Benachrichtigungsoptionen: + + + Zerocoin options: + Zerocoin Optionen: + + + failed to validate zerocoin + fehlgeschlagen beim Zerocoin validieren + on startup beim Starten diff --git a/src/qt/locale/bulwark_en.ts b/src/qt/locale/bulwark_en.ts index 63821d2b5..0c4d6d0ca 100644 --- a/src/qt/locale/bulwark_en.ts +++ b/src/qt/locale/bulwark_en.ts @@ -15,8 +15,8 @@ - &New - &New + New + New @@ -25,8 +25,8 @@ - &Copy - &Copy + Copy + Copy @@ -35,8 +35,8 @@ - &Delete - &Delete + Delete + Delete @@ -45,13 +45,13 @@ - &Export - &Export + Export + Export - C&lose - C&lose + Close + Close @@ -65,8 +65,8 @@ - C&hoose - C&hoose + Choose + Choose @@ -90,18 +90,18 @@ - &Copy Address - &Copy Address + Copy Address + Copy Address - Copy &Label - Copy &Label + Copy Label + Copy Label - &Edit - &Edit + Edit + Edit @@ -127,7 +127,7 @@ AddressTableModel - + Label Label @@ -302,7 +302,7 @@ - &BIP 38 Encrypt + BIP 38 Encrypt @@ -365,7 +365,7 @@ - Encrypt &Key + Encrypt Key @@ -376,12 +376,12 @@ - Clear &All - Clear &All + Clear All + Clear All - &BIP 38 Decrypt + BIP 38 Decrypt @@ -401,7 +401,7 @@ - Decrypt &Key + Decrypt Key @@ -505,7 +505,7 @@ BitcoinGUI - + Wallet Wallet @@ -515,9 +515,9 @@ Node - - &Overview - &Overview + + Overview + Overview @@ -526,18 +526,18 @@ - &Send - &Send + Send + Send - &Receive - &Receive + Receive + Receive - &Transactions - &Transactions + Transactions + Transactions @@ -545,9 +545,14 @@ Browse transaction history - - E&xit - E&xit + + Privacy Actions for zBWK + + + + + Exit + Exit @@ -557,8 +562,8 @@ - About &Qt - About &Qt + About Qt + About Qt @@ -567,13 +572,13 @@ - &Options... - &Options... + Options... + Options... - &Show / Hide - &Show / Hide + Show / Hide + Show / Hide @@ -582,8 +587,8 @@ - &Encrypt Wallet... - &Encrypt Wallet... + Encrypt Wallet... + Encrypt Wallet... @@ -592,8 +597,8 @@ - &Backup Wallet... - &Backup Wallet... + Backup Wallet... + Backup Wallet... @@ -602,8 +607,8 @@ - &Change Passphrase... - &Change Passphrase... + Change Passphrase... + Change Passphrase... @@ -612,8 +617,8 @@ - &Unlock Wallet... - &Unlock Wallet... + Unlock Wallet... + Unlock Wallet... @@ -622,23 +627,23 @@ - &Lock Wallet - &Lock Wallet + Lock Wallet + Lock Wallet - Sign &message... - Sign &message... + Sign message... + Sign message... - &Verify message... - &Verify message... + Verify message... + Verify message... - &Information - &Information + Information + Information @@ -647,8 +652,8 @@ - &Debug console - &Debug console + Debug console + Debug console @@ -657,8 +662,8 @@ - &Network Monitor - &Network Monitor + Network Monitor + Network Monitor @@ -667,8 +672,8 @@ - &Peers list - &Peers list + Peers list + Peers list @@ -677,8 +682,8 @@ - Wallet &Repair - Wallet &Repair + Wallet Repair + Wallet Repair @@ -692,8 +697,8 @@ - Show Automatic &Backups - Show Automatic &Backups + Show Automatic Backups + Show Automatic Backups @@ -702,8 +707,8 @@ - &Sending addresses... - &Sending addresses... + Sending addresses... + Sending addresses... @@ -712,8 +717,8 @@ - &Receiving addresses... - &Receiving addresses... + Receiving addresses... + Receiving addresses... @@ -722,16 +727,46 @@ - Open &URI... - Open &URI... + Multisignature creation... + + + + + Create a new multisignature address and add it to this wallet + + + + + Multisignature spending... + + + + + Spend from a multisignature address + + + + + Multisignature signing... + + + + + Sign with a multisignature address + + + + + Open URI... + Open URI... - &Command-line options - &Command-line options + Command-line options + Command-line options - + Processed %n blocks of transaction history. Processed %n block of transaction history. @@ -744,24 +779,29 @@ Synchronizing additional data: %p% - - &File - &File + + %1 behind. Scanning block %2 + + + + + File + File - - &Settings - &Settings + + Settings + Settings - &Tools - &Tools + Tools + Tools - &Help - &Help + Help + Help @@ -769,13 +809,13 @@ Tabs toolbar - - + + Bulwark Core - + Send coins to a Bulwark address @@ -785,8 +825,13 @@ - - &Masternodes + + Privacy + + + + + Masternodes @@ -795,8 +840,8 @@ - - &About Bulwark Core + + About Bulwark Core @@ -821,7 +866,7 @@ - &BIP38 tool + BIP38 tool @@ -831,7 +876,7 @@ - &MultiSend + MultiSend @@ -841,12 +886,12 @@ - Open Wallet &Configuration File + Open Wallet Configuration File - Open &Masternode Configuration File + Open Masternode Configuration File @@ -855,13 +900,13 @@ - + Open a Bulwark: URI or payment request - &Blockchain explorer + Blockchain explorer @@ -875,12 +920,12 @@ - + Bulwark Core client - + %n active connection(s) to Bulwark network @@ -951,12 +996,7 @@ - - %1 behind - %1 behind - - - + Catching up... Catching up... @@ -986,7 +1026,7 @@ Information - + Sent transaction Sent transaction @@ -1014,7 +1054,7 @@ Address: %4 - + Staking is active MultiSend: %1 @@ -1061,7 +1101,17 @@ Address: %4 - + + Back + + + + + Forward + + + + Address / Block / Transaction @@ -1076,7 +1126,7 @@ Address: %4 - + Not all transactions will be shown. To view all transactions you need to set txindex=1 in the configuration file (bulwark.conf). @@ -1084,9 +1134,9 @@ Address: %4 ClientModel - - Total: %1 (OBF compatible: %2 / Enabled: %3) - Total: %1 (OBF compatible: %2 / Enabled: %3) + + Total: %1 (IPv4: %2 / IPv6: %3 / Tor: %4 / Unknown: %5) + @@ -1183,8 +1233,8 @@ Address: %4 - DS Rounds - + Type + Type @@ -1207,7 +1257,7 @@ Address: %4 Priority - + Copy address Copy address @@ -1273,17 +1323,12 @@ Address: %4 Copy change - + Please switch to "List mode" to use this function. - - Non-anonymized input selected. <b>Obfuscation will be disabled.</b><br><br>If you still want to use Obfuscation, please deselect all non-nonymized inputs first and then check Obfuscation checkbox again. - - - - + highest highest @@ -1303,18 +1348,13 @@ Address: %4 medium-high - + Can vary +/- %1 duff(s) per input. Can vary +/- %1 duff(s) per input. - - - n/a - n/a - - + medium medium @@ -1344,12 +1384,12 @@ Address: %4 (%1 locked) - + none none - + yes yes @@ -1392,7 +1432,7 @@ Address: %4 - + (no label) (no label) @@ -1416,8 +1456,8 @@ Address: %4 - &Label - &Label + Label + Label @@ -1426,8 +1466,8 @@ Address: %4 - &Address - &Address + Address + Address @@ -1684,22 +1724,22 @@ Address: %4 - S&tart alias + Start alias - Start &all + Start all - Start &MISSING + Start MISSING - &Update status + Update status @@ -1718,7 +1758,7 @@ Address: %4 - + Confirm masternode start @@ -1920,244 +1960,446 @@ Please check the address and try again. - ObfuscationConfig + MultisigDialog - - Configure Obfuscation + + Multisignature Address Interactions - - Basic Privacy - Basic Privacy + + Create MultiSignature Address + - - High Privacy - High Privacy + + How many people must sign to verify a transaction + - - Maximum Privacy - Maximum Privacy + + Enter the minimum number of signatures required to sign transactions + - - Please select a privacy level. - Please select a privacy level. + + Address Label: + - - Use 2 separate masternodes to mix funds up to 5000 BWK + + Add another address that could sign to verify a transaction from the multisig address. - - Use 8 separate masternodes to mix funds up to 5000 BWK + + Add Address / Key - - Use 16 separate masternodes - Use 16 separate masternodes + + Local addresses or public keys that can sign: + - - This option is the quickest and will cost about ~0.025 BWK to anonymize 5000 BWK + + Create a new multisig address - - This option is moderately fast and will cost about 0.05 BWK to anonymize 5000 BWK + + Create - - 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 + + + + Status: + - - 0.1 BWK per 5000 BWK you anonymize. + + Use below to quickly import an address by its redeem. Don't forget to add a label before clicking import! +Keep in mind, the wallet will rescan the blockchain to find transactions containing the new address. +Please be patient after clicking import. - - - - Obfuscation Configuration + + Import Redeem - - Obfuscation was successfully set to basic (%1 and 2 rounds). You can change this at any time by opening Bulwark's configuration screen. + + Create MultiSignature Tx - - Obfuscation was successfully set to high (%1 and 8 rounds). You can change this at any time by opening Bulwark's configuration screen. + + Inputs: - - Obfuscation was successfully set to maximum (%1 and 16 rounds). You can change this at any time by opening Bulwark's configuration screen. + + Coin Control - - - OpenURIDialog - - Open URI - Open URI + + Quantity Selected: + - - Open payment request from URI or file - Open payment request from URI or file + + + 0 + - - URI: - URI: + + Amount: + Amount: - - Select payment request file - Select payment request file + + Add an input to fund the outputs + - - Select payment request file to open - Select payment request file to open + + Add a Raw Input + - - - OptionsDialog - - Options - Options + + Address / Amount: + - &Main - &Main - - - - Size of &database cache - Size of &database cache + Add destinations to send BWK to + - - MB - MB + + Add Destination + - - Number of script &verification threads - Number of script &verification threads + + Create a transaction object using the given inputs to the given outputs + - - (0 = auto, <0 = leave that many cores free) - (0 = auto, <0 = leave that many cores free) + + Create + - - W&allet - W&allet + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + - If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. - If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. + Sign MultiSignature Tx + - - Automatically open the Bulwark client port on the router. This only works when your router supports UPnP and it is enabled. + + Transaction Hex: - - Accept connections from outside - Accept connections from outside + + Sign the transaction from this wallet or from provided private keys + - Allow incoming connections - Allow incoming connections + Sign + - - &Connect through SOCKS5 proxy (default proxy): - &Connect through SOCKS5 proxy (default proxy): + + <html><head/><body><p>DISABLED until transaction has been signed enough times.</p></body></html> + - - Expert - Expert + + Commit + - - Automatically start Bulwark after logging in to the system. + + Add private keys to sign the transaction with - &Start Bulwark on system login + Add Private Key - - This setting determines the amount of individual masternodes that an input will be anonymized through.<br/>More rounds of anonymization gives a higher degree of privacy, but also costs more in fees. - This setting determines the amount of individual masternodes that an input will be anonymized through.<br/>More rounds of anonymization gives a higher degree of privacy, but also costs more in fees. + + Sign with only private keys (Not Recommened) + - - Obfuscation rounds to use + + Invalid Tx Hash. - - This amount acts as a threshold to turn off Obfuscation once it's reached. + + Vout position must be positive. - - Amount of Bulwark to keep anonymized + + Maximum possible addresses reached. (16) - - Whether to show coin control features or not. - Whether to show coin control features or not. + + Vout Position: + - - Enable coin &control features - Enable coin &control features + + Amount: + - - Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. + + Maximum (15) + + + ObfuscationConfig - - Show Masternodes Tab + + 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 5000 BWK + + + + + Use 8 separate masternodes to mix funds up to 5000 BWK + + + + + Use 16 separate masternodes + Use 16 separate masternodes + + + + This option is the quickest and will cost about ~0.025 BWK to anonymize 5000 BWK + + + + + This option is moderately fast and will cost about 0.05 BWK to anonymize 5000 BWK + + + + + 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 BWK per 5000 BWK you anonymize. + + + + + + + Obfuscation Configuration + + + + + Obfuscation was successfully set to basic (%1 and 2 rounds). You can change this at any time by opening Bulwark's configuration screen. + + + + + Obfuscation was successfully set to high (%1 and 8 rounds). You can change this at any time by opening Bulwark's configuration screen. + + + + + Obfuscation was successfully set to maximum (%1 and 16 rounds). You can change this at any time by opening Bulwark's configuration screen. + + + + + OpenURIDialog + + + Open URI + Open URI + + + + Open payment request from URI or file + Open payment request from URI or file + + + + URI: + URI: + + + + Select payment request file + Select payment request file + + + + Select payment request file to open + Select payment request file to open + + + + OptionsDialog + + + Options + Options + + + + Main + Main + + + + Size of database cache + Size of database cache + + + + MB + MB + + + + Number of script verification threads + Number of script verification threads + + + + (0 = auto, <0 = leave that many cores free) + (0 = auto, <0 = leave that many cores free) + + + + Wallet + Wallet + + + + If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. + If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. + + + + Automatically open the Bulwark client port on the router. This only works when your router supports UPnP and it is enabled. + + + + + Accept connections from outside + Accept connections from outside + + + + Allow incoming connections + Allow incoming connections + + + + Connect through SOCKS5 proxy (default proxy): + Connect through SOCKS5 proxy (default proxy): + + + + Expert + Expert + + + + Automatically start Bulwark after logging in to the system. + + + + + Start Bulwark on system login + + + + + Whether to show coin control features or not. + Whether to show coin control features or not. + + + + Enable coin control features + Enable coin control features + + + + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. + + + + + Show Masternodes Tab - &Spend unconfirmed change - &Spend unconfirmed change + Spend unconfirmed change + Spend unconfirmed change - &Network - &Network + Network + Network @@ -2172,18 +2414,39 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - Map port using &UPnP - Map port using &UPnP + Map port using UPnP + Map port using UPnP - + + Percentage of incoming BWK which get automatically converted to zBWK via Zerocoin Protocol + + + + + Percentage of autominted zBWK + + + + + + Wait with automatic conversion to Zerocoin until enough BWK for this denomination is available + + + + + Preferred Automint zBWK Denomination + + + + Connect to the Bulwark network through a SOCKS5 proxy. - Proxy &IP: - Proxy &IP: + Proxy IP: + Proxy IP: @@ -2192,8 +2455,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Port: - &Port: + Port: + Port: @@ -2202,8 +2465,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Window - &Window + Window + Window @@ -2212,8 +2475,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Minimize to the tray instead of the taskbar - &Minimize to the tray instead of the taskbar + Minimize to the tray instead of the taskbar + Minimize to the tray instead of the taskbar @@ -2222,18 +2485,18 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - M&inimize on close - M&inimize on close + Minimize on close + Minimize on close - &Display - &Display + Display + Display - User Interface &language: - User Interface &language: + User Interface language: + User Interface language: @@ -2242,8 +2505,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Unit to show amounts in: - &Unit to show amounts in: + Unit to show amounts in: + Unit to show amounts in: @@ -2278,21 +2541,26 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Reset Options - &Reset Options + Reset Options + Reset Options - &OK - &OK + OK + OK - &Cancel - &Cancel + Cancel + Cancel + + + + I don't care + - + default default @@ -2302,7 +2570,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations none - + Confirm options reset Confirm options reset @@ -2336,49 +2604,51 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Form - + + BWK Balances + + + + Available: Available: + Your current spendable balance Your current spendable balance - + Pending: Pending: + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance - + + Immature: Immature: - + Staked or masternode rewards that has not yet matured Staked or masternode rewards that has not yet matured - - Balances - Balances - - - - - + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. - + Unconfirmed transactions to watch-only addresses Unconfirmed transactions to watch-only addresses @@ -2389,11 +2659,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations + + Total: Total: - + Your current total balance Your current total balance @@ -2418,211 +2690,143 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Spendable: - - Status: - Status: + + Combined Balances (including unconfirmed and immature coins) + - - Obfuscation Balance: + + <html><head/><body><p>Combined Balances</p></body></html> - - 0 BWK / 0 Rounds + + Total Balance, including unconfirmed and immature coins. - - Enabled/Disabled - Enabled/Disabled + + BWK: + - - Try to manually submit a Obfuscation request. + + zBWK: - - Reset the current status of Obfuscation (can interrupt Obfuscation if it's in the process of Mixing, which can cost you money!) + + Current percentage of zBWK. +If AutoMint is enabled this percentage will settle around the configured AutoMint percentage - - - - - - Obfuscation + + + 0 % - - Completion: - Completion: + + + Locked BWK or Masternode collaterals. These are excluded from zBWK minting. + - - Amount and Rounds: - Amount and Rounds: + + + + + + 0.000 000 00 BWK + - - Submitted Denom: - Submitted Denom: + + Locked: + + - n/a - n/a - - - - Recent transactions - Recent transactions - - - - Start/Stop Mixing - Start/Stop Mixing - - - - The denominations you submitted to the Masternode.<br>To mix, other users must submit the exact same denominations. - The denominations you submitted to the Masternode.<br>To mix, other users must submit the exact same denominations. - - - - (Last Message) - (Last Message) - - - - Try Mix - Try Mix - - - - Reset - Reset - - - - - - out of sync - out of sync - - - - - - - Disabled - Disabled - - - - - No inputs detected - No inputs detected - - - - - - %n Rounds - - %n Round - %n Rounds - + Unlocked BWKs. These can be used for zBWK minting. + - Not enough compatible inputs to anonymize <span style='color:red;'>%1</span>,<br>will anonymize <span style='color:red;'>%2</span> instead - Not enough compatible inputs to anonymize <span style='color:red;'>%1</span>,<br>will anonymize <span style='color:red;'>%2</span> instead - - - - Overall progress - Overall progress - - - - Denominated - Denominated + Unlocked: + - - Anonymized - Anonymized - - - - Denominated inputs have %5 of %n rounds on average - - Denominated inputs have %5 of %n rounds on average - Denominated inputs have %5 of %n rounds on average - + + Zerocoin Balance + - - Last Obfuscation message: - + + + Mature: more than 20 confirmation and more than 1 mint of the same denomination after it was minted. +These zBWK are spendable. - - Obfuscation was successfully reset. + + Mature: - - If you don't want to see internal Obfuscation fees/transactions select "Most Common" as Type on the "Transactions" tab. + + + All available zBWK, unconfirmed and immature zBWK included. - - Obfuscation requires at least %1 to use. + + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted - - Wallet is locked and user declined to unlock. Disabling Obfuscation. + + Unconfirmed: - - Found enough compatible inputs to anonymize %1 - Found enough compatible inputs to anonymize %1 + + Recent transactions + Recent transactions - - - - Start Obfuscation - + + + out of sync + out of sync - - - Stop Obfuscation + + Current percentage of zBWK. +If AutoMint is enabled this percentage will settle around the configured AutoMint percentage. + - - Mixed - Mixed + + AutoMint is currently enabled and set to + - - Enabled - Enabled + + To disable AutoMint add 'enablezeromint=0' in bulwark.conf. + - - N/A - N/A + + AutoMint is currently disabled. +To enable AutoMint change 'enablezeromint=0' to 'enablezeromint=1' in bulwark.conf + @@ -2717,52 +2921,699 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Payment request %1 is too large (%2 bytes, allowed %3 bytes). - - Payment request DoS protection - Payment request DoS protection + + Payment request DoS protection + Payment request DoS protection + + + + Error communicating with %1: %2 + Error communicating with %1: %2 + + + + Payment request cannot be parsed! + Payment request cannot be parsed! + + + + Bad response from server %1 + Bad response from server %1 + + + + Network request error + Network request error + + + + Payment acknowledged + Payment acknowledged + + + + PeerTableModel + + + Address/Hostname + Address/Hostname + + + + Version + Version + + + + Ping Time + Ping Time + + + + PrivacyDialog + + + BWK which were anonymized via Zerocin Protocol + + + + + Zerocoin BWK (zBWK) + + + + + Zerocoin Actions: + + + + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + + + + + + Enter an amount of BWK to convert to zBWK + + + + + + + Mint Zerocoin + + + + + + + 0 + + + + + + zBWK + + + + + Available for minting are coins which are confirmed and not locked or Masternode collaterals. + + + + + Mintable: + + + + + 0.000 000 00 BWK + + + + + Reset Zerocoin Wallet DB. Deletes transactions that did not make it into the blockchain. + + + + + Reset + Reset + + + + Coin Control... + + + + + Quantity: + Quantity: + + + + Amount: + Amount: + + + + Rescan the complete blockchain for Zerocoin mints and their meta-data. + + + + + ReScan + + + + + Status and/or Mesages from the last Mint Action. + + + + + zBWK Control + + + + + zBWK Selected: + + + + + Quantity Selected: + + + + + Spend Zerocoin. Without 'Pay To:' address creates payments to yourself. + + + + + + + + + + Spend Zerocoin + + + + + Available (mature and spendable) zBWK for spending + + + + + Available Balance: + + + + + Available (mature and spendable) zBWK for spending + +zBWK are mature when they have more than 20 confirmations AND more than 1 mint of the same denomination after them were minted + + + + + + 0 zBWK + + + + + Security Level for Zerocoin Transactions. More is better, but needs more time and resources. + + + + + Security Level: + + + + + Security Level 1 - 100 (default: 42) + + + + + Pay To: + Pay To: + + + + The Bulwark address to send the payment to. Creates local payment to yourself when empty. + + + + + Choose previously used address + Choose previously used address + + + + Alt+A + Alt+A + + + + Paste address from clipboard + Paste address from clipboard + + + + Alt+P + Alt+P + + + + Label: + Label: + + + + Enter a label for this address to add it to the list of used addresses + Enter a label for this address to add it to the list of used addresses + + + + Amount: + Amount: + + + + Convert Change to Zerocoin (might cost additional fees) + + + + + If checked, the wallet tries to minimize the returning change instead of minimizing the number of spent denominations. + + + + + Minimize Change + + + + + Information about the available Zerocoin funds. + + + + + Zerocoin Stats: + + + + + + Total Balance including unconfirmed and immature zBWK + + + + + Total Zerocoin Balance: + + + + + Denominations with value 1: + + + + + Denom. with value 1: + + + + + + + + + + + + Unconfirmed: less than 20 confirmations +Immature: confirmed, but less than 1 mint of the same denomination after it was minted + + + + + + + + + + + + 0 x + + + + + Denominations with value 5: + + + + + Denom. with value 5: + + + + + Denominations with value 10: + + + + + Denom. with value 10: + + + + + Denominations with value 50: + + + + + Denom. with value 50: + + + + + Denominations with value 100: + + + + + Denom. with value 100: + + + + + Denominations with value 500: + + + + + Denom. with value 500: + + + + + Denominations with value 1000: + + + + + Denom. with value 1000: + + + + + Denominations with value 5000: + + + + + Denom. with value 5000: + + + + + Note: This hidden objects are used for communication between the 'Coin Control' dialog and its parent objects. We don't want to change/reimplement the existing Coin Control, so this objects must be here, even when we don't use them. No, we don't like this approach, either. + + + + + Priority: + Priority: + + + + Fee: + Fee: + + + + Dust: + Dust: + + + + no + no + + + + Bytes: + Bytes: + + + + Insufficient funds! + Insufficient funds! + + + + + + + + Coins automatically selected + + + + + medium + 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. + + + + Custom change address + Custom change address + + + + Amount After Fee: + + + + + Change: + Change: + + + + out of sync + out of sync + + + + + Mint Status: Okay + + + + + Copy quantity + Copy quantity + + + + Copy amount + Copy amount + + + + + zBWK is currently disabled due to maintenance. + + + + + + zBWK is currently undergoing maintenance. + + + + + Error: Your wallet is locked. Please enter the wallet passphrase first. + + + + + Message: Enter an amount > 0. + + + + + Minting + + + + + Successfully minted + + + + + zBWK in + + + + + sec. Used denominations: + + + + + + Starting ResetMintZerocoin: rescanning complete blockchain, this will need up to 30 minutes depending on your hardware. +Please be patient... + + + + + + + Duration: + + + + + + + sec. + + + + + + Starting ResetSpentZerocoin: + + + + + No 'Pay To' address provided, creating local payment + + + + + Invalid Bulwark Address + + + + + Invalid Send Amount + + + + + Confirm additional Fees + + + + + Are you sure you want to send?<br /><br /> + + + + + to address + + + + + to a newly generated (unused and therefore anonymous) local address <br /> + + + + + with Security Level + + + + + Confirm send coins + Confirm send coins + + + + Spending Zerocoin. +Computationally expensive, might need several minutes depending on the selected Security Level and your hardware. +Please be patient... + + + + + Too much inputs ( + + + + + ) needed. +Maximum allowed: + + + + + +Either mint higher denominations (so fewer inputs are needed) or reduce the amount to spend. + + + + + + Spend Zerocoin failed with status = + + + + + zBWK Spend #: + + + + + denomination: + - - Error communicating with %1: %2 - Error communicating with %1: %2 + + serial: + - - Payment request cannot be parsed! - Payment request cannot be parsed! + + Spend is 1 of : + - - Bad response from server %1 - Bad response from server %1 + + value out: + - - Network request error - Network request error + + address: + - - Payment acknowledged - Payment acknowledged + + zBWK Mint + - - - PeerTableModel - - Address/Hostname - Address/Hostname + + Sending successful, return code: + - - Version - Version + + txid: + - - Ping Time - Ping Time + + fee: + @@ -2778,7 +3629,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - + %1 d %1 d @@ -2832,13 +3683,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations QRImageWidget - &Save Image... - &Save Image... + Save Image... + Save Image... - &Copy Image - &Copy Image + Copy Image + Copy Image @@ -2860,8 +3711,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Information - &Information + Information + Information @@ -2887,8 +3738,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - - + + @@ -2903,22 +3754,22 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - + N/A N/A - + Number of connections Number of connections - - &Open - &Open + + Open + Open - + Startup time Startup time @@ -2928,7 +3779,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Network - + Last block time Last block time @@ -2938,7 +3789,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Debug log file - + Using OpenSSL version Using OpenSSL version @@ -2948,12 +3799,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Build date - + Current number of blocks Current number of blocks - + Client version Client version @@ -2963,7 +3814,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Using BerkeleyDB version - + Block chain Block chain @@ -2973,14 +3824,14 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - + Number of Masternodes Number of Masternodes - - &Console - &Console + + Console + Console @@ -2989,13 +3840,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Network Traffic - &Network Traffic + Network Traffic + Network Traffic - &Clear - &Clear + Clear + Clear @@ -3014,13 +3865,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Peers - &Peers + Peers + Peers - - + + Select a peer to view detailed information. Select a peer to view detailed information. @@ -3091,11 +3942,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Wallet Repair - &Wallet Repair + Wallet Repair + Wallet Repair - + + Delete local Blockchain Folders + + + + Wallet In Use: @@ -3150,7 +4006,17 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - + + -resync: + + + + + Deletes all local blockchain folders so the wallet synchronizes from scratch. + + + + The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockhain files or missing/obsolete transactions. The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockhain files or missing/obsolete transactions. @@ -3184,8 +4050,33 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Welcome to the Bulwark RPC console. + + + This will delete your local blockchain folders and the wallet will synchronize the complete Blockchain from scratch.<br /><br /> + + + + + This needs quite some time and downloads a lot of data.<br /><br /> + + + + + Your transactions and funds will be visible again after the download has completed.<br /><br /> + + + + + Do you want to continue?.<br /> + + + Confirm resync Blockchain + + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. @@ -3256,13 +4147,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - R&euse an existing receiving address (not recommended) - R&euse an existing receiving address (not recommended) + Reuse an existing receiving address (not recommended) + Reuse an existing receiving address (not recommended) - &Message: - &Message: + Message: + Message: @@ -3287,8 +4178,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Label: - &Label: + Label: + Label: @@ -3298,13 +4189,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Amount: - &Amount: + Amount: + Amount: - &Request payment - &Request payment + Request payment + Request payment @@ -3366,18 +4257,18 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - Copy &URI - Copy &URI + Copy URI + Copy URI - Copy &Address - Copy &Address + Copy Address + Copy Address - &Save Image... - &Save Image... + Save Image... + Save Image... @@ -3467,9 +4358,9 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations SendCoinsDialog - + - + Send Coins Send Coins @@ -3479,17 +4370,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Coin Control Features - - Inputs... - Inputs... - - - - automatically selected - automatically selected - - - + Insufficient funds! Insufficient funds! @@ -3594,12 +4475,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Minimize - - Obfuscation - - - - + per kilobyte per kilobyte @@ -3624,12 +4500,27 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations (Smart fee not initialized yet. This usually takes a few blocks...) - + + SwiftX + + + + Confirmation time: Confirmation time: - + + Open Coin Control... + + + + + Coins automatically selected + + + + If the custom fee is set to 1000 uBWKs and the transaction is only 250 bytes, then "per kilobyte" only pays 250 uBWKs in fee,<br />while "at least" pays 1000 uBWKs. For transactions bigger than a kilobyte both pay by kilobyte. @@ -3676,8 +4567,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - S&end - S&end + Send + Send @@ -3686,8 +4577,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - Clear &All - Clear &All + Clear All + Clear All @@ -3696,21 +4587,21 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - Add &Recipient - Add &Recipient + Add Recipient + Add Recipient - - SwiftTX - SwiftTX + + Anonymized BWK + - + Balance: Balance: - + Copy quantity Copy quantity @@ -3750,7 +4641,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Copy change - + The split block tool does not work when sending to outside addresses. Try again. @@ -3761,34 +4652,27 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - - + using using - - + anonymous funds anonymous funds - - Warning: Invalid Bulwark address + + Warning: Invalid BWK address - + any available funds (not recommended) any available funds (not recommended) - - and SwiftTX - and SwiftTX - - - + @@ -3816,7 +4700,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Confirm send coins - + A fee %1 times higher than %2 per kB is considered an insanely high fee. A fee %1 times higher than %2 per kB is considered an insanely high fee. @@ -3834,12 +4718,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations The recipient address is not valid, please recheck. - - (obfuscation requires this amount to be rounded up to the nearest %1). + + and SwiftX - + split into %1 outputs using the UTXO splitter. @@ -3849,7 +4733,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations <b>(%1 of %2 entries displayed)</b> - + The amount to pay must be larger than 0. The amount to pay must be larger than 0. @@ -3913,8 +4797,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - Pay &To: - Pay &To: + Pay To: + Pay To: @@ -3950,8 +4834,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Label: - &Label: + Label: + Label: @@ -3962,8 +4846,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - A&mount: - A&mount: + Amount: + Amount: @@ -4025,8 +4909,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - &Sign Message - &Sign Message + Sign Message + Sign Message @@ -4092,8 +4976,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - Sign &Message - Sign &Message + Sign Message + Sign Message @@ -4103,13 +4987,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - Clear &All - Clear &All + Clear All + Clear All - &Verify Message - &Verify Message + Verify Message + Verify Message @@ -4118,8 +5002,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - Verify &Message - Verify &Message + Verify Message + Verify Message @@ -4262,23 +5146,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations conflicted conflicted - - - %1/offline (verified via swifttx) - %1/offline (verified via swifttx) - - %1/confirmed (verified via swifttx) - %1/confirmed (verified via swifttx) - - - - %1 confirmations (verified via swifttx) - %1 confirmations (verified via swifttx) - - - %1/offline %1/offline @@ -4294,29 +5163,44 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations %1 confirmations - - %1/offline (SwiftTX verification in progress - %2 of %3 signatures) - %1/offline (SwiftTX verification in progress - %2 of %3 signatures) + + %1/offline (verified via SwiftX) + + + + + %1/confirmed (verified via SwiftX) + + + + + %1 confirmations (verified via SwiftX) + + + + + %1/offline (SwiftX verification in progress - %2 of %3 signatures) + - %1/confirmed (SwiftTX verification in progress - %2 of %3 signatures ) - %1/confirmed (SwiftTX verification in progress - %2 of %3 signatures ) + %1/confirmed (SwiftX verification in progress - %2 of %3 signatures ) + - %1 confirmations (SwiftTX verification in progress - %2 of %3 signatures) - %1 confirmations (SwiftTX verification in progress - %2 of %3 signatures) + %1 confirmations (SwiftX verification in progress - %2 of %3 signatures) + - %1/offline (SwiftTX verification failed) - %1/offline (SwiftTX verification failed) + %1/offline (SwiftX verification failed) + - %1/confirmed (SwiftTX verification failed) - %1/confirmed (SwiftTX verification failed) + %1/confirmed (SwiftX verification failed) + @@ -4648,12 +5532,42 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Obfuscated - + + Converted BWK to zBWK + + + + + Spent zBWK + + + + + Received BWK from zBWK + + + + + Minted Change as zBWK from zBWK Spend + + + + + Converted zBWK to BWK + + + + watch-only watch-only - + + zBWK Accumulator + + + + (n/a) (n/a) @@ -4786,6 +5700,31 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Masternode Reward + + + Received BWK from zBWK + + + + + Zerocoin Mint + + + + + Zerocoin Spend + + + + + Zerocoin Spend, Change in zBWK + + + + + Zerocoin Spend to Self + + Other @@ -4832,7 +5771,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Show transaction details - + Export Transaction History Export Transaction History @@ -4842,7 +5781,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Comma separated file (*.csv) - + Confirmed Confirmed @@ -4877,7 +5816,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations ID - + Exporting Failed Exporting Failed @@ -4887,7 +5826,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations There was an error trying to save the transaction history to %1. - + Exporting Successful Exporting Successful @@ -4897,7 +5836,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations The transaction history was successfully saved to %1. - + Range: Range: @@ -4926,7 +5865,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations WalletModel - + Send Coins @@ -4935,16 +5874,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - SwiftTX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. + SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. WalletView - - &Export - &Export + + Export + Export @@ -4957,7 +5896,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Selected amount: - + Backup Wallet Backup Wallet @@ -4967,30 +5906,64 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Wallet Data (*.dat) - - Backup Failed - Backup Failed + + Backup Failed + Backup Failed + + + + There was an error trying to save the wallet data to %1. + There was an error trying to save the wallet data to %1. + + + + Backup Successful + Backup Successful + + + + The wallet data was successfully saved to %1. + The wallet data was successfully saved to %1. + + + + ZBwkControlDialog + + + Select zBWK to Spend + + + + + Quantity + + + + + + 0 + - - There was an error trying to save the wallet data to %1. - There was an error trying to save the wallet data to %1. + + zBWK + - - Backup Successful - Backup Successful + + Select/Deselect All + - - The wallet data was successfully saved to %1. - The wallet data was successfully saved to %1. + + Is Spendable + bulwark-core - + (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) @@ -5021,6 +5994,11 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations + Calculated accumulator checkpoint is not what is recorded by block index + + + + Cannot obtain a lock on data directory %s. Bulwark Core is probably already running. @@ -5045,32 +6023,17 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup - - Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftTX, Budgeting) (0-1, default: %u) - - - - + Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. - + Enable spork administration functionality with the appropriate private key. - Enable swifttx, show confirmations for locked transactions (bool, default: %s) - Enable swifttx, show confirmations for locked transactions (bool, default: %s) - - - - Enable use of automated obfuscation for funds stored in this wallet (0-1, default: %u) - - - - Enter regression test mode, which uses a special chain in which blocks can be solved instantly. Enter regression test mode, which uses a special chain in which blocks can be solved instantly. @@ -5080,7 +6043,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Error: Listening for incoming connections failed (listen returned error %s) - + Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. @@ -5121,11 +6084,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - How thorough the block verification of -checkblocks is (0-4, default: %u) - How thorough the block verification of -checkblocks is (0-4, default: %u) - - - If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) @@ -5134,6 +6092,11 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations In this mode -genproclimit controls how many blocks are generated immediately. In this mode -genproclimit controls how many blocks are generated immediately. + + + Insufficient or insufficient confirmed funds, you might need to wait a few minutes and try again. + + Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) @@ -5180,15 +6143,15 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Output debugging information (default: %u, supplying <category> is optional) - - 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) - - - - + Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) + + + Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u) + + Require high priority for relaying free or low-fee transactions (default:%u) @@ -5225,12 +6188,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations - - SwiftTX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. - SwiftTX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. - - - + This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. @@ -5389,11 +6347,21 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Attempt to recover private keys from a corrupt wallet.dat Attempt to recover private keys from a corrupt wallet.dat + + + Automatically create Tor hidden service (default: %d) + + Block creation options: Block creation options: + + + Calculating missing accumulators... + + Can't denominate: no compatible inputs left. @@ -5499,6 +6467,16 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Debugging/Testing options: Debugging/Testing options: + + + Delete blockchain folders and resync from scratch + + + + + Disable OS notifications for incoming transactions (default: %u) + + Disable safemode, override a real safe mode event (default: %u) @@ -5525,7 +6503,22 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Done loading - + + Enable automatic Zerocoin minting (0-1, default: %u) + + + + + Enable publish hash transaction (locked via SwiftX) in <address> + + + + + Enable publish raw transaction (locked via SwiftX) in <address> + + + + Enable the client to act as a masternode (0-1, default: %u) Enable the client to act as a masternode (0-1, default: %u) @@ -5619,16 +6612,31 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Error: You already have pending entries in the Obfuscation pool + + + Failed to calculate accumulator checkpoint + + Failed to listen on any port. Use -listen=0 if you want this. Failed to listen on any port. Use -listen=0 if you want this. + + + Failed to read block index + + Failed to read block Failed to read block + + + Failed to write block index + + Fee (in BWK/kB) to add to transactions you send (default: %s) @@ -5714,6 +6722,11 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Input is not valid. Input is not valid. + + + Insufficient funds + + Insufficient funds. @@ -5721,13 +6734,13 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. - Invalid -onion address: '%s' - Invalid -onion address: '%s' + Invalid -onion address or hostname: '%s' + - Invalid -proxy address: '%s' - Invalid -proxy address: '%s' + Invalid -proxy address or hostname: '%s' + @@ -5759,6 +6772,11 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Invalid amount for -reservebalance=<amount> + + + Invalid amount + + Invalid masternodeprivkey. Please see documenation. @@ -5785,72 +6803,119 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Invalid script detected. - - This is a pre-release test build - use at your own risk - do not use for staking or merchant applications! + + SwiftX options: - - <category> can be: + + This is a pre-release test build - use at your own risk - do not use for staking or merchant applications! - - Attempt to force blockchain corruption recovery + + mints deleted + - - Display the stake modifier calculations in the debug.log file. + + mints updated, - Display verbose coin stake messages in the debug.log file. + unconfirmed transactions removed + + + + + + Disable all Bulwark specific functionality (Masternodes, Zerocoin, SwiftX, Budgeting) (0-1, default: %u) + + + + + Enable SwiftX, show confirmations for locked transactions (bool, default: %s) + + + + + Enable automatic wallet backups triggered after each zBWK minting (0-1, default: %u) + + + + + Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. - Enable publish hash block in <address> + Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! - - Enable publish hash transaction (locked via SwiftTX) in <address> + + Error: Unsupported argument -checklevel found. Checklevel must be level 4. - - Enable publish hash transaction in <address> + + Preferred Denomination for automatically minted Zerocoin (1/5/10/50/100/500/1000/5000), 0 for no preference. default: %u) - - Enable publish raw block in <address> + + SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. - - Enable publish raw transaction (locked via SwiftTX) in <address> + + <category> can be: + + + + + Attempt to force blockchain corruption recovery + + + + + Display the stake modifier calculations in the debug.log file. - Enable publish raw transaction in <address> + Display verbose coin stake messages in the debug.log file. + + + + + Enable publish hash block in <address> + + + + + Enable publish hash transaction in <address> - Enable staking functionality (0-1, default: %u) + Enable publish raw block in <address> - - Keep N BWK anonymized (default: %u) + + Enable publish raw transaction in <address> + Enable staking functionality (0-1, default: %u) + + + + Keep at most <n> unconnectable transactions in memory (default: %u) Keep at most <n> unconnectable transactions in memory (default: %u) @@ -5909,6 +6974,11 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Loading masternode payment cache... Loading masternode payment cache... + + + Loading sporks... + + Loading wallet... (%3.2f %%) @@ -6029,11 +7099,6 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Obfuscation is idle. - - - Obfuscation options: - - Obfuscation request complete: @@ -6064,6 +7129,16 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Password for JSON-RPC connections Password for JSON-RPC connections + + + Percentage of automatically minted Zerocoin (10-100, default: %u) + + + + + Preparing for resync... + + Prepend debug output with timestamp (default: %u) @@ -6104,11 +7179,26 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Rebuild block chain index from current blk000??.dat files Rebuild block chain index from current blk000??.dat files + + + Recalculating coin supply may take 30-60 minutes... + + + + + Recalculating supply statistics may take 30-60 minutes... + + Receive and display P2P network alerts (default: %u) Receive and display P2P network alerts (default: %u) + + + Reindex the accumulator database + + Relay and mine data carrier transactions (default: %u) @@ -6129,6 +7219,16 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Rescanning... Rescanning... + + + ResetMintZerocoin finished: + + + + + ResetSpentZerocoin finished: + + Run a thread to flush wallet periodically (default: %u) @@ -6189,6 +7289,11 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Set minimum block size in bytes (default: %u) Set minimum block size in bytes (default: %u) + + + Set the Maximum reorg depth (default: %u) + + Set the masternode private key @@ -6295,12 +7400,7 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Submitted to masternode, waiting in queue %s - - SwiftTX options: - SwiftTX options: - - - + Synchronization failed Synchronization failed @@ -6359,6 +7459,16 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Threshold for disconnecting misbehaving peers (default: %u) Threshold for disconnecting misbehaving peers (default: %u) + + + Tor control port password (default: empty) + + + + + Tor control port to use if onion listening enabled (default: %s) + + Transaction amount too small @@ -6424,11 +7534,6 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Upgrade wallet to latest format Upgrade wallet to latest format - - - Use N separate masternodes to anonymize funds (2-8, default: %u) - Use N separate masternodes to anonymize funds (2-8, default: %u) - Use OpenSSL (https) for JSON-RPC connections @@ -6444,6 +7549,11 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. Use UPnP to map the listening port (default: 1 when listening) Use UPnP to map the listening port (default: 1 when listening) + + + Use a custom max chain reorganization depth (default: %u) + + Use the test network @@ -6544,6 +7654,16 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo. ZeroMQ notification options: + + + Zerocoin options: + + + + + failed to validate zerocoin + + on startup diff --git a/src/qt/locale/bulwark_en_US.ts b/src/qt/locale/bulwark_en_US.ts index ed2c7cebb..47dc6673e 100644 --- a/src/qt/locale/bulwark_en_US.ts +++ b/src/qt/locale/bulwark_en_US.ts @@ -10,36 +10,36 @@ Create a new address - &New - &New + New + New Copy the currently selected address to the system clipboard Copy the currently selected address to the system clipboard - &Copy - &Copy + Copy + Copy Delete the currently selected address from the list Delete the currently selected address from the list - &Delete - &Delete + Delete + Delete Export the data in the current tab to a file Export the data in the current tab to a file - &Export - &Export + Export + Export - C&lose - C&lose + Close + Close Choose the address to send coins to @@ -50,8 +50,8 @@ Choose the address to receive coins with - C&hoose - C&hoose + Choose + Choose Sending addresses @@ -70,16 +70,16 @@ These are your Bulwark addresses for receiving payments. It is recommended to use a new receiving address for each transaction. - &Copy Address - &Copy Address + Copy Address + Copy Address - Copy &Label - Copy &Label + Copy Label + Copy Label - &Edit - &Edit + Edit + Edit Export Address List @@ -235,8 +235,8 @@ BIP 38 Tool - &BIP 38 Encrypt - &BIP 38 Encrypt + BIP 38 Encrypt + BIP 38 Encrypt Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -283,20 +283,20 @@ Sign the message to prove you own this Bulwark address - Encrypt &Key - Encrypt &Key + Encrypt Key + Encrypt Key Reset all sign message fields Reset all sign message fields - Clear &All - Clear &All + Clear All + Clear All - &BIP 38 Decrypt - &BIP 38 Decrypt + BIP 38 Decrypt + BIP 38 Decrypt Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. @@ -311,8 +311,8 @@ Verify the message to ensure it was signed with the specified Bulwark address - Decrypt &Key - Decrypt &Key + Decrypt Key + Decrypt Key Reset all verify message fields @@ -402,136 +402,136 @@ Node - &Overview - &Overview + Overview + Overview Show general overview of wallet Show general overview of wallet - &Send - &Send + Send + Send - &Receive - &Receive + Receive + Receive - &Transactions - &Transactions + Transactions + Transactions Browse transaction history Browse transaction history - E&xit - E&xit + Exit + Exit Quit application Quit application - About &Qt - About &Qt + About Qt + About Qt Show information about Qt Show information about Qt - &Options... - &Options... + Options... + Options... - &Show / Hide - &Show / Hide + Show / Hide + Show / Hide Show or hide the main Window Show or hide the main Window - &Encrypt Wallet... - &Encrypt Wallet... + Encrypt Wallet... + Encrypt Wallet... Encrypt the private keys that belong to your wallet Encrypt the private keys that belong to your wallet - &Backup Wallet... - &Backup Wallet... + Backup Wallet... + Backup Wallet... Backup wallet to another location Backup wallet to another location - &Change Passphrase... - &Change Passphrase... + Change Passphrase... + Change Passphrase... Change the passphrase used for wallet encryption Change the passphrase used for wallet encryption - &Unlock Wallet... - &Unlock Wallet... + Unlock Wallet... + Unlock Wallet... Unlock wallet Unlock wallet - &Lock Wallet - &Lock Wallet + Lock Wallet + Lock Wallet - Sign &message... - Sign &message... + Sign message... + Sign message... - &Verify message... - &Verify message... + Verify message... + Verify message... - &Information - &Information + Information + Information Show diagnostic information Show diagnostic information - &Debug console - &Debug console + Debug console + Debug console Open debugging console Open debugging console - &Network Monitor - &Network Monitor + Network Monitor + Network Monitor Show network monitor Show network monitor - &Peers list - &Peers list + Peers list + Peers list Show peers info Show peers info - Wallet &Repair - Wallet &Repair + Wallet Repair + Wallet Repair Show wallet repair options @@ -542,36 +542,36 @@ Open configuration file - Show Automatic &Backups - Show Automatic &Backups + Show Automatic Backups + Show Automatic Backups Show automatically created wallet backups Show automatically created wallet backups - &Sending addresses... - &Sending addresses... + Sending addresses... + Sending addresses... Show the list of used sending addresses and labels Show the list of used sending addresses and labels - &Receiving addresses... - &Receiving addresses... + Receiving addresses... + Receiving addresses... Show the list of used receiving addresses and labels Show the list of used receiving addresses and labels - Open &URI... - Open &URI... + Open URI... + Open URI... - &Command-line options - &Command-line options + Command-line options + Command-line options Processed %n blocks of transaction history. @@ -582,20 +582,20 @@ Synchronizing additional data: %p% - &File - &File + File + File - &Settings - &Settings + Settings + Settings - &Tools - &Tools + Tools + Tools - &Help - &Help + Help + Help Tabs toolbar @@ -614,16 +614,16 @@ Request payments (generates QR codes and bulwark: URIs) - &Masternodes - &Masternodes + Masternodes + Masternodes Browse masternodes Browse masternodes - &About Bulwark Core - &About Bulwark Core + About Bulwark Core + About Bulwark Core Show information about Bulwark Core @@ -642,28 +642,28 @@ Verify messages to ensure they were signed with specified Bulwark addresses - &BIP38 tool - &BIP38 tool + BIP38 tool + BIP38 tool Encrypt and decrypt private keys using a passphrase Encrypt and decrypt private keys using a passphrase - &MultiSend - &MultiSend + MultiSend + MultiSend MultiSend Settings MultiSend Settings - Open Wallet &Configuration File - Open Wallet &Configuration File + Open Wallet Configuration File + Open Wallet Configuration File - Open &Masternode Configuration File - Open &Masternode Configuration File + Open Masternode Configuration File + Open Masternode Configuration File Open Masternode configuration file @@ -674,8 +674,8 @@ Open a Bulwark: URI or payment request - &Blockchain explorer - &Blockchain explorer + Blockchain explorer + Blockchain explorer Block explorer window @@ -1106,16 +1106,16 @@ Address: %4 Edit Address - &Label - &Label + Label + Label The label associated with this address list entry The label associated with this address list entry - &Address - &Address + Address + Address The address associated with this address list entry. This can only be modified for sending addresses. @@ -1322,20 +1322,20 @@ Address: %4 Pubkey - S&tart alias - S&tart alias + Start alias + Start alias - Start &all - Start &all + Start all + Start all - Start &MISSING - Start &MISSING + Start MISSING + Start MISSING - &Update status - &Update status + Update status + Update status Status will be updated automatically in (sec): @@ -1618,28 +1618,28 @@ Please check the address and try again. Options - &Main - &Main + Main + Main - Size of &database cache - Size of &database cache + Size of database cache + Size of database cache MB MB - Number of script &verification threads - Number of script &verification threads + Number of script verification threads + Number of script verification threads (0 = auto, <0 = leave that many cores free) (0 = auto, <0 = leave that many cores free) - W&allet - W&allet + Wallet + Wallet If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. @@ -1658,8 +1658,8 @@ Please check the address and try again. Allow incoming connections - &Connect through SOCKS5 proxy (default proxy): - &Connect through SOCKS5 proxy (default proxy): + Connect through SOCKS5 proxy (default proxy): + Connect through SOCKS5 proxy (default proxy): Expert @@ -1670,8 +1670,8 @@ Please check the address and try again. Automatically start Bulwark after logging in to the system. - &Start Bulwark on system login - &Start Bulwark on system login + Start Bulwark on system login + Start Bulwark on system login This setting determines the amount of individual masternodes that an input will be anonymized through.<br/>More rounds of anonymization gives a higher degree of privacy, but also costs more in fees. @@ -1694,8 +1694,8 @@ Please check the address and try again. Whether to show coin control features or not. - Enable coin &control features - Enable coin &control features + Enable coin control features + Enable coin control features Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. @@ -1706,12 +1706,12 @@ Please check the address and try again. Show Masternodes Tab - &Spend unconfirmed change - &Spend unconfirmed change + Spend unconfirmed change + Spend unconfirmed change - &Network - &Network + Network + Network The user interface language can be set here. This setting will take effect after restarting Bulwark. @@ -1724,64 +1724,64 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations https://www.transifex.com/bulwark-project/bulwark-project-translations - Map port using &UPnP - Map port using &UPnP + Map port using UPnP + Map port using UPnP Connect to the Bulwark network through a SOCKS5 proxy. Connect to the Bulwark network through a SOCKS5 proxy. - Proxy &IP: - Proxy &IP: + Proxy IP: + Proxy IP: IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) - &Port: - &Port: + Port: + Port: Port of the proxy (e.g. 9050) Port of the proxy (e.g. 9050) - &Window - &Window + Window + Window Show only a tray icon after minimizing the window. Show only a tray icon after minimizing the window. - &Minimize to the tray instead of the taskbar - &Minimize to the tray instead of the taskbar + Minimize to the tray instead of the taskbar + Minimize to the tray instead of the taskbar Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. - M&inimize on close - M&inimize on close + Minimize on close + Minimize on close - &Display - &Display + Display + Display - User Interface &language: - User Interface &language: + User Interface language: + User Interface language: User Interface Theme: User Interface Theme: - &Unit to show amounts in: - &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. @@ -1808,16 +1808,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsReset all client options to default. - &Reset Options - &Reset Options + Reset Options + Reset Options - &OK - &OK + OK + OK - &Cancel - &Cancel + Cancel + Cancel default @@ -2225,12 +2225,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations QRImageWidget - &Save Image... - &Save Image... + Save Image... + Save Image... - &Copy Image - &Copy Image + Copy Image + Copy Image Save QR Code @@ -2248,8 +2248,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsTools window - &Information - &Information + Information + Information General @@ -2272,8 +2272,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsNumber of connections - &Open - &Open + Open + Open Startup time @@ -2324,20 +2324,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsNumber of Masternodes - &Console - &Console + Console + Console Clear console Clear console - &Network Traffic - &Network Traffic + Network Traffic + Network Traffic - &Clear - &Clear + Clear + Clear Totals @@ -2352,8 +2352,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSent - &Peers - &Peers + Peers + Peers Select a peer to view detailed information. @@ -2412,8 +2412,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsPing Time - &Wallet Repair - &Wallet Repair + Wallet Repair + Wallet Repair Wallet In Use: @@ -2543,12 +2543,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsReuse 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. - R&euse an existing receiving address (not recommended) - R&euse an existing receiving address (not recommended) + Reuse an existing receiving address (not recommended) + Reuse an existing receiving address (not recommended) - &Message: - &Message: + Message: + Message: An optional label to associate with the new receiving address. @@ -2567,20 +2567,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsUse this form to request payments. All fields are <b>optional</b>. - &Label: - &Label: + Label: + Label: An optional amount to request. Leave this empty or zero to not request a specific amount. An optional amount to request. Leave this empty or zero to not request a specific amount. - &Amount: - &Amount: + Amount: + Amount: - &Request payment - &Request payment + Request payment + Request payment Clear all fields of the form. @@ -2630,16 +2630,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsQR Code - Copy &URI - Copy &URI + Copy URI + Copy URI - Copy &Address - Copy &Address + Copy Address + Copy Address - &Save Image... - &Save Image... + Save Image... + Save Image... Request payment to %1 @@ -2876,28 +2876,28 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsConfirm the send action - S&end - S&end + Send + Send Clear all fields of the form. Clear all fields of the form. - Clear &All - Clear &All + Clear All + Clear All Send to multiple recipients at once Send to multiple recipients at once - Add &Recipient - Add &Recipient + Add Recipient + Add Recipient - SwiftTX - SwiftTX + SwiftX + SwiftX Balance: @@ -2960,8 +2960,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsany available funds (not recommended) - and SwiftTX - and SwiftTX + and SwiftX + and SwiftX %1 to %2 @@ -3055,8 +3055,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsThis is a normal payment. - Pay &To: - Pay &To: + Pay To: + Pay To: The Bulwark address to send the payment to @@ -3083,16 +3083,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsRemove this entry - &Label: - &Label: + Label: + Label: Enter a label for this address to add it to the list of used addresses Enter a label for this address to add it to the list of used addresses - A&mount: - A&mount: + Amount: + Amount: Message: @@ -3141,8 +3141,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSignatures - Sign / Verify a Message - &Sign Message - &Sign Message + Sign Message + Sign Message You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. @@ -3193,28 +3193,28 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsVerify the message to ensure it was signed with the specified Bulwark address - Sign &Message - Sign &Message + Sign Message + Sign Message Reset all sign message fields Reset all sign message fields - Clear &All - Clear &All + Clear All + Clear All - &Verify Message - &Verify Message + Verify Message + Verify Message Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. - Verify &Message - Verify &Message + Verify Message + Verify Message Reset all verify message fields @@ -3322,16 +3322,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsconflicted - %1/offline (verified via swifttx) - %1/offline (verified via swifttx) + %1/offline (verified via SwiftX) + %1/offline (verified via SwiftX) - %1/confirmed (verified via swifttx) - %1/confirmed (verified via swifttx) + %1/confirmed (verified via SwiftX) + %1/confirmed (verified via SwiftX) - %1 confirmations (verified via swifttx) - %1 confirmations (verified via swifttx) + %1 confirmations (verified via SwiftX) + %1 confirmations (verified via SwiftX) %1/offline @@ -3346,24 +3346,24 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations%1 confirmations - %1/offline (SwiftTX verification in progress - %2 of %3 signatures) - %1/offline (SwiftTX verification in progress - %2 of %3 signatures) + %1/offline (SwiftX verification in progress - %2 of %3 signatures) + %1/offline (SwiftX verification in progress - %2 of %3 signatures) - %1/confirmed (SwiftTX verification in progress - %2 of %3 signatures ) - %1/confirmed (SwiftTX verification in progress - %2 of %3 signatures ) + %1/confirmed (SwiftX verification in progress - %2 of %3 signatures ) + %1/confirmed (SwiftX verification in progress - %2 of %3 signatures ) - %1 confirmations (SwiftTX verification in progress - %2 of %3 signatures) - %1 confirmations (SwiftTX verification in progress - %2 of %3 signatures) + %1 confirmations (SwiftX verification in progress - %2 of %3 signatures) + %1 confirmations (SwiftX verification in progress - %2 of %3 signatures) - %1/offline (SwiftTX verification failed) - %1/offline (SwiftTX verification failed) + %1/offline (SwiftX verification failed) + %1/offline (SwiftX verification failed) - %1/confirmed (SwiftTX verification failed) - %1/confirmed (SwiftTX verification failed) + %1/confirmed (SwiftX verification failed) + %1/confirmed (SwiftX verification failed) Status @@ -3840,15 +3840,15 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSend Coins - SwiftTX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. - SwiftTX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. + SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. + SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. WalletView - &Export - &Export + Export + Export Export the data in the current tab to a file @@ -3930,8 +3930,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsDelete all wallet transactions and only recover those parts of the blockchain through -rescan on startup - Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftTX, Budgeting) (0-1, default: %u) - Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftTX, Budgeting) (0-1, default: %u) + Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftX, Budgeting) (0-1, default: %u) + Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftX, Budgeting) (0-1, default: %u) Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. @@ -3942,8 +3942,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsEnable spork administration functionality with the appropriate private key. - Enable swifttx, show confirmations for locked transactions (bool, default: %s) - Enable swifttx, show confirmations for locked transactions (bool, default: %s) + Enable SwiftX, show confirmations for locked transactions (bool, default: %s) + Enable SwiftX, show confirmations for locked transactions (bool, default: %s) Enable use of automated obfuscation for funds stored in this wallet (0-1, default: %u) @@ -4074,8 +4074,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSupport filtering of blocks and transaction with bloom filters (default: %u) - SwiftTX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. - SwiftTX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. + SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. + SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. @@ -4558,8 +4558,8 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo.com Enable publish hash block in <address> - Enable publish hash transaction (locked via SwiftTX) in <address> - Enable publish hash transaction (locked via SwiftTX) in <address> + Enable publish hash transaction (locked via SwiftX) in <address> + Enable publish hash transaction (locked via SwiftX) in <address> Enable publish hash transaction in <address> @@ -4570,8 +4570,8 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo.com Enable publish raw block in <address> - Enable publish raw transaction (locked via SwiftTX) in <address> - Enable publish raw transaction (locked via SwiftTX) in <address> + Enable publish raw transaction (locked via SwiftX) in <address> + Enable publish raw transaction (locked via SwiftX) in <address> Enable publish raw transaction in <address> @@ -4942,8 +4942,8 @@ for example: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo.com Submitted to masternode, waiting in queue %s - SwiftTX options: - SwiftTX options: + SwiftX options: + SwiftX options: Synchronization failed diff --git a/src/qt/locale/bulwark_es.ts b/src/qt/locale/bulwark_es.ts index 75720d222..76fb4363a 100644 --- a/src/qt/locale/bulwark_es.ts +++ b/src/qt/locale/bulwark_es.ts @@ -3,30 +3,30 @@ AddressBookPage Right-click to edit address or label - Click derecho para editar la dirección o etiqueta + Click derecho para editar dirección o etiqueta Create a new address - Crear una nueva dirección + Crear nueva dirección - &New - &Nuevo + New + Nuevo Copy the currently selected address to the system clipboard Copiar la dirección seleccionada al portapapeles - &Copy - &Copiar + Copy + Copiar Delete the currently selected address from the list Borrar la dirección seleccionada de la lista - &Delete + Delete Borrar @@ -34,11 +34,11 @@ Exportar los datos de la pestaña actual a un archivo - &Export - &Exportar + Export + Exportar - C&lose + Close Cerrar @@ -50,35 +50,35 @@ Escoja la dirección con las cual recibirá las monedas - C&hoose - &Escoger + Choose + Escoger Sending addresses - Enviando direcciones + Direcciones de envío Receiving addresses - Recibiendo direcciones + Direcciones de recepción These are your Bulwark addresses for sending payments. Always check the amount and the receiving address before sending coins. - Estas son sus direcciones Bulwark para realizar pagos. Siempre verifique la cantidad y la dirección de recepción antes de enviar monedas. + Estas son sus direcciones Bulwark para realizar pagos. Verifique siempre la cantidad y la dirección de recepción antes de enviar monedas. These are your Bulwark addresses for receiving payments. It is recommended to use a new receiving address for each transaction. Estas son sus direcciones Bulwark para recibir pagos. Es recomendable usar una nueva dirección de recepción para cada transacción. - &Copy Address + Copy Address Copiar dirección - Copy &Label - Copiar y Etiquetar + Copy Label + Copiar etiqueta - &Edit + Edit Editar @@ -95,7 +95,7 @@ There was an error trying to save the address list to %1. Please try again. - Hubo un error intentando guardar la lista de direcciones %1. Por favor intente nuevamente + Ha habido un error intentando guardar la lista de direcciones %1. Por favor inténtelo de nuevo. @@ -137,7 +137,7 @@ For anonymization and staking only - Para anonimización y staking solamente + Desbloquear solo para anonimización y staking Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. @@ -145,23 +145,23 @@ Encrypt wallet - Encriptar la Wallet + Cifrar monedero This operation needs your wallet passphrase to unlock the wallet. - Esta operación requiere su contraseña para desbloquear la Wallet + Esta operación requiere su contraseña para desbloquear el monedero Unlock wallet - Desbloquear wallet + Desbloquear monedero This operation needs your wallet passphrase to decrypt the wallet. - Esta operación requiere su contraseña para desbloquear la Wallet + Esta operación requiere su contraseña para descifrar el monedero Decrypt wallet - Desencriptar Wallet + Descifrar monedero Change passphrase @@ -169,55 +169,55 @@ Enter the old and new passphrase to the wallet. - Ingrese la antigua y nueva contraseña para la Wallet + Ingrese la antigua y la nueva contraseña para el monedero Confirm wallet encryption - Confirmar la encriptación de la Wallet + Confirme el cifrado del monedero Bulwark will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your BWKs from being stolen by malware infecting your computer. - Bulwark se cerrará ahora para finalizar el proceso de encriptación. Recuerde que encriptar su Wallet no previene completamente que tus BWKs sean robados mediante malware infectando su ordenador. + Bulwark se cerrará para finalizar el proceso de cifrado. Recuerde que cifrar su monedero no garantiza que sus BWKs no sean robados mediante malware de su ordenador. Are you sure you wish to encrypt your wallet? - ¿Esta seguro de que desea encriptar tu Wallet? + ¿Está seguro de que desea cifrar su monedero? Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BWK</b>! - Atención: Si encripta su Wallet y pierde su contraseña, perderá <b> TODOS SUS BWK</b>! + Atención: Si cifra su monedero y pierde su contraseña, perderá <b> TODOS SUS BWK</b>! Wallet encrypted - Wallet encriptada + Monedero cifrado IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. - IMPORTANTE: Cualquier backup anterior que haya realizado de su Wallet debe ser reemplazado por el nuevo archivo de Wallet encriptado. Por razones de seguridad, las copias anteriores de seguridad de la Wallet sin encriptar pasaran a ser obsoletas tan pronto empiece a utilizar la nueva Wallet encriptada. + IMPORTANTE: Cualquier copia de seguridad anterior que haya realizado de su monedero debe ser reemplazada por la nueva copia de seguridad cifrada. Por razones de seguridad, las copias de seguridad anteriores del monedero sin cifrar pasarán a ser obsoletas tan pronto empiece a utilizar el nuevo monedero cifrado. Wallet encryption failed - La encriptación de la Wallet ha fallado + El cifrado del monedero ha fallado Wallet encryption failed due to an internal error. Your wallet was not encrypted. - La encriptación de la wallet ha fallado debido a un error interno. Tu wallet no ha sido encriptada. + El cifrado del monedero ha fallado debido a un error interno. Su monedero no ha sido cifrado. The supplied passphrases do not match. - Las contraseñas suministradas no coinciden. + Las contraseñas introducidas no coinciden. Wallet unlock failed - Fallo en el desbloqueo de la wallet + Desbloqueo del monedero fallido The passphrase entered for the wallet decryption was incorrect. - La contraseña introducida para la desencriptación de la wallet es incorrecta. + La contraseña introducida para el descifrado del monedero es incorrecta. Wallet decryption failed - Fallo en la desencriptación de la wallet + Descifrado del monedero fallido Wallet passphrase was successfully changed. @@ -225,7 +225,7 @@ Warning: The Caps Lock key is on! - Atención: La tecla Mayúsculas está encendida! + Aviso: La tecla Mayúsculas está encendida! @@ -235,12 +235,12 @@ Herramienta BIP 38 - &BIP 38 Encrypt - &Encriptación BIP 38 + BIP 38 Encrypt + Cifrado BIP 38 Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. - Introduzca la dirección Bulwark que querría encriptar usando BIP 38. Introduzca una contraseña en la caja central. Clickee en encriptar para computar la clave privada encriptada. + Introduzca la dirección Bulwark que querría cifrar usando BIP 38. Introduzca una contraseña en el campo central. Haga clic en cifrar para generar la clave privada cifrada. Address: @@ -248,11 +248,11 @@ The Bulwark address to sign the message with - La dirección Bulwark con la que firmar el mensaje + La dirección Bulwark con la que desee firmar el mensaje Choose previously used address - Escoge una dirección usada previamente + Escoja una dirección usada previamente Alt+A @@ -260,7 +260,7 @@ Paste address from clipboard - Pegar dirección desde el clipboard + Pegar dirección desde el portapapeles Alt+P @@ -272,63 +272,63 @@ Encrypted Key: - Clave Encriptada: + Clave cifrada: Copy the current signature to the system clipboard - Copiar la firma actual al clipboard del sistema + Copiar la firma actual al portapapeles del sistema Sign the message to prove you own this Bulwark address - Firmar el mensaje para demostrar que eres el propietario de esta dirección Bulwark + Firme el mensaje para demostrar que eres el propietario de esta dirección Bulwark - Encrypt &Key - Encriptar & Clave + Encrypt Key + Cifrar Clave Reset all sign message fields - Resetear todos los campos de firma de mensaje + Limpiar todos los campos de firma de mensaje - Clear &All - Limpiar &Todo + Clear All + Limpiar Todo - &BIP 38 Decrypt - &Desencriptación BIP 38 + BIP 38 Decrypt + Descifrado BIP 38 Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. - Introducir la clave encriptada privada BIP 38. Introducir la contraseña en la caja central. Pulsar en Desencriptar Clave para computar la clave privada. Después de que la clave sea desencriptada, pulsando en 'Importar Dirección' añadirá esta clave privada a la wallet. + Introduzca la clave cifrada privada BIP 38. Introduzca la contraseña en el campo central. Haga clic en descifrar clave para generar la clave privada. Después de que la clave sea descifrada, pulsando en 'Importar dirección' añadirá esta clave privada al monedero. The Bulwark address the message was signed with - La dirección Bulwark con la que el mensaje fue firmado + La dirección Bulwark con la que se firmó el mensaje Verify the message to ensure it was signed with the specified Bulwark address - Verificar el mensaje para asegurarse que fue firmado con la dirección Bulwark especificada + Verifica el mensaje para asegurar que fue firmado con la dirección Bulwark especificada - Decrypt &Key - Desencriptar & Clave + Decrypt Key + Descifrar Clave Reset all verify message fields - Resetear todos los campos de verificación de mensaje + Limpiar todos los campos de verificación de mensaje Decrypted Key: - Clave desencriptada + Clave descifrada: Import Address - Importar Dirección + Importar dirección Click "Decrypt Key" to compute key - Clickar "Desencriptar Clave" para computar la clave + Haga clic en "Descifrar clave" para generar la clave The entered passphrase is invalid. @@ -344,15 +344,15 @@ Please check the address and try again. - Por favor comprobar la dirección y probar de nuevo. + Por favor compruebe la dirección e inténtelo de nuevo. The entered address does not refer to a key. - La dirección introducido no se refiere a ninguna clave. + La dirección introducida no se refiere a ninguna clave. Wallet unlock was cancelled. - El desbloqueo de la wallet fue cancelado. + El desbloqueo del monedero fue cancelado. Private key for the entered address is not available. @@ -360,23 +360,23 @@ Failed to decrypt. - Fallo en la desencriptación + Falló el descifrado Please check the key and passphrase and try again. - Por favor comprobar la clave y la contraseña y probar de nuevo. + Por favor compruebe la clave y la contraseña e inténtelo de nuevo. Data Not Valid. - Datos No Válidos. + Datos no válidos. Please try again. - Por favor intentar de nuevo. + Por favor inténtelo de nuevo. Please wait while key is imported - Por favor esperar mientras se importa la clave + Por favor espere mientras la clave es importada Key Already Held By Wallet @@ -402,136 +402,136 @@ Nodo - &Overview - &Visión general + Overview + Visión general Show general overview of wallet Mostrar visión general de la wallet - &Send - &Enviar + Send + Enviar - &Receive - &Recibir + Receive + Recibir - &Transactions - &Transacciones + Transactions + Transacciones Browse transaction history Navegar por el historial de transacciones - E&xit - S&alir + Exit + Salir Quit application Cerrar aplicación - About &Qt - Sobre &Qt + About Qt + Sobre Qt Show information about Qt Mostrar información sobre Qt - &Options... - &Opciones... + Options... + Opciones... - &Show / Hide - &Mostrar / Esconder + Show / Hide + Mostrar / Esconder Show or hide the main Window Mostrar o esconder la ventana principal - &Encrypt Wallet... - &Encriptar wallet... + Encrypt Wallet... + Encriptar wallet... Encrypt the private keys that belong to your wallet Encriptar las claves privadas que pertenecen a tu wallet - &Backup Wallet... - &Copia de seguridad de la wallet... + Backup Wallet... + Copia de seguridad de la wallet... Backup wallet to another location Copia de seguridad de la wallet a otra ubicación - &Change Passphrase... - &Cambiar contraseña... + Change Passphrase... + Cambiar contraseña... Change the passphrase used for wallet encryption Cambiar contraseña usada para la encriptación de la wallet - &Unlock Wallet... - &Desbloquear wallet... + Unlock Wallet... + Desbloquear wallet... Unlock wallet - Desbloquear wallet + Desbloquear monedero - &Lock Wallet - &Bloquear Wallet + Lock Wallet + Bloquear Wallet - Sign &message... - Firmar &mensaje.. + Sign message... + Firmar mensaje.. - &Verify message... - &Verificar mensaje... + Verify message... + Verificar mensaje... - &Information - &Información + Information + Información Show diagnostic information Mostrar información de diagnóstico - &Debug console - &Consola de depuración + Debug console + Consola de depuración Open debugging console Abrir consola de depuración - &Network Monitor - &Monitor de red + Network Monitor + Monitor de red Show network monitor Mostrar monitor de red - &Peers list - &Lista de Peers + Peers list + Lista de Peers Show peers info Mostrar información de peers - Wallet &Repair - &Reparación de la wallet + Wallet Repair + Reparación de la wallet Show wallet repair options @@ -542,60 +542,60 @@ Abrir archivo configuración - Show Automatic &Backups - Mostrar &copias de seguridad automatizadas + Show Automatic Backups + Mostrar copias de seguridad automatizadas Show automatically created wallet backups Mostrar las copias de seguridad creadas automáticamente - &Sending addresses... - &Direcciones de envío... + Sending addresses... + Direcciones de envío... Show the list of used sending addresses and labels Mostrar la lista y etiquetas de direcciones de envío usadas - &Receiving addresses... - &Dirección receptora + Receiving addresses... + Dirección receptora Show the list of used receiving addresses and labels Mostrar la lista de las direcciones y etiquetas usadas - Open &URI... - Abrir &URI... + Open URI... + Abrir URI... - &Command-line options - &Opciones de linea de comandos + Command-line options + Opciones de linea de comandos Processed %n blocks of transaction history. - Procesados %n bloque del histórico de transacciones.Procesados %n bloques del histórico de transacciones. + Procesado %n bloque del historial de transacciones.Procesados %n bloques del historial de transacciones. Synchronizing additional data: %p% Sincronizando datos adicionales: %p% - &File - &Archivo + File + Archivo - &Settings - &Ajustes + Settings + Ajustes - &Tools - &Herramientas + Tools + Herramientas - &Help - &Ayuda + Help + Ayuda Tabs toolbar @@ -614,16 +614,24 @@ Solicitud de pago (genera un código QR y URIs) - &Masternodes - Nodos &Maestros + Privacy + Privacidad + + + Privacy Action for zBWK and Obfuscation + Privacidad con zBWK y Ofuscación + + + Masternodes + Nodos Maestros Browse masternodes Explorar nodos maestros - &About Bulwark Core - &Sobre el núcleo de Bulwark + About Bulwark Core + Sobre el núcleo de Bulwark Show information about Bulwark Core @@ -642,28 +650,28 @@ Verificar mensajes para asegurar que están firmados con la dirección Bulwark especificada - &BIP38 tool - &Herramienta BIP38 + BIP38 tool + Herramienta BIP38 Encrypt and decrypt private keys using a passphrase Encriptar y desencriptar las llaves privadas usando una contraseña - &MultiSend - &MultiEnvío + MultiSend + MultiEnvío MultiSend Settings Configuración de MultiEnvío - Open Wallet &Configuration File - Abrir Fichero de &Configuración del Monedero + Open Wallet Configuration File + Abrir Fichero de Configuración del Monedero - Open &Masternode Configuration File - Abrir Fichero de Configuración de Nodos &Maestros + Open Masternode Configuration File + Abrir Fichero de Configuración de Nodos Maestros Open Masternode configuration file @@ -674,8 +682,8 @@ Abrir un Bulwark: URI o solicitud de pago - &Blockchain explorer - Explorador de &Bloques + Blockchain explorer + Explorador de Bloques Block explorer window @@ -713,26 +721,10 @@ Up to date Actualizado - - %n hour(s) - %n hora%n horas - - - %n day(s) - %n día%n días - - - %n week(s) - %n semana%n semanas - %1 and %2 %1 y %2 - - %n year(s) - %n año%n años - %1 behind %1 detrás @@ -824,6 +816,14 @@ MultiEnvío: %1 Blockchain Explorer Explorador de Cadena de Bloques + + Back + Atrás + + + Forward + Adelante + Address / Block / Transaction Dirección / Bloque / Transacción @@ -922,10 +922,6 @@ MultiEnvío: %1 Received with address Recibido con dirección - - DS Rounds - Rondas DS: - Date Fecha @@ -998,10 +994,6 @@ MultiEnvío: %1 Please switch to "List mode" to use this function. Por favor cambie a "Modo de Lista" para utilizar esta función. - - Non-anonymized input selected. <b>Obfuscation will be disabled.</b><br><br>If you still want to use Obfuscation, please deselect all non-nonymized inputs first and then check Obfuscation checkbox again. - Has seleccionado una entrada que no ha sido anonimizada. <b>La Ofuscación será deshabilitada.</b><br><br>Si todavía quiere utilizar la Ofuscación, por favor primero deseleccione todas las entrada no anonimizadas y entonces marque la casilla de Ofuscación de nuevo. - highest la más alta @@ -1022,10 +1014,6 @@ MultiEnvío: %1 Can vary +/- %1 duff(s) per input. Puede variar +/- %1 duff(s) por entrada. - - n/a - n/a - medium media @@ -1106,16 +1094,16 @@ MultiEnvío: %1 Editar Dirección - &Label - &Etiqueta + Label + Etiqueta The label associated with this address list entry La etiqueta asociada con esta entrada de la libreta de direcciones - &Address - &Dirección + Address + Dirección The address associated with this address list entry. This can only be modified for sending addresses. @@ -1322,20 +1310,20 @@ MultiEnvío: %1 Llave pública - S&tart alias - &Iniciar apodo + Start alias + Iniciar apodo - Start &all - Iniciar &todo + Start all + Iniciar todo - Start &MISSING - Iniciar &FALTAN + Start MISSING + Iniciar FALTAN - &Update status - Estado de &Actualización + Update status + Estado de Actualización Status will be updated automatically in (sec): @@ -1618,28 +1606,28 @@ Por favor compruebe la dirección e inténtelo de nuevo. Opciones - &Main - &Principal + Main + Principal - Size of &database cache - Tamaño del caché de &base de datos + Size of database cache + Tamaño del caché de base de datos MB MB - Number of script &verification threads - Número de procesos de &verificación de scripts + Number of script verification threads + Número de procesos de verificación de scripts (0 = auto, <0 = leave that many cores free) (0 = auto, <0 = dejar libres tal número de cores) - W&allet - &Monedero + Wallet + Monedero If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. @@ -1658,8 +1646,8 @@ Por favor compruebe la dirección e inténtelo de nuevo. Permitir conexiones entrantes - &Connect through SOCKS5 proxy (default proxy): - &Conectar a través de un proxy SOCKS5 (proxy por defecto): + Connect through SOCKS5 proxy (default proxy): + Conectar a través de un proxy SOCKS5 (proxy por defecto): Expert @@ -1670,32 +1658,16 @@ Por favor compruebe la dirección e inténtelo de nuevo. Arrancar Bulwark automáticamente después de identificarse en Windows. - &Start Bulwark on system login - &Arrancar Bulwark al inicio del sistema - - - This setting determines the amount of individual masternodes that an input will be anonymized through.<br/>More rounds of anonymization gives a higher degree of privacy, but also costs more in fees. - Esta configuración determina la cantidad máxima de nodos maestros individuales a través de los cuales una entrada se anonimizará.<br/>Más rondas de anonimización ofrecen un mayor grado de privacidad, pero también cuesta más en comisiones. - - - Obfuscation rounds to use - Rondas de Ofuscación a utilizar - - - This amount acts as a threshold to turn off Obfuscation once it's reached. - Esta cantidad actúa como un techo para desactivar la Ofuscación una vez alcanzado. - - - Amount of Bulwark to keep anonymized - Cantidad de Bulwark a mantener anonimizados + Start Bulwark on system login + Arrancar Bulwark al inicio del sistema Whether to show coin control features or not. Mostrar las características de control de monedas individuales, o no - Enable coin &control features - Activar funciones de control de &monedas + Enable coin control features + Activar funciones de control de monedas Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. @@ -1706,12 +1678,12 @@ Por favor compruebe la dirección e inténtelo de nuevo. Mostrar la pestaña de Nodos Maestros - &Spend unconfirmed change - &Gastar cambio no confirmado + Spend unconfirmed change + Gastar cambio no confirmado - &Network - &Red + Network + Red The user interface language can be set here. This setting will take effect after restarting Bulwark. @@ -1724,64 +1696,76 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations https://www.transifex.com/bulwark-project/bulwark-project-translations - Map port using &UPnP - Mapear un puerto utilizando &UPnP + Map port using UPnP + Mapear un puerto utilizando UPnP + + + Percentage of incoming BWK which get automatically converted to zBWK via Zerocoin Protocol + Porcentaje de BWKs entrantes que serán automáticamente convertidos a zBWK a través del Protocolo Zerocoin + + + Percentage of autominted zBWK + Porcentaje de zBWK autogenerados + + + Wait with automatic conversion to Zerocoin until enough BWK for this denomination is available + Retrasar la conversión automática a Zerocoin hasta que hayan suficientes BWK disponibles para esta denominación Connect to the Bulwark network through a SOCKS5 proxy. Conectar a la red Bulwark mediante un proxy SOCKS5. - Proxy &IP: - &IP del proxy: + Proxy IP: + IP del proxy: IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) Dirección IP del proxy (p.e. IPv4: 127.0.0.1 / IPv6: ::1) - &Port: - &Puerto: + Port: + Puerto: Port of the proxy (e.g. 9050) Puerto del proxy (p.e. 9050) - &Window - &Ventana + Window + Ventana Show only a tray icon after minimizing the window. Mostrar sólo un icono en la bandeja al minimizar la ventana. - &Minimize to the tray instead of the taskbar - &Minimizar a la bandeja en lugar de a la barra de tareas + Minimize to the tray instead of the taskbar + Minimizar a la bandeja en lugar de a la barra de tareas Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. Minimizar en lugar de cerrar la aplicación cuando se cierra la ventana. Cuando active esta opción, tendrá que cerrar la aplicación seleccionando Salir desde el menú. - M&inimize on close - M&inimizar al cerrar + Minimize on close + Minimizar al cerrar - &Display - &Mostrar + Display + Mostrar - User Interface &language: - &Idioma de la interface de usuario: + User Interface language: + Idioma de la interface de usuario: User Interface Theme: Tema de la Interface de Usuario: - &Unit to show amounts in: - &Unidad para mostrar cantidades: + Unit to show amounts in: + Unidad para mostrar cantidades: Choose the default subdivision unit to show in the interface and when sending coins. @@ -1808,16 +1792,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsResetear todas las opciones de cliente a su valor por defecto. - &Reset Options - Opciones de &Reset + Reset Options + Opciones de Reset - &OK - &OK + OK + OK - &Cancel - &Cancelar + Cancel + Cancelar + + + I don't care + No me preocupa default @@ -1854,6 +1842,10 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsForm Formulario + + BWK Balances + Balances BWK + Available: Disponible: @@ -1878,10 +1870,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsStaked or masternode rewards that has not yet matured Recompensa de participación o de nodo maestro que aún no ha madurado - - Balances - Balances - The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. La información mostrada puede estar desactualizada. Su monedero se sincroniza automáticamente con la red Bulwark después de establecer una conexión, pero este proceso aún no se ha completado. @@ -1918,157 +1906,14 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSpendable: Disponible: - - Status: - Estado: - - - Obfuscation Balance: - Balance de Ofuscación: - - - 0 BWK / 0 Rounds - 0 BWK / 0 Rondas - - - Enabled/Disabled - Activado/Desactivado - - - Try to manually submit a Obfuscation request. - Intentar enviar manualmente una solicitud de Ofuscación. - - - Reset the current status of Obfuscation (can interrupt Obfuscation if it's in the process of Mixing, which can cost you money!) - Reiniciar el estado actual de Ofuscación (puede interrumpir la Ofuscación si está en el proceso de Mezcla, que puede costarle dinero!) - - - Obfuscation - Ofuscación - - - Completion: - Completado: - - - Amount and Rounds: - Cantidad y Rondas: - - - Submitted Denom: - Denominación Enviada: - - - n/a - n/a - Recent transactions Transacciones recientes - - Start/Stop Mixing - Empezar/Parar Mezcla - - - The denominations you submitted to the Masternode.<br>To mix, other users must submit the exact same denominations. - Las denominaciones que enviaste al Nodo Maestro.<br>Para mezclar, otros usuarios deben enviar exactamente las mismas denominaciones. - - - (Last Message) - (Último Mensaje) - - - Try Mix - Intentar Mezclar - - - Reset - Reiniciar - out of sync desincronizado - - Disabled - Desactivado - - - No inputs detected - No se detectan entradas - - - %n Rounds - %n Ronda%n Rondas - - - Not enough compatible inputs to anonymize <span style='color:red;'>%1</span>,<br>will anonymize <span style='color:red;'>%2</span> instead - No hay suficientes entradas compatibles para anonimizar <span style='color:red;'>%1</span>,<br>anonimizará <span style='color:red;'>%2</span> en su lugar - - - - Overall progress - Progreso total - - - Denominated - Nominadas - - - Anonymized - Anonimizadas - - - Denominated inputs have %5 of %n rounds on average - La entrada denominada tiene %5 de %n rondas de promedioLas entradas seleccionadas tienen %5 de %n rondas de promedio - - - Last Obfuscation message: - - Último mensaje de Ofuscación: - - - - Obfuscation was successfully reset. - La Ofuscación fue reiniciada satisfactoriamente. - - - If you don't want to see internal Obfuscation fees/transactions select "Most Common" as Type on the "Transactions" tab. - Si no quiere ver aquí las operaciones internas de Ofuscación seleccione "Las Más Comunes" como el Tipo en la pestaña de "Transacciones". - - - Obfuscation requires at least %1 to use. - La Ofuscación requiere como mínimo %1 para usarse. - - - Wallet is locked and user declined to unlock. Disabling Obfuscation. - El Monedero está bloqueado y el usuario declinó su desbloqueo. Desactivando Ofuscación. - - - Found enough compatible inputs to anonymize %1 - Se encontraron suficientes entradas compatibles para anonimizar %1 - - - Start Obfuscation - Comenzar Ofuscación - - - Stop Obfuscation - Parar Ofuscación - - - Mixed - Mezcladas - - - Enabled - Activado - - - N/A - N/A - PaymentServer @@ -2176,6 +2021,121 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsIntervalo de Ping + + PrivacyDialog + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + La información mostrada puede estar desactualizada. Su monedero se sincroniza automáticamente con la red Bulwark después de establecer una conexión, pero este proceso aún no se ha completado. + + + 0 + 0 + + + Reset + Reiniciar + + + Quantity: + Cantidad: + + + Amount: + Cantidad: + + + Pay To: + Pagar A: + + + Choose previously used address + Escoja una dirección usada previamente + + + Alt+A + Alt + A + + + Paste address from clipboard + Pegar dirección desde el portapapeles + + + Alt+P + Alt + P + + + Label: + Etiqueta: + + + Enter a label for this address to add it to the list of used addresses + Introduzca una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas + + + Amount: + Cantidad: + + + Priority: + Prioridad: + + + Fee: + Comisión: + + + Dust: + Calderilla: + + + no + no + + + Bytes: + Octetos: + + + Insufficient funds! + ¡Fondos insuficientes! + + + medium + media + + + Coin Control Features + Funciones de Control de Monedas + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + Si esto está activado, pero la dirección de cambio está vacía o es inválida, el cambio será mandado a una nueva dirección generada. + + + Custom change address + Dirección de cambio personalizada + + + Change: + Cambio: + + + out of sync + desincronizado + + + Copy quantity + Copiar cantidad + + + Copy amount + Copiar cantidad + + + Confirm send coins + Confirmar enviar monedas + + QObject @@ -2226,12 +2186,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations QRImageWidget - &Save Image... - &Guardar Imagen... + Save Image... + Guardar Imagen... - &Copy Image - &Copiar Imagen + Copy Image + Copiar Imagen Save QR Code @@ -2249,8 +2209,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsVentana de herramientas - &Information - &Información + Information + Información General @@ -2273,8 +2233,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsNúmero de conexiones - &Open - &Abrir + Open + Abrir Startup time @@ -2325,20 +2285,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsNúmero de Nodos Maestros - &Console - &Consola + Console + Consola Clear console Limpiar consola - &Network Traffic - &Tráfico de Red + Network Traffic + Tráfico de Red - &Clear - &Limpiar + Clear + Limpiar Totals @@ -2353,8 +2313,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsEnviados - &Peers - &Nodos conectados + Peers + Nodos conectados Select a peer to view detailed information. @@ -2413,8 +2373,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsIntervalo de Ping - &Wallet Repair - Reparar &Monedero + Wallet Repair + Reparar Monedero Wallet In Use: @@ -2544,12 +2504,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsReutilizar una de las direcciones de recepción anteriores.<br>Reutilizar direcciones de recepción tiene implicaciones de seguridad y privacidad.<br>No la utilizar al menos que esté re-generando una solicitud de pago anterior. - R&euse an existing receiving address (not recommended) - R&eutilizar una dirección de recepción existente (no recomendado) + Reuse an existing receiving address (not recommended) + Reutilizar una dirección de recepción existente (no recomendado) - &Message: - &Mensaje: + Message: + Mensaje: An optional label to associate with the new receiving address. @@ -2568,20 +2528,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsUse este formulario para solicitar pagos. Todos los campos <b>opcionales</b>. - &Label: - &Etiqueta: + Label: + Etiqueta: An optional amount to request. Leave this empty or zero to not request a specific amount. Una cantidad opcional a solicitar. Deje esto vacío o en cero para no pedir una cantidad específica. - &Amount: - &Cantidad: + Amount: + Cantidad: - &Request payment - &Solicitud de pago + Request payment + Solicitud de pago Clear all fields of the form. @@ -2631,16 +2591,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsCódigo QR - Copy &URI - Copiar &Identificador + Copy URI + Copiar Identificador - Copy &Address - Copiar &Dirección + Copy Address + Copiar Dirección - &Save Image... - &Guardar Imagen... + Save Image... + Guardar Imagen... Request payment to %1 @@ -2720,14 +2680,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsCoin Control Features Funciones de Control de Monedas - - Inputs... - Entradas... - - - automatically selected - seleccionadas automáticamente - Insufficient funds! ¡Fondos insuficientes! @@ -2812,10 +2764,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsMinimize Minimizar - - Obfuscation - Ofuscación - per kilobyte por kilobyte @@ -2877,28 +2825,28 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsConfirmar la acción de enviar - S&end - &Enviar + Send + Enviar Clear all fields of the form. Limpiar todos los campos del formulario. - Clear &All - Limpiar &Todo + Clear All + Limpiar Todo Send to multiple recipients at once Enviar a varios destinatarios al mismo tiempo - Add &Recipient - Añadir Destinata&rio + Add Recipient + Añadir Destinatario - SwiftTX - SwiftTX + SwiftX + SwiftX Balance: @@ -2961,8 +2909,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationscualquier fondo disponible (no recomendado) - and SwiftTX - y SwiftTX + and SwiftX + y SwiftX %1 to %2 @@ -2988,18 +2936,10 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsA fee %1 times higher than %2 per kB is considered an insanely high fee. Una comisión %1 veces más alta que %2 por kB se considera exageradamente alta. - - Estimated to begin confirmation within %n block(s). - Estimamos que empezará la confirmación en %n bloque.Estimamos que empezará la confirmación en %n bloques. - The recipient address is not valid, please recheck. La dirección de destino no es válida, por favor compruébelo de nuevo. - - (obfuscation requires this amount to be rounded up to the nearest %1). - (la ofuscación requiere redondear hacia arriba esta cantidad al %1 más cercano). - split into %1 outputs using the UTXO splitter. separado en %1 salidas usando el separador UTXO. @@ -3056,8 +2996,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsEsto es un pago normal. - Pay &To: - Pagar &A: + Pay To: + Pagar A: The Bulwark address to send the payment to @@ -3065,7 +3005,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Choose previously used address - Escoge una dirección usada previamente + Escoja una dirección usada previamente Alt+A @@ -3073,7 +3013,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Paste address from clipboard - Pegar dirección desde el clipboard + Pegar dirección desde el portapapeles Alt+P @@ -3084,16 +3024,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsQuitar esta entrada - &Label: - &Etiqueta: + Label: + Etiqueta: Enter a label for this address to add it to the list of used addresses Introduzca una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas - A&mount: - Ca&ntidad: + Amount: + Cantidad: Message: @@ -3142,8 +3082,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsFirmas - Firmar / Verificar un Mensaje - &Sign Message - &Firmar Mensaje + Sign Message + Firmar Mensaje You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. @@ -3151,11 +3091,11 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations The Bulwark address to sign the message with - La dirección Bulwark con la que firmar el mensaje + La dirección Bulwark con la que desee firmar el mensaje Choose previously used address - Escoge una dirección usada previamente + Escoja una dirección usada previamente Alt+A @@ -3163,7 +3103,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Paste address from clipboard - Pegar dirección desde el clipboard + Pegar dirección desde el portapapeles Alt+P @@ -3179,47 +3119,47 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Copy the current signature to the system clipboard - Copiar la firma actual al clipboard del sistema + Copiar la firma actual al portapapeles del sistema Sign the message to prove you own this Bulwark address - Firmar el mensaje para demostrar que eres el propietario de esta dirección Bulwark + Firme el mensaje para demostrar que eres el propietario de esta dirección Bulwark The Bulwark address the message was signed with - La dirección Bulwark con la que el mensaje fue firmado + La dirección Bulwark con la que se firmó el mensaje Verify the message to ensure it was signed with the specified Bulwark address - Verificar el mensaje para asegurarse que fue firmado con la dirección Bulwark especificada + Verifica el mensaje para asegurar que fue firmado con la dirección Bulwark especificada - Sign &Message - Firmar &Mensaje + Sign Message + Firmar Mensaje Reset all sign message fields - Resetear todos los campos de firma de mensaje + Limpiar todos los campos de firma de mensaje - Clear &All - Limpiar &Todo + Clear All + Limpiar Todo - &Verify Message - &Verificar Mensaje + Verify Message + Verificar Mensaje Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Introduzca la dirección de firma, mensaje (asegúrese de que copia los puntos y aparte, espacios, tabuladores, etc. exactamente) y la firma debajo para verificar el mensaje. Vaya con cuidado de no leer más en la firma de loque está en el mensaje firmado propiamente dicho, para evitar ser engañado por un ataque "hombre en el medio". - Verify &Message - Verificar &Mensaje + Verify Message + Verificar Mensaje Reset all verify message fields - Resetear todos los campos de verificación de mensaje + Limpiar todos los campos de verificación de mensaje Click "Sign Message" to generate signature @@ -3231,15 +3171,15 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Please check the address and try again. - Por favor comprobar la dirección y probar de nuevo. + Por favor compruebe la dirección e inténtelo de nuevo. The entered address does not refer to a key. - La dirección introducido no se refiere a ninguna clave. + La dirección introducida no se refiere a ninguna clave. Wallet unlock was cancelled. - El desbloqueo de la wallet fue cancelado. + El desbloqueo del monedero fue cancelado. Private key for the entered address is not available. @@ -3310,10 +3250,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations TransactionDesc - - Open for %n more block(s) - Abierto para %n bloque másAbierto para %n bloques más - Open until %1 Abierto hasta %1 @@ -3323,16 +3259,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsconflictivo (bloque huérfano?) - %1/offline (verified via swifttx) - %1/offline (verificado via swifttx) + %1/offline (verified via SwiftX) + %1/offline (verificado via SwiftX) - %1/confirmed (verified via swifttx) - %1/confirmado (verificado via swifttx) + %1/confirmed (verified via SwiftX) + %1/confirmado (verificado via SwiftX) - %1 confirmations (verified via swifttx) - %1 confirmaciones (verificado via swifttx) + %1 confirmations (verified via SwiftX) + %1 confirmaciones (verificado via SwiftX) %1/offline @@ -3347,24 +3283,24 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations%1 confirmaciones - %1/offline (SwiftTX verification in progress - %2 of %3 signatures) - %1/offline (verificación SwiftTX en marcha - %2 de %3 firmas) + %1/offline (SwiftX verification in progress - %2 of %3 signatures) + %1/offline (verificación SwiftX en marcha - %2 de %3 firmas) - %1/confirmed (SwiftTX verification in progress - %2 of %3 signatures ) - %1/confirmado (verificación SwiftTX en marcha - %2 de %3 firmas) + %1/confirmed (SwiftX verification in progress - %2 of %3 signatures ) + %1/confirmado (verificación SwiftX en marcha - %2 de %3 firmas) - %1 confirmations (SwiftTX verification in progress - %2 of %3 signatures) - %1 confirmaciones (verificación SwiftTX en marcha - %2 de %3 firmas) + %1 confirmations (SwiftX verification in progress - %2 of %3 signatures) + %1 confirmaciones (verificación SwiftX en marcha - %2 de %3 firmas) - %1/offline (SwiftTX verification failed) - %1/offline (falló la verificación SwiftTX) + %1/offline (SwiftX verification failed) + %1/offline (falló la verificación SwiftX) - %1/confirmed (SwiftTX verification failed) - %1/confirmado (falló la verificación SwiftTX) + %1/confirmed (SwiftX verification failed) + %1/confirmado (falló la verificación SwiftX) Status @@ -3374,10 +3310,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations, has not been successfully broadcast yet , no ha sido correctamente transmitida todavía - - , broadcast through %n node(s) - , retransmitido a través de %n nodo, retransmitido a través de %n nodos - Date Fecha @@ -3418,10 +3350,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsCredit Crédito - - matures in %n more block(s) - madura en %n bloque másmadura en %n bloques más - not accepted rechazado @@ -3520,10 +3448,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsAddress Dirección - - Open for %n more block(s) - Abierto para %n bloque másAbierto para %n bloques más - Open until %1 Abierto hasta %1 @@ -3841,15 +3765,15 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsEnviar Monedas - SwiftTX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. - SwiftTX no soporta el envío de importes tan altos todavía. Las transacciones están actualmente limitadas a %1 BWK. + SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. + SwiftX no soporta el envío de importes tan altos todavía. Las transacciones están actualmente limitadas a %1 BWK. WalletView - &Export - &Exportar + Export + Exportar Export the data in the current tab to a file @@ -3884,6 +3808,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsLos datos del monedero se guardaron correctamente a %1. + + ZBwkControlDialog + + 0 + 0 + + bulwark-core @@ -3931,8 +3862,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsBorrar todas las transacciones del monedero y solo recuperar partes de la cadena de bloque a traves de -rescan al inicio. - Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftTX, Budgeting) (0-1, default: %u) - Desabilitar toda la funcionalidad especifica Bulwark (Masternodes, Obfuscation, SwiftTX, Budgeting) (0-1, predeterminado: %u) + Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftX, Budgeting) (0-1, default: %u) + Desabilitar toda la funcionalidad especifica Bulwark (Masternodes, Obfuscation, SwiftX, Budgeting) (0-1, predeterminado: %u) Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. @@ -3943,12 +3874,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsActivar la función de administración de sporks con la llave privada apropiada. - Enable swifttx, show confirmations for locked transactions (bool, default: %s) - Activar swifttx, mostrar confirmaciones para transacciones bloqueadas (bool, predeterminado: %s) - - - Enable use of automated obfuscation for funds stored in this wallet (0-1, default: %u) - Activar el uso de ofuscación automatica para fondos guardados en este monedero (0-1, predeterminado: %u) + Enable SwiftX, show confirmations for locked transactions (bool, default: %s) + Activar SwiftX, mostrar confirmaciones para transacciones bloqueadas (bool, predeterminado: %s) Enter regression test mode, which uses a special chain in which blocks can be solved instantly. @@ -4038,10 +3965,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsOutput debugging information (default: %u, supplying <category> is optional) Saluda de información de depuración (predeterminado: %u, proveyendo <category> es opcional) - - 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) - Proporcionar liquidez a la Ofuscación mezclando infrecuentemente las monedas continuamente (0-100, predeterminado: %u, 1=muy frecuente, altas comisiones, 100=muy infrecuente, bajas comisiones) - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) Consultar por direcciones de pares vía búsqueda en DNS, si cantidad de direcciones esta bajo (predeterminado: 1 a menos que se utilice -connect) @@ -4075,8 +3998,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSoportar filtrado de bloques y transacciones con filtros bloom (por defecto: %u) - SwiftTX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. - SwiftTX requiere entradas con hasta 6 confirmaciones, es posible que debas esperar unos minutos e intentar nuevamente. + SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. + SwiftX requiere entradas con hasta 6 confirmaciones, es posible que debas esperar unos minutos e intentar nuevamente. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. @@ -4559,8 +4482,8 @@ por ejemplo: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo.com Activar inclusión del hash del bloque en <address> - Enable publish hash transaction (locked via SwiftTX) in <address> - Activar inclusión del hash de la transacción (fijada mediante SwiftTX) en <address> + Enable publish hash transaction (locked via SwiftX) in <address> + Activar inclusión del hash de la transacción (fijada mediante SwiftX) en <address> Enable publish hash transaction in <address> @@ -4571,8 +4494,8 @@ por ejemplo: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo.com Activar inclusión del bloque en bruto en <address> - Enable publish raw transaction (locked via SwiftTX) in <address> - Activar inclusión de la transacción en bruto (fijada mediante SwiftTX) en <address> + Enable publish raw transaction (locked via SwiftX) in <address> + Activar inclusión de la transacción en bruto (fijada mediante SwiftX) en <address> Enable publish raw transaction in <address> @@ -4582,10 +4505,6 @@ por ejemplo: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo.com Enable staking functionality (0-1, default: %u) Activar funcionalidad de recompensa por participación (0-1, por defecto: %u) - - Keep N BWK anonymized (default: %u) - Mantener N BWK anonimizados (predeterminado: %u) - Keep at most <n> unconnectable transactions in memory (default: %u) Mantener como máximo <n> transacciones no conectables en memoria (predeterminado: %u) @@ -4730,10 +4649,6 @@ por ejemplo: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo.com Obfuscation is idle. La Ofuscación está sin uso. - - Obfuscation options: - Opciones de Ofuscacion: - Obfuscation request complete: Pedido de Ofuscacion completado: @@ -4943,8 +4858,8 @@ por ejemplo: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo.com Enviado a masternode, quedando en espera %s - SwiftTX options: - Opciones SwiftTX: + SwiftX options: + Opciones SwiftX: Synchronization failed @@ -5046,10 +4961,6 @@ por ejemplo: alertnotify=echo %%s | mail -s "Bulwark Alert" admin@foo.com Upgrade wallet to latest format Actualizar el monedero al formato ultimo - - Use N separate masternodes to anonymize funds (2-8, default: %u) - Utilizar N nodos maestros distintos para anonimizar fondos (2-8, predeterminado: %u) - Use OpenSSL (https) for JSON-RPC connections Usar OpenSSL (https) para conexiones JSON-RPC diff --git a/src/qt/locale/bulwark_fi.ts b/src/qt/locale/bulwark_fi.ts index e75ca825c..30f67e398 100644 --- a/src/qt/locale/bulwark_fi.ts +++ b/src/qt/locale/bulwark_fi.ts @@ -10,36 +10,36 @@ Luo uusi osoite - &New - &Uusi + New + Uusi Copy the currently selected address to the system clipboard Kopioi valittu osoite leikepöydälle - &Copy - &Kopioi + Copy + Kopioi Delete the currently selected address from the list Poista valittu osoite listalta - &Delete - &Poista + Delete + Poista Export the data in the current tab to a file Vie tiedot nykyisestä välilehdestä tiedostoon - &Export - &Vie + Export + Vie - C&lose - Su&lje + Close + Sulje Choose the address to send coins to @@ -50,8 +50,8 @@ Valitse osoite jolla vastaanottaa kolikot - C&hoose - V&alitse + Choose + Valitse Sending addresses @@ -70,16 +70,16 @@ Nämä ovat sinun Bulwark osoitteesi maksujen vastaanottamista varten. On suositeltavaa käyttää uutta vastaanottavaa osoitetta jokaiselle uudelle rahansiirrolle. - &Copy Address - &Kopioi osoite + Copy Address + Kopioi osoite - Copy &Label - Kopioi &Nimike + Copy Label + Kopioi Nimike - &Edit - &Muokkaa + Edit + Muokkaa Export Address List @@ -231,8 +231,8 @@ BIP 38 työkalu - &BIP 38 Encrypt - &BIP 38 Salaus + BIP 38 Encrypt + BIP 38 Salaus Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -280,20 +280,20 @@ Syötä salausavain laatikon keskelle. Paina salaa tuottaaksesi salatun yksityis Allekirjoita viesti todistaaksesi, että omistat tämän Bulwark osoitteen - Encrypt &Key - Salaus &Avain + Encrypt Key + Salaus Avain Reset all sign message fields Tyhjennä kaikki allekirjoita viesti kentät - Clear &All - Tyhjennä &Kaikki + Clear All + Tyhjennä Kaikki - &BIP 38 Decrypt - &BIP 38 salauksen avaus + BIP 38 Decrypt + BIP 38 salauksen avaus Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. @@ -308,8 +308,8 @@ Syötä salausavain laatikon keskelle. Paina salaa tuottaaksesi salatun yksityis Vahvista että viesti on allekirjoitettu kyseessä olevalla Bulwark osoitteella. - Decrypt &Key - Salauksen avaus &Avain + Decrypt Key + Salauksen avaus Avain Reset all verify message fields @@ -399,136 +399,136 @@ Syötä salausavain laatikon keskelle. Paina salaa tuottaaksesi salatun yksityis Solmu - &Overview - &Yleisnäkymä + Overview + Yleisnäkymä Show general overview of wallet Näytä yleinen näkymä lompakosta - &Send - &Lähetä + Send + Lähetä - &Receive - &Vastaanota + Receive + Vastaanota - &Transactions - &Rahansiirrot + Transactions + Rahansiirrot Browse transaction history Tarkastele rahansiirto historiaa - E&xit - P&oistu + Exit + Poistu Quit application Lopeta ohjelma - About &Qt - Tietoa &Qt + About Qt + Tietoa Qt Show information about Qt Näytä tietoja Qt:stä - &Options... - &Vaihtoehdot... + Options... + Vaihtoehdot... - &Show / Hide - &Näytä / Piilota + Show / Hide + Näytä / Piilota Show or hide the main Window Näytä tai piilota pääikkuna - &Encrypt Wallet... - &Salaa lompakko... + Encrypt Wallet... + Salaa lompakko... Encrypt the private keys that belong to your wallet Salaa yksityisavaimet jotka kuuluvat lompakkoosi - &Backup Wallet... - &Varmuuskopioi lompakko... + Backup Wallet... + Varmuuskopioi lompakko... Backup wallet to another location Varmuuskopioi lompakko toiseen sijaintiin - &Change Passphrase... - &Vaihda salausavain... + Change Passphrase... + Vaihda salausavain... Change the passphrase used for wallet encryption Vaihda salausavain, jota käytetään lompakon salaukseen - &Unlock Wallet... - &Avaa lompakko... + Unlock Wallet... + Avaa lompakko... Unlock wallet Avaa lompakko - &Lock Wallet - &Lukitse lompakko + Lock Wallet + Lukitse lompakko - Sign &message... - Allekirjoita &viesti... + Sign message... + Allekirjoita viesti... - &Verify message... - Vahvista &viesti... + Verify message... + Vahvista viesti... - &Information - &Informaatio + Information + Informaatio Show diagnostic information Näytä diagnostiikka informaatio - &Debug console - &Debug konsoli + Debug console + Debug konsoli Open debugging console Avaa debuggaus konsoli - &Network Monitor - &Verkkoliikenne monitori + Network Monitor + Verkkoliikenne monitori Show network monitor Näytä verkkoliikenne monitori - &Peers list - &Peer lista + Peers list + Peer lista Show peers info Näytä peer info - Wallet &Repair - Lompakko &Korjaa + Wallet Repair + Lompakko Korjaa Show wallet repair options @@ -539,56 +539,56 @@ Syötä salausavain laatikon keskelle. Paina salaa tuottaaksesi salatun yksityis Avaa konfiguraatio tiedosto - Show Automatic &Backups - Näytä automaattiset &Varmuuskopiot + Show Automatic Backups + Näytä automaattiset Varmuuskopiot Show automatically created wallet backups Näytä automaattisesti luodut varmuuskopiot lompakosta - &Sending addresses... - &Lähettävät osoitteet... + Sending addresses... + Lähettävät osoitteet... Show the list of used sending addresses and labels Näytä lista käytettävistä lähettävistä osoitteista ja nimikkeistä - &Receiving addresses... - &Vastaanottavat osoitteet... + Receiving addresses... + Vastaanottavat osoitteet... Show the list of used receiving addresses and labels Näytä lista käytettävistä vastaanottavista osoitteista ja nimikkeistä - Open &URI... - Avaa &URI... + Open URI... + Avaa URI... - &Command-line options - &Komentolinja vaihtoehdot + Command-line options + Komentolinja vaihtoehdot Synchronizing additional data: %p% Synkronisoidaan lisätietoja: %p% - &File - &Tiedosto + File + Tiedosto - &Settings - &Asetukset + Settings + Asetukset - &Tools - &Työkalut + Tools + Työkalut - &Help - &Apua + Help + Apua Bulwark Core @@ -603,16 +603,16 @@ Syötä salausavain laatikon keskelle. Paina salaa tuottaaksesi salatun yksityis Pyydä maksuja (Generoi QR koodeja ja bulwark: URIja) - &Masternodes - &Masternodet + Masternodes + Masternodet Browse masternodes Selaa masternodeja - &About Bulwark Core - Bulwark Core &ytimestä + About Bulwark Core + Bulwark Core ytimestä Show information about Bulwark Core @@ -631,28 +631,28 @@ Syötä salausavain laatikon keskelle. Paina salaa tuottaaksesi salatun yksityis Vahvista viestit varmistaaksesi, että ne allekirjoitettiin tietyllä Bulwark osoiteella. - &BIP38 tool - &BIP38 työkalu + BIP38 tool + BIP38 työkalu Encrypt and decrypt private keys using a passphrase Salaa ja avaa yksityisavainten salaus käyttämällä salasanaa - &MultiSend - &MultiSend + MultiSend + MultiSend MultiSend Settings MultiSend asetukset - Open Wallet &Configuration File - Avaa lompakko &Konfiguraatiotiedosto + Open Wallet Configuration File + Avaa lompakko Konfiguraatiotiedosto - Open &Masternode Configuration File - Avaa &Masternode konfiguraatiotiedosto + Open Masternode Configuration File + Avaa Masternode konfiguraatiotiedosto Open Masternode configuration file @@ -663,8 +663,8 @@ Syötä salausavain laatikon keskelle. Paina salaa tuottaaksesi salatun yksityis Avaa Bulwark: URI tai pyydä maksua - &Blockchain explorer - &Blockchain tutkija + Blockchain explorer + Blockchain tutkija Block explorer window @@ -908,8 +908,8 @@ Syötä salausavain laatikon keskelle. Paina salaa tuottaaksesi salatun yksityis Muokkaa osoitetta - &Address - &Osoite + Address + Osoite New receiving address @@ -988,12 +988,12 @@ Syötä salausavain laatikon keskelle. Paina salaa tuottaaksesi salatun yksityis Aktiivinen - Start &all - Aloita &kaikki + Start all + Aloita kaikki - &Update status - &Päivitä tila + Update status + Päivitä tila 0 @@ -1189,8 +1189,8 @@ Please check the address and try again. MB - W&allet - L&ompakko + Wallet + Lompakko Accept connections from outside @@ -1201,8 +1201,8 @@ Please check the address and try again. Salli sisääntulevat yhteydet - &Connect through SOCKS5 proxy (default proxy): - &Yhdistä SOCKS5 proxyn kautta (default proxy): + Connect through SOCKS5 proxy (default proxy): + Yhdistä SOCKS5 proxyn kautta (default proxy): Expert @@ -1213,28 +1213,68 @@ Please check the address and try again. Automaattisesti käynnistä Bulwark kun kirjaudut sisään. - &Start Bulwark on system login - &Aloita Bulwark järjestelmän kirjautumisessa + Start Bulwark on system login + Aloita Bulwark järjestelmän kirjautumisessa Amount of Bulwark to keep anonymized Bulwark määrä joka pidetään anonymisoituna - Enable coin &control features - Ota käyttöön coin &kontrolli palvelut + Enable coin control features + Ota käyttöön coin kontrolli palvelut + + + Show Masternodes Tab + Näytä Masternode välilehti + + + Spend unconfirmed change + Käytä vahvistamaton vaihtoraha + + + Network + Verkko + + + The user interface language can be set here. This setting will take effect after restarting Bulwark. + Käyttöliittymän kielen voi säätää täällä. Tämä asetus tulee voimaan uudelleenkäynnistettyäsi lompakon. + + + Connect to the Bulwark network through a SOCKS5 proxy. + Yhdistä Bulwark verkkoon SOCKS5 proxyn kautta + + + Proxy IP: + Proxy IP: + + + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) + Proxyn IP osoite (esim. IPv4: 127.0.0.1 / IPv6: ::1) + + + Port: + Portti: + + + Port of the proxy (e.g. 9050) + Proxyn portti (esim. 9050) + + + Enable coin control features + Ota käyttöön coin kontrolli palvelut Show Masternodes Tab Näytä Masternode välilehti - &Spend unconfirmed change - &Käytä vahvistamaton vaihtoraha + Spend unconfirmed change + Käytä vahvistamaton vaihtoraha - &Network - &Verkko + Network + Verkko The user interface language can be set here. This setting will take effect after restarting Bulwark. @@ -1245,56 +1285,56 @@ Please check the address and try again. Yhdistä Bulwark verkkoon SOCKS5 proxyn kautta - Proxy &IP: - Proxy &IP: + Proxy IP: + Proxy IP: IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) Proxyn IP osoite (esim. IPv4: 127.0.0.1 / IPv6: ::1) - &Port: - &Portti: + Port: + Portti: Port of the proxy (e.g. 9050) Proxyn portti (esim. 9050) - &Window - &Ikkuna + Window + Ikkuna Show only a tray icon after minimizing the window. Näytä vain tarjotin ikoni pienennettyäsi ikkunan. - &Minimize to the tray instead of the taskbar - &Pienennä tarjottimelle tehtäväpalkin sijaan + Minimize to the tray instead of the taskbar + Pienennä tarjottimelle tehtäväpalkin sijaan Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. Pienennä ikkuna poistumisen sijaan kun ikkuna suljetaan. Kun tämä vaihtoehto on valittuna, sovellus sulkeutuu vain kun se Lopetetaan valikosta. - M&inimize on close - P&ienennä suljettaessa + Minimize on close + Pienennä suljettaessa - &Display - &Näyttö + Display + Näyttö - User Interface &language: - Käyttöliittymän &kieli: + User Interface language: + Käyttöliittymän kieli: User Interface Theme: Käyttöliittymän teema: - &Unit to show amounts in: - &Yksikkö jossa määrä näytetään: + Unit to show amounts in: + Yksikkö jossa määrä näytetään: Choose the default subdivision unit to show in the interface and when sending coins. @@ -1309,16 +1349,16 @@ Please check the address and try again. Palauta kaikki asetukset oletuksiin - &Reset Options - &Palauta valinnat + Reset Options + Palauta valinnat - &OK - &OK + OK + OK - &Cancel - &Peruuta + Cancel + Peruuta default @@ -1375,10 +1415,6 @@ Please check the address and try again. Staked or masternode rewards that has not yet matured Panostus tai masternodem palkiinnot jotka eivät ole vielä kypsyneet. - - Balances - Saldot - Total: Määrä: @@ -1391,14 +1427,6 @@ Please check the address and try again. Spendable: Käytettävää: - - Status: - Tila: - - - Enabled/Disabled - Päällä/Pois päältä - PaymentServer @@ -1414,6 +1442,89 @@ Please check the address and try again. Ping aika + + PrivacyDialog + + 0 + 0 + + + Quantity: + Määrä: + + + Amount: + Määrä: + + + Choose previously used address + Valitse aikaisemmin käytetty osoite + + + Alt+A + Alt+A + + + Paste address from clipboard + Liitä osoite leikepöydältä + + + Alt+P + Alt+P + + + Label: + Nimike: + + + Enter a label for this address to add it to the list of used addresses + Syötä nimike tälle osoittelle lisätäksesi se käytettävien osoitteiden listaan + + + Amount: + Määrä: + + + Priority: + Tärkeys: + + + Fee: + Taksa: + + + no + ei + + + Bytes: + Tavut: + + + Insufficient funds! + Puutteelliset varat! + + + medium + kohtalainen + + + Change: + Muutos: + + + Copy quantity + Kopioi määrä + + + Copy amount + Kopioi määrä + + + Confirm send coins + Vahvista kolikoiden lähetys + + QObject @@ -1424,12 +1535,12 @@ Please check the address and try again. QRImageWidget - &Save Image... - &Tallenna Kuva... + Save Image... + Tallenna Kuva... - &Copy Image - &Kopioi Kuva + Copy Image + Kopioi Kuva Save QR Code @@ -1443,8 +1554,8 @@ Please check the address and try again. Työkaluikkuna - &Information - &Informaatio + Information + Informaatio General @@ -1459,8 +1570,8 @@ Please check the address and try again. Yhteyksien määrä - &Open - &Avaa + Open + Avaa Startup time @@ -1483,20 +1594,20 @@ Please check the address and try again. Masternodien määrä - &Console - &Konsoli + Console + Konsoli Clear console Tyhjennä konsoli - &Network Traffic - &Verkkoliikenne + Network Traffic + Verkkoliikenne - &Clear - &Tyhjennä + Clear + Tyhjennä Totals @@ -1551,8 +1662,8 @@ Please check the address and try again. Ping aika - &Wallet Repair - &Lompakon korjaus + Wallet Repair + Lompakon korjaus Wallet In Use: @@ -1618,12 +1729,12 @@ Please check the address and try again. Uudelleenkäytä yksi aikaisemmista vastaanottavista osoitteista. <br> Osoitteen uudelleenkäytössä on turvallisuus- ja yksityisyysongelmia.<br> Älä käytä tätä ellet halua uudelleen käyttää vanhaa maksupyyntöä. - R&euse an existing receiving address (not recommended) - U&udelleenkäytä olemassaoleva vastaanottava osoite (Ei suositeltu) + Reuse an existing receiving address (not recommended) + Uudelleenkäytä olemassaoleva vastaanottava osoite (Ei suositeltu) - &Message: - &Viesti: + Message: + Viesti: An optional label to associate with the new receiving address. @@ -1642,20 +1753,20 @@ Please check the address and try again. Käytä tätä lomaketta luodaksesi maksupyyntöjä. Kaikki kentät ovat <b> vaihtoehtoisia</b>. - &Label: - &Nimike: + Label: + Nimike: An optional amount to request. Leave this empty or zero to not request a specific amount. Pyydä vaihtoehtoinen määrä. Jätä tämä tyhjäksi tai 0, jos haluat pyytää ennaltamääräämättömän summan - &Amount: - &Määrä: + Amount: + Määrä: - &Request payment - &Pyydä maksua + Request payment + Pyydä maksua Clear all fields of the form. @@ -1705,16 +1816,16 @@ Please check the address and try again. QR Koodi - Copy &URI - Kopioi &URI + Copy URI + Kopioi URI - Copy &Address - Kopioi &Osoite + Copy Address + Kopioi Osoite - &Save Image... - &Tallenna Kuva... + Save Image... + Tallenna Kuva... Request payment to %1 @@ -1791,8 +1902,16 @@ Please check the address and try again. Lähetä Kolikot - automatically selected - automaattisesti valittu + Insufficient funds! + Puutteelliset varat! + + + Quantity: + Määrä: + + + Bytes: + Tavut: Insufficient funds! @@ -1875,28 +1994,28 @@ Please check the address and try again. Vahvista lähetys - S&end - L&ähetä + Send + Lähetä Clear all fields of the form. Tyhjennä kaikki kentät lomakkeesta - Clear &All - Tyhjennä &Kaikki + Clear All + Tyhjennä Kaikki Send to multiple recipients at once Lähetä useammalle vastaanottajalle kerralla - Add &Recipient - Lisää &Vastaanottaja + Add Recipient + Lisää Vastaanottaja - SwiftTX - SwiftTX + SwiftX + SwiftX Balance: @@ -1990,16 +2109,16 @@ Please check the address and try again. Poista tämä merkintä - &Label: - &Nimike: + Label: + Nimike: Enter a label for this address to add it to the list of used addresses Syötä nimike tälle osoittelle lisätäksesi se käytettävien osoitteiden listaan - A&mount: - M&äärä: + Amount: + Määrä: Message: @@ -2020,8 +2139,8 @@ Please check the address and try again. SignVerifyMessageDialog - &Sign Message - &Allekirjoita viesti + Sign Message + Allekirjoita viesti You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. @@ -2072,24 +2191,32 @@ Please check the address and try again. Vahvista että viesti on allekirjoitettu kyseessä olevalla Bulwark osoitteella. - Sign &Message - Allekirjoita &Viesti + Sign Message + Allekirjoita Viesti + + + Verify the message to ensure it was signed with the specified Bulwark address + Vahvista että viesti on allekirjoitettu kyseessä olevalla Bulwark osoitteella. + + + Sign Message + Allekirjoita Viesti Reset all sign message fields Tyhjennä kaikki allekirjoita viesti kentät - Clear &All - Tyhjennä &Kaikki + Clear All + Tyhjennä Kaikki - &Verify Message - &Vahvista Viesti + Verify Message + Vahvista Viesti - Verify &Message - Vahvista &Viesti + Verify Message + Vahvista Viesti Reset all verify message fields @@ -2442,8 +2569,8 @@ Please check the address and try again. WalletView - &Export - &Vie + Export + Vie Export the data in the current tab to a file @@ -2470,6 +2597,13 @@ Please check the address and try again. Varmuuskopiointi onnistui + + ZBwkControlDialog + + 0 + 0 + + bulwark-core @@ -2528,6 +2662,62 @@ Please check the address and try again. Error reading from database, shutting down. Virhe lukiessa tietokantaa, sammutetaan. + + Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. + Varoitus: Verkko ei näytä olevan samaa mieltä! Jotkin mainaajat saattavat kokea ongelmia. + + + Warning: error reading wallet.dat! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Varoitus: virhe yrittäessä lukea wallet.dat tiedostoa! Kaikki avaimet luettu onnistuneesti, mutta rahansiirto- tai yhteystietokirjat saattavat puuttua tai olla virheellisiä. + + + Connect through SOCKS5 proxy + Yhdistä SOCKS5 proxyn kautta + + + Connection options: + Yhteys vaihtoehdot: + + + Corrupted block database detected + Korruptoitunut lohko tietokannassa havaittu + + + Do you want to rebuild the block database now? + Haluatko rakentaa uudelleen lohkotietokannan? + + + Done loading + Lataus valmis + + + Error connecting to Masternode. + Virhe Masternodeen yhdistyksessä + + + Error initializing block database + Virhe aloittaessa lohko tietokantaa + + + Error loading block database + Virhe ladattaessa lohko tietokantaa + + + Error loading wallet.dat + Virhe ladattaessa wallet.dat tiedostoa + + + Error loading wallet.dat: Wallet corrupted + Virhe ladattaessa wallet.dat tiedostoa: Lompakko korruptoitunut + + + Error loading wallet.dat: Wallet requires newer version of Bulwark Core + Virhe ladattaessa wallet.dat tiedostoa: Lompakko vaatii uudemman version Bulwark Coresta + + + Error reading from database, shutting down. + Virhe lukiessa tietokantaa, sammutetaan. + Error Virhe diff --git a/src/qt/locale/bulwark_fr_FR.ts b/src/qt/locale/bulwark_fr_FR.ts index 9859cd11a..e12676c12 100644 --- a/src/qt/locale/bulwark_fr_FR.ts +++ b/src/qt/locale/bulwark_fr_FR.ts @@ -10,7 +10,7 @@ Créer une nouvelle adresse - &New + New Nouveau @@ -18,7 +18,7 @@ Copier l'adresse actuelle dans le presse-papier - &Copy + Copy Copier @@ -26,7 +26,7 @@ Supprimer l'adresse actuellement séléctionnée de la liste - &Delete + Delete Supprimer @@ -34,11 +34,11 @@ Exporter l - &Export + Export Exporter - C&lose + Close Fermer @@ -50,7 +50,7 @@ Choisir l'adresse avec laquelle recevoir des pièces - C&hoose + Choose Choisir @@ -62,15 +62,15 @@ Adresses de reception - &Copy Address + Copy Address Copier l'adresse - Copy &Label + Copy Label Copier le label - &Edit + Edit Modifier @@ -207,7 +207,7 @@ BIP 38 outils - &BIP 38 Encrypt + BIP 38 Encrypt BIP 38 crypter @@ -255,7 +255,7 @@ Signer le message pour prouver que vous possédez cette adresse Bulwark - Encrypt &Key + Encrypt Key Clé de cryptage @@ -263,11 +263,11 @@ Réinitialiser tous les champs de messages signés - Clear &All + Clear All Tout effacer - &BIP 38 Decrypt + BIP 38 Decrypt BIP 38 Décrypter @@ -279,7 +279,7 @@ Vérifiez le message afin de vous assurer qu'il a été signé avec l'adresse Bulwark renseignée - Decrypt &Key + Decrypt Key Décrypter la clé @@ -362,15 +362,15 @@ Vue d'ensemble du portefeuille - &Send + Send Envoyer - &Receive + Receive Recevoir - &Transactions + Transactions Transactions @@ -378,7 +378,7 @@ Afficher l'historique de transaction - E&xit + Exit Quitter @@ -386,7 +386,7 @@ Quitter l'application - About &Qt + About Qt A propos de Qt @@ -394,11 +394,11 @@ Afficher les information concernant Qt - &Options... + Options... Options... - &Show / Hide + Show / Hide Afficher / Cacher @@ -406,7 +406,7 @@ Afficher ou cacher la fenêtre principale - &Encrypt Wallet... + Encrypt Wallet... Crypter le portefeuille... @@ -414,7 +414,7 @@ Crypter les clés privées appartenant à votre portefeuille - &Backup Wallet... + Backup Wallet... Sauvegarde du portefeuille... @@ -422,7 +422,7 @@ Sauvegarder ailleurs le portefeuille - &Change Passphrase... + Change Passphrase... Changer la phrase de sécurité... @@ -430,7 +430,7 @@ Changer la phrase secrète utilisée pour l'encryptage du portefeuille - &Unlock Wallet... + Unlock Wallet... Déverrouiller le portefeuille @@ -438,27 +438,27 @@ Déverrouiller le portefeuille - &Lock Wallet + Lock Wallet Verrouiller le portefeuille - Sign &message... + Sign message... Signer le message... - &Verify message... + Verify message... Vérifier le message... - &Information - &Information + Information + Information Show diagnostic information Afficher les informations de dignostique - &Debug console + Debug console Console de déboggage @@ -466,7 +466,7 @@ Ouvrir la console de déboggage - &Peers list + Peers list Liste des pairs @@ -474,7 +474,7 @@ Afficher les infos des pairs - Wallet &Repair + Wallet Repair Réparation du portefeuille @@ -486,7 +486,7 @@ Ouvrir le fichier de configuration - Show Automatic &Backups + Show Automatic Backups Montrer les sauvegardes automatiques @@ -494,7 +494,7 @@ Montrer les sauvegardes de portefeuille créées automatiquements - &Sending addresses... + Sending addresses... Adresses d'envoie @@ -502,7 +502,7 @@ Montrer la liste des adresses et libellés d'envoies utilisés - &Receiving addresses... + Receiving addresses... Adresses de réception @@ -510,7 +510,7 @@ Montrer la liste des adresses et libellés de réception utilisés - Open &URI... + Open URI... Ouvir URI... @@ -518,27 +518,27 @@ Synchronisation des données additionnelles : %p% - &File - &Fichier + File + Fichier - &Settings - &Réglages + Settings + Réglages - &Tools - &Outils + Tools + Outils - &Help - &Aide + Help + Aide Send coins to a Bulwark address Envoyer des pièces à une adresse Bulwark - &Masternodes + Masternodes Masternodes @@ -558,7 +558,7 @@ Vérifier les messages afin de s'assurer qu'ils sont signés avec l'adresse Bulwark spécifié - &BIP38 tool + BIP38 tool Outil BIP38 @@ -834,7 +834,7 @@ Adresse : %4 Modifier l'adresse - &Address + Address Adresse @@ -1080,7 +1080,7 @@ Veuillez vérifier l'adresse et réessayer. Options - W&allet + Wallet Portefeuille @@ -1105,6 +1105,73 @@ Veuillez vérifier l'adresse et réessayer. Version + + PrivacyDialog + + 0 + 0 + + + Quantity: + Quantité : + + + Amount: + Montant : + + + Pay To: + Payer à : + + + Choose previously used address + Choisir l'adresse précédemment utilisée + + + Alt+A + Alt+A + + + Paste address from clipboard + Copier l'adresse depuis le presse-papier + + + Alt+P + Alt+P + + + Priority: + Priorité : + + + Fee: + Commission : + + + no + non + + + Insufficient funds! + Fonds insuffisants! + + + medium + moyen + + + Copy quantity + Copier la quantité + + + Copy amount + Copier le montant + + + Confirm send coins + Confirmer l'envoi des pièces + + QObject @@ -1115,7 +1182,7 @@ Veuillez vérifier l'adresse et réessayer. QRImageWidget - &Save Image... + Save Image... Enregistrer l'image @@ -1130,8 +1197,8 @@ Veuillez vérifier l'adresse et réessayer. RPCConsole - &Information - &Information + Information + Information General @@ -1170,7 +1237,7 @@ Veuillez vérifier l'adresse et réessayer. Vider la console - &Network Traffic + Network Traffic Traffic du réseau @@ -1221,7 +1288,7 @@ Veuillez vérifier l'adresse et réessayer. ReceiveCoinsDialog - &Amount: + Amount: Montant : @@ -1256,15 +1323,15 @@ Veuillez vérifier l'adresse et réessayer. QR Code - Copy &URI + Copy URI Copier L'URI - Copy &Address + Copy Address Copier l'asdresse - &Save Image... + Save Image... Enregistrer l'image @@ -1333,10 +1400,6 @@ Veuillez vérifier l'adresse et réessayer. Send Coins Envoyer des pièces - - Inputs... - Entrés... - Insufficient funds! Fonds insuffisants! @@ -1398,11 +1461,11 @@ Veuillez vérifier l'adresse et réessayer. rapide - S&end + Send Envoyer - Clear &All + Clear All Tout effacer @@ -1457,7 +1520,7 @@ Veuillez vérifier l'adresse et réessayer. SendCoinsEntry - Pay &To: + Pay To: Payer à : @@ -1503,7 +1566,7 @@ Veuillez vérifier l'adresse et réessayer. SignVerifyMessageDialog - &Sign Message + Sign Message Signer le message @@ -1547,7 +1610,7 @@ Veuillez vérifier l'adresse et réessayer. Vérifiez le message afin de vous assurer qu'il a été signé avec l'adresse Bulwark renseignée - Sign &Message + Sign Message Signer le message @@ -1555,15 +1618,15 @@ Veuillez vérifier l'adresse et réessayer. Réinitialiser tous les champs de messages signés - Clear &All + Clear All Tout effacer - &Verify Message + Verify Message Vérifier le message - Verify &Message + Verify Message Vérifier le message @@ -1729,7 +1792,7 @@ Veuillez vérifier l'adresse et réessayer. WalletView - &Export + Export Exporter @@ -1737,6 +1800,13 @@ Veuillez vérifier l'adresse et réessayer. Exporter l + + ZBwkControlDialog + + 0 + 0 + + bulwark-core diff --git a/src/qt/locale/bulwark_it.ts b/src/qt/locale/bulwark_it.ts index 6a59a9c6c..b796fe9e2 100644 --- a/src/qt/locale/bulwark_it.ts +++ b/src/qt/locale/bulwark_it.ts @@ -10,36 +10,36 @@ Crea un nuovo indirizzo - &New - &Nuovo + New + Nuovo Copy the currently selected address to the system clipboard Copia l'indirizzo selezionato negli appunti - &Copy - &Copia + Copy + Copia Delete the currently selected address from the list Elimina l'indirizzo selezionato dalla lista - &Delete - &Elimina + Delete + Elimina Export the data in the current tab to a file Esporta i dati della scheda corrente in un file - &Export - &Esporta + Export + Esporta - C&lose - C&hiudi + Close + Chiudi Choose the address to send coins to @@ -50,8 +50,8 @@ Seleziona l'indirizzo a cui ricevere valuta - C&hoose - &Seleziona + Choose + Seleziona Sending addresses @@ -70,16 +70,16 @@ Questi sono gli indirizzi Bulwark per la ricezione di pagamenti. Si raccomanda di utilizzare un indirizzo diverso per ogni transazione. - &Copy Address - &Copia indirizzo + Copy Address + Copia indirizzo - Copy &Label - Copia &etichetta + Copy Label + Copia etichetta - &Edit - &Modifica + Edit + Modifica Export Address List @@ -235,8 +235,8 @@ BIP 38 Strumento - &BIP 38 Encrypt - &BIP 38 Criptato + BIP 38 Encrypt + BIP 38 Criptato Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -283,20 +283,20 @@ Firmare il messaggio per dimostrare di possedere questo indirizzo Bulwark - Encrypt &Key - Cripta &Key + Encrypt Key + Cripta Key Reset all sign message fields Reimposta tutti i campi del messaggio segno - Clear &All - Cancella &All + Clear All + Cancella All - &BIP 38 Decrypt - &BIP 38 Decripta + BIP 38 Decrypt + BIP 38 Decripta Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. @@ -311,8 +311,8 @@ Verificare il messaggio per assicurarsi che sia stato firmato con l'indirizzo Bulwark specificato - Decrypt &Key - Decripta &Key + Decrypt Key + Decripta Key Reset all verify message fields @@ -402,136 +402,136 @@ Nodo - &Overview - &Riepilogo + Overview + Riepilogo Show general overview of wallet Mostra un riepilogo generale del portafoglio - &Send - &Invia + Send + Invia - &Receive - &Ricevi + Receive + Ricevi - &Transactions - &Transazioni + Transactions + Transazioni Browse transaction history Espora la cronologia delle transazioni - E&xit - &Esci + Exit + Esci Quit application Chiude l'applicazione - About &Qt - Informazioni su &Qt + About Qt + Informazioni su Qt Show information about Qt Visualizza informazioni su Qt - &Options... - &Opzioni... + Options... + Opzioni... - &Show / Hide - &Mostra / Nascondi + Show / Hide + Mostra / Nascondi Show or hide the main Window Mostra o nasconde la finestra principale - &Encrypt Wallet... - &Cifra portafoglio... + Encrypt Wallet... + Cifra portafoglio... Encrypt the private keys that belong to your wallet Crittografa le chiavi private nel tuo portafoglio - &Backup Wallet... - &Backup portafoglio... + Backup Wallet... + Backup portafoglio... Backup wallet to another location Fa una copia di sicurezza del tuo portafoglio in un'altra posizione - &Change Passphrase... - &Modifica parola d'ordine... + Change Passphrase... + Modifica parola d'ordine... Change the passphrase used for wallet encryption Modifica la parola d'ordine utilizzata per la crittografia del portafoglio - &Unlock Wallet... - &Sblocca portafoglio + Unlock Wallet... + Sblocca portafoglio Unlock wallet Sblocca portafoglio - &Lock Wallet - &Blocca portafoglio + Lock Wallet + Blocca portafoglio - Sign &message... - &Firma messaggio... + Sign message... + Firma messaggio... - &Verify message... - &Verifica messaggio... + Verify message... + Verifica messaggio... - &Information - &Informazioni + Information + Informazioni Show diagnostic information Visualizza informazioni di diagnostica - &Debug console - &Console di debug + Debug console + Console di debug Open debugging console Apri la console di debug - &Network Monitor - &Monitor rete + Network Monitor + Monitor rete Show network monitor Mostra monitor di rete - &Peers list - &Lista peers + Peers list + Lista peers Show peers info Mostra le informazioni sui peer - Wallet &Repair - &Ripara portafoglio + Wallet Repair + Ripara portafoglio Show wallet repair options @@ -542,31 +542,31 @@ Apri il file di configurazione - Show Automatic &Backups - Mostra &Backup automatici + Show Automatic Backups + Mostra Backup automatici Show automatically created wallet backups Mostra i backup dei portafogli creati automaticamente - &Sending addresses... - &Indirizzi Sorgente + Sending addresses... + Indirizzi Sorgente Show the list of used sending addresses and labels Mostra l'elenco degli indirizzi e delle etichette di invio utilizzati - &Receiving addresses... - &Indirizzi di Destinazione + Receiving addresses... + Indirizzi di Destinazione Show the list of used receiving addresses and labels Mostra l'elenco degli indirizzi e delle etichette di ricezione utilizzati - Open &URI... + Open URI... Apri URL @@ -574,16 +574,16 @@ Sincronizzazione dati addizionali: %p% - &Settings - &Impostazioni + Settings + Impostazioni - &Tools - &Strumenti + Tools + Strumenti - &Help - &Aiuto + Help + Aiuto Tabs toolbar @@ -602,16 +602,16 @@ Richiedi pagamenti (genera codici QR e bulwark: URIs) - &Masternodes - &Masternodes + Masternodes + Masternodes Browse masternodes Esplora i masternodes - &About Bulwark Core - &Informazioni Bulwark Core + About Bulwark Core + Informazioni Bulwark Core Show information about Bulwark Core @@ -838,14 +838,9 @@ MultiSend: %1 Please switch to "List mode" to use this function. Prego selezionare "Modalità lista" per utilizzare questa funzione - - n/a - n/a - yes - si - + si no @@ -867,12 +862,12 @@ MultiSend: %1 Modifica indirizzo - &Label - &Etichetta + Label + Etichetta - &Address - &Indirizzo + Address + Indirizzo Could not unlock wallet. @@ -965,10 +960,6 @@ MultiSend: %1 OverviewPage - - n/a - n/a - PaymentServer @@ -976,6 +967,53 @@ MultiSend: %1 PeerTableModel + + PrivacyDialog + + Quantity: + Quantità: + + + Amount: + Totale: + + + Choose previously used address + Scegli l'indirizzo utilizzato in precedenza + + + Alt+A + Alt+A + + + Paste address from clipboard + Incolla l'indirizzo dagli appunti + + + Alt+P + Alt+P + + + Priority: + Priorità: + + + Fee: + Tassa: + + + no + no + + + Change: + Differenza: + + + Copy amount + Copia ammontare + + QObject @@ -989,8 +1027,8 @@ MultiSend: %1 RPCConsole - &Information - &Informazioni + Information + Informazioni @@ -1065,8 +1103,8 @@ MultiSend: %1 Differenza: - Clear &All - Cancella &All + Clear All + Cancella All Copy amount @@ -1146,8 +1184,8 @@ MultiSend: %1 Reimposta tutti i campi del messaggio segno - Clear &All - Cancella &All + Clear All + Cancella All Reset all verify message fields @@ -1264,14 +1302,17 @@ MultiSend: %1 WalletView - &Export - &Esporta + Export + Esporta Export the data in the current tab to a file Esporta i dati della scheda corrente in un file + + ZBwkControlDialog + bulwark-core diff --git a/src/qt/locale/bulwark_ja.ts b/src/qt/locale/bulwark_ja.ts index b013060b9..9d60af92c 100644 --- a/src/qt/locale/bulwark_ja.ts +++ b/src/qt/locale/bulwark_ja.ts @@ -10,7 +10,7 @@ 新しいアドレスを作成 - &New + New &新規 @@ -18,7 +18,7 @@ クリップボードへ現在選択しているアドレスをコピー - &Copy + Copy &コピー @@ -26,15 +26,15 @@ リストから選択されたアドレスを削除 - &Delete + Delete &削除 - &Export + Export &エクスポート - C&lose + Close &閉じる @@ -46,7 +46,7 @@ 受信用アドレスを選んでコインを受け取る - C&hoose + Choose &選択 @@ -58,11 +58,11 @@ 受信用アドレス - &Copy Address + Copy Address &アドレスをコビー - &Edit + Edit &編集 @@ -179,6 +179,9 @@ PeerTableModel + + PrivacyDialog + QObject @@ -255,10 +258,13 @@ WalletView - &Export + Export &エクスポート + + ZBwkControlDialog + bulwark-core diff --git a/src/qt/locale/bulwark_ko_KR.ts b/src/qt/locale/bulwark_ko_KR.ts index c00e99d69..7e8509c82 100644 --- a/src/qt/locale/bulwark_ko_KR.ts +++ b/src/qt/locale/bulwark_ko_KR.ts @@ -10,36 +10,36 @@ 새로운 주소 만들기 - &New - &생성 + New + 생성 Copy the currently selected address to the system clipboard 현재 선택된 주소를 복사합니다. - &Copy - &복사 + Copy + 복사 Delete the currently selected address from the list 현재 선택된 주소를 목록에서 삭제합니다. - &Delete - &삭제 + Delete + 삭제 Export the data in the current tab to a file 현재 선택된 탭의 데이터를 파일로 내보내기 - &Export - &내보내기 + Export + 내보내기 - C&lose - 닫&기 + Close + 닫기 Choose the address to send coins to @@ -50,8 +50,8 @@ 전송 받을 주소를 선택해주세요. - C&hoose - 선&택 + Choose + 선택 Sending addresses @@ -70,16 +70,16 @@ 이 주소들은 전송 받을 Bulwark 주소입니다. 각 트랜잭션별로 새로운 입금 주소를 사용하는 것이 좋습니다. - &Copy Address - &주소 복사 + Copy Address + 주소 복사 - Copy &Label - 라벨 &복사 + Copy Label + 라벨 복사 - &Edit - &수정 + Edit + 수정 Export Address List @@ -232,11 +232,11 @@ Bip38ToolDialog BIP 38 Tool - BIP 38 Tool + BIP 38 도구 - &BIP 38 Encrypt - &BIP 38 암호화 + BIP 38 Encrypt + BIP 38 암호화 Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -283,20 +283,20 @@ 이 Bulwark 주소를 소유하고 있다는 것을 증명하기 위해 메세지에 서명하십시오 - Encrypt &Key - 암호화 & 키 + Encrypt Key + 암호화 키 Reset all sign message fields 모든 서명 메세지 입력 지우기 - Clear &All - 전체 &지우기 + Clear All + 전체 지우기 - &BIP 38 Decrypt - &BIP 38 암호화 해제 + BIP 38 Decrypt + BIP 38 암호화 해제 Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. @@ -311,8 +311,8 @@ 메세지가 지정된 Bulwark 주소로 서명되었는지 확인해주세요 - Decrypt &Key - 암호해제 &키 + Decrypt Key + 암호해제 키 Reset all verify message fields @@ -402,136 +402,136 @@ 노드 - &Overview - &개요 + Overview + 개요 Show general overview of wallet 지갑의 일반적인 개요 표시 - &Send - &전송 + Send + 전송 - &Receive - &받기 + Receive + 받기 - &Transactions - &트랜잭션 + Transactions + 트랜잭션 Browse transaction history 트랜잭션 내역 보기 - E&xit - 종&료 + Exit + 종료 Quit application 어플리케이션 종료 - About &Qt - &Qt 정보 + About Qt + Qt 정보 Show information about Qt Qt에 대한 정보 표시 - &Options... - &옵션... + Options... + 옵션... - &Show / Hide - &보이기 / 숨기기 + Show / Hide + 보이기 / 숨기기 Show or hide the main Window 기본 창 보이기 또는 숨기기 - &Encrypt Wallet... - &지갑 암호화... + Encrypt Wallet... + 지갑 암호화... Encrypt the private keys that belong to your wallet 지갑 개인 키 암호화 - &Backup Wallet... - &지갑 백업 + Backup Wallet... + 지갑 백업 Backup wallet to another location 다른 위치에 지갑 백업 - &Change Passphrase... - &암호 변경... + Change Passphrase... + 암호 변경... Change the passphrase used for wallet encryption 지갑 암호화에 사용되는 암호 변경 - &Unlock Wallet... - &지갑 잠금해제... + Unlock Wallet... + 지갑 잠금해제... Unlock wallet 지갑 잠금해제 - &Lock Wallet - &지갑 잠금 + Lock Wallet + 지갑 잠금 - Sign &message... - 메세지 &서명... + Sign message... + 메세지 서명... - &Verify message... - &메시지 확인... + Verify message... + 메시지 확인... - &Information - &정보 + Information + 정보 Show diagnostic information 진단 정보 표시 - &Debug console - &디버그 콘솔 + Debug console + 디버그 콘솔 Open debugging console 디버깅 콘솔 열기 - &Network Monitor - &네트워크 모니터 + Network Monitor + 네트워크 모니터 Show network monitor 네트워크 모니터 표시 - &Peers list - &피어 목록 + Peers list + 피어 목록 Show peers info 피어 정보 표시 - Wallet &Repair - 지갑 &복구 + Wallet Repair + 지갑 복구 Show wallet repair options @@ -542,60 +542,56 @@ 구성 파일 열기 - Show Automatic &Backups - 자동 &백업 표시 + Show Automatic Backups + 자동 백업 표시 Show automatically created wallet backups 자동 생성된 지갑 백업 표시 - &Sending addresses... - &주소 보내는중... + Sending addresses... + 주소 보내는중... Show the list of used sending addresses and labels 전송 된 주소 및 라벨 목록 표시 - &Receiving addresses... - &받는 주소... + Receiving addresses... + 받는 주소... Show the list of used receiving addresses and labels 입금 된 주소 및 라벨 목록 표시 - Open &URI... - &URI 열기... + Open URI... + URI 열기... - &Command-line options - &명령행 옵션 - - - Processed %n blocks of transaction history. - %n 블록의 거래내역을 처리함 + Command-line options + 명령행 옵션 Synchronizing additional data: %p% 추가 데이터 동기화: %p% - &File - &파일 + File + 파일 - &Settings - &설정 + Settings + 설정 - &Tools - &도구 + Tools + 도구 - &Help - &도움말 + Help + 도움말 Tabs toolbar @@ -614,16 +610,16 @@ 결제 요청 (QR 코드 및 bulwark: URI 생성) - &Masternodes - &마스터노드 + Masternodes + 마스터노드 Browse masternodes 마스터노드 검색 - &About Bulwark Core - Bulwark Core &정보 + About Bulwark Core + Bulwark Core 정보 Show information about Bulwark Core @@ -642,28 +638,28 @@ 메시지가 지정된 Bulwark 주소로 서명되었는지 확인합니다. - &BIP38 tool - &BIP38 도구 + BIP38 tool + BIP38 도구 Encrypt and decrypt private keys using a passphrase 암호를 사용하여 개인 키 암호화 및 암호해제 - &MultiSend - &다중전송 + MultiSend + 다중전송 MultiSend Settings 다중전송 설정 - Open Wallet &Configuration File - 지갑 &구성 파일 열기 + Open Wallet Configuration File + 지갑 구성 파일 열기 - Open &Masternode Configuration File - &마스터노드 구성 파일 열기 + Open Masternode Configuration File + 마스터노드 구성 파일 열기 Open Masternode configuration file @@ -674,8 +670,8 @@ Bulwark: URI 또는 ​​결제 요청 열기 - &Blockchain explorer - &블록체인 탐색기 + Blockchain explorer + 블록체인 탐색기 Block explorer window @@ -689,10 +685,6 @@ Bulwark Core client Bulwark Core 클라이언트 - - %n active connection(s) to Bulwark network - Bulwark 네트워크에 %n 연결됨 - Synchronizing with network... 네트워크 동기화중... @@ -713,26 +705,10 @@ Up to date 최신 - - %n hour(s) - %n 시간 - - - %n day(s) - %n 일 - - - %n week(s) - %n 주 - %1 and %2 %1 그리고 %2 - - %n year(s) - %n 년 - %1 behind %1 남음 @@ -922,10 +898,6 @@ Address: %4 Received with address 수신 된 주소 - - DS Rounds - DS 라운드 - Date 날짜 @@ -998,10 +970,6 @@ Address: %4 Please switch to "List mode" to use this function. 이 기능을 사용하려면 "목록 모드"로 전환하십시오. - - Non-anonymized input selected. <b>Obfuscation will be disabled.</b><br><br>If you still want to use Obfuscation, please deselect all non-nonymized inputs first and then check Obfuscation checkbox again. - 익명화되지 않은 입력이 선택되었습니다. <b>난독화가 비활성화 되었습니다.<b><br><br>난독화를 계속 사용하려면 먼저 익명화 되지 않은 모든 입력을 먼저 선택 취소한 뒤 다시 선택해주세요. - highest 최고 @@ -1022,10 +990,6 @@ Address: %4 Can vary +/- %1 duff(s) per input. 입력당 +/- %1 금액(s)을 변경할 수 있습니다. - - n/a - n/a - medium 중간 @@ -1106,16 +1070,16 @@ Address: %4 주소 수정 - &Label - &라벨 + Label + 라벨 The label associated with this address list entry 이 주소 목록과 관련된 라벨 - &Address - &주소 + Address + 주소 The address associated with this address list entry. This can only be modified for sending addresses. @@ -1322,20 +1286,20 @@ Address: %4 공개키 - S&tart alias - 별명 시&작 + Start alias + 별명 시작 - Start &all - &전체 시작 + Start all + 전체 시작 - Start &MISSING - 시작 &종료 + Start MISSING + 시작 종료 - &Update status - &업데이트 상태 + Update status + 업데이트 상태 Status will be updated automatically in (sec): @@ -1618,28 +1582,28 @@ Please check the address and try again. 옵션 - &Main - &메인 + Main + 메인 - Size of &database cache - &데이터베이스 캐시 크기 + Size of database cache + 데이터베이스 캐시 크기 MB MB - Number of script &verification threads - 스크립트 &검증 스레드 개수 + Number of script verification threads + 스크립트 검증 스레드 개수 (0 = auto, <0 = leave that many cores free) (0 = 자동, <0 = 많은 코어들을 여유롭게 두기) - W&allet - 지&갑 + Wallet + 지갑 If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. @@ -1658,8 +1622,8 @@ Please check the address and try again. 들어오는 연결 허용 - &Connect through SOCKS5 proxy (default proxy): - &SOCKS5 프록시를 통해 연결 (기본 프록시): + Connect through SOCKS5 proxy (default proxy): + SOCKS5 프록시를 통해 연결 (기본 프록시): Expert @@ -1670,32 +1634,16 @@ Please check the address and try again. 시스템 로그인 후 Bulwark을 자동으로 시작합니다. - &Start Bulwark on system login - &시스템 로그인시 Bulwark 시작 - - - This setting determines the amount of individual masternodes that an input will be anonymized through.<br/>More rounds of anonymization gives a higher degree of privacy, but also costs more in fees. - 이 설정은 익명화 할 입력 값의 개별 마스터노드의 수량을 결정합니다.<br/>더 많은 익명화할 액수는 높은 수준의 익명성을 제공하지만 수수료가 많이 듭니다. - - - Obfuscation rounds to use - 난독화를 사용할 영역 - - - This amount acts as a threshold to turn off Obfuscation once it's reached. - 이 금액에 도달하면 난독화를 끌 수 있는 임계 값 역할을 합니다. - - - Amount of Bulwark to keep anonymized - 익명화할 Bulwark 수량 + Start Bulwark on system login + 시스템 로그인시 Bulwark 시작 Whether to show coin control features or not. 동전 제어 기능을 표시할지 여부를 나타냅니다. - Enable coin &control features - 코인 &제어 기능 사용 + Enable coin control features + 코인 제어 기능 사용 Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. @@ -1706,12 +1654,12 @@ Please check the address and try again. 마스터노드 탭 표시 - &Spend unconfirmed change - &확인되지 않은 변경사항 전송 + Spend unconfirmed change + 확인되지 않은 변경사항 전송 - &Network - &네트워크 + Network + 네트워크 The user interface language can be set here. This setting will take effect after restarting Bulwark. @@ -1724,64 +1672,64 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations https://www.transifex.com/bulwark-project/bulwark-project-translations - Map port using &UPnP - &UPnp를 사용하여 포트 매핑 + Map port using UPnP + UPnp를 사용하여 포트 매핑 Connect to the Bulwark network through a SOCKS5 proxy. SOCKS5 프록시를 통해 Bulwark 네트워크에 연결해주세요. - Proxy &IP: - 프록시 &IP: + Proxy IP: + 프록시 IP: IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) 프록시 IP 주소 (예: IPv4: 127.0.0.1 / IPv6: ::1) - &Port: - &포트: + Port: + 포트: Port of the proxy (e.g. 9050) 프록시 포트 (예: 9050) - &Window - &윈도우 + Window + 윈도우 Show only a tray icon after minimizing the window. 창 최소화 후 트레이 아이콘으로만 표시. - &Minimize to the tray instead of the taskbar - &최소화시 작업표시줄이 아닌 트레이로 최소화 + Minimize to the tray instead of the taskbar + 최소화시 작업표시줄이 아닌 트레이로 최소화 Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. 창 닫기시 프로그램 종료하지 않고 최소화하기. 이 옵션을 사용하면 메뉴에서 종료를 선택해야 프로그램이 종료됩니다. - M&inimize on close - 닫&기시 최소화 + Minimize on close + 닫기시 최소화 - &Display - &디스플레이 + Display + 디스플레이 - User Interface &language: - 사용자 인터페이스 &언어: + User Interface language: + 사용자 인터페이스 언어: User Interface Theme: 사용자 인터페이스 테마: - &Unit to show amounts in: - &금액을 표시 할 단위: + Unit to show amounts in: + 금액을 표시 할 단위: Choose the default subdivision unit to show in the interface and when sending coins. @@ -1808,16 +1756,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations모든 클라이언트 옵션을 기본값으로 재설정. - &Reset Options - &옵션 재설정 + Reset Options + 옵션 재설정 - &OK - &예 + OK + - &Cancel - &취소 + Cancel + 취소 default @@ -1878,10 +1826,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsStaked or masternode rewards that has not yet matured 아직 완료되지 않은 스테이크 및 마스터노드 보상 - - Balances - 잔액 - The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. 표시된 정보가 오래되었을 수 있습니다. 연결이 완료되면 지갑이 Bulwark 네트워크와 자동으로 동기화될 예정이지만, 아직 해당 프로세스가 완료되지 않았습니다. @@ -1918,156 +1862,14 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSpendable: 출금 가능 액수: - - Status: - 상태: - - - Obfuscation Balance: - 난독화 된 잔액: - - - 0 BWK / 0 Rounds - 0 BWK / 0 수량 - - - Enabled/Disabled - 활성화/비활성화 - - - Try to manually submit a Obfuscation request. - 난독화 요청을 수동으로 제출해주세요. - - - Reset the current status of Obfuscation (can interrupt Obfuscation if it's in the process of Mixing, which can cost you money!) - 현재 난독화 상태를 초기화 합니다. (난독화가 믹스 중일 경우에 간섭으로 비용이 발생할 수 있습니다!) - - - Obfuscation - 난독화 - - - Completion: - 완료: - - - Amount and Rounds: - 금액 및 수량: - - - Submitted Denom: - 제출된 단위: - - - n/a - n/a - Recent transactions 최근 트랜잭션 - - Start/Stop Mixing - 믹싱 시작/종료 - - - The denominations you submitted to the Masternode.<br>To mix, other users must submit the exact same denominations. - 당신이 마스터노드에 제출한 단위.<br>믹스하려면 다른 유저들은 반드시 정확한 단위를 제출해야 합니다. - - - (Last Message) - (최근 메시지) - - - Try Mix - 믹스 시도 - - - Reset - 초기화 - out of sync 동기화되지 않음 - - Disabled - 비활성됨 - - - No inputs detected - 값이 입력되지 않음 - - - %n Rounds - %n 라운드 - - - Not enough compatible inputs to anonymize <span style='color:red;'>%1</span>,<br>will anonymize <span style='color:red;'>%2</span> instead - 익명화를 위한 값이 충분하지 않아 <span style='color:red;'>%1/span>,<br>대신 <span style='color:red;'>%2</span>가 익명화 됩니다. - - - Overall progress - 전체 내역 - - - Denominated - 표기된 - - - Anonymized - 익명화된 - - - Denominated inputs have %5 of %n rounds on average - 지정된 입력값은 평균 %n 라운드중 %5입니다. - - - Last Obfuscation message: - - 최근 Obfuscate한 메시지: - - - - Obfuscation was successfully reset. - 난독화가 성공적으로 초기화 되었습니다. - - - If you don't want to see internal Obfuscation fees/transactions select "Most Common" as Type on the "Transactions" tab. - 내부 난독화 수수료/트랜잭션를 보고 싶지 않으면 "트랜잭션" 탭에서 '기본적인'을 선택하십시오. - - - Obfuscation requires at least %1 to use. - 난독화를 사용하기 위해선 적어도 %1이 필요합니다. - - - Wallet is locked and user declined to unlock. Disabling Obfuscation. - 지갑이 잠겼으며 사용자가 잠금 해제를 거부했습니다. 난독화 중단. - - - Found enough compatible inputs to anonymize %1 - %1 익명화를 진행하기 위해서는 충분한 값이 필요합니다 - - - Start Obfuscation - 난독화 시작 - - - Stop Obfuscation - 난독화 중지 - - - Mixed - 믹스됨 - - - Enabled - 활성화됨 - - - N/A - N/A - PaymentServer @@ -2141,7 +1943,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Error communicating with %1: %2 - %1 과 통신하는 중 오류 발생: %2 + %1: %2 통신하는 중 오류 발생: Payment request cannot be parsed! @@ -2175,6 +1977,121 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations응답 시간 + + PrivacyDialog + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + 표시된 정보가 오래되었을 수 있습니다. 연결이 완료되면 지갑이 Bulwark 네트워크와 자동으로 동기화될 예정이지만, 아직 해당 프로세스가 완료되지 않았습니다. + + + 0 + 0 + + + Reset + 초기화 + + + Quantity: + 수량: + + + Amount: + 금액: + + + Pay To: + 지불 대상: + + + Choose previously used address + 이전에 사용한 주소 선택 + + + Alt+A + Alt+A + + + Paste address from clipboard + 클립보드에서 주소 붙여 넣기 + + + Alt+P + Alt+P + + + Label: + 라벨: + + + Enter a label for this address to add it to the list of used addresses + 이 주소의 라벨을 입력하여 사용된 주소 목록에 추가하십시오 + + + Amount: + 금액: + + + Priority: + 우선 순위: + + + Fee: + 수수료: + + + Dust: + 현금: + + + no + 아니오 + + + Bytes: + Bytes: + + + Insufficient funds! + 자금이 충분하지 않습니다! + + + medium + 중간 + + + Coin Control Features + 코인 제어 기능 + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + 이 옵션이 활성화되었지만, 변경 주소가 비어있거나 유효하지 않은 경우 변경사항은 새로 생성된 주소로 전송됩니다. + + + Custom change address + 커스텀 주소 변경 + + + Change: + 변경: + + + out of sync + 동기화되지 않음 + + + Copy quantity + 수량 복사 + + + Copy amount + 금액 복사 + + + Confirm send coins + 코인 전송 확인 + + QObject @@ -2229,12 +2146,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations QRImageWidget - &Save Image... - 이미지 &저장... + Save Image... + 이미지 저장... - &Copy Image - &이미지 복사 + Copy Image + 이미지 복사 Save QR Code @@ -2252,8 +2169,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations도구 창 - &Information - &정보 + Information + 정보 General @@ -2276,8 +2193,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations연결된 수 - &Open - &열기 + Open + 열기 Startup time @@ -2328,20 +2245,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations마스터노드 개수 - &Console - &콘솔 + Console + 콘솔 Clear console 콘솔 초기화 - &Network Traffic - &네트워크 트래픽 + Network Traffic + 네트워크 트래픽 - &Clear - &초기화 + Clear + 초기화 Totals @@ -2356,8 +2273,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations보냄 - &Peers - &피어 + Peers + 피어 Select a peer to view detailed information. @@ -2416,8 +2333,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations응답 시간 - &Wallet Repair - &지갑 복구 + Wallet Repair + 지갑 복구 Wallet In Use: @@ -2548,12 +2465,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations이전에 사용한 수신 주소 중 하나를 다시 사용하십시오.<br>주소 재사용은 보안 및 개인정보보호 문제가 있습니다.<br>이전에 만든 결제 요청을 다시 생성하지 않는 한 이것을 사용하지 마십시오. - R&euse an existing receiving address (not recommended) - 기&존 수신 주소 재사용 (권장하지 않음) + Reuse an existing receiving address (not recommended) + 기존 수신 주소 재사용 (권장하지 않음) - &Message: - &메세지: + Message: + 메세지: An optional label to associate with the new receiving address. @@ -2572,20 +2489,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations결제 요청을 진행하려면 해당 양식을 입력하세요. 모든 입력란은 <b>선택 사항</b>입니다. - &Label: - &라벨: + Label: + 라벨: An optional amount to request. Leave this empty or zero to not request a specific amount. 요청할 선택적 금액. 이 금액을 비워두거나 특정 금액을 요청하지 않으려면 0으로 두세요. - &Amount: - &금액: + Amount: + 금액: - &Request payment - &결제 요청 + Request payment + 결제 요청 Clear all fields of the form. @@ -2635,16 +2552,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsQR 코드 - Copy &URI - &URI 복사 + Copy URI + URI 복사 - Copy &Address - &주소 복사 + Copy Address + 주소 복사 - &Save Image... - 이미지 &저장... + Save Image... + 이미지 저장... Request payment to %1 @@ -2724,14 +2641,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsCoin Control Features 코인 제어 기능 - - Inputs... - 입력... - - - automatically selected - 자동 선택됨 - Insufficient funds! 자금이 충분하지 않습니다! @@ -2816,10 +2725,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsMinimize 최소화 - - Obfuscation - 난독화 - per kilobyte 킬로바이트당 @@ -2881,28 +2786,28 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations전송 작업 확인 - S&end - 전&송 + Send + 전송 Clear all fields of the form. 모든 입력 양식 지우기. - Clear &All - 전체 &지우기 + Clear All + 전체 지우기 Send to multiple recipients at once 한번에 여러 곳 전송 - Add &Recipient - &받는 사람 추가 + Add Recipient + 받는 사람 추가 - SwiftTX - SwiftTX + SwiftX + SwiftX Balance: @@ -2965,8 +2870,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations사용 가능한 자금 (권장하지 않음) - and SwiftTX - 그리고 SwiftTX + and SwiftX + 그리고 SwiftX %1 to %2 @@ -3000,10 +2905,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsThe recipient address is not valid, please recheck. 수신자 주소가 유효하지 않습니다. 다시 확인해주세요. - - (obfuscation requires this amount to be rounded up to the nearest %1). - (난독화로 이 금액을 가장 가까운 %1로 반올림 해야됩니다) - split into %1 outputs using the UTXO splitter. UTXO 스플리터를 사용하여 %1 출력으로 분할하십시오. @@ -3064,8 +2965,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations이것은 일반 결제입니다. - Pay &To: - 지불 &대상: + Pay To: + 지불 대상: The Bulwark address to send the payment to @@ -3092,16 +2993,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations이 항목 삭제 - &Label: - &라벨: + Label: + 라벨: Enter a label for this address to add it to the list of used addresses 이 주소의 라벨을 입력하여 사용된 주소 목록에 추가하십시오 - A&mount: - 금&액: + Amount: + 금액: Message: @@ -3150,8 +3051,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations서명 - 서명 / 메세지 검증 - &Sign Message - &메세지 서명 + Sign Message + 메세지 서명 You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. @@ -3202,28 +3103,28 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations메세지가 지정된 Bulwark 주소로 서명되었는지 확인해주세요 - Sign &Message - 서명 &메세지 + Sign Message + 서명 메세지 Reset all sign message fields 모든 서명 메세지 입력 지우기 - Clear &All - 전체 &지우기 + Clear All + 전체 지우기 - &Verify Message - &메세지 확인 + Verify Message + 메세지 확인 Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. 메세지를 확인하기 위해 서명 주소, 메세지 (줄 바꿈, 공백, 탭 등을 정확하게 복사해주세요) 및 서명을 입력하십시오. 중간자 공격에 주의해서 서명을 입력해주세요. - Verify &Message - &메세지 확인 + Verify Message + 메세지 확인 Reset all verify message fields @@ -3331,16 +3232,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations충돌됨 - %1/offline (verified via swifttx) - %1/오프라인 (swifttx를 통해 확인 됨) + %1/offline (verified via SwiftX) + %1/오프라인 (SwiftX를 통해 확인 됨) - %1/confirmed (verified via swifttx) - %1/확인 됨 (swifttx를 통해 확인 됨) + %1/confirmed (verified via SwiftX) + %1/확인 됨 (SwiftX를 통해 확인 됨) - %1 confirmations (verified via swifttx) - %1 확인 (swifttx를 통해 확인 됨) + %1 confirmations (verified via SwiftX) + %1 확인 (SwiftX를 통해 확인 됨) %1/offline @@ -3355,25 +3256,25 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations%1 확인 - %1/offline (SwiftTX verification in progress - %2 of %3 signatures) - %1/오프라인 (SwiftTX 확인 진행 중 - %2 중 %3 서명) + %1/offline (SwiftX verification in progress - %2 of %3 signatures) + %1/오프라인 (SwiftX 확인 진행 중 - %2 중 %3 서명) - %1/confirmed (SwiftTX verification in progress - %2 of %3 signatures ) - %1/확인 됨 (SwiftTX 확인 진행 중 - %2 중 %3 서명) + %1/confirmed (SwiftX verification in progress - %2 of %3 signatures ) + %1/확인 됨 (SwiftX 확인 진행 중 - %2 중 %3 서명) - %1 confirmations (SwiftTX verification in progress - %2 of %3 signatures) - %1 확인 (SwiftTX 확인 진행 중 - %2 중 %3 서명) + %1 confirmations (SwiftX verification in progress - %2 of %3 signatures) + %1 확인 (SwiftX 확인 진행 중 - %2 중 %3 서명) - %1/offline (SwiftTX verification failed) - %1/오프라인 (SwiftTX 확인 실패) + %1/offline (SwiftX verification failed) + %1/오프라인 (SwiftX 확인 실패) - %1/confirmed (SwiftTX verification failed) - %1/확인 됨 (SwiftTX 확인 실패) + %1/confirmed (SwiftX verification failed) + %1/확인 됨 (SwiftX 확인 실패) Status @@ -3850,15 +3751,15 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations코인 전송 - SwiftTX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. - SwiftTX는 아직 높은 값을 전송하는 것을 지원하지 않습니다. 트랜잭션은 현재 %1 BWK로 제한됩니다. + SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. + SwiftX는 아직 높은 값을 전송하는 것을 지원하지 않습니다. 트랜잭션은 현재 %1 BWK로 제한됩니다. WalletView - &Export - &내보내기 + Export + 내보내기 Export the data in the current tab to a file @@ -3893,6 +3794,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations지갑 데이터가 %1에 성공적으로 저장되었습니다. + + ZBwkControlDialog + + 0 + 0 + + bulwark-core @@ -3940,8 +3848,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations지갑의 모든 트랜잭션들을 삭제하고 오직 블록체인을 통한 트랜잭션 부분들만 복구합니다 -시작 시 다시 스캔 - Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftTX, Budgeting) (0-1, default: %u) - Bulwark의 모든 특정 기능들을 비활성화합니다(마스터노드, 난독화, SwiftTX, Budgeting) (0-1, 기본값: %u) + Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftX, Budgeting) (0-1, default: %u) + Bulwark의 모든 특정 기능들을 비활성화합니다(마스터노드, 난독화, SwiftX, Budgeting) (0-1, 기본값: %u) Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. @@ -3952,12 +3860,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations올바른 개인키로 spork 관리 기능을 사용 가능 - Enable swifttx, show confirmations for locked transactions (bool, default: %s) - swiftTX 활성화, 잠긴 트랜잭션들에 대한 확인 표시 (bool, 기본값: %s) - - - Enable use of automated obfuscation for funds stored in this wallet (0-1, default: %u) - 이 지갑에 저장된 금액에 대해 자동 난독화 사용을 활성화 합니다 (0-1, 기본값: %u) + Enable SwiftX, show confirmations for locked transactions (bool, default: %s) + SwiftX 활성화, 잠긴 트랜잭션들에 대한 확인 표시 (bool, 기본값: %s) Enter regression test mode, which uses a special chain in which blocks can be solved instantly. @@ -4047,10 +3951,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsOutput debugging information (default: %u, supplying <category> is optional) 디버깅 정보 출력 (기본값: %u, <category> 공급은 선택입니다) - - 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-100, 기본값: %u, 1=매우 잦음, 높은 수수료, 100=매운 드문, 낮은 수수료) - Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) DNS 검색을 통한 피어 주소 쿼리, 주소가 부족할 경우 (-connect 아닌 이상 기본값:1) @@ -4084,8 +3984,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsbloom필터를 사용한 블록 및 트랜잭션 필터링 지원 (기본값 : %u) - SwiftTX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. - SwiftTX는 최소 6회 확인이 필요한 입력으로 몇 분 후에 다시 시도해야 할 수 있습니다. + SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. + SwiftX는 최소 6회 확인이 필요한 입력으로 몇 분 후에 다시 시도해야 할 수 있습니다. This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. @@ -4568,8 +4468,8 @@ rpcpassword=%s <address> 에서 해시 블록 게시 가능 - Enable publish hash transaction (locked via SwiftTX) in <address> - <address> 에서 해시 전송 게시 가능 (SwiftTX로 설정된) + Enable publish hash transaction (locked via SwiftX) in <address> + <address> 에서 해시 전송 게시 가능 (SwiftX로 설정된) Enable publish hash transaction in <address> @@ -4580,8 +4480,8 @@ rpcpassword=%s <address>에서 Raw 블록 게시 가능 - Enable publish raw transaction (locked via SwiftTX) in <address> - <address>에서 Raw 트랜잭션 게시 지원 (SwiftTX를 통해 잠겨진) + Enable publish raw transaction (locked via SwiftX) in <address> + <address>에서 Raw 트랜잭션 게시 지원 (SwiftX를 통해 잠겨진) Enable publish raw transaction in <address> @@ -4591,10 +4491,6 @@ rpcpassword=%s Enable staking functionality (0-1, default: %u) 스테이킹 기능 사용 (0-1, 기본값: %u) - - Keep N BWK anonymized (default: %u) - N BWK 익명으로 유지 (기본값: %u) - Keep at most <n> unconnectable transactions in memory (default: %u) 메모리에서 연결 불가능한 트랜잭션을 <n>개까지 유지하십시오. (기본값: %u) @@ -4739,10 +4635,6 @@ rpcpassword=%s Obfuscation is idle. 난독화는 유휴상태입니다. - - Obfuscation options: - 난독화 옵션: - Obfuscation request complete: 난독화 요청 완료: @@ -4952,8 +4844,8 @@ rpcpassword=%s 마스터노드에 제출했습니다, 대기열을 기다리는 중 %s - SwiftTX options: - SwiftTX 옵션: + SwiftX options: + SwiftX 옵션: Synchronization failed @@ -5055,10 +4947,6 @@ rpcpassword=%s Upgrade wallet to latest format 지갑을 최신 포맷으로 업그레이드합니다 - - Use N separate masternodes to anonymize funds (2-8, default: %u) - N개의 각각의 마스터노드를 이용하여 자금 익명화 (2-8, 기본값: %u) - Use OpenSSL (https) for JSON-RPC connections JSON-RPC 연결에 OpenSSL (https)를 사용합니다 diff --git a/src/qt/locale/bulwark_nl.ts b/src/qt/locale/bulwark_nl.ts index 2b14ad780..0368d2bfd 100644 --- a/src/qt/locale/bulwark_nl.ts +++ b/src/qt/locale/bulwark_nl.ts @@ -10,36 +10,36 @@ Maak een nieuw adres aan - &New - &Nieuw + New + Nieuw Copy the currently selected address to the system clipboard Kopieer het geselecteerde adres naar het klembord - &Copy - &Kopiëren + Copy + Kopiëren Delete the currently selected address from the list Verwijder het geselecteerde adres uit de lijst - &Delete - &Verwijderen + Delete + Verwijderen Export the data in the current tab to a file Exporteer de data in de huidige tab naar een bestand - &Export - &Exporteren + Export + Exporteren - C&lose - &Sluiten + Close + Sluiten Choose the address to send coins to @@ -50,8 +50,8 @@ Kies het adres om op te ontvangen - C&hoose - K&iezen + Choose + Kiezen Sending addresses @@ -70,16 +70,16 @@ Dit zijn uw Bulwarkadressen waarop betalingen kunnen worden ontvangen. Het wordt aangeraden om een nieuw ontvangstadres voor elke transactie te gebruiken. - &Copy Address - &Kopiëer Adres + Copy Address + Kopiëer Adres - Copy &Label - Kopiëer &Label + Copy Label + Kopiëer Label - &Edit - &Bewerken + Edit + Bewerken Export Address List @@ -231,8 +231,8 @@ BIP 38 Tool - &BIP 38 Encrypt - &BIP 38 Versleuteling + BIP 38 Encrypt + BIP 38 Versleuteling Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -279,20 +279,20 @@ Onderteken het bericht om te bewijzen dat u het Bulwark adres bezit - Encrypt &Key - Versleutel &Sleutel + Encrypt Key + Versleutel Sleutel Reset all sign message fields Maak alle ondertekenvelden leeg - Clear &All - Verwijder &Alles + Clear All + Verwijder Alles - &BIP 38 Decrypt - &BIP 38 ontsleuteling + BIP 38 Decrypt + BIP 38 ontsleuteling Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. @@ -307,7 +307,7 @@ Controleer een bericht om te verifiëren dat het ondertekend is door het gespecificeerde Bulwark adres - Decrypt &Key + Decrypt Key Ontsleutelen Sleutel @@ -398,59 +398,59 @@ Node - &Overview - &Overzicht + Overview + Overzicht Show general overview of wallet Toon algemeen overzicht van de portemonnee - &Send - &Verzenden + Send + Verzenden - &Receive - &Ontvangen + Receive + Ontvangen - &Transactions - &Transacties + Transactions + Transacties Browse transaction history Blader door transactiegescheidenis - E&xit - &Sluiten + Exit + Sluiten Quit application Programma afsluiten - About &Qt - Over &Qt + About Qt + Over Qt Show information about Qt Toon informatie over Qt - &Options... - &Opties... + Options... + Opties... - &Show / Hide - &Tonen / Verbergen + Show / Hide + Tonen / Verbergen Show or hide the main Window Toon of verberg het hoofdvenster - &Encrypt Wallet... + Encrypt Wallet... Versleutel portemonnee @@ -458,7 +458,7 @@ Versleutel de geheime sleutels die bij uw portemonnee horen - &Backup Wallet... + Backup Wallet... Backup Portemonnee... @@ -466,68 +466,68 @@ Backup portemonnee naar een andere locatie - &Change Passphrase... - &Wijzig Wachtwoord... + Change Passphrase... + Wijzig Wachtwoord... Change the passphrase used for wallet encryption Wijzig het wachtwoord voor uw portemonneversleuteling - &Unlock Wallet... - &Open portemonnee... + Unlock Wallet... + Open portemonnee... Unlock wallet Open portemonnee - &Lock Wallet - &Sluit portemonnee + Lock Wallet + Sluit portemonnee - Sign &message... - Bericht &Ondertekenen... + Sign message... + Bericht Ondertekenen... - &Verify message... - Bericht &Verifiëren... + Verify message... + Bericht Verifiëren... - &Information - &Informatie + Information + Informatie Show diagnostic information Toon diagnostische informatie - &Debug console - &Debug console + Debug console + Debug console Open debugging console Open debugging console - &Network Monitor - &Netwerk Monitor + Network Monitor + Netwerk Monitor Show network monitor Toon netwerk monitor - &Peers list - &Peers lijst + Peers list + Peers lijst Show peers info Toon informatie van peers - Wallet &Repair - Portemonnee &Repareren + Wallet Repair + Portemonnee Repareren Show wallet repair options @@ -538,36 +538,36 @@ Open configuratie bestand - Show Automatic &Backups - Toon Automatische &Backups + Show Automatic Backups + Toon Automatische Backups Show automatically created wallet backups Toon automatisch aangemaakte portemonnee backups - &Sending addresses... - &Verzendadressen... + Sending addresses... + Verzendadressen... Show the list of used sending addresses and labels Toon de lijst van verzendadressen en labels - &Receiving addresses... - &Ontvangstadressen... + Receiving addresses... + Ontvangstadressen... Show the list of used receiving addresses and labels Toon de lijst van ontvangstadressen en labels - Open &URI... - Open &URI... + Open URI... + Open URI... - &Command-line options - &Opdrachtregelopties + Command-line options + Opdrachtregelopties Processed %n blocks of transaction history. @@ -578,20 +578,20 @@ Synchroniseren aanvullende gegevens: %p% - &File - &Bestand + File + Bestand - &Settings - &Instellingen + Settings + Instellingen - &Tools - &Gereedschap + Tools + Gereedschap - &Help - &Help + Help + Help Tabs toolbar @@ -610,16 +610,16 @@ Vraag betaling aan (genereert QR-codes en Bulwark: URI's) - &Masternodes - &Masternodes + Masternodes + Masternodes Browse masternodes Bekijk masternodes - &About Bulwark Core - &Over Bulwark Kern + About Bulwark Core + Over Bulwark Kern Show information about Bulwark Core @@ -638,28 +638,28 @@ Controleer berichten om te verifiëren dat deze ondertekend zijn met de gespecificeerde Bulwark adressen - &BIP38 tool - &BIP38 tool + BIP38 tool + BIP38 tool Encrypt and decrypt private keys using a passphrase Versleutelen en ontsleutelen door middel van een wachtwoord/wachtzin - &MultiSend - &MultiSend + MultiSend + MultiSend MultiSend Settings MultiSend intellingen - Open Wallet &Configuration File - Open Portemonnee &Configuratiebestand + Open Wallet Configuration File + Open Portemonnee Configuratiebestand - Open &Masternode Configuration File - Open &Masternode Configuratiebestand + Open Masternode Configuration File + Open Masternode Configuratiebestand Open Masternode configuration file @@ -670,8 +670,8 @@ Open een Bulwark: URI of betaalverzoek - &Blockchain explorer - &Blockchain verkenner + Blockchain explorer + Blockchain verkenner Block explorer window @@ -683,7 +683,7 @@ %n active connection(s) to Bulwark network - %n actieve connectie(s) naar Bulwark netwerk%n actieve connectie(s) naar Bulwark netwerk + %n actieve verbinding(en) naar het Bulwark netwerk%n actieve verbinding(en) naar het Bulwark netwerk Synchronizing with network... @@ -753,6 +753,22 @@ Incoming transaction Inkomende transactie + + Sent MultiSend transaction + Verzend MultiSend transactie + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + Datum: %1 +Hoeveelheid: %2 +Type: %3 +Adres: %4 + + Staking is active MultiSend: %1 @@ -792,6 +808,14 @@ MultiSend: %1 Blockchain Explorer Blockchain Verkenner + + Back + Terug + + + Forward + Volgende + Address / Block / Transaction Adres / Block / Transactie @@ -862,10 +886,22 @@ MultiSend: %1 (un)select all (on)selecteer alles + + List mode + Lijstmodus + Amount Hoeveelheid + + Received with label + Ontvangen met label + + + Received with address + Ontvangen met adres + Date Datum @@ -918,6 +954,10 @@ MultiSend: %1 Copy priority Kopieer prioriteit + + Copy change + Kopieer wisselgeld + highest hoogste @@ -934,10 +974,6 @@ MultiSend: %1 medium-high medium-hoog - - n/a - N/B - medium medium @@ -986,12 +1022,12 @@ MultiSend: %1 Wijzig Adres - &Label - &Label + Label + Label - &Address - &Adres + Address + Adres New receiving address @@ -1055,6 +1091,18 @@ MultiSend: %1 Command-line options Command-line opties + + (%1-bit) + (%1-bit) + + + About Bulwark Core + Over Bulwark Core + + + Command-line options + Command-line opties + Usage: Gebruik: @@ -1142,12 +1190,16 @@ MultiSend: %1 Pubkey - Start &all - &all starten + Start all + all starten - Start &MISSING - Start &ontbrekende + Start MISSING + Start ontbrekende + + + Update status + Status bijwerken 0 @@ -1272,20 +1324,20 @@ MultiSend: %1 Opties - &Main - &Algemeen + Main + Algemeen - Size of &database cache - Grootte van cache &gegevens + Size of database cache + Grootte van cache gegevens MB MB - W&allet - P&ortemonnee + Wallet + Portemonnee Accept connections from outside @@ -1304,76 +1356,72 @@ MultiSend: %1 Bulwark automatisch opstarten na inloggen op het systeem. - &Start Bulwark on system login - &Bulwark starten bij systeemlogin - - - Amount of Bulwark to keep anonymized - Hoeveelheid Bulwark anoniem te houden + Start Bulwark on system login + Bulwark starten bij systeemlogin - &Network - &Netwerk + Network + Netwerk The user interface language can be set here. This setting will take effect after restarting Bulwark. De gebruikersinterface taal kan hier ingesteld worden. Deze instelling zal uitgevoerd na herstart van Bulwark. - Map port using &UPnP - Map poort gebruikt &UPnP + Map port using UPnP + Map poort gebruikt UPnP - Proxy &IP: - Proxy &IP: + Proxy IP: + Proxy IP: - &Port: - &Poort: + Port: + Poort: Port of the proxy (e.g. 9050) Proxy-poort (v.b. 9050) - &Window - &Venster + Window + Venster - M&inimize on close + Minimize on close Minimaliseer bij sluiten - &Display - &Vertoon + Display + Weergave - User Interface &language: - Gebruiksinterface &language: + User Interface language: + Gebruiksinterface language: User Interface Theme: Gebruiksinterface thema: - &Unit to show amounts in: - Toon &Unit in volgende hoeveelheden: + Unit to show amounts in: + Toon Unit in volgende hoeveelheden: Decimal digits Decimale cijfers - &Reset Options - &Herstellings Opties + Reset Options + Herstellings Opties - &OK - &OK + OK + OK - &Cancel - &Annuleren + Cancel + Annuleren default @@ -1406,10 +1454,6 @@ MultiSend: %1 Immature: Immatuur: - - Balances - Balansen - Total: Totaal: @@ -1422,49 +1466,13 @@ MultiSend: %1 Spendable: Uitgeefbaar: - - Status: - Status: - - - 0 BWK / 0 Rounds - 0 BWK / 0 Rondes - - - Enabled/Disabled - Ingeschakeld/Uitgeschakeld - - - Obfuscation - Verduistering - - - n/a - N/B - Recent transactions Recente transacties out of sync - geen synchronisatie - - - Disabled - Uitgeschakeld - - - Mixed - Gemengd - - - Enabled - Ingeschakeld - - - N/A - NB + niet gesynchroniseerd @@ -1505,6 +1513,121 @@ MultiSend: %1 Pingtijd + + PrivacyDialog + + Enter an amount of BWK to convert to zBWK + Vul de hoeveleheid in om BWK te converteren naar zBWK + + + 0 + 0 + + + zBWK + zBWK + + + Reset + Resetten + + + Quantity: + Kwantiteit: + + + Amount: + Hoeveelheid: + + + Pay To: + Betaal Naar: + + + Choose previously used address + Kies een eerder gebruikt adres + + + Alt+A + Alt+A + + + Paste address from clipboard + Plak adres vanaf klembord + + + Alt+P + Alt+P + + + Label: + Label: + + + Amount: + Hoeveelheid: + + + Available Funds + Beschikbare Fondsen + + + 0 x + 0 x + + + Priority: + Prioriteit: + + + Fee: + Kost: + + + Dust: + Stof: + + + no + nee + + + Bytes: + Bytes: + + + medium + medium + + + Change: + Wijzig: + + + out of sync + niet gesynchroniseerd + + + Copy quantity + Kopieer kwanititeit + + + Copy amount + Kopieer hoeveelheid + + + Confirm Rescan + Bevestig Rescan + + + Duration: + Duur: + + + Confirm send coins + Bevestig verzending coins + + QObject @@ -1551,12 +1674,12 @@ MultiSend: %1 QRImageWidget - &Save Image... - &Afbeelding opslaan... + Save Image... + Afbeelding opslaan... - &Copy Image - &Kopieer afbeelding + Copy Image + Kopieer afbeelding Save QR Code @@ -1570,8 +1693,8 @@ MultiSend: %1 RPCConsole - &Information - &Informatie + Information + Informatie General @@ -1594,8 +1717,8 @@ MultiSend: %1 Aantal connecties - &Open - &Open + Open + Open Startup time @@ -1609,6 +1732,10 @@ MultiSend: %1 Last block time Laatste blocktijd + + Debug log file + Debug logbestand + Using OpenSSL version Gebruikt OpenSSL versie @@ -1638,8 +1765,16 @@ MultiSend: %1 Aantal Masternodes - &Console - &Console + Console + Console + + + Clear console + Console leegmaken + + + Clear + Leegmaken Received @@ -1650,8 +1785,8 @@ MultiSend: %1 Verstuurd - &Peers - &Peers + Peers + Peers Protocol @@ -1745,13 +1880,29 @@ MultiSend: %1 ReceiveCoinsDialog - &Message: - &Bericht: + Message: + Bericht: + + + Label: + Label: + + + Amount: + Hoeveelheid: + + + Request payment + Verzoek betaling Clear Leegmaken + + Requested payments history + Betalingsverzoeken geschiedenis + Show Toon @@ -1780,12 +1931,16 @@ MultiSend: %1 QR Code - Copy &Address - Kopieer &Adres + Copy URI + Kopieer URI + + + Copy Address + Kopieer Adres - &Save Image... - &Afbeelding opslaan... + Save Image... + Afbeelding opslaan... Payment information @@ -1849,10 +2004,6 @@ MultiSend: %1 Send Coins Verzend Munten - - automatically selected - automatisch geselecteerd - Quantity: Kwantiteit: @@ -1909,14 +2060,14 @@ MultiSend: %1 Minimize Minimaliseer - - Obfuscation - Verduistering - per kilobyte per kilobyte + + Custom: + Aangepast: + Confirmation time: Bevestigingstijd: @@ -1934,16 +2085,16 @@ MultiSend: %1 Aanbevolen - S&end - V&erzonden + Send + Verzonden - Clear &All - Verwijder &Alles + Clear All + Verwijder Alles - SwiftTX - SwiftTX + SwiftX + SwiftX Balance: @@ -1973,14 +2124,58 @@ MultiSend: %1 Copy priority Kopieer prioriteit + + Copy change + Kopieer wisselgeld + using gebruikt + + anonymous funds + anonieme financiën + + + Warning: Invalid Bulwark address + Waarschuwing: Ongeldig Bulwark adres + + + any available funds (not recommended) + elke beschikbare fonds (niet aanbevolen) + + + and SwiftX + en SwiftX + + + %1 to %2 + %1 naar %2 + + + Are you sure you want to send? + Ben je zeker dat je wilt verzenden? + + + Total Amount = <b>%1</b><br />= %2 + Totale hoeveelheid = <b>%1 </b><br />= %2 + Confirm send coins Bevestig verzending coins + + The recipient address is not valid, please recheck. + Het ontvangstadres is niet geldig, controleer deze. + + + Pay only the minimum fee of %1 + Betaal alleen de minimumkost van %1 + + + Warning: Unknown change address + Waarschuwing: Ongekend wisselgeld adres + (no label) (geen label) @@ -1989,8 +2184,16 @@ MultiSend: %1 SendCoinsEntry - Pay &To: - Betaal &Naar: + This is a normal payment. + Dit is een normale betaling. + + + Pay To: + Betaal Naar: + + + The Bulwark address to send the payment to + Het Bulwark adres om de betaling naar te verzenden Choose previously used address @@ -2008,10 +2211,22 @@ MultiSend: %1 Alt+P Alt+P + + Label: + Label: + + + Amount: + Hoeveelheid: + Message: Bericht: + + This is an unverified payment request. + Dit is een ongeverifieerde betalingsverzoek. + Pay To: Betaal aan: @@ -2020,19 +2235,35 @@ MultiSend: %1 Memo: Memo: - + + This is a verified payment request. + Dit is een geverifieerd betalingsverzoek. + + + Enter a label for this address to add it to your address book + Voer een label in voor dit adres om het toe te voegen aan jouw adresboek + + ShutdownWindow Bulwark Core is shutting down... Bulwark Core is aan het afsluiten... - + + Do not shut down the computer until this window disappears. + Sluit de computer niet af voordat dit venster verdwenen is. + + SignVerifyMessageDialog - &Sign Message - &Onderteken Bericht + Signatures - Sign / Verify a Message + Handtekeningen - Onderteken / Verifieer een Bericht + + + Sign Message + Onderteken Bericht The Bulwark address to sign the message with @@ -2078,22 +2309,34 @@ MultiSend: %1 Verify the message to ensure it was signed with the specified Bulwark address Controleer een bericht om te verifiëren dat het ondertekend is door het gespecificeerde Bulwark adres + + Sign Message + Onderteken Bericht + Reset all sign message fields Maak alle ondertekenvelden leeg - Clear &All - Verwijder &Alles + Clear All + Verwijder Alles - Verify &Message - Verifeer &Message + Verify Message + Verifieer Bericht + + + Verify Message + Verifeer Message Reset all verify message fields Maak alle verifiëren van het bericht velden leeg + + Click "Sign Message" to generate signature + Klik op "Onderteken Bericht" om een handtekening te genereren + The entered address is invalid. Het ingevoerde adres is ongeldig. @@ -2317,6 +2560,10 @@ MultiSend: %1 Sent to Verzenden naar + + Payment to yourself + Betaling naar jezelf + Obfuscated Verduisterd @@ -2372,6 +2619,10 @@ MultiSend: %1 Other Andere + + Enter address or label to search + Adres of label invullen om te zoeken + Min amount Minimale hoeveelheid @@ -2396,6 +2647,14 @@ MultiSend: %1 Edit label Label wijzigen + + Show transaction details + Bekijk transactiedetails + + + Export Transaction History + Exporteer Transactiegeschiedenis + Comma separated file (*.csv) Kommagescheiden bestand (*.csv) @@ -2432,6 +2691,10 @@ MultiSend: %1 Exporting Successful Exporteren succesvol + + Range: + Bereik: + to naar @@ -2457,8 +2720,8 @@ MultiSend: %1 WalletView - &Export - &Exporteren + Export + Exporteren Export the data in the current tab to a file @@ -2472,6 +2735,10 @@ MultiSend: %1 Backup Wallet Backup portemonnee + + Wallet Data (*.dat) + Portemonneegegevens (*.dat) + Backup Failed Backup mislukt @@ -2480,7 +2747,38 @@ MultiSend: %1 Backup Successful Backup Succesvol - + + The wallet data was successfully saved to %1. + De portemonneegegevens zijn succesvol opgeslagen op %1. + + + + ZBwkControlDialog + + Select zBWK to Spend + Selecteer zBWK om te spenderen + + + Quantity + Hoeveelheid + + + 0 + 0 + + + zBWK + zBWK + + + Select/Deselect All + Selecteer/Deselecteer Alles + + + Is Spendable + Is Uitgeefbaar + + bulwark-core @@ -2511,17 +2809,261 @@ MultiSend: %1 Copyright (C) 2017-%i The Bulwark Core Developers Copyright (C) 2017-%i The Bulwark Core Ontwikkelaars + + (default: %s) + (standaard: %s) + + + (default: 1) + (standaard: 1) + + + Block creation options: + Block creatie opties: + + + Can't find random Masternode. + Kan geen willekeurige Masternode vinden. + + + Cannot downgrade wallet + Kan de portemonnee niet downgraden + + + Collateral not valid. + Terugbetaling niet geldig. + + + Connection options: + Connectie opties: + + + Copyright (C) 2009-%i The Bitcoin Core Developers + Copyright (C) 2009-%i The Bitcoin Core Ontwikkelaars + + + Copyright (C) 2014-%i The Dash Core Developers + Copyright (C) 2014-%i The Dash Core Ontwikkelaars + + + Copyright (C) 2015-%i The PIVX Core Developers + Copyright (C) 2015-%i The PIVX Core Ontwikkelaars + + + Debugging/Testing options: + Debugging/Test opties: + + + Done loading + Klaar met laden + + + Error loading block database + Error tijdens het laden van de block database + + + Error loading wallet.dat + Error tijdens het laden van wallet.dat + + + Error loading wallet.dat: Wallet corrupted + Error tijdens het laden van wallet.dat: Portemonnee corrupt + + + Error opening block database + Error tijdens het openen van de block database + + + Error reading from database, shutting down. + Error tijdens het lezen van de database, aan het afsluiten. + Error Error + + Error: Disk space is low! + Error: Schijfruimte is laag! + + + Failed to read block + Mislukt om block te lezen + + + Finalizing transaction. + Transactie aan het voltooien. + + + Found enough users, signing ( waiting %s ) + Genoeg gebruikers gevonden, aan het ondertekenen (%s aan het wachten) + + + Found enough users, signing ... + Genoeg gebruikers gevonden, aan het ondertekenen ... + + + Importing... + Importeren... + + + Incompatible mode. + Modus is niet compatibel. + + + Incompatible version. + Versie is niet compatibel. + + + Incorrect or no genesis block found. Wrong datadir for network? + Het genesis block kan niet worden gevonden of is incorrect. Klopt datadir voor het netwerk? + Information Informatie + + Input is not valid. + Ongeldige invoer. + + + Insufficient funds. + Onvoldoende saldo. + + + Invalid amount + Ongeldige hoeveelheid + + + Invalid private key. + Ongeldige privésleutel. + + + Invalid script detected. + Ongeldige script gedetecteerd. + + + <category> can be: + <category>kan zijn: + + + Loading wallet... + Portemonnee aan het laden... + + + Masternode options: + Masternode opties: + + + Masternode queue is full. + Masternode wachtrij zit vol. + + + Masternode: + Masternode: + + + Mixing in progress... + Bezig met mixen... + + + No Masternodes detected. + Geen Masternodes gedetecteerd. + + + Node relay options: + Node relay opties: + + + Not in the Masternode list. + Niet in de Masternode lijst. + + + Options: + Opties: + + + Password for JSON-RPC connections + Wachtwoord voor JSON-RPC connecties + + + RPC server options: + RPC server opties: + + + Session not complete! + Sessie niet voltooid! + + + Signing failed. + Ondertekenen mislukt. + + + Staking options: + Staking opties: + + + SwiftX options: + SwiftX opties: + + + This is experimental software. + Dit is experimentele software. + + + This is not a Masternode. + Dit is geen Masternode. + + + Transaction fees are too high. + Transactiekosten zijn te hoog. + + + Transaction not valid. + Transactie is niet geldig. + + + Transaction too large + Transactie te groot + + + Use the test network + Gebruik het test netwerk + + + Wallet is locked. + Portemonnee is vergrendeld. + + + Wallet options: + Portemonnee opties: + + + Wallet window title + Portemonnee venster titel + Warning Waarschuwing + + Warning: This version is obsolete, upgrade required! + Waarschuwing: Deze versie is verouderd, upgrade vereist! + + + ZeroMQ notification options: + ZeroMQ notificatie opties: + + + Zerocoin options: + Zerocoin opties: + + + failed to validate zerocoin + mislukt om zerocoin te valideren + + + on startup + tijdens het opstarten + diff --git a/src/qt/locale/bulwark_pl.ts b/src/qt/locale/bulwark_pl.ts index 79efadfd1..e442e370f 100644 --- a/src/qt/locale/bulwark_pl.ts +++ b/src/qt/locale/bulwark_pl.ts @@ -10,11 +10,11 @@ Stwórz nowy adres - &New + New Nowy - &Copy + Copy Kopiuj @@ -22,15 +22,15 @@ Usuń zaznaczony adres z listy - &Delete + Delete Usuń - &Export + Export Eksportuj - C&lose + Close Zamknij @@ -42,7 +42,7 @@ Wybierz adres do otrzymania monet - C&hoose + Choose Wybierz @@ -54,16 +54,16 @@ Adres odbiorczy - &Copy Address - &Kopiuj adres + Copy Address + Kopiuj adres - Copy &Label - Kopiuj &Zakładkę + Copy Label + Kopiuj Zakładkę - &Edit - &Edytuj + Edit + Edytuj Export Address List @@ -195,7 +195,7 @@ Narzędzie BIP 38 - &BIP 38 Encrypt + BIP 38 Encrypt Zakoduj BIP 38 @@ -231,16 +231,16 @@ Zatwierdź wiadomość, aby udowodnić, że podany adres Bulwark jest w twoim posiadaniu - Encrypt &Key - Kodowanie &klucz + Encrypt Key + Kodowanie klucz - Clear &All - Wyczyść &Wszystko + Clear All + Wyczyść Wszystko - &BIP 38 Decrypt - &BIP 38 Zakoduj + BIP 38 Decrypt + BIP 38 Zakoduj Reset all verify message fields @@ -326,31 +326,31 @@ Node - &Overview - &Przegląd + Overview + Przegląd Show general overview of wallet Pokaż generalny przegląd portfela - &Send - &Wyślij + Send + Wyślij - &Receive - &Otrzymaj + Receive + Otrzymaj - &Transactions - &Transakcje + Transactions + Transakcje Browse transaction history Przeglądaj historię transakcji - E&xit + Exit Wyjdź @@ -358,87 +358,87 @@ Wyjdź z aplikacji - About &Qt - O &Qt + About Qt + O Qt Show information about Qt Pokaż więcej informacji o Qt - &Options... - &Opcje + Options... + Opcje - &Show / Hide - &Pokaż/Ukryj + Show / Hide + Pokaż/Ukryj Show or hide the main Window Pokaż lub ukryj główne okno - &Encrypt Wallet... - &Zakoduj portfel + Encrypt Wallet... + Zakoduj portfel Encrypt the private keys that belong to your wallet Zakoduj prywatne klucze, które należą do twojego portfela - &Backup Wallet... - &Kopia zapasowa portfela + Backup Wallet... + Kopia zapasowa portfela Backup wallet to another location - &Kopia zapasowa portfela z innej lokacji + Kopia zapasowa portfela z innej lokacji - &Change Passphrase... - &Zmień hasło + Change Passphrase... + Zmień hasło Change the passphrase used for wallet encryption Zmień hasło do zakodowania portfela - &Unlock Wallet... - &Odblokuj portfel + Unlock Wallet... + Odblokuj portfel Unlock wallet Odblokuj portfel - &Lock Wallet - &Zablokuj portfel + Lock Wallet + Zablokuj portfel - Sign &message... - &Zatwierdź wiadomość + Sign message... + Zatwierdź wiadomość - &Verify message... - &Zweryfikuj wiadomość + Verify message... + Zweryfikuj wiadomość - &Information - &Informacje + Information + Informacje Show diagnostic information Pokaż informacje diagnostyczne - &Debug console - &Konsola debugowania + Debug console + Konsola debugowania Open debugging console Otwórz konsolę debugowania - &Network Monitor + Network Monitor Monitor sieci @@ -446,16 +446,16 @@ Pokaż monitor sieci - &Peers list - &Lista peersów + Peers list + Lista peersów Show peers info Pokaż informacje peersów - Wallet &Repair - Portfel &Napraw + Wallet Repair + Portfel Napraw Show wallet repair options @@ -466,60 +466,60 @@ Otwórz plik konfiguracji - Show Automatic &Backups - Pokaż automatyczne &Kopie zapasowe + Show Automatic Backups + Pokaż automatyczne Kopie zapasowe Show automatically created wallet backups Pokaż automatycznie stworzone kopie zapasowe portfela - &Sending addresses... - &Adres wysyłki + Sending addresses... + Adres wysyłki Show the list of used sending addresses and labels Pokaż listę używanych adresów i zakładek do wysyłania - &Receiving addresses... - &Adres odbiorczy + Receiving addresses... + Adres odbiorczy Show the list of used receiving addresses and labels Pokaż listę używanych adresów odbiorczych i zakładek - Open &URI... - Otwórz &URL + Open URI... + Otwórz URL - &Command-line options - &Opcje Command-line + Command-line options + Opcje Command-line Synchronizing additional data: %p% Synchronizacja dodatkowych danych %p% - &File - &Plik + File + Plik - &Settings - &Ustawienia + Settings + Ustawienia - &Tools - &Narzędzia + Tools + Narzędzia - &Help - &Pomoc + Help + Pomoc Bulwark Core - &Rdzeń bitcoin + Rdzeń bitcoin Send coins to a Bulwark address @@ -530,16 +530,16 @@ Zarządaj płatności (generuje kod QR i bulwark:URI) - &Masternodes - &Masternodes + Masternodes + Masternodes Browse masternodes Przeglądaj masternodes - &About Bulwark Core - &O rdzeniu bitcoina + About Bulwark Core + O rdzeniu bitcoina Show information about Bulwark Core @@ -558,36 +558,36 @@ Zweryfikuj wiadomości by upewnić się, że zostały zatwierdzone z podanego adresu Bulwark - &BIP38 tool - &BIP 38 narzędzie + BIP38 tool + BIP 38 narzędzie Encrypt and decrypt private keys using a passphrase Zakoduj i odkoduj prywatne klucze używając hasła - &MultiSend - &MultiWysyłanie + MultiSend + MultiWysyłanie MultiSend Settings Opcje MultiWysyłania - Open Wallet &Configuration File - Otwórz portfel &Plik Konfiguracji + Open Wallet Configuration File + Otwórz portfel Plik Konfiguracji - Open &Masternode Configuration File - Otwórz &Plik konfiguracji Masternode + Open Masternode Configuration File + Otwórz Plik konfiguracji Masternode Open a Bulwark: URI or payment request Otwórz Bulwark: URI i żądanie zapłaty - &Blockchain explorer - &Eksplorer blockchain + Blockchain explorer + Eksplorer blockchain Block explorer window @@ -846,10 +846,6 @@ MultiWysyłlka: %1 medium-high Średnio-wysoki - - n/a - n/a - medium średni @@ -917,7 +913,7 @@ MultiWysyłlka: %1 HelpMessageDialog Bulwark Core - &Rdzeń bitcoin + Rdzeń bitcoin @@ -932,7 +928,7 @@ MultiWysyłlka: %1 Bulwark Core - &Rdzeń bitcoin + Rdzeń bitcoin Error @@ -978,24 +974,24 @@ MultiWysyłlka: %1 Klucz publiczny - S&tart alias + Start alias Start alias - Start &all - Start &Wszystkie + Start all + Start Wszystkie - Start &MISSING - Start &Brakujące + Start MISSING + Start Brakujące - &Update status - &Status aktualizacji + Update status + Status aktualizacji Status will be updated automatically in (sec): - Status będzie uaktualniany automatycznie w sekundach + Status będzie uaktualniany automatycznie (w sekundach) 0 @@ -1168,19 +1164,19 @@ Proszę sprawdzić adres i spróbować ponownie Opcje - &Main - &Główne + Main + Główne - Size of &database cache - Rozmiar &bazy danych cache + Size of database cache + Rozmiar bazy danych cache MB MB - W&allet + Wallet Portfel @@ -1196,19 +1192,15 @@ Proszę sprawdzić adres i spróbować ponownie Automatycznie uruchom Bulwark po zalogowaniu do systemu - &Start Bulwark on system login - &Uruchom Bulwark podczas logowania do systemu - - - Amount of Bulwark to keep anonymized - Liczba Bulwark do anonimizacji + Start Bulwark on system login + Uruchom Bulwark podczas logowania do systemu Whether to show coin control features or not. Czy pokazać cechy kontroli monety czy nie - Enable coin &control features + Enable coin control features Włącz cechy kontroli monety @@ -1216,8 +1208,8 @@ Proszę sprawdzić adres i spróbować ponownie Pokaż Masternode Tab - &Network - &Sieć + Network + Sieć The user interface language can be set here. This setting will take effect after restarting Bulwark. @@ -1234,40 +1226,40 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Połącz z siecią Bulwark poprzez SOCKS5 proxy. - Proxy &IP: - Proxy &IP + Proxy IP: + Proxy IP IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) Adres IP proxy (np. IPv4: 127.0.0.1 / IPv6: ::1) - &Port: - &Port + Port: + Port Port of the proxy (e.g. 9050) Port proxy (np. 9050) - &Window - &Okno + Window + Okno - &Display - &Pokaz + Display + Pokaz - User Interface &language: - Interfejs użytkownika &Język. + User Interface language: + Interfejs użytkownika Język. User Interface Theme: Motyw interfejsu użytkownika: - &Unit to show amounts in: - &Pokaż wartości w: + Unit to show amounts in: + Pokaż wartości w: Choose the default subdivision unit to show in the interface and when sending coins. @@ -1282,16 +1274,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Zresetuj wszystkie ustawienia by przywrócić ustawienia domyślne - &Reset Options - &Opcje resetowania + Reset Options + Opcje resetowania - &OK - &OK + OK + OK - &Cancel - &Anuluj + Cancel + Anuluj default @@ -1344,10 +1336,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Immature: Niedojrzały - - Balances - Balans - Total: Całość: @@ -1369,88 +1357,103 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Możliwy do wysłania: - Status: - Status: + Recent transactions + Ostatnie transakcje - 0 BWK / 0 Rounds - 0 OIVX / 0 Rund + out of sync + Brak synchronizacji + + + PaymentServer - Enabled/Disabled - Włączony/Wyłączony + Payment request error + BŁĄD żądania płatności - Completion: - Ukończono: + Payment request has expired. + Żadanie płatności straciło ważność - Amount and Rounds: - Liczba i rundy: + Payment request is not initialized. + Żądanie płatności nie zainicjowane + + + PeerTableModel - n/a - n/a + Version + Wersja - Recent transactions - Ostatnie transakcje + Ping Time + Czas PinguCzas pingu + + + PrivacyDialog - Try Mix - Wypróbuj MIX + 0 + 0 Reset Resetuj - out of sync - Brak synchronizacji + Amount: + Liczba: - Disabled - Wyłączony + Choose previously used address + Wybierz poprzednio używany adres - Anonymized - Zanonimizowany + Alt+A + Alt+A - Enabled - Włączony + Paste address from clipboard + Wklej adres ze schowka - N/A - N/A + Alt+P + Alt+P - - - PaymentServer - Payment request error - BŁĄD żądania płatności + Priority: + Priorytet: - Payment request has expired. - Żadanie płatności straciło ważność + Fee: + Opłata: - Payment request is not initialized. - Żądanie płatności nie zainicjowane + no + nie - - - PeerTableModel - Version - Wersja + medium + średni - Ping Time - Czas Pingu + Change: + Zmiana: - + + out of sync + Brak synchronizacji + + + Copy quantity + Kopiuj ilość + + + Copy amount + Kopiuj liczbę + + QObject @@ -1501,12 +1504,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations QRImageWidget - &Save Image... - &Zapisz obrazek + Save Image... + Zapisz obrazek - &Copy Image - &Kopiuj obrazek + Copy Image + Kopiuj obrazek Save QR Code @@ -1524,8 +1527,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Okno narzędzi - &Information - &Informacje + Information + Informacje General @@ -1544,8 +1547,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Liczba połączeń - &Open - &Otwórz + Open + Otwórz Startup time @@ -1592,20 +1595,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Liczba Masternode - &Console - &Konsola + Console + Konsola Clear console Wyczyść konsolę - &Network Traffic - &Ruch sieci + Network Traffic + Ruch sieci - &Clear - &Wyczyść& + Clear + Wyczyść Totals @@ -1620,8 +1623,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Wysłano - &Peers - &Peers + Peers + Peers Select a peer to view detailed information. @@ -1673,11 +1676,11 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Ping Time - Czas Pingu + Czas PinguCzas pingu - &Wallet Repair - &Napraw portfel + Wallet Repair + Napraw portfel Salvage wallet @@ -1743,8 +1746,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations ReceiveCoinsDialog - &Message: - &Wiadomość: + Message: + Wiadomość: Copy label @@ -1758,8 +1761,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations ReceiveRequestDialog - &Save Image... - &Zapisz obrazek + Save Image... + Zapisz obrazek Address @@ -1824,8 +1827,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Zmiana: - Clear &All - Wyczyść &Wszystko + Clear All + Wyczyść Wszystko Copy quantity @@ -1901,8 +1904,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations Zatwierdź wiadomość, aby udowodnić, że podany adres Bulwark jest w twoim posiadaniu - Clear &All - Wyczyść &Wszystko + Clear All + Wyczyść Wszystko Reset all verify message fields @@ -1933,7 +1936,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations SplashScreen Bulwark Core - &Rdzeń bitcoin + Rdzeń bitcoin @@ -2019,10 +2022,17 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations WalletView - &Export + Export Eksportuj + + ZBwkControlDialog + + 0 + 0 + + bulwark-core diff --git a/src/qt/locale/bulwark_pt.ts b/src/qt/locale/bulwark_pt.ts index 43d287123..7b4480ecd 100644 --- a/src/qt/locale/bulwark_pt.ts +++ b/src/qt/locale/bulwark_pt.ts @@ -10,7 +10,7 @@ Criar novo endereço - &New + New Novo @@ -18,28 +18,28 @@ Copiar o endereço selecionado para a área de transferência - &Copy - &Copiar + Copy + Copiar Delete the currently selected address from the list Deletar da lista o endereço selecionado - &Delete - &Excluir + Delete + Excluir Export the data in the current tab to a file Exporta os dados da aba ativa para um arquivo - &Export - &Exportar + Export + Exportar - C&lose - &Fechar + Close + Fechar Choose the address to send coins to @@ -50,8 +50,8 @@ Escolha o endereço para receber moedas - C&hoose - Escol&her + Choose + Escolher Sending addresses @@ -70,16 +70,16 @@ Esses são seus endereços Bulwark para receber pagamentos. É recomendado usar um novo endereço para cada transação. - &Copy Address - C&opiar endereço + Copy Address + Copiar endereço - Copy &Label - Cop&iar Descrição + Copy Label + Copiar Descrição - &Edit - &Editar + Edit + Editar Export Address List @@ -235,8 +235,8 @@ BIP 38 - &BIP 38 Encrypt - Encriptar com &BIP 38 + BIP 38 Encrypt + Encriptar com BIP 38 Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -283,7 +283,7 @@ Assinar a Mensagem para provar que você e dono desse endereço Bulwark. - Encrypt &Key + Encrypt Key Criptografar Chave @@ -291,11 +291,11 @@ Reiniciar todas os campos das mensagens assinadas - Clear &All + Clear All Limpar todos - &BIP 38 Decrypt + BIP 38 Decrypt Criptografia BIP 38 @@ -334,19 +334,19 @@ - &Send - &Enviar + Send + Enviar - &Receive - &Receber + Receive + Receber - &Transactions - &Transações + Transactions + Transações - &Backup Wallet... + Backup Wallet... Carteira de backup @@ -451,6 +451,41 @@ PeerTableModel + + PrivacyDialog + + Amount: + Quantidade: + + + Choose previously used address + Escolha o endereço usado anteriormente. + + + Alt+A + Alt+A + + + Paste address from clipboard + Cole o endereço da areá de trabalho. + + + Alt+P + Alt+P + + + Priority: + Prioridade: + + + Fee: + Taxa: + + + no + não + + QObject @@ -556,7 +591,7 @@ Limpar todos os campos do formulário - Clear &All + Clear All Limpar todos @@ -677,7 +712,7 @@ Reiniciar todas os campos das mensagens assinadas - Clear &All + Clear All Limpar todos @@ -855,8 +890,8 @@ WalletView - &Export - &Exportar + Export + Exportar Export the data in the current tab to a file @@ -867,6 +902,9 @@ Quantia selecionada: + + ZBwkControlDialog + bulwark-core @@ -874,8 +912,8 @@ Deletar todas as transações da carteira e somente recuperar aquelas partes do blockchain através de -rescan na inicialização - Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftTX, Budgeting) (0-1, default: %u) - Desabilitar todas as funcionacilidades específicas da Bulwark (Masternodes, Ofuscação, SwiftTX, Budgeting) (0-1, default %u) + Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftX, Budgeting) (0-1, default: %u) + Desabilitar todas as funcionacilidades específicas da Bulwark (Masternodes, Ofuscação, SwiftX, Budgeting) (0-1, default %u) Connect through SOCKS5 proxy @@ -929,10 +967,6 @@ No compatible Masternode found. Nenhum Masternode compatível encontrado. - - Obfuscation options: - Opções de ofuscação: - Obfuscation request complete: Requisição de ofuscação completa: @@ -1094,8 +1128,8 @@ Enviado para masternode, esperando na fila %s - SwiftTX options: - Opções SwiftTX: + SwiftX options: + Opções SwiftX: Synchronization failed @@ -1197,10 +1231,6 @@ Upgrade wallet to latest format Atualizar a carteira para a ultimo formato - - Use N separate masternodes to anonymize funds (2-8, default: %u) - Use N masternodes separados para anonimizar fundos (2-8, padrão: %u) - Use OpenSSL (https) for JSON-RPC connections Use o OpenSSL(https) para conexões JSON-RPC diff --git a/src/qt/locale/bulwark_pt_BR.ts b/src/qt/locale/bulwark_pt_BR.ts index 1a6c4ad23..80b166f94 100644 --- a/src/qt/locale/bulwark_pt_BR.ts +++ b/src/qt/locale/bulwark_pt_BR.ts @@ -10,36 +10,36 @@ Criar um novo endereço - &New - &Novo + New + Novo Copy the currently selected address to the system clipboard Copiar o endereço selecionado para a área de transferência - &Copy - &Copiar + Copy + Copiar Delete the currently selected address from the list Deletar da lista o endereço selecionado - &Delete - &Deletar + Delete + Deletar Export the data in the current tab to a file Exportar as informações da aba atual para um arquivo - &Export - &Exportar + Export + Exportar - C&lose - &Fechar + Close + Fechar Choose the address to send coins to @@ -50,8 +50,8 @@ Escolha o endereço para receber moedas - C&hoose - &Selecionar + Choose + Selecionar Sending addresses @@ -70,16 +70,16 @@ Esses são seus endereços Bulwark para recebimento de pagamentos. É recomendado usar um novo endereço para cada transação. - &Copy Address - &Copiar endereço + Copy Address + Copiar endereço - Copy &Label - Copiar &Rotular + Copy Label + Copiar Rotular - &Edit - &Alterar + Edit + Alterar Export Address List @@ -231,8 +231,8 @@ Ferramenta da BIP 38 - &BIP 38 Encrypt - &Encriptação BIP 38 + BIP 38 Encrypt + Encriptação BIP 38 Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -279,7 +279,7 @@ Assine a mensagem para provar que você possui este endereço Bulwark - Encrypt &Key + Encrypt Key Chave encriptada: @@ -287,8 +287,8 @@ Reiniciar todos os campos de mensagem - Clear &All - Limpar &Tudo + Clear All + Limpar Tudo The Bulwark address the message was signed with @@ -299,8 +299,8 @@ Verifique a mensagem para ter certeza que foi assinada com o endereço Bulwark especificado. - Decrypt &Key - Descriptografar &Chave + Decrypt Key + Descriptografar Chave Reset all verify message fields @@ -390,136 +390,136 @@ - &Overview - &Visão Geral + Overview + Visão Geral Show general overview of wallet Mostrar visão geral da carteira - &Send - &Enviar + Send + Enviar - &Receive - &Receber + Receive + Receber - &Transactions - &Transações + Transactions + Transações Browse transaction history Olhar histórico de transação - E&xit - &Sair + Exit + Sair Quit application Sair da aplicação - About &Qt - Sobre &Qt + About Qt + Sobre Qt Show information about Qt Mostrar informação sobre Qt - &Options... - &Opções... + Options... + Opções... - &Show / Hide - &Mostrar / Esconder + Show / Hide + Mostrar / Esconder Show or hide the main Window Mostrar ou esconder a janela principal - &Encrypt Wallet... - &Criptografar carteira + Encrypt Wallet... + Criptografar carteira Encrypt the private keys that belong to your wallet Criptografar as chaves privadas que pertencem à sua carteira - &Backup Wallet... - &Carteira de backup... + Backup Wallet... + Carteira de backup... Backup wallet to another location Backup da carteira em outro local - &Change Passphrase... - &Alterar palavra-chave... + Change Passphrase... + Alterar palavra-chave... Change the passphrase used for wallet encryption Altera a palavra-chave utilizada para encriptação da carteira - &Unlock Wallet... - &Destravar carteira... + Unlock Wallet... + Destravar carteira... Unlock wallet Desbloquear carteira - &Lock Wallet - &Travar carteira + Lock Wallet + Travar carteira - Sign &message... - Assinar &mensagem... + Sign message... + Assinar mensagem... - &Verify message... - &Verificar mensagem... + Verify message... + Verificar mensagem... - &Information - &Informação + Information + Informação Show diagnostic information Mostrar informação de diagnóstico - &Debug console - &Debug console + Debug console + Debug console Open debugging console Abra o console de Debug - &Network Monitor - &Monitor de rede + Network Monitor + Monitor de rede Show network monitor Mostrar monitor de rede - &Peers list - &Lista de pares + Peers list + Lista de pares Show peers info Mostrar informação da lista de pares - Wallet &Repair - Carteira &Reparo + Wallet Repair + Carteira Reparo Show wallet repair options @@ -530,56 +530,56 @@ Abrir arquivo de configuração - Show Automatic &Backups - Mostrar &Backups automáticos + Show Automatic Backups + Mostrar Backups automáticos Show automatically created wallet backups Mostrar backups de carteira criados automaticamente - &Sending addresses... - &Endereços de envio... + Sending addresses... + Endereços de envio... Show the list of used sending addresses and labels Mostrar a lista de endereços de envio e rótulos utilizados - &Receiving addresses... - &Endereços de recebimento... + Receiving addresses... + Endereços de recebimento... Show the list of used receiving addresses and labels Mostrar a lista de endereços de recebimento e rótulos utilizados - Open &URI... - Abrir &URI... + Open URI... + Abrir URI... - &Command-line options - &Opções de linha de comando + Command-line options + Opções de linha de comando Synchronizing additional data: %p% Sincronizando informação adicional: %p% - &File - &Arquivo + File + Arquivo - &Settings - &Configurações + Settings + Configurações - &Tools - &Ferramentas + Tools + Ferramentas - &Help - &Ajuda + Help + Ajuda Tabs toolbar @@ -598,16 +598,16 @@ Requisitar pagamentos (gera códigos QR e bulwark: URIs) - &Masternodes - &Masternodes + Masternodes + Masternodes Browse masternodes Procurar masternodes - &About Bulwark Core - &Sobre o Bulwark Core + About Bulwark Core + Sobre o Bulwark Core Show information about Bulwark Core @@ -626,28 +626,28 @@ Verifique as mensagens para ter certeza que estão assinadas com os endereços Bulwark especificados - &BIP38 tool - &Ferramenta da BIP38 + BIP38 tool + Ferramenta da BIP38 Encrypt and decrypt private keys using a passphrase Criptografar e descriptografar chaves privadas usando uma palavra-chave - &MultiSend - &MultiSend + MultiSend + MultiSend MultiSend Settings Configurações MultiSend - Open Wallet &Configuration File - Abrir arquivo de &Configuração de Carteira + Open Wallet Configuration File + Abrir arquivo de Configuração de Carteira - Open &Masternode Configuration File - Abrir arquivo de Configuração de &Masternode + Open Masternode Configuration File + Abrir arquivo de Configuração de Masternode Open Masternode configuration file @@ -658,8 +658,8 @@ Abrir um Bulwark: URI ou requisição de pagamento - &Blockchain explorer - Explorador da &Blockchain + Blockchain explorer + Explorador da Blockchain Block explorer window @@ -955,10 +955,6 @@ MultiSend: %1 Please switch to "List mode" to use this function. Favor alterar para o "Modo de lista" para usar esta função. - - Non-anonymized input selected. <b>Obfuscation will be disabled.</b><br><br>If you still want to use Obfuscation, please deselect all non-nonymized inputs first and then check Obfuscation checkbox again. - Input não-anonimizado selecionado. <b>Ofuscação será desabilitada.</b><br><br> Se você ainda quiser usar a Ofuscação, favor desmarcar todos os inputs não anônimos primeiro e então marque a opção de Ofuscação novamente. - highest mais alto @@ -979,10 +975,6 @@ MultiSend: %1 Can vary +/- %1 duff(s) per input. pode variar entre +/-%1 duff(s) por input - - n/a - n/a - medium médio @@ -1063,16 +1055,16 @@ MultiSend: %1 Alterar endereço - &Label - &Rótulo + Label + Rótulo The label associated with this address list entry Rótulo referente a essa entrada na lista de endereços - &Address - &Endereço + Address + Endereço The address associated with this address list entry. This can only be modified for sending addresses. @@ -1263,12 +1255,12 @@ MultiSend: %1 Pubkey - S&tart alias + Start alias iniciar apelido - &Update status - &Atualizar situação + Update status + Atualizar situação Status will be updated automatically in (sec): @@ -1534,12 +1526,12 @@ Favor verificar o endereço e tente novamente. Opções - &Main - &Principal + Main + Principal - Size of &database cache - Tamanho do cachê da &basededados + Size of database cache + Tamanho do cachê da basededados MB @@ -1550,8 +1542,8 @@ Favor verificar o endereço e tente novamente. (0 = auto, <0 = deixe esse tanto de núcleos livres) - W&allet - C&arteira + Wallet + Carteira Automatically open the Bulwark client port on the router. This only works when your router supports UPnP and it is enabled. @@ -1566,8 +1558,8 @@ Favor verificar o endereço e tente novamente. Aceitar conexões chegando - &Connect through SOCKS5 proxy (default proxy): - &Conectar através de proxy SOCKS5 (proxy padrão): + Connect through SOCKS5 proxy (default proxy): + Conectar através de proxy SOCKS5 (proxy padrão): Expert @@ -1578,32 +1570,20 @@ Favor verificar o endereço e tente novamente. Iniciar automaticamente Bulwark depois de logar no sistema. - &Start Bulwark on system login - &Iniciar Bulwark ao logar no sistema + Start Bulwark on system login + Iniciar Bulwark ao logar no sistema - This setting determines the amount of individual masternodes that an input will be anonymized through.<br/>More rounds of anonymization gives a higher degree of privacy, but also costs more in fees. - Esta configuração determina a quantidade de masternodes individuais em que um input será feito anônimo. <br/>Mais rodadas de anonimidade darão um grau maior de privacidade, mas também custarão mais em taxas. - - - Obfuscation rounds to use - Rodadas de ofuscação para usar - - - Amount of Bulwark to keep anonymized - Quantidade de Bulwark a manter anônima - - - Enable coin &control features - Habilitar &funcções de controle de moeda + Enable coin control features + Habilitar funcções de controle de moeda Show Masternodes Tab Mostra aba de Masternodes - &Network - &Rede + Network + Rede The user interface language can be set here. This setting will take effect after restarting Bulwark. @@ -1620,52 +1600,52 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsConectar à rede Bulwark através de um proxy SOCKS5 - Proxy &IP: - Proxy &IP: + Proxy IP: + Proxy IP: IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) Endereço IP do proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) - &Port: - &Porta: + Port: + Porta: Port of the proxy (e.g. 9050) Porta do proxy (e.g. 9050) - &Window - &Janela + Window + Janela Show only a tray icon after minimizing the window. Mostrar somente um icone depois de minimizar a janela. - &Minimize to the tray instead of the taskbar - &Minimizar para a bandeja ao invés da barra de tarefas + Minimize to the tray instead of the taskbar + Minimizar para a bandeja ao invés da barra de tarefas - M&inimize on close + Minimize on close Minimizar quando fechar - &Display - &Mostrar + Display + Mostrar - User Interface &language: - Interface do usuário &Linguagem: + User Interface language: + Interface do usuário Linguagem: User Interface Theme: Usar tema de inferface: - &Unit to show amounts in: - &Unidades para mostrar as quantias: + Unit to show amounts in: + Unidades para mostrar as quantias: Choose the default subdivision unit to show in the interface and when sending coins. @@ -1684,16 +1664,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsReiniciar todas as opções do cliente para o padrão. - &Reset Options - &Reiniciar Opções + Reset Options + Reiniciar Opções - &OK - &OK + OK + OK - &Cancel - &Cancel + Cancel + Cancel default @@ -1750,10 +1730,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsImmature: Imaturo: - - Balances - Fundos - The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. A informação mostrada pode estar desatualizada. A sua carteira se sincroniza automaticamente com a rede Bulwark após estabelecer uma conexão, mas esse processo ainda não foi concluído. @@ -1783,182 +1759,167 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsDisponível: - Status: - Situação: - - - Obfuscation Balance: - Saldo ofuscado: - - - 0 BWK / 0 Rounds - 0 BWK / 0 Rodadas + Recent transactions + Transações recentes - Enabled/Disabled - Ativado/Desativado + out of sync + fora de sincronia + + + PaymentServer - Try to manually submit a Obfuscation request. - Tente encaminhar uma requisição manualmente de Ofuscação. + Payment request error + Erro na requisição de pagamento - Reset the current status of Obfuscation (can interrupt Obfuscation if it's in the process of Mixing, which can cost you money!) - Reinicia o presente estado de ofuscação (pode interromper a Ofuscação se estiver em processo de Embaralhamento, o que pode lhe custar dinheiro!) + Payment request fetch URL is invalid: %1 + Pagamento solicitado pela URL é inválido: %1 - Obfuscation - Ofuscação + Invalid payment address %1 + Carteira de pagamento inválida %1 - Completion: - Conclusão: + Payment request rejected + Requisição de pagamento rejeitada - Amount and Rounds: - Quantia e Rodadas: + Payment request has expired. + Requisição de pagamento expirou. - n/a - n/a + Payment request is not initialized. + A requisição de pagamento não está iniciada. - Recent transactions - Transações recentes + Refund from %1 + Reembolso de %1 - Start/Stop Mixing - Iniciar/Parar embaralhamento + Error communicating with %1: %2 + Erro ao comunicar com %1: %2 - (Last Message) - (Última mensagem) + Network request error + Erro na requisição de rede + + + PeerTableModel - Try Mix - Tente embaralhar + Version + Versão - Reset - Reinicia + Ping Time + Tempo de resposta + + + PrivacyDialog - out of sync - fora de sincronia + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + A informação mostrada pode estar desatualizada. A sua carteira se sincroniza automaticamente com a rede Bulwark após estabelecer uma conexão, mas esse processo ainda não foi concluído. - Disabled - Desativado + 0 + 0 - No inputs detected - Nenhum input detectado + Reset + Reinicia - Overall progress - Progresso geral + Quantity: + Quantidade: - Denominated - Denominado + Amount: + Quantia: - Anonymized - Anonimizado + Pay To: + Pagar Para: - Last Obfuscation message: - - Última mensagem de ofuscação: - + Choose previously used address + Escolha o endereço previamente utilizado - Obfuscation was successfully reset. - Ofuscação foi reiniciada com sucesso. + Alt+A + Alt+A - Obfuscation requires at least %1 to use. - Ofuscação requer pelo menos %1 para usar. + Paste address from clipboard + Cole o endereço da área de transferência - Wallet is locked and user declined to unlock. Disabling Obfuscation. - A carteira está travada e o usuário recusou o destravamento. Desabilitando a Ofuscação. + Alt+P + Alt+P - Found enough compatible inputs to anonymize %1 - Foram encontrados inputos suficientes para anonimizar %1 + Label: + Rótulo: - Start Obfuscation - Iniciar ofuscação + Enter a label for this address to add it to the list of used addresses + Coloque uma etiqueta neste endereço para adicioná-lo à lista de endereços utilizados - Stop Obfuscation - Parar ofuscação + Amount: + Quantia: - Mixed - Embaralhado + Priority: + Prioridade: - Enabled - Ativado + Fee: + Taxa: - N/A - N/A + no + não - - - PaymentServer - Payment request error - Erro na requisição de pagamento + Bytes: + Bytes: - Payment request fetch URL is invalid: %1 - Pagamento solicitado pela URL é inválido: %1 + Insufficient funds! + Fundos insuficientes! - Invalid payment address %1 - Carteira de pagamento inválida %1 + medium + médio - Payment request rejected - Requisição de pagamento rejeitada + Coin Control Features + Funções do Controle de Moedas - Payment request has expired. - Requisição de pagamento expirou. + Change: + Troco: - Payment request is not initialized. - A requisição de pagamento não está iniciada. + out of sync + fora de sincronia - Refund from %1 - Reembolso de %1 + Copy quantity + Copiar quantidade - Error communicating with %1: %2 - Erro ao comunicar com %1: %2 + Copy amount + Copiar quantia - Network request error - Erro na requisição de rede + Confirm send coins + Confirmar envio de moedas - - PeerTableModel - - Version - Versão - - - Ping Time - Tempo de resposta - - QObject @@ -2009,12 +1970,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations QRImageWidget - &Save Image... - &Salvar imagem... + Save Image... + Salvar imagem... - &Copy Image - &Copiar imagem + Copy Image + Copiar imagem Save QR Code @@ -2028,8 +1989,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations RPCConsole - &Information - &Informação + Information + Informação General @@ -2052,8 +2013,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsNúmero de conexões - &Open - &Abrir + Open + Abrir Startup time @@ -2092,20 +2053,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsNúmero de Masternodes - &Console - &Console + Console + Console Clear console Limpar console - &Network Traffic - &Tráfego da Rede + Network Traffic + Tráfego da Rede - &Clear - &Limpar + Clear + Limpar Totals @@ -2120,8 +2081,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsEnviado - &Peers - &Pares + Peers + Pares Select a peer to view detailed information. @@ -2176,8 +2137,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsTempo de resposta - &Wallet Repair - &Reparo da Carteira + Wallet Repair + Reparo da Carteira Rescan blockchain files @@ -2263,24 +2224,24 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations ReceiveCoinsDialog - &Message: - &Mensagem: + Message: + Mensagem: An optional label to associate with the new receiving address. Um rótulo opcional para associar a novos endereços de recebimento. - &Label: - Rótu&lo: + Label: + Rótulo: - &Amount: - &Quantidade: + Amount: + Quantidade: - &Request payment - &Requisitar pagamento + Request payment + Requisitar pagamento Clear all fields of the form. @@ -2330,12 +2291,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsCódigo QR - Copy &URI - Copiar &URI + Copy URI + Copiar URI - &Save Image... - &Salvar imagem... + Save Image... + Salvar imagem... Request payment to %1 @@ -2415,10 +2376,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsCoin Control Features Funções do Controle de Moedas - - automatically selected - selecionado automaticamente - Insufficient funds! Fundos insuficientes! @@ -2491,10 +2448,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsMinimize Minimizar - - Obfuscation - Ofuscação - per kilobyte por kilobyte @@ -2552,20 +2505,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsLimpa todos os campos do formulário. - Clear &All - Limpar &Tudo + Clear All + Limpar Tudo Send to multiple recipients at once Envia para diversos recipientes de uma vez - Add &Recipient - Adicionar &Recipiente + Add Recipient + Adicionar Recipiente - SwiftTX - SwiftTX + SwiftX + SwiftX Balance: @@ -2616,8 +2569,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsquaisquer fundos disponíveis (não recomendado) - and SwiftTX - e SwiftTX + and SwiftX + e SwiftX %1 to %2 @@ -2699,8 +2652,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsEsse é um pagamento normal. - Pay &To: - Pagar &Para: + Pay To: + Pagar Para: The Bulwark address to send the payment to @@ -2727,15 +2680,15 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsRemova esta entrada - &Label: - &Rótulo: + Label: + Rótulo: Enter a label for this address to add it to the list of used addresses Coloque uma etiqueta neste endereço para adicioná-lo à lista de endereços utilizados - A&mount: + Amount: Quantia: @@ -2781,8 +2734,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsAssinaturas - Assinar / Verificar uma Mensagem - &Sign Message - &Assinar mensagem + Sign Message + Assinar mensagem The Bulwark address to sign the message with @@ -2829,7 +2782,7 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsVerifique a mensagem para ter certeza que foi assinada com o endereço Bulwark especificado. - Sign &Message + Sign Message Você pode assinar mensagens com os seus endereços para provar que você os possui. Cuidado ao assinar mensagens vagas, pois há ataques de phishing que podem tentar te manipular a assinar a sua identidade para eles. Assine apenas mensagens que você esteja ciente e concorde com o conteúdo. @@ -2837,16 +2790,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsReiniciar todos os campos de mensagem - Clear &All - Limpar &Tudo + Clear All + Limpar Tudo - &Verify Message - &Verificar mensagem + Verify Message + Verificar mensagem - Verify &Message - Verificar &Mensagem + Verify Message + Verificar Mensagem Reset all verify message fields @@ -2950,16 +2903,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsconflitou - %1/offline (verified via swifttx) - %1/offline (verificado via swifttx) + %1/offline (verified via SwiftX) + %1/offline (verificado via SwiftX) - %1/confirmed (verified via swifttx) - %1/confirmado (verificado via swifttx) + %1/confirmed (verified via SwiftX) + %1/confirmado (verificado via SwiftX) - %1 confirmations (verified via swifttx) - %1 confirmações (verificado via swifttx) + %1 confirmations (verified via SwiftX) + %1 confirmações (verificado via SwiftX) %1/offline @@ -2974,24 +2927,24 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations%1 confirmações - %1/offline (SwiftTX verification in progress - %2 of %3 signatures) - %1/offline (verificação SwiftTX em progresso - %2 de %3 assinaturas) + %1/offline (SwiftX verification in progress - %2 of %3 signatures) + %1/offline (verificação SwiftX em progresso - %2 de %3 assinaturas) - %1/confirmed (SwiftTX verification in progress - %2 of %3 signatures ) - %1/confirmado (verificação SwiftTX em progresso - %2 de %3 assinaturas) + %1/confirmed (SwiftX verification in progress - %2 of %3 signatures ) + %1/confirmado (verificação SwiftX em progresso - %2 de %3 assinaturas) - %1 confirmations (SwiftTX verification in progress - %2 of %3 signatures) - %1 confirmações (verificação SwiftTX em progresso - %2 de %3 assinaturas) + %1 confirmations (SwiftX verification in progress - %2 of %3 signatures) + %1 confirmações (verificação SwiftX em progresso - %2 de %3 assinaturas) - %1/offline (SwiftTX verification failed) - %1/offline (verificação SwiftTX falhou) + %1/offline (SwiftX verification failed) + %1/offline (verificação SwiftX falhou) - %1/confirmed (SwiftTX verification failed) - %1/confirmado (verificação SwiftTX falhou) + %1/confirmed (SwiftX verification failed) + %1/confirmado (verificação SwiftX falhou) Status @@ -3408,15 +3361,15 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsEnviar Moedas - SwiftTX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. - SwiftTX ainda não suporta o envio de valores altos assim. As transações atualmente são limitadas a %1 BWK. + SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK. + SwiftX ainda não suporta o envio de valores altos assim. As transações atualmente são limitadas a %1 BWK. WalletView - &Export - &Exportar + Export + Exportar Export the data in the current tab to a file @@ -3451,6 +3404,13 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsOs dados da carteira foram salvos em %1 com sucesso. + + ZBwkControlDialog + + 0 + 0 + + bulwark-core @@ -3458,12 +3418,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsDeletar todas as transações da carteira e somente recuperar aquelas partes da blockchain através de -rescan na inicialização - Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftTX, Budgeting) (0-1, default: %u) - Desabilitar todas as funcionalidades específicas Bulwark (Masternodes, Ofuscação, SwiftTX, Budgeting) (0-1, padrão: %u) - - - Enable use of automated obfuscation for funds stored in this wallet (0-1, default: %u) - Permitir o uso de ofuscação automática para fundos armazenados nesta carteira (0-1, padrão: %u) + Disable all Bulwark specific functionality (Masternodes, Obfuscation, SwiftX, Budgeting) (0-1, default: %u) + Desabilitar todas as funcionalidades específicas Bulwark (Masternodes, Ofuscação, SwiftX, Budgeting) (0-1, padrão: %u) Error: Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. @@ -3502,8 +3458,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsDefine o tamanho máximo de transações de alta prioridade/taxa baixa em bytes (padrão: %d) - SwiftTX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. - SwiftTX requer inputs com pelo menos 6 confirmações, você precisar aguardar alguns minutos e tentar novamente. + SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. + SwiftX requer inputs com pelo menos 6 confirmações, você precisar aguardar alguns minutos e tentar novamente. Unable to locate enough funds for this transaction that are not equal 5000 BWK. @@ -3805,10 +3761,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsInvalid script detected. Script inválido detectado. - - Keep N BWK anonymized (default: %u) - Manter N BWK anônimo (padrão: %u) - Last Obfuscation was too recent. Última ofuscação foi muito recente. @@ -3909,10 +3861,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsObfuscation is idle. Ofuscação está ociosa. - - Obfuscation options: - Opções de ofuscação: - Obfuscation request complete: Requisição de ofuscação completa: @@ -4042,8 +3990,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsEnviado ao masternode, aguardando na fila %s - SwiftTX options: - opções SwiftTX: + SwiftX options: + opções SwiftX: Synchronization failed diff --git a/src/qt/locale/bulwark_ro_RO.ts b/src/qt/locale/bulwark_ro_RO.ts index 0ddfe402f..4a74ca125 100644 --- a/src/qt/locale/bulwark_ro_RO.ts +++ b/src/qt/locale/bulwark_ro_RO.ts @@ -10,36 +10,36 @@ Creează o nouă adresă - &New - &Nou/Nouă + New + Nou/Nouă Copy the currently selected address to the system clipboard Copiază adresa selectată în clipboard - &Copy - &Copiază + Copy + Copiază Delete the currently selected address from the list Șterge adresa selectată din listă - &Delete - &Șterge + Delete + Șterge Export the data in the current tab to a file Exportă datele din fila curentă într-un fișier - &Export - &Exportă + Export + Exportă - C&lose - &Închide + Close + Închide Choose the address to send coins to @@ -50,8 +50,8 @@ Alege adresa la care vrei să primești monedele - C&hoose - &Alege + Choose + Alege @@ -111,6 +111,9 @@ PeerTableModel + + PrivacyDialog + QObject @@ -171,14 +174,17 @@ WalletView - &Export - &Exportă + Export + Exportă Export the data in the current tab to a file Exportă datele din fila curentă într-un fișier + + ZBwkControlDialog + bulwark-core diff --git a/src/qt/locale/bulwark_ru.ts b/src/qt/locale/bulwark_ru.ts index c9433ccb3..007b41fb7 100644 --- a/src/qt/locale/bulwark_ru.ts +++ b/src/qt/locale/bulwark_ru.ts @@ -10,36 +10,36 @@ Создать новый адрес - &New - &Новый + New + Новый Copy the currently selected address to the system clipboard Скопировать текущий выбранный адрес в буфер обмена системы - &Copy - &Копировать + Copy + Копировать Delete the currently selected address from the list Удалить текущий выбранный адрес из списка - &Delete - &Удалить + Delete + Удалить Export the data in the current tab to a file Экспортировать данные с текущей вкладки в файл - &Export - &Экспорт + Export + Экспорт - C&lose - З&акрыть + Close + Закрыть Choose the address to send coins to @@ -50,8 +50,8 @@ Выберите адрес для получения монет - C&hoose - В&ыберите + Choose + Выберите Sending addresses @@ -70,16 +70,16 @@ Это ваши Bulwark-адреса для получения платежей. Для каждой транзакции рекомендуется использовать новый адрес получения. - &Copy Address - &Копировать Адрес + Copy Address + Копировать Адрес - Copy &Label - Копировать &Метку + Copy Label + Копировать Метку - &Edit - &Редактировать + Edit + Редактировать Export Address List @@ -231,8 +231,8 @@ BIP 38 Утилита - &BIP 38 Encrypt - &BIP 38 Шифрование + BIP 38 Encrypt + BIP 38 Шифрование Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -279,20 +279,20 @@ Подпишите сообщение, чтобы подтвердить свой адрес Bulwark - Encrypt &Key - Зашифровать &Ключ + Encrypt Key + Зашифровать Ключ Reset all sign message fields Сбросить все поля сообщений - Clear &All - Очистить &Все + Clear All + Очистить Все - &BIP 38 Decrypt - &BIP 38 Дешифрование + BIP 38 Decrypt + BIP 38 Дешифрование Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. @@ -307,8 +307,8 @@ Проверте сообщение, чтобы убедиться, что оно было подписано указанным Bulwark адресом - Decrypt &Key - Дешифровать &Ключ + Decrypt Key + Дешифровать Ключ Reset all verify message fields @@ -398,136 +398,136 @@ Узел - &Overview - &Обзор + Overview + Обзор Show general overview of wallet Общий обзор кошелька - &Send - &Отправить + Send + Отправить - &Receive - &Получить + Receive + Получить - &Transactions - &Транзакции + Transactions + Транзакции Browse transaction history Просмотр истории транзакций - E&xit - В&ыход + Exit + Выход Quit application Завершить работу - About &Qt - О &Qt + About Qt + О Qt Show information about Qt Показать информацию о Qt - &Options... - &Опции... + Options... + Опции... - &Show / Hide - &Показать / Скрыть + Show / Hide + Показать / Скрыть Show or hide the main Window Показать или скрыть основное Окно - &Encrypt Wallet... - &Зашифровать кошелек... + Encrypt Wallet... + Зашифровать кошелек... Encrypt the private keys that belong to your wallet Зашифровать личные ключи, принадлежащие вашему кошельку - &Backup Wallet... - &Резервная копия кошелька... + Backup Wallet... + Резервная копия кошелька... Backup wallet to another location Сделать резервную копию кошелька в другом месте - &Change Passphrase... - &Изменить кодовую фразу + Change Passphrase... + Изменить кодовую фразу Change the passphrase used for wallet encryption Изменение кодовой фразы, используемой для шифрования кошелька - &Unlock Wallet... - &Разблокировать кошелек... + Unlock Wallet... + Разблокировать кошелек... Unlock wallet Снятие блокировки кошелька - &Lock Wallet - &Блокировка кошелька + Lock Wallet + Блокировка кошелька - Sign &message... - Подписать &сообщение... + Sign message... + Подписать сообщение... - &Verify message... - &Проверить сообщение... + Verify message... + Проверить сообщение... - &Information - &Информация + Information + Информация Show diagnostic information Показать диагностическую информацию - &Debug console - &Консоль отладки + Debug console + Консоль отладки Open debugging console Открыть консоль отладки - &Network Monitor - &Сетевой монитор + Network Monitor + Сетевой монитор Show network monitor Показать сетевой монитор - &Peers list - &Список пиров + Peers list + Список пиров Show peers info Показать информацию о пирах - Wallet &Repair - Ремонт &кошелька + Wallet Repair + Ремонт кошелька Show wallet repair options @@ -538,56 +538,56 @@ Открыть файл настроек - Show Automatic &Backups - Показать автоматические &резервные копии + Show Automatic Backups + Показать автоматические резервные копии Show automatically created wallet backups Показать автоматически созданные резервные копии кошелька - &Sending addresses... - &Адреса отправки... + Sending addresses... + Адреса отправки... Show the list of used sending addresses and labels Показать список использованых адресов отправки - &Receiving addresses... - &Адреса получения... + Receiving addresses... + Адреса получения... Show the list of used receiving addresses and labels Показать список использованых адресов приёма - Open &URI... - Открыть &URI + Open URI... + Открыть URI - &Command-line options - &Параметры командной строки + Command-line options + Параметры командной строки Synchronizing additional data: %p% Синхронизация дополнительных данных: %p% - &File - &Файл + File + Файл - &Settings - &Настройки + Settings + Настройки - &Tools - &Инструменты + Tools + Инструменты - &Help - &Помощь + Help + Помощь Tabs toolbar @@ -606,16 +606,16 @@ Запросить платежи (генерирует QR-код и Bulwark: URI) - &Masternodes - &Мастерноды + Masternodes + Мастерноды Browse masternodes Обзор мастернод - &About Bulwark Core - &О Bulwark Core + About Bulwark Core + О Bulwark Core Show information about Bulwark Core @@ -634,28 +634,28 @@ Проверте сообщения, чтобы убедиться, что они были подписаны указанным Bulwark адресом - &BIP38 tool - &BIP38 Утилита + BIP38 tool + BIP38 Утилита Encrypt and decrypt private keys using a passphrase Шифрование и дешифрование личных ключей с использованием кодовой фразы - &MultiSend - &MultiSend + MultiSend + MultiSend MultiSend Settings Настройки MultiSend - Open Wallet &Configuration File - Открыть файл &настроек кошелька + Open Wallet Configuration File + Открыть файл настроек кошелька - Open &Masternode Configuration File - Открыть файл &настроек мастернод + Open Masternode Configuration File + Открыть файл настроек мастернод Open Masternode configuration file @@ -666,8 +666,8 @@ Открыть Bulwark: URI или запрос платежа - &Blockchain explorer - &Обзор блокчейна + Blockchain explorer + Обзор блокчейна Block explorer window @@ -705,26 +705,10 @@ Up to date Обновление не требуется - - %n hour(s) - %n час%n часов%n часов%n часов - - - %n day(s) - %n день%n дней%n дней%n дней - - - %n week(s) - %n неделя%n недель%n недель%n недель - %1 and %2 %1 и %2 - - %n year(s) - %n год%n лет%n лет%n лет - %1 behind %1 позади @@ -914,10 +898,6 @@ MultiSend: %1 Received with address Полученно на адрес - - DS Rounds - DS циклов - Date Дата @@ -990,10 +970,6 @@ MultiSend: %1 Please switch to "List mode" to use this function. Для использования этой функции перейдите в "Режим списка" - - Non-anonymized input selected. <b>Obfuscation will be disabled.</b><br><br>If you still want to use Obfuscation, please deselect all non-nonymized inputs first and then check Obfuscation checkbox again. - Выбран неанонимизированный ввод. <b>Запутывание будет отключено. </b> <br><br>. Если вы всё же хотите использовать запутывание, пожалуйста отмените сначала выбор всех неанонимизированных вводов, затем снова поставте флажок "Запутывание". - highest самый высокий @@ -1014,10 +990,6 @@ MultiSend: %1 Can vary +/- %1 duff(s) per input. Может вариировать +/- %1 duff(s) к вводу - - n/a - недоступен - medium промежуточный @@ -1098,16 +1070,16 @@ MultiSend: %1 Изменить адрес - &Label - &Метка + Label + Метка The label associated with this address list entry Метка, связанная с этой записью в списке адресов - &Address - &Адрес + Address + Адрес The address associated with this address list entry. This can only be modified for sending addresses. @@ -1314,20 +1286,20 @@ MultiSend: %1 Публичный ключ - S&tart alias - З&апуск алиаса + Start alias + Запуск алиаса - Start &all - Запустить &все + Start all + Запустить все - Start &MISSING - Запуск &НЕАКТИВНЫХ + Start MISSING + Запуск НЕАКТИВНЫХ - &Update status - &Обновить состояние + Update status + Обновить состояние Status will be updated automatically in (sec): @@ -1610,28 +1582,28 @@ Please check the address and try again. Настройки - &Main - &Основной + Main + Основной - Size of &database cache - Размер кэша &базы данных + Size of database cache + Размер кэша базы данных MB MB - Number of script &verification threads - Количество сценариев &проверочных потоков + Number of script verification threads + Количество сценариев проверочных потоков (0 = auto, <0 = leave that many cores free) (0 = авто, <0 = оставить свободных ядер) - W&allet - К&ошелек + Wallet + Кошелек If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. @@ -1650,8 +1622,8 @@ Please check the address and try again. Разрешить входящие подключения - &Connect through SOCKS5 proxy (default proxy): - &Подключиться через SOCKS5 (прокси-сервер по умолчанию): + Connect through SOCKS5 proxy (default proxy): + Подключиться через SOCKS5 (прокси-сервер по умолчанию): Expert @@ -1662,32 +1634,16 @@ Please check the address and try again. Автоматически запускать Bulwark после входа в систему. - &Start Bulwark on system login - &Запускать Bulwark при входе в систему - - - This setting determines the amount of individual masternodes that an input will be anonymized through.<br/>More rounds of anonymization gives a higher degree of privacy, but also costs more in fees. - Эта настройка определяет количество мастернод, используемых для анонимизации. Чем больше циклов, тем выше уровень конфиденциальности, но не стоит забывать также об увеличивающейся комиссии. - - - Obfuscation rounds to use - Количество циклов Перемешивания - - - This amount acts as a threshold to turn off Obfuscation once it's reached. - При достижении этого значения Перемешивание будет отключено. - - - Amount of Bulwark to keep anonymized - Количество Bulwark, держащихся анонимизированными + Start Bulwark on system login + Запускать Bulwark при входе в систему Whether to show coin control features or not. Показывает или скрывает особенности управления монетами. - Enable coin &control features - Включить функции &управления монет + Enable coin control features + Включить функции управления монет Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. @@ -1698,12 +1654,12 @@ Please check the address and try again. Показать вкладку Мастернод - &Spend unconfirmed change - &Проведение неподтвержденных изменений + Spend unconfirmed change + Проведение неподтвержденных изменений - &Network - &Сеть + Network + Сеть The user interface language can be set here. This setting will take effect after restarting Bulwark. @@ -1716,63 +1672,63 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations https://www.transifex.com/bulwark-project/bulwark-project-translations - Map port using &UPnP - Карта порта, использующего &UPnP + Map port using UPnP + Карта порта, использующего UPnP Connect to the Bulwark network through a SOCKS5 proxy. Подключиться к сети Bulwark через SOCKS5 прокси. - Proxy &IP: - &IP адрес: + Proxy IP: + IP адрес: IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) IP-адрес прокси сервера (например: IPv4: 127.0.0.1 / IPv6: ::1) - &Port: - &Порт + Port: + Порт Port of the proxy (e.g. 9050) Порт прокси сервера (например: 9050) - &Window - &Окно + Window + Окно Show only a tray icon after minimizing the window. После сворачивания окна показывать только значок в трее. - &Minimize to the tray instead of the taskbar - &Свернуть в трей, а не на панель задач + Minimize to the tray instead of the taskbar + Свернуть в трей, а не на панель задач Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu. Сворачивать окно при закрывании вместо выхода из приложения. При включении этой опции покинуть приложение можно только после нажатия Выйти в меню программы. - M&inimize on close - C&ворачивать при закрытии + Minimize on close + Cворачивать при закрытии - &Display - &Экран + Display + Экран - User Interface &language: - &Язык Интерфейса + User Interface language: + Язык Интерфейса User Interface Theme: Тема Интерфейса - &Unit to show amounts in: + Unit to show amounts in: В каких единицах показывать сумму: @@ -1800,16 +1756,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsВернуть стандартные настройки клиента - &Reset Options - &Сбросить Настройки + Reset Options + Сбросить Настройки - &OK - &OK + OK + OK - &Cancel - &Отмена + Cancel + Отмена default @@ -1870,10 +1826,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsStaked or masternode rewards that has not yet matured Награды за хранение и мастерноды, которые еще не *созрели* - - Balances - Балансы - The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. Возможно отображаемая информация устарела. Ваш кошелек автоматически синхронизируется с сетью Bulwark после установки соединения, но этот процесс еще не завершен. @@ -1910,148 +1862,14 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsSpendable: Расходуемый: - - Status: - Статус: - - - Obfuscation Balance: - Баланс Обфускации - - - 0 BWK / 0 Rounds - 0 BWK / 0 Циклов - - - Enabled/Disabled - Включено/Выключено - - - Try to manually submit a Obfuscation request. - Попробуюте вручную создать запрос на Обфускацию. - - - Reset the current status of Obfuscation (can interrupt Obfuscation if it's in the process of Mixing, which can cost you money!) - Сбросить текущий статус Обфускации (может прервать обфускацию, если она уже началась, что может стоить ваших денег!) - - - Obfuscation - Обфускация - - - Completion: - Завершение: - - - Amount and Rounds: - Количесво повторений: - - - Submitted Denom: - Выбранная единица: - - - n/a - недоступен - Recent transactions Последние транзакции - - Start/Stop Mixing - Запустить/Остановить смешивание - - - The denominations you submitted to the Masternode.<br>To mix, other users must submit the exact same denominations. - Деноминации, которые вы отправили на мастерноду. <br>Для смешиваыния, другие пользователи должны отправить точно такие же деноминации. - - - (Last Message) - (Последнее сообщение) - - - Try Mix - Попытка смешать - - - Reset - Сброс - out of sync несинронизировано - - Disabled - Выключено - - - No inputs detected - Нет ввода - - - %n Rounds - %n Цикл%n Циклов%n Циклов%n Циклов - - - Not enough compatible inputs to anonymize <span style='color:red;'>%1</span>,<br>will anonymize <span style='color:red;'>%2</span> instead - Недостаточно совместимых вводов для анонимизации <span style='color:red;'>%1</span>,<br> вместо этого будет анонимизировано <span style='color:red;'>%2</span> - - - Overall progress - Общий ход выполнения - - - Anonymized - Анонимизировано - - - Last Obfuscation message: - - Последнее сообщение Обфускации: - - - - Obfuscation was successfully reset. - Обфускация была успешно сброшена. - - - If you don't want to see internal Obfuscation fees/transactions select "Most Common" as Type on the "Transactions" tab. - Если вы не хотите видеть внутреннию плату / трансакции Обфускацци выберите "Наиболее распространненные" как Тип в закладке "Транзакции". - - - Obfuscation requires at least %1 to use. - Для использования обфускации необходимо как минимум %1 - - - Wallet is locked and user declined to unlock. Disabling Obfuscation. - Кошелёк заблокирован и пользователь отклонен для разблокировки. Отключение Обфускации. - - - Found enough compatible inputs to anonymize %1 - Найдено достаточно совместимых вводов для анонимизации %1 - - - Start Obfuscation - Начать Обфускацию - - - Stop Obfuscation - Остановить Обфускацию - - - Mixed - Смешано - - - Enabled - Включено - - - N/A - Недоступно - PaymentServer @@ -2155,6 +1973,85 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsВремя отклика + + PrivacyDialog + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + Возможно отображаемая информация устарела. Ваш кошелек автоматически синхронизируется с сетью Bulwark после установки соединения, но этот процесс еще не завершен. + + + 0 + 0 + + + Reset + Сброс + + + Quantity: + Количество: + + + Amount: + Сумма: + + + Choose previously used address + Выбрать ранее использованный адрес + + + Alt+A + Alt+A + + + Paste address from clipboard + Вставить адрес из буфера обмена + + + Alt+P + Alt+P + + + Priority: + Приоритет: + + + Fee: + Комиссия: + + + Dust: + Пыль: + + + no + нет + + + Bytes: + Байты: + + + medium + промежуточный + + + Change: + Изменить: + + + out of sync + несинронизировано + + + Copy quantity + Копировать количество + + + Copy amount + Копировать сумму + + QObject @@ -2205,12 +2102,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations QRImageWidget - &Save Image... - &Сохранить изображение + Save Image... + Сохранить изображение - &Copy Image - &Копировать изображение + Copy Image + Копировать изображение Save QR Code @@ -2228,8 +2125,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsОкно с инструментами - &Information - &Информация + Information + Информация General @@ -2252,8 +2149,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsКоличество соениднений - &Open - &Открыть + Open + Открыть Startup time @@ -2304,20 +2201,20 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsКоличество мастернод - &Console - &Коммандая строка + Console + Коммандая строка Clear console Очистить коммандную строку - &Network Traffic - &Сетевая передача данных + Network Traffic + Сетевая передача данных - &Clear - &Очистить + Clear + Очистить Totals @@ -2332,8 +2229,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsОтправлено - &Peers - &Пиры + Peers + Пиры Select a peer to view detailed information. @@ -2392,8 +2289,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsВремя отклика - &Wallet Repair - &Ремонт кошелька + Wallet Repair + Ремонт кошелька Wallet In Use: @@ -2504,16 +2401,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations ReceiveCoinsDialog - &Message: - &Сообщение: + Message: + Сообщение: - &Amount: - &Количество: + Amount: + Количество: - &Request payment - &Запрос платежа + Request payment + Запрос платежа Clear all fields of the form. @@ -2563,16 +2460,16 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsQR код - Copy &URI - Скопировать &URI + Copy URI + Скопировать URI - Copy &Address - Скопировать &Адрес + Copy Address + Скопировать Адрес - &Save Image... - &Сохранить изображение + Save Image... + Сохранить изображение Payment information @@ -2692,10 +2589,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsMinimize Свернуть - - Obfuscation - Обфускация - per kilobyte за килобайт @@ -2717,12 +2610,12 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsОчистить все поля этой формы. - Clear &All - Очистить &Все + Clear All + Очистить Все - SwiftTX - SwiftTX + SwiftX + SwiftX Balance: @@ -2765,8 +2658,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsПредупреждение: неправильный Bulwark адрес - and SwiftTX - и SwiftTX + and SwiftX + и SwiftX %1 to %2 @@ -2866,8 +2759,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsСбросить все поля сообщений - Clear &All - Очистить &Все + Clear All + Очистить Все Reset all verify message fields @@ -3160,8 +3053,8 @@ https://www.transifex.com/bulwark-project/bulwark-project-translations WalletView - &Export - &Экспорт + Export + Экспорт Export the data in the current tab to a file @@ -3172,11 +3065,18 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsРезервная копия кошелька + + ZBwkControlDialog + + 0 + 0 + + bulwark-core - SwiftTX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. - Для SwiftTX требуется как минимум 6 подтверждений, Вам нужно подождать несколько минут и попытаться снова. + SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. + Для SwiftX требуется как минимум 6 подтверждений, Вам нужно подождать несколько минут и попытаться снова. Block creation options: @@ -3394,10 +3294,6 @@ https://www.transifex.com/bulwark-project/bulwark-project-translationsNot enough file descriptors available. Недостаточно доступных дескрипторов файлов. - - Obfuscation options: - Варианты обфускации: - Obfuscation request complete: Запрос об обфускации завершен: diff --git a/src/qt/locale/bulwark_sk.ts b/src/qt/locale/bulwark_sk.ts index bd41b7585..67c5f54d4 100644 --- a/src/qt/locale/bulwark_sk.ts +++ b/src/qt/locale/bulwark_sk.ts @@ -10,7 +10,7 @@ Vytvoriť novú adresu - &New + New Nový @@ -18,7 +18,7 @@ Skopírovať označenú adresu do schránky - &Copy + Copy Kopírovať @@ -26,7 +26,7 @@ Vymazať označenú adresu zo zoznamu - &Delete + Delete Vymazať @@ -34,11 +34,11 @@ Exportovať údaje na aktuálnej karte do súboru - &Export + Export Exportovať - C&lose + Close Zatvoriť @@ -50,7 +50,7 @@ Vyberte adresu, na ktorej chcete mince prijať - C&hoose + Choose Vybrať @@ -70,15 +70,15 @@ Toto sú vaše Bulwark adresy na prijímanie platieb. Pre každú transakciu sa odporúča použiť novú prijímaciu adresu. - &Copy Address + Copy Address Skopírovať adresu - Copy &Label + Copy Label Skopírovať štítok - &Edit + Edit Editovať @@ -235,7 +235,7 @@ BIP 38 Utilita - &BIP 38 Encrypt + BIP 38 Encrypt BIP 38 Šifrovanie @@ -283,7 +283,7 @@ Podpíšte správu, aby ste preukázali, že ste vlastníkom tejto Bulwark adresy - Encrypt &Key + Encrypt Key Zašifrovať kľúč @@ -291,11 +291,11 @@ Zmazať všetky polia správy - Clear &All + Clear All Všetko zmazať - &BIP 38 Decrypt + BIP 38 Decrypt BIP 38 dešifrovanie @@ -311,7 +311,7 @@ Skontrolujte správu, aby ste sa uistili, že bola podpísaná zadanou Bulwark adresou - Decrypt &Key + Decrypt Key Dešifrovať kľúč @@ -402,7 +402,7 @@ Uzol - &Overview + Overview Prehľad @@ -410,15 +410,15 @@ Zobraziť všeobecný prehľad peňaženky - &Send + Send Odoslať - &Receive + Receive Prijať - &Transactions + Transactions Transakcie @@ -426,7 +426,7 @@ Prezrieť históriu transakcií - E&xit + Exit Koniec @@ -434,7 +434,7 @@ Ukončiť aplikáciu - About &Qt + About Qt O aplikácii @@ -442,11 +442,11 @@ Zobraziť informácie o Qt - &Options... + Options... Možnosti... - &Show / Hide + Show / Hide Zobraziť / Skryť @@ -454,7 +454,7 @@ Zobraziť alebo skryť hlavné okno - &Encrypt Wallet... + Encrypt Wallet... Šifrovať peňaženku... @@ -462,7 +462,7 @@ Šifrujte súkromné kľúče, ktoré patria Vašej peňaženke - &Backup Wallet... + Backup Wallet... Zálohovať peňaženku... @@ -470,7 +470,7 @@ Zálohovať peňaženku na iné miesto - &Change Passphrase... + Change Passphrase... Zmeniť prístupovú frázu... @@ -478,7 +478,7 @@ Zmeniť prístupovú frázu, ktorá bola použitá na šifrovanie peňaženky - &Unlock Wallet... + Unlock Wallet... Odomknúť peňaženku... @@ -486,19 +486,19 @@ Odomknúť peňaženku - &Lock Wallet + Lock Wallet Zamknúť peňaženku - Sign &message... + Sign message... Podpísať správu... - &Verify message... + Verify message... Overiť správu... - &Information + Information Informácie @@ -506,7 +506,7 @@ Zobraziť diagnostické informácie - &Debug console + Debug console Debugovacia konzola @@ -514,7 +514,7 @@ Otvoriť debugovaciu konzola - &Network Monitor + Network Monitor Monitor siete @@ -522,7 +522,7 @@ Zobraziť monitor siete - &Peers list + Peers list Zoznam uzlov @@ -530,7 +530,7 @@ Zobraziť informácie o uzloch - Wallet &Repair + Wallet Repair Oprava peňaženky @@ -542,7 +542,7 @@ Otvoriť konfiguračný súbor - Show Automatic &Backups + Show Automatic Backups Zobraziť automatické zálohy @@ -550,7 +550,7 @@ Zobraziť automaticky vytvorené zálohy peňaženky - &Sending addresses... + Sending addresses... Odosielacie adresy @@ -558,7 +558,7 @@ Zobraziť zoznam použitých odosielajúcich adries a štítkov - &Receiving addresses... + Receiving addresses... Prijímacie adresy... @@ -566,11 +566,11 @@ Zobraziť zoznam použitých odosielajúcich adries a štítkov - Open &URI... + Open URI... Otvoriť URI... - &Command-line options + Command-line options Možnosti príkazového riadku @@ -578,19 +578,19 @@ Synchronizácia dodatočných údajov: %p% - &File + File Súbor - &Settings + Settings Nastavenia - &Tools + Tools Nástroje - &Help + Help Pomoc @@ -610,15 +610,15 @@ Vyžiadať platby (generuje QR kódy a bulwark: identifikátory URI) - &Masternodes - &Masternodes + Masternodes + Masternodes Browse masternodes Prezrieť masternody - &About Bulwark Core + About Bulwark Core O Bulwark Core @@ -638,7 +638,7 @@ Overte správy, aby sa zabezpečilo, že boli podpísané zadanými Bulwark adresami - &BIP38 tool + BIP38 tool BIP 38 Utilita @@ -646,19 +646,19 @@ Šifrovať a dešifrovať privátne kľúče pomocou prístupovej frázy - &MultiSend - &MultiSend + MultiSend + MultiSend MultiSend Settings MultiSend Nastavenia - Open Wallet &Configuration File + Open Wallet Configuration File Otvoriť konfiguračný súbor peňaženky - Open &Masternode Configuration File + Open Masternode Configuration File Otvoriť konfiguračný súbor masternodu @@ -670,7 +670,7 @@ Otvorte Bulwark: URI alebo žiadosť o platbu - &Blockchain explorer + Blockchain explorer Blockchain prehliadač @@ -963,6 +963,53 @@ MultiSend: %1 PeerTableModel + + PrivacyDialog + + Quantity: + Množstvo: + + + Amount: + Suma: + + + Choose previously used address + Vyberte predtým použitú adresu + + + Alt+A + Alt+A + + + Paste address from clipboard + Vložte adresu zo schránky + + + Alt+P + Alt+P + + + Priority: + Priorita: + + + Fee: + Poplatok: + + + Bytes: + Bytov: + + + Change: + Zmena: + + + Copy amount + Skopírovať sumu + + QObject @@ -976,7 +1023,7 @@ MultiSend: %1 RPCConsole - &Information + Information Informácie @@ -1056,7 +1103,7 @@ MultiSend: %1 Zmena: - Clear &All + Clear All Všetko zmazať @@ -1133,7 +1180,7 @@ MultiSend: %1 Zmazať všetky polia správy - Clear &All + Clear All Všetko zmazať @@ -1251,7 +1298,7 @@ MultiSend: %1 WalletView - &Export + Export Exportovať @@ -1259,6 +1306,9 @@ MultiSend: %1 Exportovať údaje na aktuálnej karte do súboru + + ZBwkControlDialog + bulwark-core diff --git a/src/qt/locale/bulwark_sv.ts b/src/qt/locale/bulwark_sv.ts index ba27eed4f..e0a18de17 100644 --- a/src/qt/locale/bulwark_sv.ts +++ b/src/qt/locale/bulwark_sv.ts @@ -3,38 +3,38 @@ AddressBookPage Right-click to edit address or label - Höger klicka för att ändra adress eller beteckning + Höger klicka för att redigera adress eller etikett Create a new address Skapa en ny adress - &New - &Ny + New + Ny - &Copy - &Kopiera + Copy + Kopiera Delete the currently selected address from the list Radera den valda adressen från listan - &Delete - &Radera + Delete + Radera Export the data in the current tab to a file Exportera data in den nuvarande fliken till en fil - &Export - &Exportera + Export + Exportera - C&lose + Close Stäng @@ -46,7 +46,7 @@ Välj adress att ta emot mynt med - C&hoose + Choose Välj @@ -66,16 +66,16 @@ Det här är dina Bulwark adresser för att ta emot betalningar. Det är rekomenderat att använda en ny mottagaradress för varje transaktion. - &Copy Address - &Kopiera Adress + Copy Address + Kopiera Adress - Copy &Label - Kopiera & Märk + Copy Label + Kopiera Ettikera - &Edit - &Redigera + Edit + Redigera Export Address List @@ -219,13 +219,13 @@ BIP 38 Verktyg - &BIP 38 Encrypt + BIP 38 Encrypt BIP 38 Kryptering Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. - Skriv in en Bulwark adress som du vill kryptera med BIP 38. -Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna den krypterade privata nyckeln. + Ange en Bulwark adress som du vill kryptera med BIP 38. +Ange en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna den krypterade privata nyckeln. Address: @@ -268,24 +268,24 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Signera meddelandet för att bevisa att du äger denna Bulwark adress - Encrypt &Key - Kryptera &Nyckel + Encrypt Key + Kryptera Nyckel Reset all sign message fields Återställ alla signatur meddelande fält - Clear &All - Rensa &allt + Clear All + Rensa allt - &BIP 38 Decrypt - &BIP 38 Avkryptera + BIP 38 Decrypt + BIP 38 Avkryptera Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. - Ange + Ange BIP 38 krypterade privata nyckeln. Ange lösenfrasen i med mittersta boxen. Tryck på krypetra nyckel för att beräkna den privata nyckeln. Efter att nyckeln är avkrypterad, Tryck på 'Importera Adress' kommer att lägga till denna privata nyckel till plånboken. The Bulwark address the message was signed with @@ -296,8 +296,8 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Verifiera meddelandet för att säkerställa att de blev signerat med den specifika Bulwark adressen. - Decrypt &Key - Avkryptera &Nyckel + Decrypt Key + Avkryptera Nyckel Reset all verify message fields @@ -337,7 +337,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Wallet unlock was cancelled. - Plånboks upplåsningen var avbruten + Upplåsningen av plånboken var avbruten. Private key for the entered address is not available. @@ -387,31 +387,31 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Nod - &Overview - &Översikt + Overview + Översikt Show general overview of wallet Visa generell översikt av plånbok - &Send - &Skicka + Send + Skicka - &Receive - &Motta + Receive + Motta - &Transactions - &Transaktioner + Transactions + Transaktioner Browse transaction history - Bläddra i transaktions historien + Bläddra i transaktions historiken - E&xit + Exit gå ut @@ -419,27 +419,27 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Avsluta applikationen - About &Qt - Om &Qt + About Qt + Om Qt Show information about Qt Visa information om Qt - &Options... - &Alternativ... + Options... + Alternativ... - &Show / Hide - &Visa / Dölj + Show / Hide + Visa / Dölj Show or hide the main Window Visa eller Dölj huvudfönstret - &Encrypt Wallet... + Encrypt Wallet... Kryptera Plånbok @@ -447,15 +447,15 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Kryptera privata nycklar som tillhör din plånbok - &Backup Wallet... - &Säkerhetskopiera plånbok + Backup Wallet... + Säkerhetskopiera plånbok Backup wallet to another location Säkerhetskopiera din plånbok till en annan plats - &Change Passphrase... + Change Passphrase... Ändra lösenfras @@ -463,7 +463,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Ändra lösenfrasen som används för kryptering av plånbok - &Unlock Wallet... + Unlock Wallet... lås upp plånbok @@ -471,19 +471,19 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d lås upp plånbok - &Lock Wallet + Lock Wallet lås plånbok - Sign &message... - signera & meddelande... + Sign message... + signera meddelande... - &Verify message... + Verify message... Verifiera meddelande - &Information + Information information @@ -491,7 +491,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Visa diagnostik information - &Debug console + Debug console Felsökningskonsol @@ -499,7 +499,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Öppna felsökningskonsol - &Network Monitor + Network Monitor Nätverks övervakare @@ -507,7 +507,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Visa nätverksövervakare - &Peers list + Peers list enhets lista @@ -515,8 +515,8 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Visa enhetslista - Wallet &Repair - Plånbok &Reparera + Wallet Repair + Plånbok Reparera Show wallet repair options @@ -527,15 +527,15 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Öppna konfigurations fil - Show Automatic &Backups - Visa Automatiskt &Säkerthetskopior + Show Automatic Backups + Visa Automatiskt Säkerthetskopior Show automatically created wallet backups Visa automatiskt skapade säkerhetskopior av plånbok - &Sending addresses... + Sending addresses... Sändnings adresser @@ -543,7 +543,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Visa listan över använda sändningsadresser och etiketter - &Receiving addresses... + Receiving addresses... Mottagar adresser @@ -551,11 +551,11 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Visa listan över använda mottagar adresser och etiketter - Open &URI... - Öppna & URl + Open URI... + Öppna URl - &Command-line options + Command-line options komanndo linje val @@ -563,19 +563,19 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d synchroniserar ytterligare data %p% - &File + File Fil - &Settings + Settings Inställningar - &Tools + Tools Verktyg - &Help + Help Hjälp @@ -595,7 +595,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Begär betalning (genererar QR kod och bulwark: URls) - &Masternodes + Masternodes Masternoder @@ -603,7 +603,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Utforska masternoder - &About Bulwark Core + About Bulwark Core Om Bulwark Kärnan @@ -623,7 +623,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Verifiera meddelandet för att säkerställa att de blev signerat med den specifika Bulwark adressen. - &BIP38 tool + BIP38 tool BIP38 Verktyg @@ -791,10 +791,6 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d medium-high medel-hög - - n/a - ingen uppgift - medium medel @@ -897,10 +893,6 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d OverviewPage - - n/a - ingen uppgift - PaymentServer @@ -908,6 +900,65 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d PeerTableModel + + PrivacyDialog + + Quantity: + Kvantitet: + + + Amount: + Antal: + + + Choose previously used address + Använd den föregående använda adressen + + + Alt+A + Alt+A + + + Paste address from clipboard + Limma in adress från urklipp + + + Alt+P + Alt+P + + + Label: + Etikett: + + + Priority: + Prioritet: + + + Fee: + Avgift: + + + no + nej + + + Bytes: + Bytes: + + + medium + medel + + + Copy quantity + Kopiera kvantitet + + + Copy amount + Kopiera antal + + QObject @@ -921,7 +972,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d RPCConsole - &Information + Information information @@ -936,7 +987,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d ReceiveCoinsDialog - &Label: + Label: Etikett: @@ -1041,8 +1092,8 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Efter Avgift: - Clear &All - Rensa &allt + Clear All + Rensa allt Copy quantity @@ -1088,7 +1139,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Alt+P - &Label: + Label: Etikett: @@ -1146,8 +1197,8 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Återställ alla signatur meddelande fält - Clear &All - Rensa &allt + Clear All + Rensa allt Reset all verify message fields @@ -1167,7 +1218,7 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d Wallet unlock was cancelled. - Plånboks upplåsningen var avbruten + Upplåsningen av plånboken var avbruten. Private key for the entered address is not available. @@ -1356,14 +1407,17 @@ Skriv in en lösenfras i den mellersta boxen. Tryck kryptera för att beräkna d WalletView - &Export - &Exportera + Export + Exportera Export the data in the current tab to a file Exportera data in den nuvarande fliken till en fil + + ZBwkControlDialog + bulwark-core diff --git a/src/qt/locale/bulwark_tr.ts b/src/qt/locale/bulwark_tr.ts new file mode 100644 index 000000000..749844583 --- /dev/null +++ b/src/qt/locale/bulwark_tr.ts @@ -0,0 +1,403 @@ + + + AddressBookPage + + Right-click to edit address or label + Adresi ya da etiketi değiştirmek için sağ tuşa tıklayın + + + Create a new address + Yeni bir adres oluştur + + + New + Yeni + + + Copy the currently selected address to the system clipboard + Seçili olan adresi sistem panosuna kopyala + + + Copy + Kopyala + + + Delete the currently selected address from the list + Seçili olan adresi listeden sil + + + Delete + Sil + + + Export the data in the current tab to a file + Güncel sekmedeki verileri bir dosyaya aktar + + + Export + Çıkart + + + Close + Kapat + + + Choose the address to send coins to + Coinleri gönderecek adresi seçin + + + Choose the address to receive coins with + Coinleri Alacak adresi seçin + + + Choose + Seçin + + + Sending addresses + Gönderen adres + + + Receiving addresses + Alıcı Adres + + + These are your Bulwark addresses for sending payments. Always check the amount and the receiving address before sending coins. + Bunlar ödemeleri göndermek için olan Bulwark adreslerinizdir.Coinleri göndermeden önce her zaman gönderilen miktarı ve adresi kontrol edin + + + These are your Bulwark addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Bunlar ödemeleri almak için olan Bulwark adreslerinizdirHer işlem için yeni bir adres kullanmanız önerilir. + + + Copy Address + Adresi kopyala + + + Copy Label + Etiketi Kopyala + + + Edit + Düzelt + + + Export Address List + Adres listesini çıkart + + + Comma separated file (*.csv) + Virgül ile ayrılmış dosya(*.csv) + + + Exporting Failed + Çıkartma işlemi başarısız + + + There was an error trying to save the address list to %1. Please try again. + Adres listesini %1e kaydederken hata oldu.Lütfen tekrar deneyin + + + + AddressTableModel + + Label + Etiket + + + Address + adres + + + (no label) + (etiket yok) + + + + AskPassphraseDialog + + Passphrase Dialog + Şifre sözcüğü Diyaloğu + + + Enter passphrase + Şifre sözcüğünüzü girin + + + New passphrase + Yeni şifre sözcüğü + + + Repeat new passphrase + yeni şifre sözcüğünü tekrarlayın + + + Serves to disable the trivial sendmoney when OS account compromised. Provides no real security. + OS hesabı tehlikeye atıldığında önemsiz para göndermeyi devre dışı bırakır. Gerçek bir güvenlik sağlamaz. + + + For anonymization and staking only + Sadece anonimleştirme ve staking için + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Yeni şifre sözcüğünü cüzdana girinLütfen bir şifre söcüğü kullanın <br/><b>10 veya daha fazla karakter içeren</b>veya<b>8 veya daha fazla kelime içeren</b> + + + Encrypt wallet + Cüzdanı şifreleyin + + + This operation needs your wallet passphrase to unlock the wallet. + Bu işlem, cüzdan kilidini açmak için cüzdan parolanıza ihtiyaç duyuyor. + + + Unlock wallet + Cüzdanı aç + + + This operation needs your wallet passphrase to decrypt the wallet. + Bu işlem, cüzdan şifresini çözmek için cüzdan parolanıza ihtiyaç duyuyor. + + + Decrypt wallet + cüzdan şifresini çöz + + + Change passphrase + Şifreyi değiştir + + + Enter the old and new passphrase to the wallet. + Cüzdanınıza eski ve yeni parolayı girin. + + + Confirm wallet encryption + cüzdan şifrelemesini onayla + + + Bulwark will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your BWKs from being stolen by malware infecting your computer. + Bulwark şifreleme işlemini tamamlamak için şimdi kapanacaktır. Cüzdanınızı şifrelemenin, BWK'lerinizi bilgisayarınıza bulaşan kötücül yazılımlar tarafından çalınmasına tamamen engelleyemediğini unutmayın + + + Are you sure you wish to encrypt your wallet? + Cüzdanınızı şifrelemek istediğinizden emin misiniz? + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BWK</b>! + Dikkat! Eğer cüzdanınızı şifrelerseniz ve şifrenizi unutursanız <b>Tüm Pıvlerinizi kaybedersiniz</b>! + + + Wallet encrypted + Cüzdan şifrelendi + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + Önemli: wallet dosyası ile daha önce yaptığınız yedeklemeler şifreleme sonrası yenisi ile tekrar yedeklenmelidir.Güvenlik nedenleri ile, şifrelenmemiş cüzdanınıza ait yedeklemeler yeni şifrelenmiş cüzdanoınızla birlikte kullanılmaz hale gelecektir. + + + Wallet encryption failed + Cüzdan şifrelemesi başarısız oldu + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Dahili bir hata nedeniyle cüzdan şifrelemesi başarısız oldu. Cüzdanınız şifrelenmedi. + + + The supplied passphrases do not match. + Verilen parolalar uyuşmuyor. + + + Wallet unlock failed + Cüzdan kilidini açma başarısız oldu + + + The passphrase entered for the wallet decryption was incorrect. + cüzdan şifre çözme işlemi için girilen parola yanlıştı. + + + Wallet decryption failed + Cüzdan şifre çözme işlemi başarısız oldu + + + + Bip38ToolDialog + + + BitcoinGUI + + Unlock wallet + Cüzdanı aç + + + + BlockExplorer + + + ClientModel + + + CoinControlDialog + + (no label) + (etiket yok) + + + + EditAddressDialog + + + FreespaceChecker + + + HelpMessageDialog + + + Intro + + + MasternodeList + + Address + adres + + + + MultiSendDialog + + + ObfuscationConfig + + + OpenURIDialog + + + OptionsDialog + + + OverviewPage + + + PaymentServer + + + PeerTableModel + + + PrivacyDialog + + + QObject + + + QRImageWidget + + + RPCConsole + + + ReceiveCoinsDialog + + + ReceiveRequestDialog + + Address + adres + + + Label + Etiket + + + + RecentRequestsTableModel + + Label + Etiket + + + (no label) + (etiket yok) + + + + SendCoinsDialog + + (no label) + (etiket yok) + + + + SendCoinsEntry + + + ShutdownWindow + + + SignVerifyMessageDialog + + + SplashScreen + + + TrafficGraphWidget + + + TransactionDesc + + + TransactionDescDialog + + + TransactionTableModel + + Address + adres + + + + TransactionView + + Comma separated file (*.csv) + Virgül ile ayrılmış dosya(*.csv) + + + Label + Etiket + + + Address + adres + + + Exporting Failed + Çıkartma işlemi başarısız + + + + UnitDisplayStatusBarControl + + + WalletFrame + + + WalletModel + + + WalletView + + Export + Çıkart + + + Export the data in the current tab to a file + Güncel sekmedeki verileri bir dosyaya aktar + + + + ZBwkControlDialog + + + bulwark-core + + \ No newline at end of file diff --git a/src/qt/locale/bulwark_uk.ts b/src/qt/locale/bulwark_uk.ts index afde31175..caaaf25ce 100644 --- a/src/qt/locale/bulwark_uk.ts +++ b/src/qt/locale/bulwark_uk.ts @@ -10,7 +10,7 @@ Створити нову адресу - &New + New Новий @@ -18,7 +18,7 @@ Скопіювати вибрану адресу в буфер обміну - &Copy + Copy Копіювати @@ -26,7 +26,7 @@ Видалити вибрану адресу зі списку - &Delete + Delete Видалити @@ -34,23 +34,23 @@ Експортуйтувати дані поточної вкладки у файл - &Export + Export Експорт - C&lose + Close Закрити Choose the address to send coins to - Виберіть адресу для надсилання монет + Виберіть адресу надсилання монет Choose the address to receive coins with Виберіть адресу отримання монет - C&hoose + Choose Вибір @@ -63,22 +63,22 @@ These are your Bulwark addresses for sending payments. Always check the amount and the receiving address before sending coins. - Це ваша Bulwark-адреса для надсилання платежів. Завжди перевіряйте суму та адресу одержувача перед відправленням монет. + Це ваші Bulwark-адреси для надсилання платежів. Завжди перевіряйте суму та адресу одержувача перед відправленням монет. These are your Bulwark addresses for receiving payments. It is recommended to use a new receiving address for each transaction. Це ваші Bulwark адреси для отримання платежів. Для кожної транзакції рекомендується використовувати нову адресу одержувача. - &Copy Address + Copy Address Копіювати адресу - Copy &Label + Copy Label Копіювати мітку - &Edit + Edit Редагувати @@ -255,6 +255,9 @@ PeerTableModel + + PrivacyDialog + QObject @@ -355,7 +358,7 @@ WalletView - &Export + Export Експорт @@ -363,6 +366,9 @@ Експортуйтувати дані поточної вкладки у файл + + ZBwkControlDialog + bulwark-core diff --git a/src/qt/locale/bulwark_zh_CN.ts b/src/qt/locale/bulwark_zh_CN.ts index 4d5afcf83..1605d1353 100644 --- a/src/qt/locale/bulwark_zh_CN.ts +++ b/src/qt/locale/bulwark_zh_CN.ts @@ -7,26 +7,26 @@ Create a new address - 创建新地址 + 创建新的地址 - &New - + New + 新地址 Copy the currently selected address to the system clipboard 复制当前地址至剪贴板 - &Copy + Copy 复制 Delete the currently selected address from the list - 从列表移除此地址 + 从列表移除这个地址 - &Delete + Delete 删除 @@ -34,48 +34,840 @@ 导出当前数据至文件 - &Export + Export 导出 - + + Close + C关闭 + + + Choose the address to send coins to + 选择发送Bulwark coin的地址 + + + Choose the address to receive coins with + 选择接收Bulwark coin的地址 + + + Choose + C选择 + + + Sending addresses + 发送地址 + + + Receiving addresses + 接收地址 + + + These are your Bulwark addresses for sending payments. Always check the amount and the receiving address before sending coins. + 这是用于发送Bulwark的地址。在发送Bulwark之前,请认真核查发送金额和接收地址。 + + + These are your Bulwark addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + 这是用于接收Bulwark的钱包地址。建议每一笔交易都使用一个新的钱包地址。 + + + Copy Address + 复制地址 + + + Copy Label + 复制标签 + + + Edit + 编辑 + + + Export Address List + 导出地址列表 + + + Comma separated file (*.csv) + 存成(.csv)格式 + + + Exporting Failed + 导出失败 + + + There was an error trying to save the address list to %1. Please try again. + 尝试将地址列表保存到 %1时出错。 请再试一次。 + + AddressTableModel - + + Label + 标签 + + + Address + 地址 + + + (no label) + 未设置标签 + + AskPassphraseDialog - + + Passphrase Dialog + 密码输入框 + + + Enter passphrase + 输入钱包密码 + + + New passphrase + 输入新密码 + + + Repeat new passphrase + 再次输入新密码 + + + Serves to disable the trivial sendmoney when OS account compromised. Provides no real security. + 用于在操作系统帐户遭到破坏时禁用琐碎的sendmoney。没有真正的安全性。 + + + For anonymization and staking only + 仅用于匿名化和加密 + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + 输入一个新的钱包密码<br/>钱包密码<b>建议使用10位以上的随机字符</b>,或者<b> 3个以上的单词</b>。并建议有序使用大小写字母。 + + + Encrypt wallet + 加密钱包 + + + This operation needs your wallet passphrase to unlock the wallet. + 需要您输入钱包密码来进行解锁。 + + + Unlock wallet + 解锁钱包 + + + This operation needs your wallet passphrase to decrypt the wallet. + 需要您输入钱包密码来进行解锁。 + + + Decrypt wallet + 解密钱包 + + + Change passphrase + 修改密码 + + + Enter the old and new passphrase to the wallet. + 输入钱包信旧密码 + + + Confirm wallet encryption + 确认钱包加密 + + + Bulwark will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your BWKs from being stolen by malware infecting your computer. + Bulwark将关闭以完成加密过程。但是,仅仅加密您的钱包是不够的,因为它并不能阻止恶意软件从您的电脑里面偷取BWKs。 + + + Are you sure you wish to encrypt your wallet? + 您确定加密您的钱包吗? + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BWK</b>! + 注意:请妥善保管好你的密码,因为在加密后,没有密码将无法打开钱包。这将会让您<b>损失钱包中所有的BWK</b>! + + + Wallet encrypted + 钱包加密 + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + 重要提示:一旦您开始使用新的加密钱包,以前未加密的钱包备份都将失效。所以在新加密钱包生效后请务必重新备份您的钱包。 + + + Wallet encryption failed + 钱包加密失败 + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + 由于内部错误,钱包加密失败,您的钱包本次加密没有成功。 + + + The supplied passphrases do not match. + 输入的密码不正确 + + + Wallet unlock failed + 钱包解锁失败 + + + The passphrase entered for the wallet decryption was incorrect. + 为钱包解密输入的密码不正确。 + + + Wallet decryption failed + 钱包解密失败 + + + Wallet passphrase was successfully changed. + 钱包密码已经更换为新密码 + + + Warning: The Caps Lock key is on! + 注意:键盘目前为大写锁定状态。 + + Bip38ToolDialog - + + BIP 38 Tool + BIP 38 工具 + + + BIP 38 Encrypt + BIP 38 加密 + + + Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. + 输入您要使用BIP 38加密的Bulwark地址。在中间框中输入密码。按加密计算加密私钥。 + + + Address: + 地址: + + + The Bulwark address to sign the message with + 该Bulwark地址签名的消息 + + + Choose previously used address + 选以前使用的地址 + + + Alt+A + Alt+A + + + Paste address from clipboard + 从剪贴板复制地址 + + + Alt+P + Alt+P + + + Passphrase: + 密码: + + + Encrypted Key: + 加密密钥: + + + Copy the current signature to the system clipboard + 将当前签名复制到系统剪贴板 + + + Sign the message to prove you own this Bulwark address + 签署消息以证明您拥有此Bulwark地址 + + + Encrypt Key + 加密秘钥 + + + Reset all sign message fields + 重置所有签名信息 + + + Clear All + 清除全部 + + + BIP 38 Decrypt + BIP 38 解密 + + + Enter the BIP 38 encrypted private key. Enter the passphrase in the middle box. Click Decrypt Key to compute the private key. After the key is decrypted, clicking 'Import Address' will add this private key to the wallet. + 输入BIP 38加密私钥。 在中间框中输入密码。 单击解密密钥计算私钥。 密钥解密后,单击“导入地址”将将该私钥添加到钱包中。 + + + The Bulwark address the message was signed with + 由Bulwark地址签名的消息 + + + Verify the message to ensure it was signed with the specified Bulwark address + 验证消息确保它已使用指定的Bulwark地址进行签名 + + + Decrypt Key + 解密秘钥 + + + Reset all verify message fields + 重置所有验证消息 + + + Decrypted Key: + 解密秘钥: + + + Import Address + 导入地址 + + + Click "Decrypt Key" to compute key + 点击“解密密钥”完成密钥计算 + + + The entered passphrase is invalid. + 输入的密码无效。 + + + Allowed: 0-9,a-z,A-Z, + 允许: 0-9,a-z,A-Z, + + + The entered address is invalid. + 输入的地址无效 + + + Please check the address and try again. + 请检查地址,并重新输入。 + + + The entered address does not refer to a key. + 输入的地址不是指密钥。 + + + Wallet unlock was cancelled. + 钱包解锁终止。 + + + Private key for the entered address is not available. + 输入地址的私钥不可用。 + + + Failed to decrypt. + 解密失败。 + + + Please check the key and passphrase and try again. + 请检查密钥和密码短语,然后再试一次。 + + + Data Not Valid. + 无效数据。 + + + Please try again. + 请再试一次。 + + + Please wait while key is imported + 等待key被导入。 + + + Key Already Held By Wallet + 钱包已经有此密钥(key) + + + Error Adding Key To Wallet + 钱包无法加载该密钥(key) + + + Successfully Added Private Key To Wallet + 为钱包成功添加私人密钥(Private Key) + + BitcoinGUI + + Wallet + 钱包 + + + Node + 节点 + + + Overview + 概述 + + + Show general overview of wallet + 显示钱包的概述 + + + Send + 发送 + + + Receive + 接收 + + + Transactions + 交易 + + + Browse transaction history + 查阅历史交易 + + + Exit + E退出 + + + Quit application + 关闭应用 + + + About Qt + 关于Qt + + + Show information about Qt + 显示Qt的相关信息 + + + Options... + 选项 + + + Show / Hide + 显示/隐藏 + + + Show or hide the main Window + 显示或隐藏主窗口 + + + Encrypt Wallet... + 加密钱包... + + + Encrypt the private keys that belong to your wallet + 加密属于您钱包的私钥 + + + Backup Wallet... + 备份钱包... + + + Backup wallet to another location + 备份钱包至其他目录 + + + Change Passphrase... + 修改密码 + + + Change the passphrase used for wallet encryption + 修改用于钱包加密的密码 + + + Unlock Wallet... + 解锁钱包... + + + Unlock wallet + 解锁钱包 + + + Lock Wallet + 锁定钱包 + + + Sign message... + 签名消息 + + + Verify message... + 验证消息 + + + Information + 信息 + + + Show diagnostic information + 显示诊断调试信息 + + + Debug console + 调试控制台 + + + Open debugging console + 打开调试控制台 + + + Network Monitor + 网络监视器 + + + Show network monitor + 查看网络监视器 + + + Peers list + 并列列表 + + + Show peers info + 显示并列信息 + + + Wallet Repair + 钱包修复 + + + Show wallet repair options + 显示钱包修复选项 + + + Open configuration file + 打开配置文件 + + + Show Automatic Backups + 显示自动备份 + + + Show automatically created wallet backups + 查看自动备份建立的钱包 + + + Sending addresses... + 发送地址... + + + Show the list of used sending addresses and labels + 查看已发送地址和标签 + + + Receiving addresses... + 接收地址 + + + Show the list of used receiving addresses and labels + 查看已接收地址和标签 + + + Open URI... + 打开URI + + + Command-line options + 命令行选项 + + + Synchronizing additional data: %p% + 同步其他数据:%p% + + + File + 文件 + + + Settings + 设置 + + + Tools + 工具 + + + Help + 帮助 + + + Tabs toolbar + 标签工具栏 + + + Bulwark Core + Bulwark 核心 + + + Send coins to a Bulwark address + 发送数字货币到Bulwark地址 + + + Request payments (generates QR codes and bulwark: URIs) + 请求支付(生成二维码和bulwark:URIs) + + + Masternodes + 主节点 + + + Browse masternodes + 浏览主节点 + + + About Bulwark Core + 关于Bulwark核心 + + + Show information about Bulwark Core + 显示Bulwark核心的相关信息 + + + Modify configuration options for Bulwark + 修改Bulwark的配置选项 + + + Sign messages with your Bulwark addresses to prove you own them + 使用您的Bulwark地址验证消息,以证明您拥有他们 + + + Verify messages to ensure they were signed with specified Bulwark addresses + 验证消息确保它已使用指定的Bulwark地址进行签名 + + + BIP38 tool + BIP38工具 + + + Encrypt and decrypt private keys using a passphrase + 使用密码加密和解密私钥 + + + MultiSend + 多重发送 + + + MultiSend Settings + 多重发送设置 + + + Open Wallet Configuration File + 打开钱包配置文件 + + + Open Masternode Configuration File + 打开主节点配置文件 + + + Open Masternode configuration file + 打开主节点配置文件 + + + Open a bulwark: URI or payment request + 打开bulwark:URI或付款请求 + + + Blockchain explorer + 区块浏览器 + + + Block explorer window + 区块浏览窗口 + + + Show the Bulwark Core help message to get a list with possible Bulwark command-line options + 显示Bulwark Core帮助信息以获取可能的Bulwark命令行选项的列表 + + + Bulwark Core client + Bulwark核心客户端 + + + Synchronizing with network... + 与网络同步 + + + Importing blocks from disk... + 从硬盘导入区块… + + + Reindexing blocks on disk... + 在硬盘重建索引区块 + + + No block source available... + 没有区块源可用 + + + Up to date + 最新 + + + %1 behind + %1 落后 + + + Catching up... + 追赶… + + + Last received block was generated %1 ago. + 最后接收区块生成与%1之前 + + + Transactions after this will not yet be visible. + 之后的交易尚不可见。 + + + Error + 出错 + + + Warning + 注意 + + + Information + 信息 + + + Date: %1 +Amount: %2 +Type: %3 +Address: %4 + + 日期:%1 +金额:%2 +类型:%3 +地址:%4 + + BlockExplorer + + Address / Block / Transaction + 地址/区块/交易 + ClientModel CoinControlDialog + + Received with address + 收到地址 + + + Copy address + 复制地址 + + + none + + + + (no label) + 未设置标签 + EditAddressDialog + + Edit Address + 编辑地址 + + + Label + 标签 + + + The label associated with this address list entry + 与该地址列表条目相关联的标签 + + + Address + 地址 + + + The address associated with this address list entry. This can only be modified for sending addresses. + 与该地址列表条目相关联的地址。 只能修改发送地址。 + + + New receiving address + 新接受地址 + + + New sending address + 新发送地址 + FreespaceChecker HelpMessageDialog + + Bulwark Core + Bulwark 核心 + Intro + + Bulwark Core + Bulwark 核心 + + + Error + 出错 + MasternodeList + + Form + 来自 + + + 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. + 注意:在本地钱包您主节点状态可能会稍微不正确。<br />总是等待钱包从另一个节点同步的附加数据,然后仔细检查<br />如果您的节点正在运行,但您仍然在“Status”字段中看到“MISSING”。 + + + Address + 地址 + + + Start alias + S开始别名 + + + Start all + 开始全部 + + + Start MISSING + 开始MISSING + + + Update status + 更新状态 + MultiSendDialog + + Alt+A + Alt+A + + + Address: + 地址: + ObfuscationConfig @@ -85,9 +877,185 @@ OptionsDialog - + + Main + + + + Size of database cache + 缓存database 大小 + + + Number of script verification threads + 脚本验证线程数 + + + Wallet + W钱包 + + + If you disable the spending of unconfirmed change, the change from a transaction<br/>cannot be used until that transaction has at least one confirmation.<br/>This also affects how your balance is computed. + 如果您要禁用未经确认发送,在至少有一个确认之前<br/>不能更改。<br/>这也将影响您的余额计算。 + + + Automatically open the Bulwark client port on the router. This only works when your router supports UPnP and it is enabled. + 自动打开路由器上的Bulwark钱包使用的端口。 这只有当您的路由器支持UPnP并且该享生效时才有用。 + + + Connect through SOCKS5 proxy (default proxy): + 使用SOCKS5代理(默认代理) + + + Start Bulwark on system login + 开机启动Bulwark + + + Enable coin control features + 启用硬币控制功能 + + + Show additional tab listing all your masternodes in first sub-tab<br/>and all masternodes on the network in second sub-tab. + 显示附加的标签,列出所有您的主节点在第一子列表上<br/>所有主节点的网络在第二个子列表上。 + + + Spend unconfirmed change + 花费未经证实的变化 + + + Network + 网络 + + + Map port using UPnP + 端口使用UPnP + + + Proxy IP: + 代理IP地址: + + + Port: + 端口: + + + Window + 视窗 + + + Minimize to the tray instead of the taskbar + 最小化到托盘而不是任务栏 + + + Minimize on close + M关闭最小化 + + + Display + 显示 + + + User Interface language: + 选择语言包 + + + User Interface Theme: + 界面主题(语言包): + + + Unit to show amounts in: + 单位显示金额 + + + Choose the default subdivision unit to show in the interface and when sending coins. + 选择显示发送Bulwark的默认单位。 + + + Decimal digits + 小数位数 + + + 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 |. + 第三方网址(如区块浏览器中)出现的交易选项卡,上下文菜单项。 在URL %s 被交易哈希取代。 多个URL被竖线分隔|。 + + + Third party transaction URLs + 第三方交易URLs + + + Active command-line options that override above options: + 上述选项的主动命令行选项: + + + Reset all client options to default. + 清空当前设置,恢复为初始状态 + + + Reset Options + 重置选项 + + + OK + OK + + + Cancel + 取消 + + + default + 默认 + + + none + + + + Confirm options reset + 确认选项重置 + + + Client restart required to activate changes. + 钱包重启后修改才能生效。 + + + Client will be shutdown, do you want to proceed? + 软件将要关闭,您确定嘛? + + + This change would require a client restart. + 修改需要重启钱包。 + + + The supplied proxy address is invalid. + 提供的代理地址无效。 + + OverviewPage + + Form + 来自 + + + Available: + 可得到 + + + Your current spendable balance + 您目前的支出余额 + + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + 显示的信息可能已过期。建立连接后,您的钱包会自动与Bulwark网络同步,但此过程尚未完成。 + + + Your current total balance + 您当前的总余额 + + + Your current balance in watch-only addresses + 您目前仅在观察地址中的余额 + PaymentServer @@ -95,53 +1063,436 @@ PeerTableModel + + PrivacyDialog + + The displayed information may be out of date. Your wallet automatically synchronizes with the Bulwark network after a connection is established, but this process has not completed yet. + 显示的信息可能已过期。建立连接后,您的钱包会自动与Bulwark网络同步,但此过程尚未完成。 + + + Pay To: + 支付 + + + Choose previously used address + 选以前使用的地址 + + + Alt+A + Alt+A + + + Paste address from clipboard + 从剪贴板复制地址 + + + Alt+P + Alt+P + + + Label: + 标签 + + + Amount: + A总计 + + QObject QRImageWidget + + Save Image... + 保存图片... + + + Copy Image + 复制图像 + RPCConsole + + Information + 信息 + + + Open + 打开 + + + Console + 调试台 + + + Network Traffic + 网络流量 + + + Clear + 清除 + + + Peers + 并列 + + + Wallet Repair + 修复钱包 + ReceiveCoinsDialog + + Reuse an existing receiving address (not recommended) + R使用现有的地址接收(不推荐) + + + Message: + 消息: + + + An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bulwark network. + 附加到付款请求的可选消息,将在请求打开时显示。 注意:消息不会在付款时通过Bulwark网络发送。 + + + 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 Bulwark network. + 附加到付款请求的可选消息,将在请求打开时显示。<br> 注意:消息不会在付款时通过Bulwark网络发送。 + + + Label: + 标签 + + + Amount: + 总计 + + + Request payment + 请求支付 + + + Copy message + 复制消息 + ReceiveRequestDialog + + Copy URI + 复制URI + + + Copy Address + 复制地址 + + + Save Image... + 保存图片... + + + Address + 地址 + + + Label + 标签 + + + Message + 消息 + + + Resulting URI too long, try to reduce the text for label / message. + 获取的URI太长,尝试减少标签/消息的文本数量。 + RecentRequestsTableModel + + Label + 标签 + + + Message + 消息 + + + (no label) + 未设置标签 + + + (no message) + (没有消息) + SendCoinsDialog - + + Send + S发送 + + + Clear All + 清除全部 + + + Add Recipient + 增加收件人 + + + The amount exceeds your balance. + 金额超过您的余额。 + + + The total exceeds your balance when the %1 transaction fee is included. + 当包含%1交易费用时,总额超过您的余额。 + + + The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + 交易被拒绝! 可能在您的钱包中这些硬币已经花了,比如,您使用了wallet.dat的副本,硬币在副本中被使用,但并没有被标记就可能发生这种情况。 + + + (no label) + 未设置标签 + + SendCoinsEntry - + + Pay To: + 支付 + + + Choose previously used address + 选以前使用的地址 + + + Alt+A + Alt+A + + + Paste address from clipboard + 从剪贴板复制地址 + + + Alt+P + Alt+P + + + Label: + 标签 + + + Amount: + A总计 + + + Message: + 消息: + + + A message that was attached to the bulwark: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bulwark network. + 附加到bulwark:URI的消息,该消息将与转账信息一起存储以供参考。 注意:此消息不会通过Bulwark网络发送。 + + + Enter a label for this address to add it to your address book + 输入此地址的标签,将其添加到您的地址列表中 + + ShutdownWindow SignVerifyMessageDialog - + + Signatures - Sign / Verify a Message + 签名 - 签署 / 验证消息 + + + Sign Message + 签名消息 + + + You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to. + 您可以使用地址签名消息,以证明您拥有他们。 小心不要签名任何您不了解的,因为网络钓鱼攻击可能会试图欺骗您,以让您签名。 只能签署您熟悉并且了解和同意的。 + + + The Bulwark address to sign the message with + 该Bulwark地址签名的消息 + + + Choose previously used address + 选以前使用的地址 + + + Alt+A + Alt+A + + + Paste address from clipboard + 从剪贴板复制地址 + + + Alt+P + Alt+P + + + Enter the message you want to sign here + 输入您要在这里签名的消息。 + + + Copy the current signature to the system clipboard + 将当前签名复制到系统剪贴板 + + + Sign the message to prove you own this Bulwark address + 签署消息以证明您拥有此Bulwark地址 + + + The Bulwark address the message was signed with + 由Bulwark地址签名的消息 + + + Verify the message to ensure it was signed with the specified Bulwark address + 验证消息确保它已使用指定的Bulwark地址进行签名 + + + Sign Message + 签名消息 + + + Reset all sign message fields + 重置所有签名信息 + + + Clear All + 清除全部 + + + Verify Message + 验证消息 + + + Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. + 输入签名地址,消息(确保您准确地复制换行符,空格,制表符等)和签名以验证消息。注意不要比签名的消息本身更多地阅读签名,以避免被中间人的袭击所欺骗。 + + + Verify Message + 验证消息 + + + Reset all verify message fields + 重置所有验证消息 + + + Click "Sign Message" to generate signature + 点击“签名消息”生成一个签名 + + + The entered address is invalid. + 输入的地址无效 + + + Please check the address and try again. + 请检查地址,并重新输入。 + + + The entered address does not refer to a key. + 输入的地址不是指密钥。 + + + Wallet unlock was cancelled. + 钱包解锁终止。 + + + Private key for the entered address is not available. + 输入地址的私钥不可用。 + + + Message signing failed. + 消息签名失败 + + + Message signed. + 消息已被签名 + + + The signature did not match the message digest. + 签名与消息摘要不符。 + + + Message verification failed. + 消息验证失败。 + + + Message verified. + 消息已被验证 + + SplashScreen + + Bulwark Core + Bulwark 核心 + TrafficGraphWidget TransactionDesc + + Message + 消息 + TransactionDescDialog TransactionTableModel + + Address + 地址 + + + Orphan Block - Generated but not accepted. This does not impact your holdings. + 孤儿块 - 生成但不被接受。 但这不会影响你。 + + + Payment to yourself + 支付给您自己 + TransactionView + + To yourself + 给您自己 + + + Copy address + 复制地址 + + + Comma separated file (*.csv) + 存成(.csv)格式 + + + Label + 标签 + + + Address + 地址 + + + Exporting Failed + 导出失败 + UnitDisplayStatusBarControl @@ -155,7 +1506,7 @@ WalletView - &Export + Export 导出 @@ -163,7 +1514,50 @@ 导出当前数据至文件 + + ZBwkControlDialog + bulwark-core + + Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) + 在收到相关警报时执行命令,或者看到一个很长的分叉(cmd中的%s被消息替换) + + + Warning: Please check that your computer's date and time are correct! If your clock is wrong Bulwark Core will not work properly. + 注意:请检查您的电脑的日期和时间是否正确! 如果您的时间设置不正确,Bulwark Core将无法正常工作。 + + + Warning: wallet.dat corrupt, data salvaged! Original wallet.dat saved as wallet.{timestamp}.bak in %s; if your balance or transactions are incorrect you should restore from a backup. + 注意:wallet.dat损坏,请恢复数据!原始wallet.dat保存为钱包。{timestamp} .bak in %s; 如果您的余额或交易不正确,您应该从备份还原。 + + + Error + 出错 + + + Information + 信息 + + + This is a pre-release test build - use at your own risk - do not use for staking or merchant applications! + 这是一个预发行测试版本 - 您自己承担风险 - 不要用于商业应用! + + + Specify your own public address + 指定您自己的公共地址 + + + Warning + 注意 + + + Your entries added successfully. + 您的输入成功添加。 + + + Your transaction was accepted into the pool! + 您的交易被矿池接受! + \ No newline at end of file diff --git a/src/qt/locale/bulwark_zh_TW.ts b/src/qt/locale/bulwark_zh_TW.ts index 6bd00aeee..04c617ad8 100644 --- a/src/qt/locale/bulwark_zh_TW.ts +++ b/src/qt/locale/bulwark_zh_TW.ts @@ -10,36 +10,36 @@ 產生新位址 - &New - &新增 + New + 新增 Copy the currently selected address to the system clipboard 複製目前選取的位址到系統剪貼簿 - &Copy - &刪除 + Copy + 刪除 Delete the currently selected address from the list 刪除列表中已選擇的位址 - &Delete - &刪除 + Delete + 刪除 Export the data in the current tab to a file 匯出目前面板中的資料 - &Export - &匯出 + Export + 匯出 - C&lose - &關閉 + Close + 關閉 Choose the address to send coins to @@ -50,8 +50,8 @@ 選擇要接收Bulwark幣的位址 - C&hoose - &選取 + Choose + 選取 Sending addresses @@ -70,16 +70,16 @@ 這是你用來接收款項的 Bulwark 位址, 建議你每次付款都使用新的位址. - &Copy Address - &拷貝位址 + Copy Address + 拷貝位址 - Copy &Label + Copy Label 複製標記 - &Edit - &編輯 + Edit + 編輯 Export Address List @@ -223,8 +223,8 @@ BIP 38 工具 - &BIP 38 Encrypt - &BIP 38 加密 + BIP 38 Encrypt + BIP 38 加密 Enter a Bulwark Address that you would like to encrypt using BIP 38. Enter a passphrase in the middle box. Press encrypt to compute the encrypted private key. @@ -271,20 +271,20 @@ 使用簽章來證明你是該 Bulwark 位址的擁有者, - Encrypt &Key - 加密 &鑰匙 + Encrypt Key + 加密 鑰匙 Reset all sign message fields 重設所有已簽章訊息 - Clear &All - 清除 &全部 + Clear All + 清除 全部 - &BIP 38 Decrypt - &BIP 38 解密 + BIP 38 Decrypt + BIP 38 解密 The Bulwark address the message was signed with @@ -295,8 +295,8 @@ 驗證訊息以確保該 Bulwark 位址已被簽章 - Decrypt &Key - 解密 &鑰匙 + Decrypt Key + 解密 鑰匙 Reset all verify message fields @@ -386,136 +386,136 @@ 節點 - &Overview - &總覽 + Overview + 總覽 Show general overview of wallet 顯示錢包資訊 - &Send - &發送 + Send + 發送 - &Receive - &接收 + Receive + 接收 - &Transactions - &交易 + Transactions + 交易 Browse transaction history 瀏覽交易紀錄 - E&xit - &退出 + Exit + 退出 Quit application 關閉程式 - About &Qt - 關於 &Qt + About Qt + 關於 Qt Show information about Qt 顯示 Qt 資訊 - &Options... - &選項 + Options... + 選項 - &Show / Hide - &顯示 / 隱藏 + Show / Hide + 顯示 / 隱藏 Show or hide the main Window 顯示或隱藏主視窗 - &Encrypt Wallet... - &錢包加密 + Encrypt Wallet... + 錢包加密 Encrypt the private keys that belong to your wallet 將你錢包中的私鑰加密 - &Backup Wallet... - &備份錢包 + Backup Wallet... + 備份錢包 Backup wallet to another location 備份錢包到另外的位置 - &Change Passphrase... - &更改密碼 + Change Passphrase... + 更改密碼 Change the passphrase used for wallet encryption 更改使用中的錢包密碼 - &Unlock Wallet... - &錢包解鎖 + Unlock Wallet... + 錢包解鎖 Unlock wallet 錢包解鎖 - &Lock Wallet - &錢包上鎖 + Lock Wallet + 錢包上鎖 - Sign &message... - &訊息簽章 + Sign message... + 訊息簽章 - &Verify message... - &查驗訊息 + Verify message... + 查驗訊息 - &Information - &資訊 + Information + 資訊 Show diagnostic information 顯示診斷訊息 - &Debug console - &除錯命令列 + Debug console + 除錯命令列 Open debugging console 開啟除錯命令列 - &Network Monitor - &網路監控 + Network Monitor + 網路監控 Show network monitor 顯示網路監控 - &Peers list - &接點(Peers)列表 + Peers list + 接點(Peers)列表 Show peers info 顯示接點(Peers)資訊 - Wallet &Repair - &錢包修復 + Wallet Repair + 錢包修復 Show wallet repair options @@ -526,56 +526,56 @@ 打開設定檔 - Show Automatic &Backups - &顯示自動備份 + Show Automatic Backups + 顯示自動備份 Show automatically created wallet backups 顯示自動建立的錢包備份 - &Sending addresses... - &發送地址 + Sending addresses... + 發送地址 Show the list of used sending addresses and labels 顯示曾經使用的發送地址及標籤 - &Receiving addresses... - &接收地址 + Receiving addresses... + 接收地址 Show the list of used receiving addresses and labels 顯示曾經使用過的接收地址 - Open &URI... - &打開網址 + Open URI... + 打開網址 - &Command-line options - &命令列工具 + Command-line options + 命令列工具 Synchronizing additional data: %p% 其他資料同步中: %p% - &File - &檔案 + File + 檔案 - &Settings - &設定 + Settings + 設定 - &Tools - &工具 + Tools + 工具 - &Help - &幫助 + Help + 幫助 Tabs toolbar @@ -594,16 +594,16 @@ 請求付款 (會產生 QR Code跟 bulwark 位址) - &Masternodes - &Masternodes + Masternodes + Masternodes Browse masternodes 瀏覽 Masternodes - &About Bulwark Core - &關於 Bulwark Core + About Bulwark Core + 關於 Bulwark Core Show information about Bulwark Core @@ -622,28 +622,28 @@ 驗證訊息簽章與 Bulwark 位址吻合 - &BIP38 tool - &BIP38 工具 + BIP38 tool + BIP38 工具 Encrypt and decrypt private keys using a passphrase 使用密碼對私鑰加密解密 - &MultiSend - &多重發送 + MultiSend + 多重發送 MultiSend Settings 多重發送設定 - Open Wallet &Configuration File - &打開錢包設定檔 + Open Wallet Configuration File + 打開錢包設定檔 - Open &Masternode Configuration File - &打開Masternode設定檔 + Open Masternode Configuration File + 打開Masternode設定檔 Open Masternode configuration file @@ -654,8 +654,8 @@ 打開Bulwark: 位址或付款請求 - &Blockchain explorer - &區塊鏈瀏覽 + Blockchain explorer + 區塊鏈瀏覽 Block explorer window @@ -743,6 +743,25 @@ PeerTableModel + + PrivacyDialog + + Choose previously used address + 選擇之前用過的位址 + + + Alt+A + Alt+A + + + Paste address from clipboard + 從剪貼簿貼上 + + + Alt+P + Alt+P + + QObject @@ -752,8 +771,8 @@ RPCConsole - &Information - &資訊 + Information + 資訊 @@ -784,8 +803,8 @@ SendCoinsDialog - Clear &All - 清除 &全部 + Clear All + 清除 全部 (no label) @@ -857,8 +876,8 @@ 重設所有已簽章訊息 - Clear &All - 清除 &全部 + Clear All + 清除 全部 Reset all verify message fields @@ -943,14 +962,17 @@ WalletView - &Export - &匯出 + Export + 匯出 Export the data in the current tab to a file 匯出目前面板中的資料 + + ZBwkControlDialog + bulwark-core diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index 34271dfd3..0a95639f8 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -34,6 +34,7 @@ MasternodeList::MasternodeList(QWidget* parent) : QWidget(parent), int columnActiveWidth = 130; int columnLastSeenWidth = 130; + ui->tableWidgetMyMasternodes->setAlternatingRowColors(true); ui->tableWidgetMyMasternodes->setColumnWidth(0, columnAliasWidth); ui->tableWidgetMyMasternodes->setColumnWidth(1, columnAddressWidth); ui->tableWidgetMyMasternodes->setColumnWidth(2, columnProtocolWidth); diff --git a/src/qt/multisigdialog.cpp b/src/qt/multisigdialog.cpp index 63f2cb03c..78ff8b966 100644 --- a/src/qt/multisigdialog.cpp +++ b/src/qt/multisigdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2017 The PIVX developers +// Copyright (c) 2017 The PIVX developers // Copyright (c) 2017-2018 The Bulwark developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -807,12 +807,12 @@ void MultisigDialog::on_addAddressButton_clicked() addressFrame->setObjectName(QStringLiteral("addressFrame")); QVBoxLayout* frameLayout = new QVBoxLayout(addressFrame); - frameLayout->setSpacing(2); + frameLayout->setSpacing(1); frameLayout->setObjectName(QStringLiteral("frameLayout")); frameLayout->setContentsMargins(6, 6, 6, 6); QHBoxLayout* addressLayout = new QHBoxLayout(); - addressLayout->setSpacing(4); + addressLayout->setSpacing(0); addressLayout->setObjectName(QStringLiteral("addressLayout")); QLabel* addressLabel = new QLabel(addressFrame); diff --git a/src/qt/obfuscationconfig.cpp b/src/qt/obfuscationconfig.cpp index 19d3d99d4..94308ab3a 100644 --- a/src/qt/obfuscationconfig.cpp +++ b/src/qt/obfuscationconfig.cpp @@ -83,6 +83,6 @@ void ObfuscationConfig::configure(bool enabled, int coins, int rounds) settings.setValue("nObfuscationRounds", rounds); settings.setValue("nAnonymizeBulwarkAmount", coins); - nObfuscationRounds = rounds; + nZeromintPercentage = rounds; nAnonymizeBulwarkAmount = coins; } diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 6915cdfdb..8e66f89b5 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -84,6 +84,16 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(paren /* Theme selector static themes */ ui->theme->addItem(QString("Default"), QVariant("default")); + /* Preferred Zerocoin Denominations */ + ui->preferredDenom->addItem(QString(tr("Any")), QVariant("0")); + ui->preferredDenom->addItem(QString("1"), QVariant("1")); + ui->preferredDenom->addItem(QString("5"), QVariant("5")); + ui->preferredDenom->addItem(QString("10"), QVariant("10")); + ui->preferredDenom->addItem(QString("50"), QVariant("50")); + ui->preferredDenom->addItem(QString("100"), QVariant("100")); + ui->preferredDenom->addItem(QString("500"), QVariant("500")); + ui->preferredDenom->addItem(QString("1000"), QVariant("1000")); + /* Theme selector external themes */ boost::filesystem::path pathAddr = GetDataDir() / "themes"; QDir dir(pathAddr.string().c_str()); @@ -185,6 +195,10 @@ void OptionsDialog::setMapper() mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup); mapper->addMapping(ui->threadsScriptVerif, OptionsModel::ThreadsScriptVerif); mapper->addMapping(ui->databaseCache, OptionsModel::DatabaseCache); + // Zerocoin mint percentage + mapper->addMapping(ui->zeromintPercentage, OptionsModel::ZeromintPercentage); + // Zerocoin preferred denomination + mapper->addMapping(ui->preferredDenom, OptionsModel::ZeromintPrefDenom); /* Wallet */ mapper->addMapping(ui->spendZeroConfChange, OptionsModel::SpendZeroConfChange); @@ -199,7 +213,7 @@ void OptionsDialog::setMapper() mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP); mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort); -/* Window */ + /* Window */ #ifndef Q_OS_MAC mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray); mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose); @@ -213,10 +227,7 @@ void OptionsDialog::setMapper() mapper->addMapping(ui->unit, OptionsModel::DisplayUnit); mapper->addMapping(ui->thirdPartyTxUrls, OptionsModel::ThirdPartyTxUrls); - - /* Obfuscation Rounds */ - mapper->addMapping(ui->obfuscationRounds, OptionsModel::ObfuscationRounds); - mapper->addMapping(ui->anonymizeBulwark, OptionsModel::AnonymizeBulwarkAmount); + /* Masternode Tab */ mapper->addMapping(ui->showMasternodesTab, OptionsModel::ShowMasternodesTab); } diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index ba9d8d31b..ab7bd3a60 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -79,7 +79,6 @@ void OptionsModel::Init() if (!settings.contains("nAnonymizeBulwarkAmount")) settings.setValue("nAnonymizeBulwarkAmount", 1000); - nObfuscationRounds = settings.value("nObfuscationRounds").toLongLong(); nAnonymizeBulwarkAmount = settings.value("nAnonymizeBulwarkAmount").toLongLong(); if (!settings.contains("fShowMasternodesTab")) @@ -107,7 +106,7 @@ void OptionsModel::Init() // Wallet #ifdef ENABLE_WALLET if (!settings.contains("bSpendZeroConfChange")) - settings.setValue("bSpendZeroConfChange", true); + settings.setValue("bSpendZeroConfChange", false); if (!SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool())) addOverriddenOption("-spendzeroconfchange"); if (!settings.contains("fShowOrphans")) @@ -148,8 +147,10 @@ void OptionsModel::Init() if (!SoftSetArg("-lang", settings.value("language").toString().toStdString())) addOverriddenOption("-lang"); - if (settings.contains("nObfuscationRounds")) - SoftSetArg("-obfuscationrounds", settings.value("nObfuscationRounds").toString().toStdString()); + if (settings.contains("nZeromintPercentage")) + SoftSetArg("-zeromintpercentage", settings.value("nZeromintPercentage").toString().toStdString()); + if (settings.contains("nPreferredDenom")) + SoftSetArg("-preferredDenom", settings.value("nPreferredDenom").toString().toStdString()); if (settings.contains("nAnonymizeBulwarkAmount")) SoftSetArg("-anonymizebulwarkamount", settings.value("nAnonymizeBulwarkAmount").toString().toStdString()); @@ -231,8 +232,10 @@ QVariant OptionsModel::data(const QModelIndex& index, int role) const return settings.value("nDatabaseCache"); case ThreadsScriptVerif: return settings.value("nThreadsScriptVerif"); - case ObfuscationRounds: - return QVariant(nObfuscationRounds); + case ZeromintPercentage: + return QVariant(nZeromintPercentage); + case ZeromintPrefDenom: + return QVariant(nPreferredDenom); case AnonymizeBulwarkAmount: return QVariant(nAnonymizeBulwarkAmount); case Listen: @@ -343,11 +346,17 @@ bool OptionsModel::setData(const QModelIndex& index, const QVariant& value, int setRestartRequired(true); } break; - case ObfuscationRounds: - nObfuscationRounds = value.toInt(); - settings.setValue("nObfuscationRounds", nObfuscationRounds); - emit obfuscationRoundsChanged(nObfuscationRounds); + case ZeromintPercentage: + nZeromintPercentage = value.toInt(); + settings.setValue("nZeromintPercentage", nZeromintPercentage); + emit zeromintPercentageChanged(nZeromintPercentage); break; + case ZeromintPrefDenom: + nPreferredDenom = value.toInt(); + settings.setValue("nPreferredDenom", nPreferredDenom); + emit preferredDenomChanged(nPreferredDenom); + break; + case AnonymizeBulwarkAmount: nAnonymizeBulwarkAmount = value.toInt(); settings.setValue("nAnonymizeBulwarkAmount", nAnonymizeBulwarkAmount); @@ -404,8 +413,8 @@ bool OptionsModel::getProxySettings(QNetworkProxy& proxy) const proxyType curProxy; if (GetProxy(NET_IPV4, curProxy)) { proxy.setType(QNetworkProxy::Socks5Proxy); - proxy.setHostName(QString::fromStdString(curProxy.ToStringIP())); - proxy.setPort(curProxy.GetPort()); + proxy.setHostName(QString::fromStdString(curProxy.proxy.ToStringIP())); + proxy.setPort(curProxy.proxy.GetPort()); return true; } else diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 84f990963..71834adae 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -44,7 +44,8 @@ class OptionsModel : public QAbstractListModel DatabaseCache, // int SpendZeroConfChange, // bool ShowOrphans, // bool - ObfuscationRounds, // int + ZeromintPercentage, // int + ZeromintPrefDenom, // int AnonymizeBulwarkAmount, //int ShowMasternodesTab, // bool Listen, // bool @@ -91,7 +92,8 @@ class OptionsModel : public QAbstractListModel signals: void displayUnitChanged(int unit); - void obfuscationRoundsChanged(int); + void zeromintPercentageChanged(int); + void preferredDenomChanged(int); void anonymizeBulwarkAmountChanged(int); void coinControlFeaturesChanged(bool); }; diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index d4224530a..c0cceb577 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -17,6 +17,7 @@ #include "obfuscationconfig.h" #include "optionsmodel.h" #include "transactionfilterproxy.h" +#include "transactionrecord.h" #include "transactiontablemodel.h" #include "walletmodel.h" #include "qtmaterialflatbutton.h" @@ -29,7 +30,9 @@ #define DECORATION_SIZE 48 #define ICON_OFFSET 16 -#define NUM_ITEMS 15 +#define NUM_ITEMS 9 + +extern CWallet* pwalletMain; class TxViewDelegate : public QAbstractItemDelegate { @@ -45,7 +48,7 @@ class TxViewDelegate : public QAbstractItemDelegate QIcon icon = qvariant_cast(index.data(Qt::DecorationRole)); QRect mainRect = option.rect; - mainRect.moveLeft(ICON_OFFSET); + //mainRect.moveLeft(ICON_OFFSET); QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE)); int xspace = DECORATION_SIZE + 8; int ypad = 6; @@ -58,6 +61,14 @@ class TxViewDelegate : public QAbstractItemDelegate QString address = index.data(Qt::DisplayRole).toString(); qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong(); bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool(); + + // Check transaction status + int nStatus = index.data(TransactionTableModel::StatusRole).toInt(); + bool fConflicted = false; + if (nStatus == TransactionStatus::Conflicted || nStatus == TransactionStatus::NotAccepted) { + fConflicted = true; // Most probably orphaned, but could have other reasons as well + } + QVariant value = index.data(Qt::ForegroundRole); QColor foreground = COLOR_BLACK; if (value.canConvert()) { @@ -65,8 +76,8 @@ class TxViewDelegate : public QAbstractItemDelegate foreground = brush.color(); } - painter->setPen(foreground); QRect boundingRect; + painter->setPen(foreground); painter->drawText(addressRect, Qt::AlignLeft | Qt::AlignVCenter, address, &boundingRect); if (index.data(TransactionTableModel::WatchonlyRole).toBool()) { @@ -75,22 +86,26 @@ class TxViewDelegate : public QAbstractItemDelegate iconWatchonly.paint(painter, watchonlyRect); } - if (amount < 0) { + QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true, BitcoinUnits::separatorAlways); + if (!confirmed) { + amountText = QString("[") + amountText + QString("]"); + } + + if(fConflicted) { // No need to check anything else for conflicted transactions + foreground = COLOR_CONFLICTED; + } else if (amount < 0) { foreground = COLOR_NEGATIVE; } else if (!confirmed) { foreground = COLOR_UNCONFIRMED; } else { foreground = COLOR_BLACK; } + painter->setPen(foreground); - QString amountText = BitcoinUnits::formatWithUnit(unit, amount, true, BitcoinUnits::separatorAlways); - if (!confirmed) { - amountText = QString("[") + amountText + QString("]"); - } painter->setFont(QFont("Roboto", 10, QFont::Bold)); painter->drawText(amountRect, Qt::AlignRight | Qt::AlignVCenter, amountText); - painter->setFont(QFont("Roboto", 10, QFont::Medium)); + painter->setFont(QFont("Roboto", 10, QFont::Medium)); painter->setPen(COLOR_BLACK); painter->drawText(amountRect, Qt::AlignLeft | Qt::AlignVCenter, GUIUtil::dateTimeStr(date)); @@ -113,6 +128,9 @@ OverviewPage::OverviewPage(QWidget* parent) : QWidget(parent), currentBalance(-1), currentUnconfirmedBalance(-1), currentImmatureBalance(-1), + currentZerocoinBalance(-1), + currentUnconfirmedZerocoinBalance(-1), + currentimmatureZerocoinBalance(-1), currentWatchOnlyBalance(-1), currentWatchUnconfBalance(-1), currentWatchImmatureBalance(-1), @@ -130,32 +148,10 @@ OverviewPage::OverviewPage(QWidget* parent) : QWidget(parent), connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex))); - // init "out of sync" warning labels ui->labelWalletStatus->setText("(" + tr("out of sync") + ")"); - ui->labelObfuscationSyncStatus->setText("(" + tr("out of sync") + ")"); ui->labelTransactionsStatus->setText("(" + tr("out of sync") + ")"); - if (fLiteMode) { - ui->frameObfuscation->setVisible(false); - } else { - if (fMasterNode) { - ui->toggleObfuscation->setText("(" + tr("Disabled") + ")"); - ui->obfuscationAuto->setText("(" + tr("Disabled") + ")"); - ui->obfuscationReset->setText("(" + tr("Disabled") + ")"); - ui->frameObfuscation->setEnabled(false); - } else { - if (!fEnableObfuscation) { - ui->toggleObfuscation->setText(tr("Start Obfuscation")); - } else { - ui->toggleObfuscation->setText(tr("Stop Obfuscation")); - } - timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(obfuScationStatus())); - timer->start(1000); - } - } - // start with displaying the "out of sync" warnings showOutOfSyncWarning(true); } @@ -168,44 +164,110 @@ void OverviewPage::handleTransactionClicked(const QModelIndex& index) OverviewPage::~OverviewPage() { - if (!fLiteMode && !fMasterNode) disconnect(timer, SIGNAL(timeout()), this, SLOT(obfuScationStatus())); delete ui; } -void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& anonymizedBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance) +void OverviewPage::getPercentage(CAmount nUnlockedBalance, CAmount nZerocoinBalance, QString& sBWKPercentage, QString& szBWKPercentage) +{ + int nPrecision = 2; + double dzPercentage = 0.0; + + if (nZerocoinBalance <= 0){ + dzPercentage = 0.0; + } + else{ + if (nUnlockedBalance <= 0){ + dzPercentage = 100.0; + } + else{ + dzPercentage = 100.0 * (double)(nZerocoinBalance / (double)(nZerocoinBalance + nUnlockedBalance)); + } + } + + double dPercentage = 100.0 - dzPercentage; + + szBWKPercentage = "(" + QLocale(QLocale::system()).toString(dzPercentage, 'f', nPrecision) + " %)"; + sBWKPercentage = "(" + QLocale(QLocale::system()).toString(dPercentage, 'f', nPrecision) + " %)"; + +} + +void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& zerocoinBalance, const CAmount& unconfirmedZerocoinBalance, const CAmount& immatureZerocoinBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance) { currentBalance = balance; currentUnconfirmedBalance = unconfirmedBalance; currentImmatureBalance = immatureBalance; - currentAnonymizedBalance = anonymizedBalance; + currentZerocoinBalance = zerocoinBalance; + currentUnconfirmedZerocoinBalance = unconfirmedZerocoinBalance; + currentimmatureZerocoinBalance = immatureZerocoinBalance; currentWatchOnlyBalance = watchOnlyBalance; currentWatchUnconfBalance = watchUnconfBalance; currentWatchImmatureBalance = watchImmatureBalance; + + CAmount _balance = balance - (immatureBalance + unconfirmedBalance); + if (_balance < 0) _balance = 0; - ui->labelBalance->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, balance-immatureBalance, false, BitcoinUnits::separatorAlways)); + ui->labelBalance->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, _balance, false, BitcoinUnits::separatorAlways)); + ui->labelzBalance->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, zerocoinBalance, false, BitcoinUnits::separatorAlways)); ui->labelUnconfirmed->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, unconfirmedBalance, false, BitcoinUnits::separatorAlways)); ui->labelImmature->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, immatureBalance, false, BitcoinUnits::separatorAlways)); - ui->labelAnonymized->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, anonymizedBalance, false, BitcoinUnits::separatorAlways)); - ui->labelTotal->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, balance + unconfirmedBalance, false, BitcoinUnits::separatorAlways)); + ui->labelTotal->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, balance, false, BitcoinUnits::separatorAlways)); - ui->labelWatchAvailable->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchOnlyBalance-watchOnlyBalance, false, BitcoinUnits::separatorAlways)); + // Watchonly labels + ui->labelWatchAvailable->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchOnlyBalance, false, BitcoinUnits::separatorAlways)); ui->labelWatchPending->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchUnconfBalance, false, BitcoinUnits::separatorAlways)); ui->labelWatchImmature->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchImmatureBalance, false, BitcoinUnits::separatorAlways)); - ui->labelWatchTotal->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, watchOnlyBalance + watchUnconfBalance, false, BitcoinUnits::separatorAlways)); + ui->labelWatchTotal->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, (watchOnlyBalance + watchUnconfBalance), false, BitcoinUnits::separatorAlways)); + + // zBWK labels + QString szPercentage = ""; + QString sPercentage = ""; + CAmount nLockedBalance = 0; + if (pwalletMain) { + nLockedBalance = pwalletMain->GetLockedCoins(); + } + ui->labelLockedBalance->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, nLockedBalance, false, BitcoinUnits::separatorAlways)); + + CAmount nTotalBalance = balance + unconfirmedBalance; + CAmount nUnlockedBalance = nTotalBalance - nLockedBalance; + CAmount matureZerocoinBalance = zerocoinBalance - immatureZerocoinBalance; + getPercentage(nUnlockedBalance, zerocoinBalance, sPercentage, szPercentage); + + ui->labelBalancez->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, nTotalBalance, false, BitcoinUnits::separatorAlways)); + ui->labelzBalancez->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, zerocoinBalance, false, BitcoinUnits::separatorAlways)); + ui->labelzBalanceImmature->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, immatureZerocoinBalance, false, BitcoinUnits::separatorAlways)); + ui->labelzBalanceUnconfirmed->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, unconfirmedZerocoinBalance, false, BitcoinUnits::separatorAlways)); + ui->labelzBalanceMature->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, matureZerocoinBalance, false, BitcoinUnits::separatorAlways)); + ui->labelTotalz->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, nTotalBalance + zerocoinBalance, false, BitcoinUnits::separatorAlways)); + ui->labelUnLockedBalance->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, nUnlockedBalance, false, BitcoinUnits::separatorAlways)); + ui->labelBWKPercent->setText(sPercentage); + ui->labelzBWKPercent->setText(szPercentage); + + // Adjust bubble-help according to AutoMint settings + QString automintHelp = tr("Current percentage of zBWK.\nIf AutoMint is enabled this percentage will settle around the configured AutoMint percentage (default = 0%).\n"); + bool fEnableZeromint = GetBoolArg("-enablezeromint", false); + int nZeromintPercentage = GetArg("-zeromintpercentage", 00); + if (fEnableZeromint) { + automintHelp += tr("AutoMint is currently enabled and set to ") + QString::number(nZeromintPercentage) + "%.\n"; + automintHelp += tr("To disable AutoMint add 'enablezeromint=0' in bulwark.conf."); + } + else { + automintHelp += tr("AutoMint is currently disabled.\nTo enable AutoMint change 'enablezeromint=0' to 'enablezeromint=1' in bulwark.conf"); + } + ui->labelzBWKPercent->setToolTip(automintHelp); // only show immature (newly mined) balance if it's non-zero, so as not to complicate things // for the non-mining users bool showImmature = immatureBalance != 0; bool showWatchOnlyImmature = watchImmatureBalance != 0; - + // for symmetry reasons also show immature label when the watch-only one is shown // watch balances include addresses that are imported to watch without the priv. key. ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature); ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature); ui->labelWatchImmature->setVisible(showWatchOnlyImmature); // show watch-only immature balance - updateObfuscationProgress(); - static int cachedTxLocks = 0; if (cachedTxLocks != nCompleteTXLocks) { @@ -214,31 +276,16 @@ void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmed } } -void OverviewPage::on_toggleStaking_clicked() -{ - if (walletModel->getEncryptionStatus() == WalletModel::Locked) { - WalletModel::UnlockContext ctx(walletModel->requestUnlock(false)); - } - else { - QMessageBox::information(this, tr("Staking"), - tr("Staking is already enabled"), - QMessageBox::Ok, QMessageBox::Ok); - } -} - // show/hide watch-only labels void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly) { ui->labelSpendable->setVisible(showWatchOnly); // show spendable label (only when watch-only is active) ui->labelWatchonly->setVisible(showWatchOnly); // show watch-only label - ui->lineWatchOnlyBalance->setVisible(showWatchOnly); // show watch-only balance separator line +/* ui->lineWatchBalance->setVisible(showWatchOnly); // show watch-only balance separator line */ ui->labelWatchAvailable->setVisible(showWatchOnly); // show watch-only available balance ui->labelWatchPending->setVisible(showWatchOnly); // show watch-only pending balance ui->labelWatchTotal->setVisible(showWatchOnly); // show watch-only total balance - - if (!showWatchOnly) { - ui->labelWatchImmature->hide(); - } + ui->labelWatchImmature->setVisible(showWatchOnly); } void OverviewPage::setClientModel(ClientModel* model) @@ -268,15 +315,14 @@ void OverviewPage::setWalletModel(WalletModel* model) ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress); // Keep up to date with wallet - setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), model->getAnonymizedBalance(), - model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); - connect(model, SIGNAL(balanceChanged(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount)), this, SLOT(setBalance(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount))); + setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), + model->getZerocoinBalance(), model->getUnconfirmedZerocoinBalance(), model->getImmatureZerocoinBalance(), + model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); + connect(model, SIGNAL(balanceChanged(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount)), this, + SLOT(setBalance(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount))); connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); - connect(ui->obfuscationAuto, SIGNAL(clicked()), this, SLOT(obfuscationAuto())); - connect(ui->obfuscationReset, SIGNAL(clicked()), this, SLOT(obfuscationReset())); - connect(ui->toggleObfuscation, SIGNAL(clicked()), this, SLOT(toggleObfuscation())); updateWatchOnlyLabels(model->haveWatchOnly()); connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool))); } @@ -290,7 +336,7 @@ void OverviewPage::updateDisplayUnit() if (walletModel && walletModel->getOptionsModel()) { nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit(); if (currentBalance != -1) - setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance, currentAnonymizedBalance, + setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance, currentZerocoinBalance, currentUnconfirmedZerocoinBalance, currentimmatureZerocoinBalance, currentWatchOnlyBalance, currentWatchUnconfBalance, currentWatchImmatureBalance); // Update txdelegate->unit with the current unit @@ -309,240 +355,5 @@ void OverviewPage::updateAlerts(const QString& warnings) void OverviewPage::showOutOfSyncWarning(bool fShow) { ui->labelWalletStatus->setVisible(fShow); - ui->labelObfuscationSyncStatus->setVisible(fShow); ui->labelTransactionsStatus->setVisible(fShow); } - -void OverviewPage::updateObfuscationProgress() -{ - if (!masternodeSync.IsBlockchainSynced() || ShutdownRequested()) return; - - if (!pwalletMain) return; - - QString strAmountAndRounds; - QString strAnonymizeBulwarkAmount = BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, nAnonymizeBulwarkAmount * COIN, false, BitcoinUnits::separatorAlways); - - if (currentBalance == 0) { - ui->obfuscationProgress->setValue(0); - ui->obfuscationProgress->setToolTip(tr("No inputs detected")); - - // when balance is zero just show info from settings - strAnonymizeBulwarkAmount = strAnonymizeBulwarkAmount.remove(strAnonymizeBulwarkAmount.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1); - strAmountAndRounds = strAnonymizeBulwarkAmount + " / " + tr("%n Rounds", "", nObfuscationRounds); - - ui->labelAmountRounds->setToolTip(tr("No inputs detected")); - ui->labelAmountRounds->setText(strAmountAndRounds); - return; - } - - CAmount nDenominatedConfirmedBalance; - CAmount nDenominatedUnconfirmedBalance; - CAmount nAnonymizableBalance; - CAmount nNormalizedAnonymizedBalance; - double nAverageAnonymizedRounds; - - { - TRY_LOCK(cs_main, lockMain); - if (!lockMain) return; - - nDenominatedConfirmedBalance = pwalletMain->GetDenominatedBalance(); - nDenominatedUnconfirmedBalance = pwalletMain->GetDenominatedBalance(true); - nAnonymizableBalance = pwalletMain->GetAnonymizableBalance(); - nNormalizedAnonymizedBalance = pwalletMain->GetNormalizedAnonymizedBalance(); - nAverageAnonymizedRounds = pwalletMain->GetAverageAnonymizedRounds(); - } - - CAmount nMaxToAnonymize = nAnonymizableBalance + currentAnonymizedBalance + nDenominatedUnconfirmedBalance; - - // If it's more than the anon threshold, limit to that. - if (nMaxToAnonymize > nAnonymizeBulwarkAmount * COIN) nMaxToAnonymize = nAnonymizeBulwarkAmount * COIN; - - if (nMaxToAnonymize == 0) return; - - if (nMaxToAnonymize >= nAnonymizeBulwarkAmount * COIN) { - ui->labelAmountRounds->setToolTip(tr("Found enough compatible inputs to anonymize %1") - .arg(strAnonymizeBulwarkAmount)); - strAnonymizeBulwarkAmount = strAnonymizeBulwarkAmount.remove(strAnonymizeBulwarkAmount.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1); - strAmountAndRounds = strAnonymizeBulwarkAmount + " / " + tr("%n Rounds", "", nObfuscationRounds); - } else { - QString strMaxToAnonymize = BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, nMaxToAnonymize, false, BitcoinUnits::separatorAlways); - ui->labelAmountRounds->setToolTip(tr("Not enough compatible inputs to anonymize %1,
" - "will anonymize %2 instead") - .arg(strAnonymizeBulwarkAmount) - .arg(strMaxToAnonymize)); - strMaxToAnonymize = strMaxToAnonymize.remove(strMaxToAnonymize.indexOf("."), BitcoinUnits::decimals(nDisplayUnit) + 1); - strAmountAndRounds = "" + - QString(BitcoinUnits::factor(nDisplayUnit) == 1 ? "" : "~") + strMaxToAnonymize + - " / " + tr("%n Rounds", "", nObfuscationRounds) + ""; - } - ui->labelAmountRounds->setText(strAmountAndRounds); - - // calculate parts of the progress, each of them shouldn't be higher than 1 - // progress of denominating - float denomPart = 0; - // mixing progress of denominated balance - float anonNormPart = 0; - // completeness of full amount anonimization - float anonFullPart = 0; - - CAmount denominatedBalance = nDenominatedConfirmedBalance + nDenominatedUnconfirmedBalance; - denomPart = (float)denominatedBalance / nMaxToAnonymize; - denomPart = denomPart > 1 ? 1 : denomPart; - denomPart *= 100; - - anonNormPart = (float)nNormalizedAnonymizedBalance / nMaxToAnonymize; - anonNormPart = anonNormPart > 1 ? 1 : anonNormPart; - anonNormPart *= 100; - - anonFullPart = (float)currentAnonymizedBalance / nMaxToAnonymize; - anonFullPart = anonFullPart > 1 ? 1 : anonFullPart; - anonFullPart *= 100; - - // apply some weights to them ... - float denomWeight = 1; - float anonNormWeight = nObfuscationRounds; - float anonFullWeight = 2; - float fullWeight = denomWeight + anonNormWeight + anonFullWeight; - // ... and calculate the whole progress - float denomPartCalc = ceilf((denomPart * denomWeight / fullWeight) * 100) / 100; - float anonNormPartCalc = ceilf((anonNormPart * anonNormWeight / fullWeight) * 100) / 100; - float anonFullPartCalc = ceilf((anonFullPart * anonFullWeight / fullWeight) * 100) / 100; - float progress = denomPartCalc + anonNormPartCalc + anonFullPartCalc; - if (progress >= 100) progress = 100; - - ui->obfuscationProgress->setValue(progress); - - QString strToolPip = ("" + tr("Overall progress") + ": %1%
" + - tr("Denominated") + ": %2%
" + - tr("Mixed") + ": %3%
" + - tr("Anonymized") + ": %4%
" + - tr("Denominated inputs have %5 of %n rounds on average", "", nObfuscationRounds)) - .arg(progress) - .arg(denomPart) - .arg(anonNormPart) - .arg(anonFullPart) - .arg(nAverageAnonymizedRounds); - ui->obfuscationProgress->setToolTip(strToolPip); -} - - -void OverviewPage::obfuScationStatus() -{ - static int64_t nLastDSProgressBlockTime = 0; - - int nBestHeight = chainActive.Tip()->nHeight; - - // we we're processing more then 1 block per second, we'll just leave - if (((nBestHeight - obfuScationPool.cachedNumBlocks) / (GetTimeMillis() - nLastDSProgressBlockTime + 1) > 1)) return; - nLastDSProgressBlockTime = GetTimeMillis(); - - if (!fEnableObfuscation) { - if (nBestHeight != obfuScationPool.cachedNumBlocks) { - obfuScationPool.cachedNumBlocks = nBestHeight; - updateObfuscationProgress(); - - ui->obfuscationEnabled->setText(tr("Disabled")); - ui->obfuscationStatus->setText(""); - ui->toggleObfuscation->setText(tr("Start Obfuscation")); - } - - return; - } - - // check obfuscation status and unlock if needed - if (nBestHeight != obfuScationPool.cachedNumBlocks) { - // Balance and number of transactions might have changed - obfuScationPool.cachedNumBlocks = nBestHeight; - updateObfuscationProgress(); - - ui->obfuscationEnabled->setText(tr("Enabled")); - } - - QString strStatus = QString(obfuScationPool.GetStatus().c_str()); - - QString s = tr("Last Obfuscation message:\n") + strStatus; - - if (s != ui->obfuscationStatus->text()) - LogPrintf("Last Obfuscation message: %s\n", strStatus.toStdString()); - - ui->obfuscationStatus->setText(s); - - if (obfuScationPool.sessionDenom == 0) { - ui->labelSubmittedDenom->setText(tr("N/A")); - } else { - std::string out; - obfuScationPool.GetDenominationsToString(obfuScationPool.sessionDenom, out); - QString s2(out.c_str()); - ui->labelSubmittedDenom->setText(s2); - } -} - -void OverviewPage::obfuscationAuto() -{ - obfuScationPool.DoAutomaticDenominating(); -} - -void OverviewPage::obfuscationReset() -{ - obfuScationPool.Reset(); - - QMessageBox::warning(this, tr("Obfuscation"), - tr("Obfuscation was successfully reset."), - QMessageBox::Ok, QMessageBox::Ok); -} - -void OverviewPage::toggleObfuscation() -{ - QSettings settings; - // Popup some information on first mixing - QString hasMixed = settings.value("hasMixed").toString(); - if (hasMixed.isEmpty()) { - QMessageBox::information(this, tr("Obfuscation"), - tr("If you don't want to see internal Obfuscation fees/transactions select \"Most Common\" as Type on the \"Transactions\" tab."), - QMessageBox::Ok, QMessageBox::Ok); - settings.setValue("hasMixed", "hasMixed"); - } - if (!fEnableObfuscation) { - int64_t balance = currentBalance; - float minAmount = 14.90 * COIN; - if (balance < minAmount) { - QString strMinAmount(BitcoinUnits::formatWithUnit(nDisplayUnit, minAmount)); - QMessageBox::warning(this, tr("Obfuscation"), - tr("Obfuscation requires at least %1 to use.").arg(strMinAmount), - QMessageBox::Ok, QMessageBox::Ok); - return; - } - - // if wallet is locked, ask for a passphrase - if (walletModel->getEncryptionStatus() == WalletModel::Locked) { - WalletModel::UnlockContext ctx(walletModel->requestUnlock(false)); - if (!ctx.isValid()) { - //unlock was cancelled - obfuScationPool.cachedNumBlocks = std::numeric_limits::max(); - QMessageBox::warning(this, tr("Obfuscation"), - tr("Wallet is locked and user declined to unlock. Disabling Obfuscation."), - QMessageBox::Ok, QMessageBox::Ok); - if (fDebug) LogPrintf("Wallet is locked and user declined to unlock. Disabling Obfuscation.\n"); - return; - } - } - } - - fEnableObfuscation = !fEnableObfuscation; - obfuScationPool.cachedNumBlocks = std::numeric_limits::max(); - - if (!fEnableObfuscation) { - ui->toggleObfuscation->setText(tr("Start Obfuscation")); - obfuScationPool.UnlockCoins(); - } else { - ui->toggleObfuscation->setText(tr("Stop Obfuscation")); - - /* show obfuscation configuration if client has defaults set */ - - if (nAnonymizeBulwarkAmount == 0) { - ObfuscationConfig dlg(this); - dlg.setModel(walletModel); - dlg.exec(); - } - } -} diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index ea9859e55..e27f88abf 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -35,12 +35,12 @@ class OverviewPage : public QWidget void setClientModel(ClientModel* clientModel); void setWalletModel(WalletModel* walletModel); void showOutOfSyncWarning(bool fShow); - void updateObfuscationProgress(); public slots: - void obfuScationStatus(); - void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& anonymizedBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); - void on_toggleStaking_clicked(); + void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& zerocoinBalance, const CAmount& unconfirmedZerocoinBalance, const CAmount& immatureZerocoinBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); + signals: void transactionClicked(const QModelIndex& index); @@ -52,19 +52,19 @@ public slots: CAmount currentBalance; CAmount currentUnconfirmedBalance; CAmount currentImmatureBalance; - CAmount currentAnonymizedBalance; + CAmount currentZerocoinBalance; + CAmount currentUnconfirmedZerocoinBalance; + CAmount currentimmatureZerocoinBalance; CAmount currentWatchOnlyBalance; CAmount currentWatchUnconfBalance; CAmount currentWatchImmatureBalance; int nDisplayUnit; + void getPercentage(CAmount nTotalBalance, CAmount nZerocoinBalance, QString& sBWKPercentage, QString& szBWKPercentage); TxViewDelegate* txdelegate; TransactionFilterProxy* filter; private slots: - void toggleObfuscation(); - void obfuscationAuto(); - void obfuscationReset(); void updateDisplayUnit(); void handleTransactionClicked(const QModelIndex& index); void updateAlerts(const QString& warnings); diff --git a/src/qt/privacydialog.cpp b/src/qt/privacydialog.cpp new file mode 100644 index 000000000..328aac964 --- /dev/null +++ b/src/qt/privacydialog.cpp @@ -0,0 +1,760 @@ +// Copyright (c) 2011-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "privacydialog.h" +#include "ui_privacydialog.h" + +#include "addressbookpage.h" +#include "addresstablemodel.h" +#include "bitcoinunits.h" +#include "coincontroldialog.h" +#include "libzerocoin/Denominations.h" +#include "optionsmodel.h" +#include "sendcoinsentry.h" +#include "walletmodel.h" +#include "coincontrol.h" +#include "zbwkcontroldialog.h" +#include "spork.h" + +#include +#include +#include +#include + +PrivacyDialog::PrivacyDialog(QWidget* parent) : QDialog(parent), + ui(new Ui::PrivacyDialog), + walletModel(0), + currentBalance(-1) +{ + nDisplayUnit = 0; // just make sure it's not unitialized + ui->setupUi(this); + + // "Spending 999999 zBWK ought to be enough for anybody." - Bill Gates, 2017 + ui->zBWKpayAmount->setValidator(new QDoubleValidator(0.0, 21000000.0, 20, this)); + ui->labelMintAmountValue->setValidator(new QIntValidator(0, 999999, this)); + + // Default texts for (mini-) coincontrol + ui->labelCoinControlQuantity->setText (tr("Coins automatically selected")); + ui->labelCoinControlAmount->setText (tr("Coins automatically selected")); + ui->labelzBWKSyncStatus->setText("(" + tr("out of sync") + ")"); + + // Sunken frame for minting messages + ui->TEMintStatus->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + ui->TEMintStatus->setLineWidth (2); + ui->TEMintStatus->setMidLineWidth (2); + ui->TEMintStatus->setPlainText(tr("Mint Status: Okay")); + + // Coin Control signals + connect(ui->pushButtonCoinControl, SIGNAL(clicked()), this, SLOT(coinControlButtonClicked())); + + // Coin Control: clipboard actions + QAction* clipboardQuantityAction = new QAction(tr("Copy quantity"), this); + QAction* clipboardAmountAction = new QAction(tr("Copy amount"), this); + connect(clipboardQuantityAction, SIGNAL(triggered()), this, SLOT(coinControlClipboardQuantity())); + 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:")); + ui->labelzDenom2Text->setText(tr("Denom. with value 5:")); + ui->labelzDenom3Text->setText(tr("Denom. with value 10:")); + ui->labelzDenom4Text->setText(tr("Denom. with value 50:")); + ui->labelzDenom5Text->setText(tr("Denom. with value 100:")); + ui->labelzDenom6Text->setText(tr("Denom. with value 500:")); + ui->labelzDenom7Text->setText(tr("Denom. with value 1000:")); + + // AutoMint status + ui->label_AutoMintStatus->setText(tr("AutoMint Status:")); + + // Global Supply labels + ui->labelZsupplyText1->setText(tr("Denom. 1:")); + ui->labelZsupplyText5->setText(tr("Denom. 5:")); + ui->labelZsupplyText10->setText(tr("Denom. 10:")); + ui->labelZsupplyText50->setText(tr("Denom. 50:")); + ui->labelZsupplyText100->setText(tr("Denom. 100:")); + ui->labelZsupplyText500->setText(tr("Denom. 500:")); + ui->labelZsupplyText1000->setText(tr("Denom. 1000:")); + + // Bulwark settings + QSettings settings; + if (!settings.contains("nSecurityLevel")){ + nSecurityLevel = 42; + settings.setValue("nSecurityLevel", nSecurityLevel); + } + else{ + nSecurityLevel = settings.value("nSecurityLevel").toInt(); + } + + if (!settings.contains("fMinimizeChange")){ + fMinimizeChange = false; + settings.setValue("fMinimizeChange", fMinimizeChange); + } + else{ + fMinimizeChange = settings.value("fMinimizeChange").toBool(); + } + ui->checkBoxMinimizeChange->setChecked(fMinimizeChange); + + // Start with displaying the "out of sync" warnings + showOutOfSyncWarning(true); + + // Hide those placeholder elements needed for CoinControl interaction + ui->WarningLabel->hide(); // Explanatory text visible in QT-Creator + ui->dummyHideWidget->hide(); // Dummy widget with elements to hide + + //temporary disable for maintenance + if(GetAdjustedTime() > GetSporkValue(SPORK_22_ZEROCOIN_MAINTENANCE_MODE)) { + ui->pushButtonMintzBWK->setEnabled(false); + ui->pushButtonMintzBWK->setToolTip(tr("zBWK is currently disabled due to maintenance.")); + + ui->pushButtonSpendzBWK->setEnabled(false); + ui->pushButtonSpendzBWK->setToolTip(tr("zBWK is currently disabled due to maintenance.")); + } +} + +PrivacyDialog::~PrivacyDialog() +{ + delete ui; +} + +void PrivacyDialog::setModel(WalletModel* walletModel) +{ + this->walletModel = walletModel; + + if (walletModel && walletModel->getOptionsModel()) { + // Keep up to date with wallet + setBalance(walletModel->getBalance(), walletModel->getUnconfirmedBalance(), walletModel->getImmatureBalance(), + walletModel->getZerocoinBalance(), walletModel->getUnconfirmedZerocoinBalance(), walletModel->getImmatureZerocoinBalance(), + walletModel->getWatchBalance(), walletModel->getWatchUnconfirmedBalance(), walletModel->getWatchImmatureBalance()); + + connect(walletModel, SIGNAL(balanceChanged(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount)), this, + SLOT(setBalance(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount))); + ui->securityLevel->setValue(nSecurityLevel); + } +} + +void PrivacyDialog::on_pasteButton_clicked() +{ + // Paste text from clipboard into recipient field + ui->payTo->setText(QApplication::clipboard()->text()); +} + +void PrivacyDialog::on_addressBookButton_clicked() +{ + if (!walletModel) + return; + AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this); + dlg.setModel(walletModel->getAddressTableModel()); + if (dlg.exec()) { + ui->payTo->setText(dlg.getReturnValue()); + ui->zBWKpayAmount->setFocus(); + } +} + +void PrivacyDialog::on_pushButtonMintzBWK_clicked() +{ + if (!walletModel || !walletModel->getOptionsModel()) + return; + + if (GetAdjustedTime() < GetSporkValue(SPORK_21_ENABLE_ZEROCOIN)) { + QMessageBox::information(this, tr("Mint Zerocoin"), tr("Zerocoin functionality is not enabled on the Bulwark network yet."), QMessageBox::Ok, QMessageBox::Ok); + return; + } + + if(GetAdjustedTime() > GetSporkValue(SPORK_22_ZEROCOIN_MAINTENANCE_MODE)) { + QMessageBox::information(this, tr("Mint Zerocoin"), tr("zBWK is currently undergoing maintenance."), QMessageBox::Ok, QMessageBox::Ok); + return; + } + + // Reset message text + ui->TEMintStatus->setPlainText(tr("Mint Status: Okay")); + + // Request unlock if wallet was locked or unlocked for mixing: + WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); + if (encStatus == walletModel->Locked) { + WalletModel::UnlockContext ctx(walletModel->requestUnlock(true)); + if (!ctx.isValid()) { + // Unlock wallet was cancelled + ui->TEMintStatus->setPlainText(tr("Error: Your wallet is locked. Please enter the wallet passphrase first.")); + return; + } + } + + QString sAmount = ui->labelMintAmountValue->text(); + CAmount nAmount = sAmount.toInt() * COIN; + + // Minting amount must be > 0 + if(nAmount <= 0){ + ui->TEMintStatus->setPlainText(tr("Message: Enter an amount > 0.")); + return; + } + + ui->TEMintStatus->setPlainText(tr("Minting ") + ui->labelMintAmountValue->text() + " zBWK..."); + ui->TEMintStatus->repaint (); + + int64_t nTime = GetTimeMillis(); + + CWalletTx wtx; + vector vMints; + string strError = pwalletMain->MintZerocoin(nAmount, wtx, vMints, CoinControlDialog::coinControl); + + // Return if something went wrong during minting + if (strError != ""){ + ui->TEMintStatus->setPlainText(QString::fromStdString(strError)); + return; + } + + double fDuration = (double)(GetTimeMillis() - nTime)/1000.0; + + // Minting successfully finished. Show some stats for entertainment. + QString strStatsHeader = tr("Successfully minted ") + ui->labelMintAmountValue->text() + tr(" zBWK in ") + + QString::number(fDuration) + tr(" sec. Used denominations:\n"); + + // Clear amount to avoid double spending when accidentally clicking twice + ui->labelMintAmountValue->setText ("0"); + + QString strStats = ""; + ui->TEMintStatus->setPlainText(strStatsHeader); + + for (CZerocoinMint mint : vMints) { + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + strStats = strStats + QString::number(mint.GetDenomination()) + " "; + ui->TEMintStatus->setPlainText(strStatsHeader + strStats); + ui->TEMintStatus->repaint (); + + } + + // Available balance isn't always updated, so force it. + setBalance(walletModel->getBalance(), walletModel->getUnconfirmedBalance(), walletModel->getImmatureBalance(), + walletModel->getZerocoinBalance(), walletModel->getUnconfirmedZerocoinBalance(), walletModel->getImmatureZerocoinBalance(), + walletModel->getWatchBalance(), walletModel->getWatchUnconfirmedBalance(), walletModel->getWatchImmatureBalance()); + coinControlUpdateLabels(); + + return; +} + +void PrivacyDialog::on_pushButtonMintReset_clicked() +{ + if (!walletModel || !walletModel->getOptionsModel()) + return; + + ui->TEMintStatus->setPlainText(tr("Starting ResetMintZerocoin: rescanning complete blockchain, this will need up to 30 minutes depending on your hardware. \nPlease be patient...")); + ui->TEMintStatus->repaint (); + + int64_t nTime = GetTimeMillis(); + string strResetMintResult = pwalletMain->ResetMintZerocoin(false); // do not do the extended search from GUI + double fDuration = (double)(GetTimeMillis() - nTime)/1000.0; + ui->TEMintStatus->setPlainText(QString::fromStdString(strResetMintResult) + tr("Duration: ") + QString::number(fDuration) + tr(" sec.\n")); + ui->TEMintStatus->repaint (); + + return; +} + +void PrivacyDialog::on_pushButtonSpentReset_clicked() +{ + if (!walletModel || !walletModel->getOptionsModel()) + return; + + ui->TEMintStatus->setPlainText(tr("Starting ResetSpentZerocoin: ")); + ui->TEMintStatus->repaint (); + int64_t nTime = GetTimeMillis(); + string strResetSpentResult = pwalletMain->ResetSpentZerocoin(); + double fDuration = (double)(GetTimeMillis() - nTime)/1000.0; + ui->TEMintStatus->setPlainText(QString::fromStdString(strResetSpentResult) + tr("Duration: ") + QString::number(fDuration) + tr(" sec.\n")); + ui->TEMintStatus->repaint (); + + return; +} + +void PrivacyDialog::on_pushButtonSpendzBWK_clicked() +{ + + if (!walletModel || !walletModel->getOptionsModel() || !pwalletMain) + return; + + if (GetAdjustedTime() < GetSporkValue(SPORK_21_ENABLE_ZEROCOIN)) { + QMessageBox::information(this, tr("Spend Zerocoin"), tr("Zerocoin functionality is not enabled on the Bulwark network yet."), QMessageBox::Ok, QMessageBox::Ok); + return; + } + + if(GetAdjustedTime() > GetSporkValue(SPORK_22_ZEROCOIN_MAINTENANCE_MODE)) { + QMessageBox::information(this, tr("Mint Zerocoin"), + tr("zBWK is currently undergoing maintenance."), QMessageBox::Ok, QMessageBox::Ok); + return; + } + + // Request unlock if wallet was locked or unlocked for mixing: + WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); + if (encStatus == walletModel->Locked || encStatus == walletModel->UnlockedForAnonymizationOnly) { + WalletModel::UnlockContext ctx(walletModel->requestUnlock(true)); + if (!ctx.isValid()) { + // Unlock wallet was cancelled + return; + } + // Wallet is unlocked now, sedn zBWK + sendzBWK(); + return; + } + // Wallet already unlocked or not encrypted at all, send zBWK + sendzBWK(); +} + +void PrivacyDialog::on_pushButtonZBWKControl_clicked() +{ + ZBwkControlDialog* zBwkControl = new ZBwkControlDialog(this); + zBwkControl->setModel(walletModel); + zBwkControl->exec(); +} + +void PrivacyDialog::setZBwkControlLabels(int64_t nAmount, int nQuantity) +{ + ui->labelzBWKSelected_int->setText(QString::number(nAmount)); + ui->labelQuantitySelected_int->setText(QString::number(nQuantity)); +} + +static inline int64_t roundint64(double d) +{ + return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); +} + +void PrivacyDialog::sendzBWK() +{ + QSettings settings; + + // Double is allowed now + double dAmount = ui->zBWKpayAmount->text().toDouble(); + CAmount nAmount = roundint64(dAmount* COIN); + + // If we don't have a balance then post an error. + if (nAmount <= 0) { + QMessageBox::warning(this, tr("Spend Zerocoin"), tr("Invalid balance amount."), QMessageBox::Ok, QMessageBox::Ok); + return; + } + + // Handle 'Pay To' address options + CBitcoinAddress address(ui->payTo->text().toStdString()); + if(ui->payTo->text().isEmpty()){ + QMessageBox::information(this, tr("Spend Zerocoin"), tr("No 'Pay To' address provided, creating local payment"), QMessageBox::Ok, QMessageBox::Ok); + } + else{ + if (!address.IsValid()) { + QMessageBox::warning(this, tr("Spend Zerocoin"), tr("Invalid Bulwark Address"), QMessageBox::Ok, QMessageBox::Ok); + ui->payTo->setFocus(); + return; + } + } + + // Check amount validity + if (!MoneyRange(nAmount) || nAmount <= 0.0) { + QMessageBox::warning(this, tr("Spend Zerocoin"), tr("Invalid Send Amount"), QMessageBox::Ok, QMessageBox::Ok); + ui->zBWKpayAmount->setFocus(); + return; + } + + // Convert change to zBWK + bool fMintChange = ui->checkBoxMintChange->isChecked(); + + // Persist minimize change setting + fMinimizeChange = ui->checkBoxMinimizeChange->isChecked(); + settings.setValue("fMinimizeChange", fMinimizeChange); + + // Warn for additional fees if amount is not an integer and change as zBWK is requested + bool fWholeNumber = floor(dAmount) == dAmount; + double dzFee = 0.0; + + if(!fWholeNumber) + dzFee = 1.0 - (dAmount - floor(dAmount)); + + if(!fWholeNumber && fMintChange){ + QString strFeeWarning = "You've entered an amount with fractional digits and want the change to be converted to Zerocoin.

"; + strFeeWarning += QString::number(dzFee, 'f', 8) + " BWK will be added to the standard transaction fees!
"; + QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm additional Fees"), + strFeeWarning, + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel); + + if (retval != QMessageBox::Yes) { + // Sending canceled + ui->zBWKpayAmount->setFocus(); + return; + } + } + + // Persist Security Level for next start + nSecurityLevel = ui->securityLevel->value(); + settings.setValue("nSecurityLevel", nSecurityLevel); + + // Spend confirmation message box + + // Add address info if available + QString strAddressLabel = ""; + if(!ui->payTo->text().isEmpty() && !ui->addAsLabel->text().isEmpty()){ + strAddressLabel = "
(" + ui->addAsLabel->text() + ") "; + } + + // General info + QString strQuestionString = tr("Are you sure you want to send?

"); + QString strAmount = "" + QString::number(dAmount, 'f', 8) + " zBWK"; + QString strAddress = tr(" to address ") + QString::fromStdString(address.ToString()) + strAddressLabel + "
"; + + if(ui->payTo->text().isEmpty()){ + // No address provided => send to local address + strAddress = tr(" to a newly generated (unused and therefore anonymous) local address
"); + } + + QString strSecurityLevel = tr("with Security Level ") + ui->securityLevel->text() + " ?"; + strQuestionString += strAmount + strAddress + strSecurityLevel; + + // Display message box + QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"), + strQuestionString, + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel); + + if (retval != QMessageBox::Yes) { + // Sending canceled + return; + } + + int64_t nTime = GetTimeMillis(); + ui->TEMintStatus->setPlainText(tr("Spending Zerocoin.\nComputationally expensive, might need several minutes depending on the selected Security Level and your hardware. \nPlease be patient...")); + ui->TEMintStatus->repaint(); + + // use mints from zBWK selector if applicable + vector vMintsSelected; + if (!ZBwkControlDialog::listSelectedMints.empty()) { + vMintsSelected = ZBwkControlDialog::GetSelectedMints(); + } + + // Spend zBWK + CWalletTx wtxNew; + CZerocoinSpendReceipt receipt; + bool fSuccess = false; + if(ui->payTo->text().isEmpty()){ + // Spend to newly generated local address + fSuccess = pwalletMain->SpendZerocoin(nAmount, nSecurityLevel, wtxNew, receipt, vMintsSelected, fMintChange, fMinimizeChange); + } + else { + // Spend to supplied destination address + fSuccess = pwalletMain->SpendZerocoin(nAmount, nSecurityLevel, wtxNew, receipt, vMintsSelected, fMintChange, fMinimizeChange, &address); + } + + // 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 zBWK transaction + if (nNeededSpends > nMaxSpends) { + QString strStatusMessage = tr("Too much inputs (") + QString::number(nNeededSpends, 10) + tr(") needed. \nMaximum allowed: ") + QString::number(nMaxSpends, 10); + strStatusMessage += tr("\nEither mint higher denominations (so fewer inputs are needed) or reduce the amount to spend."); + QMessageBox::warning(this, tr("Spend Zerocoin"), strStatusMessage.toStdString().c_str(), QMessageBox::Ok, QMessageBox::Ok); + 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())); + } + ui->zBWKpayAmount->setFocus(); + ui->TEMintStatus->repaint(); + return; + } + + // Clear zbwk selector in case it was used + ZBwkControlDialog::listSelectedMints.clear(); + + // Some statistics for entertainment + QString strStats = ""; + CAmount nValueIn = 0; + int nCount = 0; + for (CZerocoinSpend spend : receipt.GetSpends()) { + strStats += tr("zBWK Spend #: ") + QString::number(nCount) + ", "; + strStats += tr("denomination: ") + QString::number(spend.GetDenomination()) + ", "; + strStats += tr("serial: ") + spend.GetSerial().ToString().c_str() + "\n"; + strStats += tr("Spend is 1 of : ") + QString::number(spend.GetMintCount()) + " mints in the accumulator\n"; + nValueIn += libzerocoin::ZerocoinDenominationToAmount(spend.GetDenomination()); + } + + CAmount nValueOut = 0; + for (const CTxOut& txout: wtxNew.vout) { + strStats += tr("value out: ") + FormatMoney(txout.nValue).c_str() + " BWK, "; + nValueOut += txout.nValue; + + strStats += tr("address: "); + CTxDestination dest; + if(txout.scriptPubKey.IsZerocoinMint()) + strStats += tr("zBWK Mint"); + else if(ExtractDestination(txout.scriptPubKey, dest)) + strStats += tr(CBitcoinAddress(dest).ToString().c_str()); + strStats += "\n"; + } + double fDuration = (double)(GetTimeMillis() - nTime)/1000.0; + strStats += tr("Duration: ") + QString::number(fDuration) + tr(" sec.\n"); + strStats += tr("Sending successful, return code: ") + QString::number(receipt.GetStatus()) + "\n"; + + QString strReturn; + strReturn += tr("txid: ") + wtxNew.GetHash().ToString().c_str() + "\n"; + strReturn += tr("fee: ") + QString::fromStdString(FormatMoney(nValueIn-nValueOut)) + "\n"; + strReturn += strStats; + + // Clear amount to avoid double spending when accidentally clicking twice + ui->zBWKpayAmount->setText("0"); + ui->labelzBWKSelected_int->setText("0"); + ui->labelQuantitySelected_int->setText("0"); + + ui->TEMintStatus->setPlainText(strReturn); + ui->TEMintStatus->repaint(); +} + +void PrivacyDialog::on_payTo_textChanged(const QString& address) +{ + updateLabel(address); +} + +// Coin Control: copy label "Quantity" to clipboard +void PrivacyDialog::coinControlClipboardQuantity() +{ + GUIUtil::setClipboard(ui->labelCoinControlQuantity->text()); +} + +// Coin Control: copy label "Amount" to clipboard +void PrivacyDialog::coinControlClipboardAmount() +{ + GUIUtil::setClipboard(ui->labelCoinControlAmount->text().left(ui->labelCoinControlAmount->text().indexOf(" "))); +} + +// Coin Control: button inputs -> show actual coin control dialog +void PrivacyDialog::coinControlButtonClicked() +{ + CoinControlDialog dlg; + dlg.setModel(walletModel); + dlg.exec(); + coinControlUpdateLabels(); +} + +// Coin Control: update labels +void PrivacyDialog::coinControlUpdateLabels() +{ + if (!walletModel || !walletModel->getOptionsModel() || !walletModel->getOptionsModel()->getCoinControlFeatures()) + return; + + // set pay amounts + CoinControlDialog::payAmounts.clear(); + + if (CoinControlDialog::coinControl->HasSelected()) { + // Actual coin control calculation + CoinControlDialog::updateLabels(walletModel, this); + } else { + ui->labelCoinControlQuantity->setText (tr("Coins automatically selected")); + ui->labelCoinControlAmount->setText (tr("Coins automatically selected")); + } +} + +bool PrivacyDialog::updateLabel(const QString& address) +{ + if (!walletModel) + return false; + + // Fill in label from address book, if address has an associated label + QString associatedLabel = walletModel->getAddressTableModel()->labelForAddress(address); + if (!associatedLabel.isEmpty()) { + ui->addAsLabel->setText(associatedLabel); + return true; + } + + return false; +} + +void PrivacyDialog::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& zerocoinBalance, const CAmount& unconfirmedZerocoinBalance, const CAmount& immatureZerocoinBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance) +{ + + currentBalance = balance; + currentUnconfirmedBalance = unconfirmedBalance; + currentImmatureBalance = immatureBalance; + currentZerocoinBalance = zerocoinBalance; + currentUnconfirmedZerocoinBalance = unconfirmedZerocoinBalance; + currentImmatureZerocoinBalance = immatureZerocoinBalance; + currentWatchOnlyBalance = watchOnlyBalance; + currentWatchUnconfBalance = watchUnconfBalance; + currentWatchImmatureBalance = watchImmatureBalance; + + CWalletDB walletdb(pwalletMain->strWalletFile); + list listMints = walletdb.ListMintedCoins(true, false, true); + + std::map mapDenomBalances; + std::map mapUnconfirmed; + std::map mapImmature; + for (const auto& denom : libzerocoin::zerocoinDenomList){ + mapDenomBalances.insert(make_pair(denom, 0)); + mapUnconfirmed.insert(make_pair(denom, 0)); + mapImmature.insert(make_pair(denom, 0)); + } + + int nBestHeight = chainActive.Height(); + for (auto& mint : listMints){ + // All denominations + mapDenomBalances.at(mint.GetDenomination())++; + + if (!mint.GetHeight() || chainActive.Height() - mint.GetHeight() <= Params().Zerocoin_MintRequiredConfirmations()) { + // All unconfirmed denominations + mapUnconfirmed.at(mint.GetDenomination())++; + continue; + } + + // After a denomination is confirmed it might still be immature because < 1 of the same denomination were minted after it + CBlockIndex *pindex = chainActive[mint.GetHeight() + 1]; + int nHeight2CheckpointsDeep = nBestHeight - (nBestHeight % 10) - 20; + int nMintsAdded = 0; + while (pindex->nHeight < nHeight2CheckpointsDeep) { //at least 2 checkpoints from the top block + nMintsAdded += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), mint.GetDenomination()); + if (nMintsAdded >= Params().Zerocoin_RequiredAccumulation()) + break; + pindex = chainActive[pindex->nHeight + 1]; + } + if (nMintsAdded < Params().Zerocoin_RequiredAccumulation()){ + // Immature denominations + mapImmature.at(mint.GetDenomination())++; + } + } + + int64_t nCoins = 0; + int64_t nSumPerCoin = 0; + int64_t nUnconfirmed = 0; + int64_t nImmature = 0; + QString strDenomStats, strUnconfirmed = ""; + + for (const auto& denom : libzerocoin::zerocoinDenomList) { + nCoins = libzerocoin::ZerocoinDenominationToInt(denom); + nSumPerCoin = nCoins * mapDenomBalances.at(denom); + nUnconfirmed = mapUnconfirmed.at(denom); + nImmature = mapImmature.at(denom); + + strUnconfirmed = ""; + if (nUnconfirmed) { + strUnconfirmed += QString::number(nUnconfirmed) + QString(" unconf. "); + } + if(nImmature) { + strUnconfirmed += QString::number(nImmature) + QString(" immature "); + } + if(nImmature || nUnconfirmed) { + strUnconfirmed = QString("( ") + strUnconfirmed + QString(") "); + } + + strDenomStats = strUnconfirmed + QString::number(mapDenomBalances.at(denom)) + " x " + + QString::number(nCoins) + " = " + + QString::number(nSumPerCoin) + " zBWK "; + + switch (nCoins) { + case libzerocoin::CoinDenomination::ZQ_ONE: + ui->labelzDenom1Amount->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_FIVE: + ui->labelzDenom2Amount->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_TEN: + ui->labelzDenom3Amount->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_FIFTY: + ui->labelzDenom4Amount->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_ONE_HUNDRED: + ui->labelzDenom5Amount->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_FIVE_HUNDRED: + ui->labelzDenom6Amount->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_ONE_THOUSAND: + ui->labelzDenom7Amount->setText(strDenomStats); + break; + default: + // Error Case: don't update display + break; + } + } + CAmount matureZerocoinBalance = zerocoinBalance - immatureZerocoinBalance; + CAmount nLockedBalance = 0; + if (walletModel) { + nLockedBalance = walletModel->getLockedBalance(); + } + + CAmount bwkBalance = balance - (immatureBalance + nLockedBalance); + if (bwkBalance < 0) bwkBalance = 0; + + ui->labelzAvailableAmount->setText(QString::number(zerocoinBalance/COIN) + QString(" zBWK ")); + ui->labelzAvailableAmount_2->setText(QString::number(matureZerocoinBalance/COIN) + QString(" zBWK ")); + ui->labelzBWKAmountValue->setText(BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, bwkBalance, false, BitcoinUnits::separatorAlways)); + + // Display AutoMint status + QString strAutomintStatus = tr("AutoMint Status:"); + + if (pwalletMain->isZeromintEnabled()) { + strAutomintStatus += tr(" enabled."); + } + else { + strAutomintStatus += tr(" disabled."); + } + + strAutomintStatus += tr(" Configured target percentage: ") + QString::number(pwalletMain->getZeromintPercentage()) + "%"; + ui->label_AutoMintStatus->setText(strAutomintStatus); + + // Display global supply + ui->labelZsupplyAmount->setText(QString::number(chainActive.Tip()->GetZerocoinSupply()/COIN) + QString(" zBWK ")); + for (auto denom : libzerocoin::zerocoinDenomList) { + int64_t nSupply = chainActive.Tip()->mapZerocoinSupply.at(denom); + QString strSupply = QString::number(nSupply) + " x " + QString::number(denom) + " = " + + QString::number(nSupply*denom) + " zBWK "; + switch (denom) { + case libzerocoin::CoinDenomination::ZQ_ONE: + ui->labelZsupplyAmount1->setText(strSupply); + break; + case libzerocoin::CoinDenomination::ZQ_FIVE: + ui->labelZsupplyAmount5->setText(strSupply); + break; + case libzerocoin::CoinDenomination::ZQ_TEN: + ui->labelZsupplyAmount10->setText(strSupply); + break; + case libzerocoin::CoinDenomination::ZQ_FIFTY: + ui->labelZsupplyAmount50->setText(strSupply); + break; + case libzerocoin::CoinDenomination::ZQ_ONE_HUNDRED: + ui->labelZsupplyAmount100->setText(strSupply); + break; + case libzerocoin::CoinDenomination::ZQ_FIVE_HUNDRED: + ui->labelZsupplyAmount500->setText(strSupply); + break; + case libzerocoin::CoinDenomination::ZQ_ONE_THOUSAND: + ui->labelZsupplyAmount1000->setText(strSupply); + break; + default: + // Error Case: don't update display + break; + } + } +} + +void PrivacyDialog::updateDisplayUnit() +{ + if (walletModel && walletModel->getOptionsModel()) { + nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit(); + if (currentBalance != -1) + setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance, + currentZerocoinBalance, currentUnconfirmedZerocoinBalance, currentImmatureZerocoinBalance, + currentWatchOnlyBalance, currentWatchUnconfBalance, currentWatchImmatureBalance); + } +} + +void PrivacyDialog::showOutOfSyncWarning(bool fShow) +{ + ui->labelzBWKSyncStatus->setVisible(fShow); +} + +void PrivacyDialog::keyPressEvent(QKeyEvent* event) +{ + if (event->key() != Qt::Key_Escape) // press esc -> ignore + { + this->QDialog::keyPressEvent(event); + } else { + event->ignore(); + } +} diff --git a/src/qt/privacydialog.h b/src/qt/privacydialog.h new file mode 100644 index 000000000..dc6e7a1a6 --- /dev/null +++ b/src/qt/privacydialog.h @@ -0,0 +1,108 @@ +// Copyright (c) 2011-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_PRIVACYDIALOG_H +#define BITCOIN_QT_PRIVACYDIALOG_H + +#include "guiutil.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +class OptionsModel; +class WalletModel; + +namespace Ui +{ +class PrivacyDialog; +} + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +/** Dialog for requesting payment of bitcoins */ +class PrivacyDialog : public QDialog +{ + Q_OBJECT + +public: + enum ColumnWidths { + DATE_COLUMN_WIDTH = 130, + LABEL_COLUMN_WIDTH = 120, + AMOUNT_MINIMUM_COLUMN_WIDTH = 160, + MINIMUM_COLUMN_WIDTH = 130 + }; + + explicit PrivacyDialog(QWidget* parent = 0); + ~PrivacyDialog(); + + void setModel(WalletModel* model); + void showOutOfSyncWarning(bool fShow); + void setZBwkControlLabels(int64_t nAmount, int nQuantity); + +public slots: + void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& zerocoinBalance, const CAmount& unconfirmedZerocoinBalance, const CAmount& immatureZerocoinBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); +protected: + virtual void keyPressEvent(QKeyEvent* event); + +private: + Ui::PrivacyDialog* ui; + QTimer* timer; + GUIUtil::TableViewLastColumnResizingFixer* columnResizingFixer; + WalletModel* walletModel; + QMenu* contextMenu; + CAmount currentBalance; + CAmount currentUnconfirmedBalance; + CAmount currentImmatureBalance; + CAmount currentZerocoinBalance; + CAmount currentUnconfirmedZerocoinBalance; + CAmount currentImmatureZerocoinBalance; + CAmount currentWatchOnlyBalance; + CAmount currentWatchUnconfBalance; + CAmount currentWatchImmatureBalance; + + int nSecurityLevel = 0; + bool fMinimizeChange = false; + + int nDisplayUnit; + bool updateLabel(const QString& address); + void sendzBWK(); + +private slots: + void on_payTo_textChanged(const QString& address); + void on_addressBookButton_clicked(); +// void coinControlFeatureChanged(bool); + void coinControlButtonClicked(); +// void coinControlChangeChecked(int); +// void coinControlChangeEdited(const QString&); + void coinControlUpdateLabels(); + + void coinControlClipboardQuantity(); + void coinControlClipboardAmount(); +// void coinControlClipboardFee(); +// void coinControlClipboardAfterFee(); +// void coinControlClipboardBytes(); +// void coinControlClipboardPriority(); +// void coinControlClipboardLowOutput(); +// void coinControlClipboardChange(); + + void on_pushButtonMintzBWK_clicked(); + void on_pushButtonMintReset_clicked(); + void on_pushButtonSpentReset_clicked(); + void on_pushButtonSpendzBWK_clicked(); + void on_pushButtonZBWKControl_clicked(); + void on_pasteButton_clicked(); + void updateDisplayUnit(); +}; + +#endif // BITCOIN_QT_PRIVACYDIALOG_H diff --git a/src/qt/res/css/default.css b/src/qt/res/css/default.css old mode 100644 new mode 100755 index 8b49a160b..11e807a11 --- a/src/qt/res/css/default.css +++ b/src/qt/res/css/default.css @@ -18,10 +18,10 @@ QMenuBar::item { background-color: #fff } QMenuBar::item:selected { - background-color: #fafefd + background-color: #ffffff } QMenu { - background-color: #fafefd + background-color: #ffffff } QMenu::item { color: #333 @@ -409,7 +409,7 @@ QDialog .QTabWidget::pane { border: 1px solid #d7d7d7 } QDialog .QTabWidget QTabBar::tab { - background-color: #fafefd; + background-color: #ffffff; color: #333; padding-left: 10px; padding-right: 10px; @@ -426,7 +426,7 @@ QDialog .QTabWidget QTabBar::tab:last { QDialog .QTabWidget QTabBar::tab:selected, QDialog .QTabWidget QTabBar::tab:hover { background-color: #ffffff; - color: #333 + color: #0091ea; } QDialog .QTabWidget .QWidget { background-color: #fff; @@ -464,7 +464,7 @@ QDialog#OpenURIDialog QtMaterialFlatButton#selectFileButton:pressed { border: 1px solid #9e9e9e } QWidget#AddressBookPage { - background-color: #fafefd + background-color: #ffffff } QWidget#AddressBookPage QTableView { font-size: 12px @@ -573,7 +573,7 @@ QDialog#RPCConsole QLineEdit#lineEdit { QDialog#RPCConsole QtMaterialFlatButton#clearButton { background-color: transparent; padding-left: 10px; - padding-right: 10px + padding-right: 10px; } QDialog#RPCConsole .QGroupBox #line { background-color: #0091ea @@ -617,15 +617,15 @@ QWidget .QFrame#frame_Header { } QWidget .QFrame#frame_BG { min-width: 400px; - background-color: #fafefd + background-color: #ffffff } QWidget .QFrame#frame_Space { min-width: 400px; - background-color: #fafefd + background-color: #ffffff } QWidget .QFrame#frame_Content { min-width: 400px; - background-color: #fafefd + background-color: #ffffff } QWidget .QFrame#frame_Balances { min-width: 400px; @@ -636,7 +636,8 @@ QWidget .QFrame#frame_CombinedBalances { background-color: #ffffff } QWidget .QFrame#frame_RecentTransactions { - min-width: 400px; + font-size: 10pt; + min-width: 500px; background-color: #ffffff } QWidget .QFrame#frame_Balances .QLabel#BalanceTitle { @@ -712,31 +713,24 @@ QWidget .QFrame#frame_CombinedBalances .QLabel#BalanceTitlez { min-width: 160px; background-color: transparent; text-transform: uppercase; - color: #0091ea; font-weight: 700; font-size: 12px; } QWidget .QFrame#frame_CombinedBalances .QLabel#labelBalanceTextz { min-width: 160px; - color: #003c8f; font-weight: 700; font-size: 12px } QWidget .QFrame#frame_CombinedBalances .QLabel#labelBalancez { - font-size: 26px; - font-weight: 400; - color: #003c8f + font-size: 12px; } QWidget .QFrame#frame_CombinedBalances .QLabel#labelTotalTextz { min-width: 160px; - color: #003c8f; font-weight: 700; font-size: 12px } QWidget .QFrame#frame_CombinedBalances .QLabel#labelTotalz { - font-size: 26px; - font-weight: 400; - color: #003c8f + font-size: 12px; } QWidget .QFrame#frame_RecentTransactions { min-width: 410px; diff --git a/src/qt/res/icons/privacy.png b/src/qt/res/icons/privacy.png new file mode 100644 index 000000000..cbfe54bc1 Binary files /dev/null and b/src/qt/res/icons/privacy.png differ diff --git a/src/qt/res/icons/privacy_m.png b/src/qt/res/icons/privacy_m.png new file mode 100644 index 000000000..65617c275 Binary files /dev/null and b/src/qt/res/icons/privacy_m.png differ diff --git a/src/qt/res/icons/transaction0_dark.png b/src/qt/res/icons/transaction0_dark.png new file mode 100644 index 000000000..80a6ca7fc Binary files /dev/null and b/src/qt/res/icons/transaction0_dark.png differ diff --git a/src/qt/res/images/about.png b/src/qt/res/images/about.png index 7fc116bd0..b8c856a33 100644 Binary files a/src/qt/res/images/about.png and b/src/qt/res/images/about.png differ diff --git a/src/qt/res/images/downArrow.png b/src/qt/res/images/downArrow_dark.png similarity index 100% rename from src/qt/res/images/downArrow.png rename to src/qt/res/images/downArrow_dark.png diff --git a/src/qt/res/images/downArrow_small_dark.png b/src/qt/res/images/downArrow_small_dark.png new file mode 100644 index 000000000..9ac429254 Binary files /dev/null and b/src/qt/res/images/downArrow_small_dark.png differ diff --git a/src/qt/res/images/leftArrow_small.png b/src/qt/res/images/leftArrow_small_dark.png similarity index 100% rename from src/qt/res/images/leftArrow_small.png rename to src/qt/res/images/leftArrow_small_dark.png diff --git a/src/qt/res/images/rightArrow_small.png b/src/qt/res/images/rightArrow_small_dark.png similarity index 100% rename from src/qt/res/images/rightArrow_small.png rename to src/qt/res/images/rightArrow_small_dark.png diff --git a/src/qt/res/images/splash.png b/src/qt/res/images/splash.png index 026387393..dc2478c0e 100644 Binary files a/src/qt/res/images/splash.png and b/src/qt/res/images/splash.png differ diff --git a/src/qt/res/images/splash_testnet.png b/src/qt/res/images/splash_testnet.png index 5779720dd..470ae4a00 100644 Binary files a/src/qt/res/images/splash_testnet.png and b/src/qt/res/images/splash_testnet.png differ diff --git a/src/qt/res/images/upArrow_small_dark.png b/src/qt/res/images/upArrow_small_dark.png new file mode 100644 index 000000000..2ecd94d4d Binary files /dev/null and b/src/qt/res/images/upArrow_small_dark.png differ diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index ba1296b65..5430b634c 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -20,10 +20,10 @@ #include "util.h" #include "qtmaterialflatbutton.h" -#include "json/json_spirit_value.h" - #include +#include + #ifdef ENABLE_WALLET #include #endif @@ -57,6 +57,7 @@ const QString ZAPTXES1("-zapwallettxes=1"); const QString ZAPTXES2("-zapwallettxes=2"); const QString UPGRADEWALLET("-upgradewallet"); const QString REINDEX("-reindex"); +const QString RESYNC("-resync"); const struct { const char* url; @@ -194,20 +195,20 @@ void RPCExecutor::request(const QString& command) std::string strPrint; // Convert argument list to JSON objects in method-dependent way, // and pass it along with the method name to the dispatcher. - json_spirit::Value result = tableRPC.execute( + UniValue result = tableRPC.execute( args[0], RPCConvertValues(args[0], std::vector(args.begin() + 1, args.end()))); // Format result reply - if (result.type() == json_spirit::null_type) + if (result.isNull()) strPrint = ""; - else if (result.type() == json_spirit::str_type) + else if (result.isStr()) strPrint = result.get_str(); else - strPrint = write_string(result, true); + strPrint = result.write(2); emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint)); - } catch (json_spirit::Object& objError) { + } catch (UniValue& objError) { try // Nice formatting for standard-format error { int code = find_value(objError, "code").get_int(); @@ -215,7 +216,7 @@ void RPCExecutor::request(const QString& command) emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); } catch (std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message { // Show raw JSON object - emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false))); + emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write())); } } catch (std::exception& e) { emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what())); @@ -251,6 +252,7 @@ RPCConsole::RPCConsole(QWidget* parent) : QDialog(parent), connect(ui->btn_zapwallettxes2, SIGNAL(clicked()), this, SLOT(walletZaptxes2())); connect(ui->btn_upgradewallet, SIGNAL(clicked()), this, SLOT(walletUpgrade())); connect(ui->btn_reindex, SIGNAL(clicked()), this, SLOT(walletReindex())); + connect(ui->btn_resync, SIGNAL(clicked()), this, SLOT(walletResync())); // set library version labels ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION)); @@ -496,6 +498,27 @@ void RPCConsole::walletReindex() buildParameterlist(REINDEX); } +/** Restart wallet with "-resync" */ +void RPCConsole::walletResync() +{ + QString resyncWarning = tr("This will delete your local blockchain folders and the wallet will synchronize the complete Blockchain from scratch.

"); + resyncWarning += tr("This needs quite some time and downloads a lot of data.

"); + resyncWarning += tr("Your transactions and funds will be visible again after the download has completed.

"); + resyncWarning += tr("Do you want to continue?.
"); + QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm resync Blockchain"), + resyncWarning, + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel); + + if (retval != QMessageBox::Yes) { + // Resync canceled + return; + } + + // Restart and resync + buildParameterlist(RESYNC); +} + /** Build command-line parameter list for restart */ void RPCConsole::buildParameterlist(QString arg) { diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 912909e57..f5fdfb5a7 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -69,6 +69,7 @@ public slots: void walletZaptxes2(); void walletUpgrade(); void walletReindex(); + void walletResync(); void reject(); void message(int category, const QString& message, bool html = false); diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 5f457d57d..78c6db20a 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -68,22 +68,16 @@ SendCoinsDialog::SendCoinsDialog(QWidget* parent) : QDialog(parent), if (!settings.contains("bUseSwiftTX")) settings.setValue("bUseSwiftTX", false); - bool useObfuScation = settings.value("bUseObfuScation").toBool(); bool useSwiftTX = settings.value("bUseSwiftTX").toBool(); if (fLiteMode) { - ui->checkUseObfuscation->setChecked(false); - ui->checkUseObfuscation->setVisible(false); ui->checkSwiftTX->setVisible(false); CoinControlDialog::coinControl->useObfuScation = false; CoinControlDialog::coinControl->useSwiftTX = false; } else { - ui->checkUseObfuscation->setChecked(useObfuScation); ui->checkSwiftTX->setChecked(useSwiftTX); - CoinControlDialog::coinControl->useObfuScation = useObfuScation; CoinControlDialog::coinControl->useSwiftTX = useSwiftTX; } - connect(ui->checkUseObfuscation, SIGNAL(stateChanged(int)), this, SLOT(updateDisplayUnit())); connect(ui->checkSwiftTX, SIGNAL(stateChanged(int)), this, SLOT(updateSwiftTX())); // Coin Control: clipboard actions @@ -142,6 +136,7 @@ SendCoinsDialog::SendCoinsDialog(QWidget* parent) : QDialog(parent), ui->customFee->setValue(settings.value("nTransactionFee").toLongLong()); ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool()); ui->checkBoxFreeTx->setChecked(settings.value("fSendFreeTransactions").toBool()); + ui->checkzBWK->hide(); minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); } @@ -166,9 +161,11 @@ void SendCoinsDialog::setModel(WalletModel* model) } } - setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), model->getAnonymizedBalance(), - model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); - connect(model, SIGNAL(balanceChanged(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount)), this, SLOT(setBalance(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount))); + setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), + model->getZerocoinBalance (), model->getUnconfirmedZerocoinBalance (), model->getImmatureZerocoinBalance (), + model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); + connect(model, SIGNAL(balanceChanged(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount)), this, + SLOT(setBalance(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount))); connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); updateDisplayUnit(); @@ -269,26 +266,13 @@ void SendCoinsDialog::on_sendButton_clicked() QString strFunds = tr("using") + " " + tr("anonymous funds") + ""; QString strFee = ""; - recipients[0].inputType = ONLY_DENOMINATED; - - if (ui->checkUseObfuscation->isChecked()) { - recipients[0].inputType = ONLY_DENOMINATED; - strFunds = tr("using") + " " + tr("anonymous funds") + ""; - QString strNearestAmount( - BitcoinUnits::formatWithUnit( - model->getOptionsModel()->getDisplayUnit(), 0.1 * COIN)); - strFee = QString(tr( - "(obfuscation requires this amount to be rounded up to the nearest %1).") - .arg(strNearestAmount)); - } else { - recipients[0].inputType = ALL_COINS; - strFunds = tr("using") + " " + tr("any available funds (not recommended)") + ""; - } + recipients[0].inputType = ALL_COINS; + strFunds = tr("using") + " " + tr("any available funds (not recommended)") + ""; if (ui->checkSwiftTX->isChecked()) { recipients[0].useSwiftTX = true; strFunds += " "; - strFunds += tr("and SwiftTX"); + strFunds += tr("and SwiftX"); } else { recipients[0].useSwiftTX = false; } @@ -447,9 +431,15 @@ void SendCoinsDialog::clear() while (ui->entries->count()) { ui->entries->takeAt(0)->widget()->deleteLater(); } - addEntry(); + addEntry(); updateTabsAndLabels(); + + // Clear utxo and change address. + ui->checkBoxCoinControlChange->setCheckState(Qt::Unchecked); + ui->lineEditCoinControlChange->setText(""); + ui->splitBlockCheckBox->setCheckState(Qt::Unchecked); + ui->splitBlockLineEdit->setText(""); } void SendCoinsDialog::reject() @@ -562,25 +552,22 @@ bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient& rv) return true; } -void SendCoinsDialog::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& anonymizedBalance, const CAmount& watchBalance, const CAmount& watchUnconfirmedBalance, const CAmount& watchImmatureBalance) +void SendCoinsDialog::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& zerocoinBalance, const CAmount& unconfirmedZerocoinBalance, const CAmount& immatureZerocoinBalance, + const CAmount& watchBalance, const CAmount& watchUnconfirmedBalance, const CAmount& watchImmatureBalance) { Q_UNUSED(unconfirmedBalance); Q_UNUSED(immatureBalance); - Q_UNUSED(anonymizedBalance); + Q_UNUSED(zerocoinBalance); + Q_UNUSED(unconfirmedZerocoinBalance); + Q_UNUSED(immatureZerocoinBalance); Q_UNUSED(watchBalance); Q_UNUSED(watchUnconfirmedBalance); Q_UNUSED(watchImmatureBalance); if (model && model->getOptionsModel()) { uint64_t bal = 0; - QSettings settings; - settings.setValue("bUseObfuScation", ui->checkUseObfuscation->isChecked()); - if (ui->checkUseObfuscation->isChecked()) { - bal = anonymizedBalance; - } else { - bal = balance; - } - + bal = balance; ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), bal)); } } @@ -590,9 +577,9 @@ void SendCoinsDialog::updateDisplayUnit() TRY_LOCK(cs_main, lockMain); if (!lockMain) return; - setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), model->getAnonymizedBalance(), - model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); - CoinControlDialog::coinControl->useObfuScation = ui->checkUseObfuscation->isChecked(); + setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), + model->getZerocoinBalance (), model->getUnconfirmedZerocoinBalance (), model->getImmatureZerocoinBalance (), + model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); coinControlUpdateLabels(); ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit()); updateMinFeeLabel(); @@ -945,8 +932,6 @@ void SendCoinsDialog::coinControlUpdateLabels() CoinControlDialog::payAmounts.append(entry->getValue().amount); } - ui->checkUseObfuscation->setChecked(CoinControlDialog::coinControl->useObfuScation); - if (CoinControlDialog::coinControl->HasSelected()) { // actual coin control calculation CoinControlDialog::updateLabels(model, this); diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 064741d3c..27ef4ec76 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -53,7 +53,9 @@ public slots: void accept(); SendCoinsEntry* addEntry(); void updateTabsAndLabels(); - void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& anonymizedBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); + void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& zerocoinBalance, const CAmount& unconfirmedZerocoinBalance, const CAmount& immatureZerocoinBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); private: Ui::SendCoinsDialog* ui; diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 5c61ebeab..807c9961f 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -43,30 +43,30 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) if (nDepth < 0) return tr("conflicted"); else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) - return tr("%1/offline (verified via swifttx)").arg(nDepth); + return tr("%1/offline (verified via SwiftX)").arg(nDepth); else if (nDepth < 6) - return tr("%1/confirmed (verified via swifttx)").arg(nDepth); + return tr("%1/confirmed (verified via SwiftX)").arg(nDepth); else - return tr("%1 confirmations (verified via swifttx)").arg(nDepth); + return tr("%1 confirmations (verified via SwiftX)").arg(nDepth); } else { if (!wtx.IsTransactionLockTimedOut()) { int nDepth = wtx.GetDepthInMainChain(); if (nDepth < 0) return tr("conflicted"); else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) - return tr("%1/offline (SwiftTX verification in progress - %2 of %3 signatures)").arg(nDepth).arg(signatures).arg(SWIFTTX_SIGNATURES_TOTAL); + return tr("%1/offline (SwiftX verification in progress - %2 of %3 signatures)").arg(nDepth).arg(signatures).arg(SWIFTTX_SIGNATURES_TOTAL); else if (nDepth < 6) - return tr("%1/confirmed (SwiftTX verification in progress - %2 of %3 signatures )").arg(nDepth).arg(signatures).arg(SWIFTTX_SIGNATURES_TOTAL); + return tr("%1/confirmed (SwiftX verification in progress - %2 of %3 signatures )").arg(nDepth).arg(signatures).arg(SWIFTTX_SIGNATURES_TOTAL); else - return tr("%1 confirmations (SwiftTX verification in progress - %2 of %3 signatures)").arg(nDepth).arg(signatures).arg(SWIFTTX_SIGNATURES_TOTAL); + return tr("%1 confirmations (SwiftX verification in progress - %2 of %3 signatures)").arg(nDepth).arg(signatures).arg(SWIFTTX_SIGNATURES_TOTAL); } else { int nDepth = wtx.GetDepthInMainChain(); if (nDepth < 0) return tr("conflicted"); else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) - return tr("%1/offline (SwiftTX verification failed)").arg(nDepth); + return tr("%1/offline (SwiftX verification failed)").arg(nDepth); else if (nDepth < 6) - return tr("%1/confirmed (SwiftTX verification failed)").arg(nDepth); + return tr("%1/confirmed (SwiftX verification failed)").arg(nDepth); else return tr("%1 confirmations").arg(nDepth); } diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 0e9f3dafe..58ef7c6ca 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -24,8 +24,8 @@ class TransactionFilterProxy : public QSortFilterProxyModel static const QDateTime MAX_DATE; /** Type filter bit field (all types) */ static const quint32 ALL_TYPES = 0xFFFFFFFF; - /** Type filter bit field (all types but Obfuscation-SPAM) */ - static const quint32 COMMON_TYPES = 4479; + /** Type filter bit field (all types but Obfuscation-SPAM ... enum 0-13 are common) */ + static const quint32 COMMON_TYPES = 0x000003FFF; static quint32 TYPE(int type) { return 1 << type; } diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 28bb56f24..137530b2d 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -24,6 +24,7 @@ bool TransactionRecord::showTransaction(const CWalletTx& wtx) if (!wtx.IsInMainChain()) { return false; } + return true; } else { QSettings settings; @@ -37,7 +38,7 @@ bool TransactionRecord::showTransaction(const CWalletTx& wtx) QList TransactionRecord::decomposeTransaction(const CWallet* wallet, const CWalletTx& wtx) { QList parts; - int64_t nTime = wtx.GetTxTime(); + int64_t nTime = wtx.GetComputedTxTime(); CAmount nCredit = wtx.GetCredit(ISMINE_ALL); CAmount nDebit = wtx.GetDebit(ISMINE_ALL); CAmount nNet = nCredit - nDebit; @@ -73,6 +74,66 @@ QList TransactionRecord::decomposeTransaction(const CWallet* sub.credit = nNet; } parts.append(sub); + } else if (wtx.IsZerocoinSpend()) { + // a zerocoin spend that was created by this wallet + libzerocoin::CoinSpend zcspend = TxInToZerocoinSpend(wtx.vin[0]); + bool fSpendFromMe = wallet->IsMyZerocoinSpend(zcspend.getCoinSerialNumber()); + + //zerocoin spend outputs + bool fFeeAssigned = false; + for (const CTxOut txout : wtx.vout) { + // change that was reminted as zerocoins + if (txout.IsZerocoinMint()) { + // do not display record if this isn't from our wallet + if (!fSpendFromMe) + continue; + + TransactionRecord sub(hash, nTime); + sub.type = TransactionRecord::ZerocoinSpend_Change_zBWK; + sub.address = mapValue["zerocoinmint"]; + sub.debit = -txout.nValue; + if (!fFeeAssigned) { + sub.debit -= (wtx.GetZerocoinSpent() - wtx.GetValueOut()); + fFeeAssigned = true; + } + sub.idx = parts.size(); + parts.append(sub); + continue; + } + + string strAddress = ""; + CTxDestination address; + if (ExtractDestination(txout.scriptPubKey, address)) + strAddress = CBitcoinAddress(address).ToString(); + + // a zerocoinspend that was sent to an address held by this wallet + isminetype mine = wallet->IsMine(txout); + if (mine) { + TransactionRecord sub(hash, nTime); + sub.type = (fSpendFromMe ? TransactionRecord::ZerocoinSpend_FromMe : TransactionRecord::RecvFromZerocoinSpend); + sub.debit = txout.nValue; + sub.address = mapValue["recvzerocoinspend"]; + if (strAddress != "") + sub.address = strAddress; + sub.idx = parts.size(); + parts.append(sub); + continue; + } + + // spend is not from us, so do not display the spend side of the record + if (!fSpendFromMe) + continue; + + // zerocoin spend that was sent to someone else + TransactionRecord sub(hash, nTime); + sub.debit = -txout.nValue; + sub.type = TransactionRecord::ZerocoinSpend; + sub.address = mapValue["zerocoinspend"]; + if (strAddress != "") + sub.address = strAddress; + sub.idx = parts.size(); + parts.append(sub); + } } else if (nNet > 0 || wtx.IsCoinBase()) { // // Credit @@ -193,6 +254,9 @@ QList TransactionRecord::decomposeTransaction(const CWallet* // Sent to Bulwark Address sub.type = TransactionRecord::SendToAddress; sub.address = CBitcoinAddress(address).ToString(); + } else if (txout.IsZerocoinMint()){ + sub.type = TransactionRecord::ZerocoinMint; + sub.address = mapValue["zerocoinmint"]; } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.type = TransactionRecord::SendToOther; diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 04bd5a9a4..82c720a91 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -81,6 +81,11 @@ class TransactionRecord MNReward, RecvFromOther, SendToSelf, + ZerocoinMint, + ZerocoinSpend, + RecvFromZerocoinSpend, + ZerocoinSpend_Change_zBWK, + ZerocoinSpend_FromMe, RecvWithObfuscation, ObfuscationDenominate, ObfuscationCollateralPayment, diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 95e7a4831..3728213b5 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -355,6 +355,16 @@ QString TransactionTableModel::formatTxType(const TransactionRecord* wtx) const return tr("Obfuscation Create Denominations"); case TransactionRecord::Obfuscated: return tr("Obfuscated"); + case TransactionRecord::ZerocoinMint: + return tr("Converted BWK to zBWK"); + case TransactionRecord::ZerocoinSpend: + return tr("Spent zBWK"); + case TransactionRecord::RecvFromZerocoinSpend: + return tr("Received BWK from zBWK"); + case TransactionRecord::ZerocoinSpend_Change_zBWK: + return tr("Minted Change as zBWK from zBWK Spend"); + case TransactionRecord::ZerocoinSpend_FromMe: + return tr("Converted zBWK to BWK"); default: return QString(); @@ -371,9 +381,11 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord* wtx case TransactionRecord::RecvWithObfuscation: case TransactionRecord::RecvWithAddress: case TransactionRecord::RecvFromOther: + case TransactionRecord::RecvFromZerocoinSpend: return QIcon(":/icons/tx_input"); case TransactionRecord::SendToAddress: case TransactionRecord::SendToOther: + case TransactionRecord::ZerocoinSpend: return QIcon(":/icons/tx_output"); default: return QIcon(":/icons/tx_inout"); @@ -397,11 +409,17 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord* wtx, b case TransactionRecord::SendToAddress: case TransactionRecord::Generated: case TransactionRecord::StakeMint: + case TransactionRecord::ZerocoinSpend: + case TransactionRecord::ZerocoinSpend_FromMe: + case TransactionRecord::RecvFromZerocoinSpend: return lookupAddress(wtx->address, tooltip); case TransactionRecord::Obfuscated: return lookupAddress(wtx->address, tooltip) + watchAddress; case TransactionRecord::SendToOther: return QString::fromStdString(wtx->address) + watchAddress; + case TransactionRecord::ZerocoinMint: + case TransactionRecord::ZerocoinSpend_Change_zBWK: + return tr("zBWK Accumulator"); case TransactionRecord::SendToSelf: default: return tr("(n/a)") + watchAddress; @@ -549,6 +567,10 @@ QVariant TransactionTableModel::data(const QModelIndex& index, int role) const case Qt::TextAlignmentRole: return column_alignments[index.column()]; case Qt::ForegroundRole: + // Conflicted, most probably orphaned + if (rec->status.status == TransactionStatus::NotAccepted) { + return COLOR_CONFLICTED; + } // Non-confirmed (but not immature) as transactions are grey if (!rec->status.countsForBalance && rec->status.status != TransactionStatus::Immature) { return COLOR_UNCONFIRMED; diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 7c8abda33..99e57b157 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -86,15 +86,25 @@ TransactionView::TransactionView(QWidget* parent) : QWidget(parent), model(0), t typeWidget->addItem(tr("Most Common"), TransactionFilterProxy::COMMON_TYPES); typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) | TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther)); typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) | TransactionFilterProxy::TYPE(TransactionRecord::SendToOther)); + +/* Obsolete Obfuscation entries. Remove once the corresponding TYPES are removed: + * typeWidget->addItem(tr("Obfuscated"), TransactionFilterProxy::TYPE(TransactionRecord::Obfuscated)); typeWidget->addItem(tr("Obfuscation Make Collateral Inputs"), TransactionFilterProxy::TYPE(TransactionRecord::ObfuscationMakeCollaterals)); typeWidget->addItem(tr("Obfuscation Create Denominations"), TransactionFilterProxy::TYPE(TransactionRecord::ObfuscationCreateDenominations)); typeWidget->addItem(tr("Obfuscation Denominate"), TransactionFilterProxy::TYPE(TransactionRecord::ObfuscationDenominate)); typeWidget->addItem(tr("Obfuscation Collateral Payment"), TransactionFilterProxy::TYPE(TransactionRecord::ObfuscationCollateralPayment)); + */ + typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf)); typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated)); typeWidget->addItem(tr("Minted"), TransactionFilterProxy::TYPE(TransactionRecord::StakeMint)); typeWidget->addItem(tr("Masternode Reward"), TransactionFilterProxy::TYPE(TransactionRecord::MNReward)); + typeWidget->addItem(tr("Received BWK from zBWK"), TransactionFilterProxy::TYPE(TransactionRecord::RecvFromZerocoinSpend)); + typeWidget->addItem(tr("Zerocoin Mint"), TransactionFilterProxy::TYPE(TransactionRecord::ZerocoinMint)); + typeWidget->addItem(tr("Zerocoin Spend"), TransactionFilterProxy::TYPE(TransactionRecord::ZerocoinSpend)); + typeWidget->addItem(tr("Zerocoin Spend, Change in zBWK"), TransactionFilterProxy::TYPE(TransactionRecord::ZerocoinSpend_Change_zBWK)); + typeWidget->addItem(tr("Zerocoin Spend to Self"), TransactionFilterProxy::TYPE(TransactionRecord::ZerocoinSpend_FromMe)); typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other)); typeWidget->setCurrentIndex(settings.value("transactionType").toInt()); @@ -327,14 +337,16 @@ void TransactionView::changedAmount(const QString& amount) return; CAmount amount_parsed = 0; - // Replace "," by "." so BitcoinUnits::parse will not fail for users entering "," as decimal separator - QString newAmount = amount; - newAmount.replace(QString(","), QString(".")); + if (model) { + // Replace "," by "." so BitcoinUnits::parse will not fail for users entering "," as decimal separator + QString newAmount = amount; + newAmount.replace(QString(","), QString(".")); - if (BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), newAmount, &amount_parsed)) { - transactionProxyModel->setMinAmount(amount_parsed); - } else { - transactionProxyModel->setMinAmount(0); + if (BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), newAmount, &amount_parsed)) { + transactionProxyModel->setMinAmount(amount_parsed); + } else { + transactionProxyModel->setMinAmount(0); + } } } @@ -349,25 +361,31 @@ void TransactionView::exportClicked() return; CSVModelWriter writer(filename); + bool fExport = false; - // name, column, role - writer.setModel(transactionProxyModel); - writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole); - if (model && model->haveWatchOnly()) - writer.addColumn(tr("Watch-only"), TransactionTableModel::Watchonly); - writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole); - writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole); - writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole); - writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole); - writer.addColumn(BitcoinUnits::getAmountColumnTitle(model->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole); - writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole); - - if (!writer.write()) { - emit message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename), - CClientUIInterface::MSG_ERROR); - } else { + if (model) { + // name, column, role + writer.setModel(transactionProxyModel); + writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole); + if (model->haveWatchOnly()) + writer.addColumn(tr("Watch-only"), TransactionTableModel::Watchonly); + writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole); + writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole); + writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole); + writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole); + writer.addColumn(BitcoinUnits::getAmountColumnTitle(model->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole); + writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole); + + fExport = writer.write(); + } + + if (fExport) { emit message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename), - CClientUIInterface::MSG_INFORMATION); + CClientUIInterface::MSG_INFORMATION); + } + else { + emit message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename), + CClientUIInterface::MSG_ERROR); } } diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index d25ae6754..b40860655 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -139,6 +139,13 @@ void WalletFrame::gotoReceiveCoinsPage() i.value()->gotoReceiveCoinsPage(); } +void WalletFrame::gotoPrivacyPage() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoPrivacyPage(); +} + void WalletFrame::gotoSendCoinsPage(QString addr) { QMap::const_iterator i; @@ -218,6 +225,13 @@ void WalletFrame::lockWallet() walletView->lockWallet(); } +void WalletFrame::toggleLockWallet() +{ + WalletView* walletView = currentWalletView(); + if (walletView) + walletView->toggleLockWallet(); +} + void WalletFrame::usedSendingAddresses() { WalletView* walletView = currentWalletView(); diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 1a1277122..b5bfe6c54 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -58,6 +58,8 @@ public slots: void gotoMasternodePage(); /** Switch to receive coins page */ void gotoReceiveCoinsPage(); + /** Switch to privacy page */ + void gotoPrivacyPage(); /** Switch to send coins page */ void gotoSendCoinsPage(QString addr = ""); /** Switch to explorer page */ @@ -68,10 +70,8 @@ public slots: void gotoVerifyMessageTab(QString addr = ""); /** Show MultiSend Dialog **/ void gotoMultiSendDialog(); - - /** show a multisig tab **/ + /** show a multisig tab **/ void gotoMultisigDialog(int index); - /** Show BIP 38 tool - default to Encryption tab */ void gotoBip38Tool(); @@ -85,6 +85,8 @@ public slots: void unlockWallet(); /** Lock wallet */ void lockWallet(); + /** Toggle Wallet Lock State */ + void toggleLockWallet(); /** Show used sending addresses */ void usedSendingAddresses(); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 235dc4af2..d52c141f5 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -33,6 +33,7 @@ WalletModel::WalletModel(CWallet* wallet, OptionsModel* optionsModel, QObject* p transactionTableModel(0), recentRequestsTableModel(0), cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0), + cachedZerocoinBalance(0), cachedUnconfirmedZerocoinBalance(0), cachedImmatureZerocoinBalance(0), cachedEncryptionStatus(Unencrypted), cachedNumBlocks(0) { @@ -73,12 +74,6 @@ CAmount WalletModel::getBalance(const CCoinControl* coinControl) const return wallet->GetBalance(); } - -CAmount WalletModel::getAnonymizedBalance() const -{ - return wallet->GetAnonymizedBalance(); -} - CAmount WalletModel::getUnconfirmedBalance() const { return wallet->GetUnconfirmedBalance(); @@ -89,6 +84,27 @@ CAmount WalletModel::getImmatureBalance() const return wallet->GetImmatureBalance(); } +CAmount WalletModel::getLockedBalance() const +{ + return wallet->GetLockedCoins(); +} + +CAmount WalletModel::getZerocoinBalance() const +{ + return wallet->GetZerocoinBalance(false); +} + +CAmount WalletModel::getUnconfirmedZerocoinBalance() const +{ + return wallet->GetUnconfirmedZerocoinBalance(); +} + +CAmount WalletModel::getImmatureZerocoinBalance() const +{ + return wallet->GetImmatureZerocoinBalance(); +} + + bool WalletModel::haveWatchOnly() const { return fHaveWatchOnly; @@ -129,12 +145,12 @@ void WalletModel::pollBalanceChanged() if (!lockWallet) return; - if (fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks || nObfuscationRounds != cachedObfuscationRounds || cachedTxLocks != nCompleteTXLocks) { + if (fForceCheckBalanceChanged || chainActive.Height() != cachedNumBlocks || nZeromintPercentage != cachedZeromintPercentage || cachedTxLocks != nCompleteTXLocks) { fForceCheckBalanceChanged = false; // Balance and number of transactions might have changed cachedNumBlocks = chainActive.Height(); - cachedObfuscationRounds = nObfuscationRounds; + cachedZeromintPercentage = nZeromintPercentage; checkBalanceChanged(); if (transactionTableModel) { @@ -143,6 +159,14 @@ void WalletModel::pollBalanceChanged() } } +void WalletModel::emitBalanceChanged() +{ + // Force update of UI elements even when no values have changed + emit balanceChanged(cachedBalance, cachedUnconfirmedBalance, cachedImmatureBalance, + cachedZerocoinBalance, cachedUnconfirmedZerocoinBalance, cachedImmatureZerocoinBalance, + cachedWatchOnlyBalance, cachedWatchUnconfBalance, cachedWatchImmatureBalance); +} + void WalletModel::checkBalanceChanged() { TRY_LOCK(cs_main, lockMain); @@ -151,7 +175,9 @@ void WalletModel::checkBalanceChanged() CAmount newBalance = getBalance(); CAmount newUnconfirmedBalance = getUnconfirmedBalance(); CAmount newImmatureBalance = getImmatureBalance(); - CAmount newAnonymizedBalance = getAnonymizedBalance(); + CAmount newZerocoinBalance = getZerocoinBalance(); + CAmount newUnconfirmedZerocoinBalance = getUnconfirmedZerocoinBalance(); + CAmount newImmatureZerocoinBalance = getImmatureZerocoinBalance(); CAmount newWatchOnlyBalance = 0; CAmount newWatchUnconfBalance = 0; CAmount newWatchImmatureBalance = 0; @@ -162,18 +188,22 @@ void WalletModel::checkBalanceChanged() } if (cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance || - cachedAnonymizedBalance != newAnonymizedBalance || cachedTxLocks != nCompleteTXLocks || - cachedWatchOnlyBalance != newWatchOnlyBalance || cachedWatchUnconfBalance != newWatchUnconfBalance || cachedWatchImmatureBalance != newWatchImmatureBalance) { + cachedZerocoinBalance != newZerocoinBalance || cachedUnconfirmedZerocoinBalance != newUnconfirmedZerocoinBalance || cachedImmatureZerocoinBalance != newImmatureZerocoinBalance || + cachedWatchOnlyBalance != newWatchOnlyBalance || cachedWatchUnconfBalance != newWatchUnconfBalance || cachedWatchImmatureBalance != newWatchImmatureBalance || + cachedTxLocks != nCompleteTXLocks ) { cachedBalance = newBalance; cachedUnconfirmedBalance = newUnconfirmedBalance; cachedImmatureBalance = newImmatureBalance; - cachedAnonymizedBalance = newAnonymizedBalance; + cachedZerocoinBalance = newZerocoinBalance; + cachedUnconfirmedZerocoinBalance = newUnconfirmedZerocoinBalance; + cachedImmatureZerocoinBalance = newImmatureZerocoinBalance; cachedTxLocks = nCompleteTXLocks; cachedWatchOnlyBalance = newWatchOnlyBalance; cachedWatchUnconfBalance = newWatchUnconfBalance; cachedWatchImmatureBalance = newWatchImmatureBalance; - emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance, newAnonymizedBalance, - newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance); + emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance, + newZerocoinBalance, newUnconfirmedZerocoinBalance, newImmatureZerocoinBalance, + newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance); } } @@ -188,6 +218,12 @@ void WalletModel::updateAddressBook(const QString& address, const QString& label if (addressTableModel) addressTableModel->updateEntry(address, label, isMine, purpose, status); } +void WalletModel::updateAddressBook(const QString &pubCoin, const QString &isUsed, int status) +{ + if(addressTableModel) + addressTableModel->updateEntry(pubCoin, isUsed, status); +} + void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly) { @@ -293,7 +329,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact if (recipients[0].useSwiftTX && total > GetSporkValue(SPORK_5_MAX_VALUE) * COIN) { - emit message(tr("Send Coins"), tr("SwiftTX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK.").arg(GetSporkValue(SPORK_5_MAX_VALUE)), + emit message(tr("Send Coins"), tr("SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK.").arg(GetSporkValue(SPORK_5_MAX_VALUE)), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } @@ -302,7 +338,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact transaction.setTransactionFee(nFeeRequired); if (recipients[0].useSwiftTX && newTx->GetValueOut() > GetSporkValue(SPORK_5_MAX_VALUE) * COIN) { - emit message(tr("Send Coins"), tr("SwiftTX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK.").arg(GetSporkValue(SPORK_5_MAX_VALUE)), + emit message(tr("Send Coins"), tr("SwiftX doesn't support sending values that high yet. Transactions are currently limited to %1 BWK.").arg(GetSporkValue(SPORK_5_MAX_VALUE)), CClientUIInterface::MSG_ERROR); return TransactionCreationFailed; } @@ -429,6 +465,7 @@ bool WalletModel::setWalletLocked(bool locked, const SecureString& passPhrase, b { if (locked) { // Lock + wallet->fWalletUnlockAnonymizeOnly = false; return wallet->Lock(); } else { // Unlock @@ -517,6 +554,18 @@ static void NotifyMultiSigChanged(WalletModel* walletmodel, bool fHaveMultiSig) Q_ARG(bool, fHaveMultiSig)); } +static void NotifyZerocoinChanged(WalletModel* walletmodel, CWallet* wallet, const std::string& hexString, + const std::string& isUsed, ChangeType status) +{ + QString HexStr = QString::fromStdString(hexString); + QString isUsedStr = QString::fromStdString(isUsed); + qDebug() << "NotifyZerocoinChanged : " + HexStr + " " + isUsedStr + " status= " + QString::number(status); + QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, + Q_ARG(QString, HexStr), + Q_ARG(QString, isUsedStr), + Q_ARG(int, status)); +} + void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet @@ -526,6 +575,7 @@ void WalletModel::subscribeToCoreSignals() wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, _1)); wallet->NotifyMultiSigChanged.connect(boost::bind(NotifyMultiSigChanged, this, _1)); + wallet->NotifyZerocoinChanged.connect(boost::bind(NotifyZerocoinChanged, this, _1, _2, _3, _4)); } void WalletModel::unsubscribeFromCoreSignals() @@ -537,6 +587,7 @@ void WalletModel::unsubscribeFromCoreSignals() wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, _1)); wallet->NotifyMultiSigChanged.disconnect(boost::bind(NotifyMultiSigChanged, this, _1)); + wallet->NotifyZerocoinChanged.disconnect(boost::bind(NotifyZerocoinChanged, this, _1, _2, _3, _4)); } // WalletModel::UnlockContext implementation @@ -557,13 +608,11 @@ WalletModel::UnlockContext WalletModel::requestUnlock(bool relock) // If wallet is still locked, unlock was failed or cancelled, mark context as invalid bool valid = getEncryptionStatus() != Locked; - return UnlockContext(this, valid, relock); + return UnlockContext(valid, relock); // return UnlockContext(this, valid, was_locked && !isAnonymizeOnlyUnlocked()); } -WalletModel::UnlockContext::UnlockContext(WalletModel* wallet, bool valid, bool relock) : wallet(wallet), - valid(valid), - relock(relock) +WalletModel::UnlockContext::UnlockContext(bool valid, bool relock) : valid(valid), relock(relock) { } @@ -666,6 +715,14 @@ void WalletModel::listLockedCoins(std::vector& vOutpts) wallet->ListLockedCoins(vOutpts); } + +void WalletModel::listZerocoinMints(std::list& listMints, bool fUnusedOnly, bool fMaturedOnly, bool fUpdateStatus) +{ + listMints.clear(); + CWalletDB walletdb(wallet->strWalletFile); + listMints = walletdb.ListMintedCoins(fUnusedOnly, fMaturedOnly, fUpdateStatus); +} + void WalletModel::loadReceiveRequests(std::vector& vReceiveRequests) { LOCK(wallet->cs_wallet); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 40d258450..784ec6ce6 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -133,7 +133,10 @@ class WalletModel : public QObject CAmount getBalance(const CCoinControl* coinControl = NULL) const; CAmount getUnconfirmedBalance() const; CAmount getImmatureBalance() const; - CAmount getAnonymizedBalance() const; + CAmount getLockedBalance() const; + CAmount getZerocoinBalance() const; + CAmount getUnconfirmedZerocoinBalance() const; + CAmount getImmatureZerocoinBalance() const; bool haveWatchOnly() const; CAmount getWatchBalance() const; CAmount getWatchUnconfirmedBalance() const; @@ -143,6 +146,7 @@ class WalletModel : public QObject bool setAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose); void encryptKey(const CKey key, const std::string& pwd, const std::string& slt, std::vector& crypted); void decryptKey(const std::vector& crypted, const std::string& slt, const std::string& pwd, CKey& key); + void emitBalanceChanged(); // Force update of UI-elements even when no values have changed // Check address for validity bool validateAddress(const QString& address); @@ -173,7 +177,7 @@ class WalletModel : public QObject class UnlockContext { public: - UnlockContext(WalletModel* wallet, bool valid, bool relock); + UnlockContext(bool valid, bool relock); ~UnlockContext(); bool isValid() const { return valid; } @@ -187,7 +191,6 @@ class WalletModel : public QObject } private: - WalletModel* wallet; bool valid; mutable bool relock; // mutable, as it can be set to false by copying @@ -207,6 +210,8 @@ class WalletModel : public QObject void unlockCoin(COutPoint& output); void listLockedCoins(std::vector& vOutpts); + void listZerocoinMints(std::list& listMints, bool fUnusedOnly = false, bool fMaturedOnly = false, bool fUpdateStatus = false); + void loadReceiveRequests(std::vector& vReceiveRequests); bool saveReceiveRequest(const std::string& sAddress, const int64_t nId, const std::string& sRequest); @@ -228,14 +233,16 @@ class WalletModel : public QObject CAmount cachedBalance; CAmount cachedUnconfirmedBalance; CAmount cachedImmatureBalance; - CAmount cachedAnonymizedBalance; + CAmount cachedZerocoinBalance; + CAmount cachedUnconfirmedZerocoinBalance; + CAmount cachedImmatureZerocoinBalance; CAmount cachedWatchOnlyBalance; CAmount cachedWatchUnconfBalance; CAmount cachedWatchImmatureBalance; EncryptionStatus cachedEncryptionStatus; int cachedNumBlocks; int cachedTxLocks; - int cachedObfuscationRounds; + int cachedZeromintPercentage; QTimer* pollTimer; @@ -245,7 +252,9 @@ class WalletModel : public QObject signals: // Signal that balance in wallet changed - void balanceChanged(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& anonymizedBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); + void balanceChanged(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& zerocoinBalance, const CAmount& unconfirmedZerocoinBalance, const CAmount& immatureZerocoinBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); // Encryption status of wallet changed void encryptionStatusChanged(int status); @@ -269,7 +278,6 @@ class WalletModel : public QObject // MultiSig address added void notifyMultiSigChanged(bool fHaveMultiSig); - public slots: /* Wallet status might have changed */ void updateStatus(); @@ -277,6 +285,8 @@ public slots: void updateTransaction(); /* New, updated or removed address book entry */ void updateAddressBook(const QString& address, const QString& label, bool isMine, const QString& purpose, int status); + /* Zerocoin update */ + void updateAddressBook(const QString &pubCoin, const QString &isUsed, int status); /* Watch-only added */ void updateWatchOnlyFlag(bool fHaveWatchonly); /* MultiSig added */ diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 85dce4093..8c7afdd6f 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -17,6 +17,7 @@ #include "optionsmodel.h" #include "overviewpage.h" #include "receivecoinsdialog.h" +#include "privacydialog.h" #include "sendcoinsdialog.h" #include "signverifymessagedialog.h" #include "transactiontablemodel.h" @@ -39,7 +40,7 @@ WalletView::WalletView(QWidget* parent) : QStackedWidget(parent), clientModel(0), walletModel(0) -{ +{ // Create tabs overviewPage = new OverviewPage(); explorerWindow = new BlockExplorer(this); @@ -70,11 +71,13 @@ WalletView::WalletView(QWidget* parent) : QStackedWidget(parent), vbox->addLayout(hbox_buttons); transactionsPage->setLayout(vbox); + privacyPage = new PrivacyDialog(); receiveCoinsPage = new ReceiveCoinsDialog(); sendCoinsPage = new SendCoinsDialog(); addWidget(overviewPage); addWidget(transactionsPage); + addWidget(privacyPage); addWidget(receiveCoinsPage); addWidget(sendCoinsPage); addWidget(explorerWindow); @@ -148,6 +151,7 @@ void WalletView::setWalletModel(WalletModel* walletModel) if (settings.value("fShowMasternodesTab").toBool()) { masternodeListPage->setWalletModel(walletModel); } + privacyPage->setModel(walletModel); receiveCoinsPage->setModel(walletModel); sendCoinsPage->setModel(walletModel); @@ -192,6 +196,8 @@ void WalletView::processNewTransaction(const QModelIndex& parent, int start, int void WalletView::gotoOverviewPage() { setCurrentWidget(overviewPage); + // Refresh UI-elements in case coins were locked/unlocked in CoinControl + walletModel->emitBalanceChanged(); } void WalletView::gotoHistoryPage() @@ -218,6 +224,13 @@ void WalletView::gotoReceiveCoinsPage() setCurrentWidget(receiveCoinsPage); } +void WalletView::gotoPrivacyPage() +{ + setCurrentWidget(privacyPage); + // Refresh UI-elements in case coins were locked/unlocked in CoinControl + walletModel->emitBalanceChanged(); +} + void WalletView::gotoSendCoinsPage(QString addr) { setCurrentWidget(sendCoinsPage); @@ -272,7 +285,6 @@ void WalletView::gotoMultisigDialog(int index) multisig->showTab(index); } - bool WalletView::handlePaymentRequest(const SendCoinsRecipient& recipient) { return sendCoinsPage->handlePaymentRequest(recipient); @@ -281,6 +293,7 @@ bool WalletView::handlePaymentRequest(const SendCoinsRecipient& recipient) void WalletView::showOutOfSyncWarning(bool fShow) { overviewPage->showOutOfSyncWarning(fShow); + privacyPage->showOutOfSyncWarning(fShow); } void WalletView::updateEncryptionStatus() @@ -342,6 +355,24 @@ void WalletView::lockWallet() walletModel->setWalletLocked(true); } +void WalletView::toggleLockWallet() +{ + if (!walletModel) + return; + + WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); + + // Unlock the wallet when requested + if (encStatus == walletModel->Locked) { + AskPassphraseDialog dlg(AskPassphraseDialog::UnlockAnonymize, this, walletModel); + dlg.exec(); + } + + else if (encStatus == walletModel->Unlocked || encStatus == walletModel->UnlockedForAnonymizationOnly) { + walletModel->setWalletLocked(true); + } +} + void WalletView::usedSendingAddresses() { if (!walletModel) diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 8d9d0e486..eb637ba5e 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -14,6 +14,7 @@ class BitcoinGUI; class ClientModel; class OverviewPage; class ReceiveCoinsDialog; +class PrivacyDialog; class SendCoinsDialog; class SendCoinsRecipient; class TransactionView; @@ -62,6 +63,7 @@ class WalletView : public QStackedWidget OverviewPage* overviewPage; QWidget* transactionsPage; ReceiveCoinsDialog* receiveCoinsPage; + PrivacyDialog* privacyPage; SendCoinsDialog* sendCoinsPage; BlockExplorer* explorerWindow; MasternodeList* masternodeListPage; @@ -80,6 +82,8 @@ public slots: void gotoMasternodePage(); /** Switch to explorer page */ void gotoBlockExplorerPage(); + /** Switch to privacy page */ + void gotoPrivacyPage(); /** Switch to receive coins page */ void gotoReceiveCoinsPage(); /** Switch to send coins page */ @@ -91,10 +95,8 @@ public slots: void gotoVerifyMessageTab(QString addr = ""); /** Show MultiSend Dialog */ void gotoMultiSendDialog(); - - /** Show a multisig tab **/ + /** Show a multisig tab **/ void gotoMultisigDialog(int index); - /** Show BIP 38 tool - default to Encryption tab */ void gotoBip38Tool(); @@ -113,6 +115,8 @@ public slots: void unlockWallet(); /** Lock wallet */ void lockWallet(); + /** Toggle wallet lock state */ + void toggleLockWallet(); /** Show used sending addresses */ void usedSendingAddresses(); diff --git a/src/qt/zbwkcontroldialog.cpp b/src/qt/zbwkcontroldialog.cpp new file mode 100644 index 000000000..f86045aa9 --- /dev/null +++ b/src/qt/zbwkcontroldialog.cpp @@ -0,0 +1,211 @@ +// Copyright (c) 2017 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 "zbwkcontroldialog.h" +#include "ui_zbwkcontroldialog.h" + +#include "main.h" +#include "walletmodel.h" + +using namespace std; + +std::list ZBwkControlDialog::listSelectedMints; +std::list ZBwkControlDialog::listMints; + +ZBwkControlDialog::ZBwkControlDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ZBwkControlDialog), + model(0) +{ + ui->setupUi(this); + listMints.clear(); + privacyDialog = (PrivacyDialog*)parent; + + // click on checkbox + connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(updateSelection(QTreeWidgetItem*, int))); + + // push select/deselect all button + connect(ui->pushButtonAll, SIGNAL(clicked()), this, SLOT(ButtonAllClicked())); +} + +ZBwkControlDialog::~ZBwkControlDialog() +{ + delete ui; +} + +void ZBwkControlDialog::setModel(WalletModel *model) +{ + this->model = model; + updateList(); +} + +//Update the tree widget +void ZBwkControlDialog::updateList() +{ + // need to prevent the slot from being called each time something is changed + ui->treeWidget->blockSignals(true); + ui->treeWidget->clear(); + + // add a top level item for each denomination + QFlags flgTristate = Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; + map mapDenomPosition; + for (auto denom : libzerocoin::zerocoinDenomList) { + QTreeWidgetItem* itemDenom(new QTreeWidgetItem); + ui->treeWidget->addTopLevelItem(itemDenom); + + //keep track of where this is positioned in tree widget + mapDenomPosition[denom] = ui->treeWidget->indexOfTopLevelItem(itemDenom); + + itemDenom->setFlags(flgTristate); + itemDenom->setText(COLUMN_DENOMINATION, QString::number(denom)); + } + + // select all unused coins - including not mature. Update status of coins too. + std::list list; + model->listZerocoinMints(list, true, false, true); + this->listMints = list; + + //populate rows with mint info + int nBestHeight = chainActive.Height(); + for(const CZerocoinMint mint : listMints) { + // assign this mint to the correct denomination in the tree view + libzerocoin::CoinDenomination denom = mint.GetDenomination(); + QTreeWidgetItem *itemMint = new QTreeWidgetItem(ui->treeWidget->topLevelItem(mapDenomPosition.at(denom))); + + // if the mint is already selected, then it needs to have the checkbox checked + std::string strPubCoin = mint.GetValue().GetHex(); + itemMint->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); + if(count(listSelectedMints.begin(), listSelectedMints.end(), strPubCoin)) + itemMint->setCheckState(COLUMN_CHECKBOX, Qt::Checked); + + itemMint->setText(COLUMN_DENOMINATION, QString::number(mint.GetDenomination())); + itemMint->setText(COLUMN_PUBCOIN, QString::fromStdString(strPubCoin)); + + int nConfirmations = (mint.GetHeight() ? nBestHeight - mint.GetHeight() : 0); + if (nConfirmations < 0) { + // Sanity check + nConfirmations = 0; + } + + itemMint->setText(COLUMN_CONFIRMATIONS, QString::number(nConfirmations)); + + // check to make sure there are at least 3 other mints added to the accumulators after this + int nMintsAdded = 0; + if(mint.GetHeight() != 0 && mint.GetHeight() < nBestHeight - 2) { + CBlockIndex *pindex = chainActive[mint.GetHeight() + 1]; + + int nHeight2CheckpointsDeep = nBestHeight - (nBestHeight % 10) - 20; + while (pindex->nHeight < nHeight2CheckpointsDeep) { // 20 just to make sure that its at least 2 checkpoints from the top block + nMintsAdded += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), mint.GetDenomination()); + if(nMintsAdded >= Params().Zerocoin_RequiredAccumulation()) + break; + pindex = chainActive[pindex->nHeight + 1]; + } + } + + // disable selecting this mint if it is not spendable - also display a reason why + bool fSpendable = nMintsAdded >= Params().Zerocoin_RequiredAccumulation() && nConfirmations >= Params().Zerocoin_MintRequiredConfirmations(); + if(!fSpendable) { + itemMint->setDisabled(true); + itemMint->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); + + //if this mint is in the selection list, then remove it + auto it = std::find(listSelectedMints.begin(), listSelectedMints.end(), mint.GetValue().GetHex()); + if (it != listSelectedMints.end()) { + listSelectedMints.erase(it); + } + + string strReason = ""; + if(nConfirmations < Params().Zerocoin_MintRequiredConfirmations()) + strReason = strprintf("Needs %d more confirmations", Params().Zerocoin_MintRequiredConfirmations() - nConfirmations); + else + strReason = strprintf("Needs %d more mints added to network", Params().Zerocoin_RequiredAccumulation() - nMintsAdded); + + itemMint->setText(COLUMN_ISSPENDABLE, QString::fromStdString(strReason)); + } else { + itemMint->setText(COLUMN_ISSPENDABLE, QString("Yes")); + } + } + + ui->treeWidget->blockSignals(false); + updateLabels(); +} + +// Update the list when a checkbox is clicked +void ZBwkControlDialog::updateSelection(QTreeWidgetItem* item, int column) +{ + // only want updates from non top level items that are available to spend + if (item->parent() && column == COLUMN_CHECKBOX && !item->isDisabled()){ + + // see if this mint is already selected in the selection list + std::string strPubcoin = item->text(COLUMN_PUBCOIN).toStdString(); + auto iter = std::find(listSelectedMints.begin(), listSelectedMints.end(), strPubcoin); + bool fSelected = iter != listSelectedMints.end(); + + // set the checkbox to the proper state and add or remove the mint from the selection list + if (item->checkState(COLUMN_CHECKBOX) == Qt::Checked) { + if (fSelected) return; + listSelectedMints.emplace_back(strPubcoin); + } else { + if (!fSelected) return; + listSelectedMints.erase(iter); + } + updateLabels(); + } +} + +// Update the Quantity and Amount display +void ZBwkControlDialog::updateLabels() +{ + int64_t nAmount = 0; + for (const CZerocoinMint mint : listMints) { + if (count(listSelectedMints.begin(), listSelectedMints.end(), mint.GetValue().GetHex())) { + nAmount += mint.GetDenomination(); + } + } + + //update this dialog's labels + ui->labelZBwk_int->setText(QString::number(nAmount)); + ui->labelQuantity_int->setText(QString::number(listSelectedMints.size())); + + //update PrivacyDialog labels + privacyDialog->setZBwkControlLabels(nAmount, listSelectedMints.size()); +} + +std::vector ZBwkControlDialog::GetSelectedMints() +{ + std::vector listReturn; + for (const CZerocoinMint mint : listMints) { + if (count(listSelectedMints.begin(), listSelectedMints.end(), mint.GetValue().GetHex())) { + listReturn.emplace_back(mint); + } + } + + return listReturn; +} + +// select or deselect all of the mints +void ZBwkControlDialog::ButtonAllClicked() +{ + ui->treeWidget->blockSignals(true); + Qt::CheckState state = Qt::Checked; + for(int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) { + if(ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != Qt::Unchecked) { + state = Qt::Unchecked; + break; + } + } + + //much quicker to start from scratch than to have QT go through all the objects and update + ui->treeWidget->clear(); + + if(state == Qt::Checked) { + for(const CZerocoinMint mint : listMints) + listSelectedMints.emplace_back(mint.GetValue().GetHex()); + } else { + listSelectedMints.clear(); + } + + updateList(); +} diff --git a/src/qt/zbwkcontroldialog.h b/src/qt/zbwkcontroldialog.h new file mode 100644 index 000000000..6efaf088e --- /dev/null +++ b/src/qt/zbwkcontroldialog.h @@ -0,0 +1,55 @@ +// Copyright (c) 2017 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 ZBWKCONTROLDIALOG_H +#define ZBWKCONTROLDIALOG_H + +#include +#include +#include "primitives/zerocoin.h" +#include "privacydialog.h" + +class CZerocoinMint; +class WalletModel; + +namespace Ui { +class ZBwkControlDialog; +} + +class ZBwkControlDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ZBwkControlDialog(QWidget *parent); + ~ZBwkControlDialog(); + + void setModel(WalletModel* model); + + static std::list listSelectedMints; + static std::list listMints; + static std::vector GetSelectedMints(); + +private: + Ui::ZBwkControlDialog *ui; + WalletModel* model; + PrivacyDialog* privacyDialog; + + void updateList(); + void updateLabels(); + + enum { + COLUMN_CHECKBOX, + COLUMN_DENOMINATION, + COLUMN_PUBCOIN, + COLUMN_CONFIRMATIONS, + COLUMN_ISSPENDABLE + }; + +private slots: + void updateSelection(QTreeWidgetItem* item, int column); + void ButtonAllClicked(); +}; + +#endif // ZBWKCONTROLDIALOG_H diff --git a/src/rest.cpp b/src/rest.cpp index 170eacb38..55da5a60d 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -14,8 +14,9 @@ #include +#include + using namespace std; -using namespace json_spirit; enum RetFormat { RF_UNDEF, @@ -41,8 +42,8 @@ class RestErr string message; }; -extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry); -extern Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); +extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); +extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); static RestErr RESTERR(enum HTTPStatusCode status, string message) { @@ -132,8 +133,8 @@ static bool rest_block(AcceptedConnection* conn, } case RF_JSON: { - Object objBlock = blockToJSON(block, pblockindex, showTxDetails); - string strJSON = write_string(Value(objBlock), false) + "\n"; + UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails); + string strJSON = objBlock.write() + "\n"; conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush; return true; } @@ -198,9 +199,9 @@ static bool rest_tx(AcceptedConnection* conn, } case RF_JSON: { - Object objTx; + UniValue objTx(UniValue::VOBJ); TxToJSON(tx, hashBlock, objTx); - string strJSON = write_string(Value(objTx), false) + "\n"; + string strJSON = objTx.write() + "\n"; conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush; return true; } diff --git a/src/reverse_iterate.h b/src/reverse_iterate.h new file mode 100644 index 000000000..1fcd08099 --- /dev/null +++ b/src/reverse_iterate.h @@ -0,0 +1,37 @@ +// Copyright (c) 2017 The PIVX Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +/* + Template used for reverse iteration in C++11 range-based for loops. + std::vector v = {1, 2, 3, 4, 5}; + for (auto x : reverse_iterate(v)) + std::cout << x << " "; + */ + +template +class reverse_range +{ + T &x; + +public: + reverse_range(T &x) : x(x) {} + + auto begin() const -> decltype(this->x.rbegin()) + { + return x.rbegin(); + } + + auto end() const -> decltype(this->x.rend()) + { + return x.rend(); + } +}; + +template +reverse_range reverse_iterate(T &x) +{ + return reverse_range(x); +} + diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 793a80c97..98e9e9858 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -6,21 +6,23 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "base58.h" #include "checkpoints.h" +#include "clientversion.h" #include "main.h" #include "rpcserver.h" #include "sync.h" +#include "txdb.h" #include "util.h" +#include "utilmoneystr.h" #include +#include -#include "json/json_spirit_value.h" - -using namespace json_spirit; using namespace std; -extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry); -void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex); +extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); +void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); double GetDifficulty(const CBlockIndex* blockindex) { @@ -51,9 +53,9 @@ double GetDifficulty(const CBlockIndex* blockindex) } -Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) +UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain @@ -64,10 +66,11 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); - Array txs; + result.push_back(Pair("acc_checkpoint", block.nAccumulatorCheckpoint.GetHex())); + UniValue txs(UniValue::VARR); BOOST_FOREACH (const CTransaction& tx, block.vtx) { if (txDetails) { - Object objTx; + UniValue objTx(UniValue::VOBJ); TxToJSON(tx, uint256(0), objTx); txs.push_back(objTx); } else @@ -85,13 +88,23 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe CBlockIndex* pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); + + result.push_back(Pair("moneysupply",ValueFromAmount(blockindex->nMoneySupply))); + + UniValue zBWKObj(UniValue::VOBJ); + for (auto denom : libzerocoin::zerocoinDenomList) { + zBWKObj.push_back(Pair(to_string(denom), ValueFromAmount(blockindex->mapZerocoinSupply.at(denom) * (denom*COIN)))); + } + zBWKObj.push_back(Pair("total", ValueFromAmount(blockindex->GetZerocoinSupply()))); + result.push_back(Pair("zBWKsupply", zBWKObj)); + return result; } -Object blockHeaderToJSON(const CBlock& block, const CBlockIndex* blockindex) +UniValue blockHeaderToJSON(const CBlock& block, const CBlockIndex* blockindex) { - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("version", block.nVersion)); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); @@ -103,7 +116,7 @@ Object blockHeaderToJSON(const CBlock& block, const CBlockIndex* blockindex) } -Value getblockcount(const Array& params, bool fHelp) +UniValue getblockcount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -117,7 +130,7 @@ Value getblockcount(const Array& params, bool fHelp) return chainActive.Height(); } -Value getbestblockhash(const Array& params, bool fHelp) +UniValue getbestblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -131,7 +144,7 @@ Value getbestblockhash(const Array& params, bool fHelp) return chainActive.Tip()->GetBlockHash().GetHex(); } -Value getdifficulty(const Array& params, bool fHelp) +UniValue getdifficulty(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -146,7 +159,7 @@ Value getdifficulty(const Array& params, bool fHelp) } -Value getrawmempool(const Array& params, bool fHelp) +UniValue getrawmempool(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -182,11 +195,11 @@ Value getrawmempool(const Array& params, bool fHelp) if (fVerbose) { LOCK(mempool.cs); - Object o; + UniValue o(UniValue::VOBJ); BOOST_FOREACH (const PAIRTYPE(uint256, CTxMemPoolEntry) & entry, mempool.mapTx) { const uint256& hash = entry.first; const CTxMemPoolEntry& e = entry.second; - Object info; + UniValue info(UniValue::VOBJ); info.push_back(Pair("size", (int)e.GetTxSize())); info.push_back(Pair("fee", ValueFromAmount(e.GetFee()))); info.push_back(Pair("time", e.GetTime())); @@ -199,7 +212,12 @@ Value getrawmempool(const Array& params, bool fHelp) if (mempool.exists(txin.prevout.hash)) setDepends.insert(txin.prevout.hash.ToString()); } - Array depends(setDepends.begin(), setDepends.end()); + + UniValue depends(UniValue::VARR); + BOOST_FOREACH(const string& dep, setDepends) { + depends.push_back(dep); + } + info.push_back(Pair("depends", depends)); o.push_back(Pair(hash.ToString(), info)); } @@ -208,7 +226,7 @@ Value getrawmempool(const Array& params, bool fHelp) vector vtxid; mempool.queryHashes(vtxid); - Array a; + UniValue a(UniValue::VARR); BOOST_FOREACH (const uint256& hash, vtxid) a.push_back(hash.ToString()); @@ -216,7 +234,7 @@ Value getrawmempool(const Array& params, bool fHelp) } } -Value getblockhash(const Array& params, bool fHelp) +UniValue getblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -237,7 +255,7 @@ Value getblockhash(const Array& params, bool fHelp) return pblockindex->GetBlockHash().GetHex(); } -Value getblock(const Array& params, bool fHelp) +UniValue getblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -265,6 +283,18 @@ Value getblock(const Array& params, bool fHelp) " \"difficulty\" : x.xxx, (numeric) The difficulty\n" " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" + " \"moneysupply\" : \"supply\" (numeric) The money supply when this block was added to the blockchain\n" + " \"zBWKsupply\" :\n" + " {\n" + " \"1\" : n, (numeric) supply of 1 zBWK denomination\n" + " \"5\" : n, (numeric) supply of 5 zBWK denomination\n" + " \"10\" : n, (numeric) supply of 10 zBWK denomination\n" + " \"50\" : n, (numeric) supply of 50 zBWK denomination\n" + " \"100\" : n, (numeric) supply of 100 zBWK denomination\n" + " \"500\" : n, (numeric) supply of 500 zBWK denomination\n" + " \"1000\" : n, (numeric) supply of 1000 zBWK denomination\n" + " \"total\" : n, (numeric) The total supply of all zBWK denominations\n" + " }\n" "}\n" "\nResult (for verbose=false):\n" "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" @@ -297,7 +327,7 @@ Value getblock(const Array& params, bool fHelp) return blockToJSON(block, pblockindex); } -Value getblockheader(const Array& params, bool fHelp) +UniValue getblockheader(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -347,7 +377,7 @@ Value getblockheader(const Array& params, bool fHelp) return blockHeaderToJSON(block, pblockindex); } -Value gettxoutsetinfo(const Array& params, bool fHelp) +UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -367,7 +397,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("gettxoutsetinfo", "") + HelpExampleRpc("gettxoutsetinfo", "")); - Object ret; + UniValue ret(UniValue::VOBJ); CCoinsStats stats; FlushStateToDisk(); @@ -383,7 +413,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) return ret; } -Value gettxout(const Array& params, bool fHelp) +UniValue gettxout(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( @@ -418,7 +448,7 @@ Value gettxout(const Array& params, bool fHelp) "\nView the details\n" + HelpExampleCli("gettxout", "\"txid\" 1") + "\nAs a json rpc call\n" + HelpExampleRpc("gettxout", "\"txid\", 1")); - Object ret; + UniValue ret(UniValue::VOBJ); std::string strHash = params[0].get_str(); uint256 hash(strHash); @@ -432,14 +462,14 @@ Value gettxout(const Array& params, bool fHelp) LOCK(mempool.cs); CCoinsViewMemPool view(pcoinsTip, mempool); if (!view.GetCoins(hash, coins)) - return Value::null; + return NullUniValue; mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool } else { if (!pcoinsTip->GetCoins(hash, coins)) - return Value::null; + return NullUniValue; } if (n < 0 || (unsigned int)n >= coins.vout.size() || coins.vout[n].IsNull()) - return Value::null; + return NullUniValue; BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); CBlockIndex* pindex = it->second; @@ -449,7 +479,7 @@ Value gettxout(const Array& params, bool fHelp) else ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1)); ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue))); - Object o; + UniValue o(UniValue::VOBJ); ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true); ret.push_back(Pair("scriptPubKey", o)); ret.push_back(Pair("version", coins.nVersion)); @@ -458,31 +488,28 @@ Value gettxout(const Array& params, bool fHelp) return ret; } -Value verifychain(const Array& params, bool fHelp) +UniValue verifychain(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( - "verifychain ( checklevel numblocks )\n" + "verifychain ( numblocks )\n" "\nVerifies blockchain database.\n" "\nArguments:\n" - "1. checklevel (numeric, optional, 0-4, default=3) How thorough the block verification is.\n" - "2. numblocks (numeric, optional, default=288, 0=all) The number of blocks to check.\n" + "1. numblocks (numeric, optional, default=288, 0=all) The number of blocks to check.\n" "\nResult:\n" "true|false (boolean) Verified or not\n" "\nExamples:\n" + HelpExampleCli("verifychain", "") + HelpExampleRpc("verifychain", "")); - int nCheckLevel = GetArg("-checklevel", 3); + int nCheckLevel = 4; int nCheckDepth = GetArg("-checkblocks", 288); if (params.size() > 0) - nCheckLevel = params[0].get_int(); - if (params.size() > 1) nCheckDepth = params[1].get_int(); return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth); } -Value getblockchaininfo(const Array& params, bool fHelp) +UniValue getblockchaininfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -501,7 +528,7 @@ Value getblockchaininfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getblockchaininfo", "") + HelpExampleRpc("getblockchaininfo", "")); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("chain", Params().NetworkIDString())); obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); @@ -526,7 +553,7 @@ struct CompareBlocksByHeight { } }; -Value getchaintips(const Array& params, bool fHelp) +UniValue getchaintips(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -573,9 +600,9 @@ Value getchaintips(const Array& params, bool fHelp) setTips.insert(chainActive.Tip()); /* Construct the output array. */ - Array res; + UniValue res(UniValue::VARR); BOOST_FOREACH (const CBlockIndex* block, setTips) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("height", block->nHeight)); obj.push_back(Pair("hash", block->phashBlock->GetHex())); @@ -610,7 +637,87 @@ Value getchaintips(const Array& params, bool fHelp) return res; } -Value getmempoolinfo(const Array& params, bool fHelp) +UniValue getfeeinfo(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getfeeinfo blocks\n" + "\nReturns details of transaction fees over the last n blocks.\n" + "\nArguments:\n" + "1. blocks (int, required) the number of blocks to get transaction data from\n" + "\nResult:\n" + "{\n" + " \"txcount\": xxxxx (numeric) Current tx count\n" + " \"txbytes\": xxxxx (numeric) Sum of all tx sizes\n" + " \"ttlfee\": xxxxx (numeric) Sum of all fees\n" + " \"feeperkb\": xxxxx (numeric) Average fee per kb over the block range\n" + " \"rec_highpriorityfee_perkb\": xxxxx (numeric) Recommended fee per kb to use for a high priority tx\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getfeeinfo", "5") + HelpExampleRpc("getfeeinfo", "5")); + + + int nBlocks = params[0].get_int(); + int 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"); + + 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; +} + +UniValue getmempoolinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -624,14 +731,14 @@ Value getmempoolinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getmempoolinfo", "") + HelpExampleRpc("getmempoolinfo", "")); - Object ret; + UniValue ret(UniValue::VOBJ); ret.push_back(Pair("size", (int64_t)mempool.size())); ret.push_back(Pair("bytes", (int64_t)mempool.GetTotalTxSize())); return ret; } -Value invalidateblock(const Array& params, bool fHelp) +UniValue invalidateblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -664,10 +771,10 @@ Value invalidateblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); } - return Value::null; + return NullUniValue; } -Value reconsiderblock(const Array& params, bool fHelp) +UniValue reconsiderblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -701,5 +808,34 @@ Value reconsiderblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); } - return Value::null; + return NullUniValue; } + +UniValue findserial(const UniValue& params, bool fHelp) +{ + if(fHelp || params.size() != 1) + throw runtime_error( + "findserial \"serial\"\n" + "\nSearches the zerocoin database for a zerocoin spend transaction that contains the specified serial\n" + "\nArguments:\n" + "1. serial (string, required) the serial of a zerocoin spend to search for.\n" + "\nResult:\n" + "{\n" + " \"success\": true/false (boolean) Whether the serial was found\n" + " \"txid\": xxxxx (numeric) The transaction that contains the spent serial\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("findserial", "\"serial\"") + HelpExampleRpc("findserial", "\"serial\"")); + + std::string strSerial = params[0].get_str(); + CBigNum bnSerial(strSerial); + + uint256 txid = 0; + bool fSuccess = zerocoinDB->ReadCoinSpend(bnSerial, txid); + + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("success", fSuccess)); + ret.push_back(Pair("txid", txid.GetHex())); + + return ret; +} \ No newline at end of file diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 9fb39c020..5be37a5e2 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -15,8 +15,10 @@ #include #include +#include // for to_lower() +#include + using namespace std; -using namespace json_spirit; class CRPCConvertParam { @@ -80,6 +82,7 @@ static const CRPCConvertParam vRPCConvertParams[] = {"signrawtransaction", 1}, {"signrawtransaction", 2}, {"sendrawtransaction", 1}, + {"sendrawtransaction", 2}, {"gettxout", 1}, {"gettxout", 2}, {"lockunspent", 0}, @@ -116,7 +119,23 @@ static const CRPCConvertParam vRPCConvertParams[] = {"reservebalance", 1}, {"setstakesplitthreshold", 0}, {"autocombinerewards", 0}, - {"autocombinerewards", 1}}; + {"autocombinerewards", 1}, + {"getzerocoinbalance", 0}, + {"listmintedzerocoins", 0}, + {"listspentzerocoins", 0}, + {"listzerocoinamounts", 0}, + {"mintzerocoin", 0}, + {"spendzerocoin", 0}, + {"spendzerocoin", 1}, + {"spendzerocoin", 2}, + {"spendzerocoin", 3}, + {"importzerocoins", 0}, + {"exportzerocoins", 0}, + {"exportzerocoins", 1}, + {"resetmintzerocoin", 0}, + {"getspentzerocoinamount", 1}, + {"getfeeinfo", 0} + }; class CRPCConvertTable { @@ -145,25 +164,32 @@ CRPCConvertTable::CRPCConvertTable() static CRPCConvertTable rpcCvtTable; +/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) + * as well as objects and arrays. + */ +UniValue ParseNonRFCJSONValue(const std::string& strVal) +{ + UniValue jVal; + if (!jVal.read(std::string("[")+strVal+std::string("]")) || + !jVal.isArray() || jVal.size()!=1) + throw runtime_error(string("Error parsing JSON:")+strVal); + return jVal[0]; +} + /** Convert strings to command-specific RPC representation */ -Array RPCConvertValues(const std::string& strMethod, const std::vector& strParams) +UniValue RPCConvertValues(const std::string &strMethod, const std::vector &strParams) { - Array params; + UniValue params(UniValue::VARR); for (unsigned int idx = 0; idx < strParams.size(); idx++) { const std::string& strVal = strParams[idx]; - // insert string value directly if (!rpcCvtTable.convert(strMethod, idx)) { + // insert string value directly params.push_back(strVal); - } - - // parse string as JSON, insert bool/number/object/etc. value - else { - Value jVal; - if (!read_string(strVal, jVal)) - throw runtime_error(string("Error parsing JSON:") + strVal); - params.push_back(jVal); + } else { + // parse string as JSON, insert bool/number/object/etc. value + params.push_back(ParseNonRFCJSONValue(strVal)); } } diff --git a/src/rpcclient.h b/src/rpcclient.h index a91c2eb03..14f1cc160 100644 --- a/src/rpcclient.h +++ b/src/rpcclient.h @@ -6,10 +6,12 @@ #ifndef BITCOIN_RPCCLIENT_H #define BITCOIN_RPCCLIENT_H -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" +#include -json_spirit::Array RPCConvertValues(const std::string& strMethod, const std::vector& strParams); +UniValue RPCConvertValues(const std::string& strMethod, const std::vector& strParams); +/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) + * as well as objects and arrays. + */ +UniValue ParseNonRFCJSONValue(const std::string& strVal); #endif // BITCOIN_RPCCLIENT_H diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 4c57038be..915eb5345 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -26,9 +26,8 @@ #include #include -#include "json/json_spirit_value.h" +#include -using namespace json_spirit; using namespace std; void EnsureWalletIsUnlocked(); @@ -80,7 +79,7 @@ std::string DecodeDumpString(const std::string& str) return ret.str(); } -Value importprivkey(const Array& params, bool fHelp) +UniValue importprivkey(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( @@ -127,7 +126,7 @@ Value importprivkey(const Array& params, bool fHelp) // Don't throw error in case a key is already there if (pwalletMain->HaveKey(vchAddress)) - return Value::null; + return NullUniValue; pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; @@ -142,10 +141,10 @@ Value importprivkey(const Array& params, bool fHelp) } } - return Value::null; + return NullUniValue; } -Value importaddress(const Array& params, bool fHelp) +UniValue importaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( @@ -193,7 +192,7 @@ Value importaddress(const Array& params, bool fHelp) // Don't throw error in case an address is already there if (pwalletMain->HaveWatchOnly(script)) - return Value::null; + return NullUniValue; pwalletMain->MarkDirty(); @@ -206,10 +205,10 @@ Value importaddress(const Array& params, bool fHelp) } } - return Value::null; + return NullUniValue; } -Value importwallet(const Array& params, bool fHelp) +UniValue importwallet(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -302,10 +301,10 @@ Value importwallet(const Array& params, bool fHelp) if (!fGood) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); - return Value::null; + return NullUniValue; } -Value dumpprivkey(const Array& params, bool fHelp) +UniValue dumpprivkey(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -335,7 +334,7 @@ Value dumpprivkey(const Array& params, bool fHelp) } -Value dumpwallet(const Array& params, bool fHelp) +UniValue dumpwallet(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -390,10 +389,10 @@ Value dumpwallet(const Array& params, bool fHelp) file << "\n"; file << "# End of dump\n"; file.close(); - return Value::null; + return NullUniValue; } -Value bip38encrypt(const Array& params, bool fHelp) +UniValue bip38encrypt(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) throw runtime_error( @@ -422,24 +421,24 @@ Value bip38encrypt(const Array& params, bool fHelp) throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); uint256 privKey = vchSecret.GetPrivKey_256(); - string encryptedOut = BIP38_Encrypt(strAddress, strPassphrase, privKey); + string encryptedOut = BIP38_Encrypt(strAddress, strPassphrase, privKey, vchSecret.IsCompressed()); - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("Addess", strAddress)); result.push_back(Pair("Encrypted Key", encryptedOut)); return result; } -Value bip38decrypt(const Array& params, bool fHelp) +UniValue bip38decrypt(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) throw runtime_error( "bip38decrypt \"bulwarkaddress\"\n" "\nDecrypts and then imports password protected private key.\n" "\nArguments:\n" - "1. \"passphrase\" (string, required) The passphrase you want the private key to be encrypted with\n" - "2. \"encryptedkey\" (string, required) The encrypted private key\n" + "1. \"encryptedkey\" (string, required) The encrypted private key\n" + "2. \"passphrase\" (string, required) The passphrase you want the private key to be encrypted with\n" "\nResult:\n" "\"key\" (string) The decrypted private key\n" @@ -448,15 +447,15 @@ Value bip38decrypt(const Array& params, bool fHelp) EnsureWalletIsUnlocked(); /** Collect private key and passphrase **/ - string strPassphrase = params[0].get_str(); - string strKey = params[1].get_str(); + string strKey = params[0].get_str(); + string strPassphrase = params[1].get_str(); uint256 privKey; bool fCompressed; if (!BIP38_Decrypt(strPassphrase, strKey, privKey, fCompressed)) throw JSONRPCError(RPC_WALLET_ERROR, "Failed To Decrypt"); - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("privatekey", HexStr(privKey))); CKey key; diff --git a/src/rpcmasternode-budget.cpp b/src/rpcmasternode-budget.cpp index 6dd1d68ad..6f4bfb2e9 100644 --- a/src/rpcmasternode-budget.cpp +++ b/src/rpcmasternode-budget.cpp @@ -15,11 +15,12 @@ #include "rpcserver.h" #include "utilmoneystr.h" +#include + #include -using namespace json_spirit; using namespace std; -void budgetToJSON(CBudgetProposal* pbudgetProposal, Object& bObj) +void budgetToJSON(CBudgetProposal* pbudgetProposal, UniValue& bObj) { CTxDestination address1; ExtractDestination(pbudgetProposal->GetPayee(), address1); @@ -50,7 +51,7 @@ void budgetToJSON(CBudgetProposal* pbudgetProposal, Object& bObj) // This command is retained for backwards compatibility, but is depreciated. // Future removal of this command is planned to keep things clean. -Value mnbudget(const Array& params, bool fHelp) +UniValue mnbudget(const UniValue& params, bool fHelp) { string strCommand; if (params.size() >= 1) @@ -77,20 +78,29 @@ Value mnbudget(const Array& params, bool fHelp) " nextblock - Get next superblock for budget system\n"); if (strCommand == "nextblock") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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); } @@ -104,33 +114,45 @@ Value mnbudget(const Array& params, bool fHelp) } if (strCommand == "projection") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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 Value::null; + return NullUniValue; } -Value preparebudget(const Array& params, bool fHelp) +UniValue preparebudget(const UniValue& params, bool fHelp) { int nBlockMin = 0; CBlockIndex* pindexPrev = chainActive.Tip(); @@ -169,8 +191,8 @@ Value preparebudget(const Array& params, bool fHelp) if (nPaymentCount < 1) throw runtime_error("Invalid payment count, must be more than zero."); - //set block min - if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - GetBudgetPaymentCycleBlocks() * (nPaymentCount + 1); + // Start must be in the next budget cycle + if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); int nBlockStart = params[3].get_int(); if (nBlockStart % GetBudgetPaymentCycleBlocks() != 0) { @@ -178,7 +200,7 @@ Value preparebudget(const Array& params, bool fHelp) throw runtime_error(strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext)); } - int nBlockEnd = nBlockStart + GetBudgetPaymentCycleBlocks() * nPaymentCount; + int nBlockEnd = nBlockStart + GetBudgetPaymentCycleBlocks() * nPaymentCount; // End must be AFTER current cycle if (nBlockStart < nBlockMin) throw runtime_error("Invalid block start, must be more than current height."); @@ -223,7 +245,7 @@ Value preparebudget(const Array& params, bool fHelp) return wtx.GetHash().ToString(); } -Value submitbudget(const Array& params, bool fHelp) +UniValue submitbudget(const UniValue& params, bool fHelp) { int nBlockMin = 0; CBlockIndex* pindexPrev = chainActive.Tip(); @@ -263,8 +285,8 @@ Value submitbudget(const Array& params, bool fHelp) if (nPaymentCount < 1) throw runtime_error("Invalid payment count, must be more than zero."); - //set block min - if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - GetBudgetPaymentCycleBlocks() * (nPaymentCount + 1); + // Start must be in the next budget cycle + if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); int nBlockStart = params[3].get_int(); if (nBlockStart % GetBudgetPaymentCycleBlocks() != 0) { @@ -272,7 +294,7 @@ Value submitbudget(const Array& params, bool fHelp) throw runtime_error(strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext)); } - int nBlockEnd = nBlockStart + (GetBudgetPaymentCycleBlocks() * nPaymentCount); + int nBlockEnd = nBlockStart + (GetBudgetPaymentCycleBlocks() * nPaymentCount); // End must be AFTER current cycle if (nBlockStart < nBlockMin) throw runtime_error("Invalid block start, must be more than current height."); @@ -314,7 +336,7 @@ Value submitbudget(const Array& params, bool fHelp) throw runtime_error("Invalid proposal, see debug.log for details."); } -Value mnbudgetvote(const Array& params, bool fHelp) +UniValue mnbudgetvote(const UniValue& params, bool fHelp) { std::string strCommand; if (params.size() >= 1) { @@ -366,14 +388,14 @@ Value mnbudgetvote(const Array& params, bool fHelp) int success = 0; int failed = 0; - Array resultsObj; + UniValue resultsObj(UniValue::VARR); if (strCommand == "local") { CPubKey pubKeyMasternode; CKey keyMasternode; std::string errorMessage; - Object statusObj; + UniValue statusObj(UniValue::VOBJ); while (true) { if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { @@ -423,7 +445,7 @@ Value mnbudgetvote(const Array& params, bool fHelp) break; } - Object returnObj; + UniValue returnObj(UniValue::VOBJ); returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", success, failed))); returnObj.push_back(Pair("detail", resultsObj)); @@ -441,7 +463,7 @@ Value mnbudgetvote(const Array& params, bool fHelp) CPubKey pubKeyMasternode; CKey keyMasternode; - Object statusObj; + UniValue statusObj(UniValue::VOBJ); if (!obfuScationSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)) { failed++; @@ -490,7 +512,7 @@ Value mnbudgetvote(const Array& params, bool fHelp) resultsObj.push_back(statusObj); } - Object returnObj; + UniValue returnObj(UniValue::VOBJ); returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", success, failed))); returnObj.push_back(Pair("detail", resultsObj)); @@ -515,7 +537,7 @@ Value mnbudgetvote(const Array& params, bool fHelp) CPubKey pubKeyMasternode; CKey keyMasternode; - Object statusObj; + UniValue statusObj(UniValue::VOBJ); if(!obfuScationSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)){ failed++; @@ -565,17 +587,17 @@ Value mnbudgetvote(const Array& params, bool fHelp) resultsObj.push_back(statusObj); } - Object returnObj; + UniValue returnObj(UniValue::VOBJ); returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", success, failed))); returnObj.push_back(Pair("detail", resultsObj)); return returnObj; } - return Value::null; + return NullUniValue; } -Value getbudgetvotes(const Array& params, bool fHelp) +UniValue getbudgetvotes(const UniValue& params, bool fHelp) { if (params.size() != 1) throw runtime_error( @@ -601,7 +623,7 @@ Value getbudgetvotes(const Array& params, bool fHelp) std::string strProposalName = SanitizeString(params[0].get_str()); - Array ret; + UniValue ret(UniValue::VARR); CBudgetProposal* pbudgetProposal = budget.FindProposal(strProposalName); @@ -609,7 +631,7 @@ Value getbudgetvotes(const Array& params, bool fHelp) std::map::iterator it = pbudgetProposal->mapVotes.begin(); while (it != pbudgetProposal->mapVotes.end()) { - Object bObj; + UniValue bObj(UniValue::VOBJ); bObj.push_back(Pair("mnId", (*it).second.vin.prevout.hash.ToString())); bObj.push_back(Pair("nHash", (*it).first.ToString().c_str())); bObj.push_back(Pair("Vote", (*it).second.GetVoteString())); @@ -624,7 +646,7 @@ Value getbudgetvotes(const Array& params, bool fHelp) return ret; } -Value getnextsuperblock(const Array& params, bool fHelp) +UniValue getnextsuperblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -643,7 +665,7 @@ Value getnextsuperblock(const Array& params, bool fHelp) return nNext; } -Value getbudgetprojection(const Array& params, bool fHelp) +UniValue getbudgetprojection(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -680,8 +702,8 @@ Value getbudgetprojection(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getbudgetprojection", "") + HelpExampleRpc("getbudgetprojection", "")); - Array ret; - Object resultObj; + UniValue ret(UniValue::VARR); + UniValue resultObj(UniValue::VOBJ); CAmount nTotalAllotted = 0; std::vector winningProps = budget.GetBudget(); @@ -692,7 +714,7 @@ Value getbudgetprojection(const Array& params, bool fHelp) ExtractDestination(pbudgetProposal->GetPayee(), address1); CBitcoinAddress address2(address1); - Object bObj; + UniValue bObj(UniValue::VOBJ); budgetToJSON(pbudgetProposal, bObj); bObj.push_back(Pair("Alloted", ValueFromAmount(pbudgetProposal->GetAllotted()))); bObj.push_back(Pair("TotalBudgetAlloted", ValueFromAmount(nTotalAllotted))); @@ -703,7 +725,7 @@ Value getbudgetprojection(const Array& params, bool fHelp) return ret; } -Value getbudgetinfo(const Array& params, bool fHelp) +UniValue getbudgetinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -741,14 +763,14 @@ Value getbudgetinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getbudgetprojection", "") + HelpExampleRpc("getbudgetprojection", "")); - Array ret; + UniValue ret(UniValue::VARR); std::string strShow = "valid"; if (params.size() == 1) { std::string strProposalName = SanitizeString(params[0].get_str()); CBudgetProposal* pbudgetProposal = budget.FindProposal(strProposalName); if (pbudgetProposal == NULL) throw runtime_error("Unknown proposal name"); - Object bObj; + UniValue bObj(UniValue::VOBJ); budgetToJSON(pbudgetProposal, bObj); ret.push_back(bObj); return ret; @@ -758,7 +780,7 @@ Value getbudgetinfo(const Array& params, bool fHelp) BOOST_FOREACH (CBudgetProposal* pbudgetProposal, winningProps) { if (strShow == "valid" && !pbudgetProposal->fValid) continue; - Object bObj; + UniValue bObj(UniValue::VOBJ); budgetToJSON(pbudgetProposal, bObj); ret.push_back(bObj); @@ -767,7 +789,7 @@ Value getbudgetinfo(const Array& params, bool fHelp) return ret; } -Value mnbudgetrawvote(const Array& params, bool fHelp) +UniValue mnbudgetrawvote(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 6) throw runtime_error( @@ -830,7 +852,7 @@ Value mnbudgetrawvote(const Array& params, bool fHelp) } } -Value mnfinalbudget(const Array& params, bool fHelp) +UniValue mnfinalbudget(const UniValue& params, bool fHelp) { string strCommand; if (params.size() >= 1) @@ -857,7 +879,7 @@ Value mnfinalbudget(const Array& params, bool fHelp) int success = 0; int failed = 0; - Object resultsObj; + UniValue resultsObj(UniValue::VOBJ); BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { std::string errorMessage; @@ -869,7 +891,7 @@ Value mnfinalbudget(const Array& params, bool fHelp) CPubKey pubKeyMasternode; CKey keyMasternode; - Object statusObj; + UniValue statusObj(UniValue::VOBJ); if (!obfuScationSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)) { failed++; @@ -912,7 +934,7 @@ Value mnfinalbudget(const Array& params, bool fHelp) resultsObj.push_back(Pair(mne.getAlias(), statusObj)); } - Object returnObj; + UniValue returnObj(UniValue::VOBJ); returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", success, failed))); returnObj.push_back(Pair("detail", resultsObj)); @@ -954,11 +976,11 @@ Value mnfinalbudget(const Array& params, bool fHelp) } if (strCommand == "show") { - Object resultObj; + UniValue resultObj(UniValue::VOBJ); std::vector winningFbs = budget.GetFinalizedBudgets(); BOOST_FOREACH (CFinalizedBudget* finalizedBudget, winningFbs) { - Object bObj; + UniValue bObj(UniValue::VOBJ); bObj.push_back(Pair("FeeTX", finalizedBudget->nFeeTXHash.ToString())); bObj.push_back(Pair("Hash", finalizedBudget->GetHash().ToString())); bObj.push_back(Pair("BlockStart", (int64_t)finalizedBudget->GetBlockStart())); @@ -984,7 +1006,7 @@ Value mnfinalbudget(const Array& params, bool fHelp) std::string strHash = params[1].get_str(); uint256 hash(strHash); - Object obj; + UniValue obj(UniValue::VOBJ); CFinalizedBudget* pfinalBudget = budget.FindFinalizedBudget(hash); @@ -992,7 +1014,7 @@ Value mnfinalbudget(const Array& params, bool fHelp) std::map::iterator it = pfinalBudget->mapVotes.begin(); while (it != pfinalBudget->mapVotes.end()) { - Object bObj; + UniValue bObj(UniValue::VOBJ); bObj.push_back(Pair("nHash", (*it).first.ToString().c_str())); bObj.push_back(Pair("nTime", (int64_t)(*it).second.nTime)); bObj.push_back(Pair("fValid", (*it).second.fValid)); @@ -1005,10 +1027,10 @@ Value mnfinalbudget(const Array& params, bool fHelp) return obj; } - return Value::null; + return NullUniValue; } -Value checkbudgets(const Array& params, bool fHelp) +UniValue checkbudgets(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -1019,5 +1041,5 @@ Value checkbudgets(const Array& params, bool fHelp) budget.CheckAndRemove(); - return Value::null; + return NullUniValue; } diff --git a/src/rpcmasternode.cpp b/src/rpcmasternode.cpp index 2e7a162a6..e4188ddf6 100644 --- a/src/rpcmasternode.cpp +++ b/src/rpcmasternode.cpp @@ -1,4 +1,3 @@ -// Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Copyright (c) 2015-2017 The PIVX developers // Copyright (c) 2017-2018 The Bulwark developers @@ -16,10 +15,11 @@ #include "rpcserver.h" #include "utilmoneystr.h" -#include +#include +#include #include -using namespace json_spirit; + void SendMoney(const CTxDestination& address, CAmount nValue, CWalletTx& wtxNew, AvailableCoinsType coin_type = ALL_COINS) { @@ -53,8 +53,10 @@ void SendMoney(const CTxDestination& address, CAmount nValue, CWalletTx& wtxNew, throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); } -Value obfuscation(const Array& params, bool fHelp) +UniValue obfuscation(const UniValue& params, bool fHelp) { + throw runtime_error("Obfuscation is not supported any more. Use Zerocoin\n"); + if (fHelp || params.size() == 0) throw runtime_error( "obfuscation \n" @@ -101,7 +103,8 @@ Value obfuscation(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } -Value getpoolinfo(const Array& params, bool fHelp) + +UniValue getpoolinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -119,7 +122,7 @@ Value getpoolinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getpoolinfo", "") + HelpExampleRpc("getpoolinfo", "")); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("current_masternode", mnodeman.GetCurrentMasterNode()->addr.ToString())); obj.push_back(Pair("state", obfuScationPool.GetState())); obj.push_back(Pair("entries", obfuScationPool.GetEntriesCount())); @@ -129,7 +132,7 @@ Value getpoolinfo(const Array& params, bool fHelp) // This command is retained for backwards compatibility, but is depreciated. // Future removal of this command is planned to keep things clean. -Value masternode(const Array& params, bool fHelp) +UniValue masternode(const UniValue& params, bool fHelp) { string strCommand; if (params.size() >= 1) @@ -163,32 +166,47 @@ Value masternode(const Array& params, bool fHelp) " winners - Print list of masternode winners\n"); if (strCommand == "list") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() -1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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); } @@ -197,45 +215,63 @@ Value masternode(const Array& params, bool fHelp) } if (strCommand == "genkey") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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") { - Array newParams(params.size() - 1); - std::copy(params.begin() + 1, params.end(), newParams.begin()); + 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 Value::null; + return NullUniValue; } -Value listmasternodes(const Array& params, bool fHelp) +UniValue listmasternodes(const UniValue& params, bool fHelp) { std::string strFilter = ""; @@ -267,7 +303,7 @@ Value listmasternodes(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("masternodelist", "") + HelpExampleRpc("masternodelist", "")); - Array ret; + UniValue ret(UniValue::VARR); int nHeight; { LOCK(cs_main); @@ -277,7 +313,7 @@ Value listmasternodes(const Array& params, bool fHelp) } std::vector > vMasternodeRanks = mnodeman.GetMasternodeRanks(nHeight); BOOST_FOREACH (PAIRTYPE(int, CMasternode) & s, vMasternodeRanks) { - Object obj; + UniValue obj(UniValue::VOBJ); std::string strVin = s.second.vin.prevout.ToStringShort(); std::string strTxHash = s.second.vin.prevout.hash.ToString(); uint32_t oIdx = s.second.vin.prevout.n; @@ -314,7 +350,7 @@ Value listmasternodes(const Array& params, bool fHelp) return ret; } -Value masternodeconnect(const Array& params, bool fHelp) +UniValue masternodeconnect(const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 1)) throw runtime_error( @@ -334,13 +370,13 @@ Value masternodeconnect(const Array& params, bool fHelp) CNode* pnode = ConnectNode((CAddress)addr, NULL, false); if (pnode) { pnode->Release(); - return Value::null; + return NullUniValue; } else { throw runtime_error("error connecting\n"); } } -Value getmasternodecount (const Array& params, bool fHelp) +UniValue getmasternodecount (const UniValue& params, bool fHelp) { if (fHelp || (params.size() > 0)) throw runtime_error( @@ -358,7 +394,7 @@ Value getmasternodecount (const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getmasternodecount", "") + HelpExampleRpc("getmasternodecount", "")); - Object obj; + UniValue obj(UniValue::VOBJ); int nCount = 0; int ipv4 = 0, ipv6 = 0, onion = 0; @@ -379,7 +415,7 @@ Value getmasternodecount (const Array& params, bool fHelp) return obj; } -Value masternodecurrent (const Array& params, bool fHelp) +UniValue masternodecurrent (const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0)) throw runtime_error( @@ -399,7 +435,7 @@ Value masternodecurrent (const Array& params, bool fHelp) CMasternode* winner = mnodeman.GetCurrentMasterNode(1); if (winner) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("protocol", (int64_t)winner->protocolVersion)); obj.push_back(Pair("txhash", winner->vin.prevout.hash.ToString())); @@ -412,7 +448,7 @@ Value masternodecurrent (const Array& params, bool fHelp) throw runtime_error("unknown"); } -Value masternodedebug (const Array& params, bool fHelp) +UniValue masternodedebug (const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0)) throw runtime_error( @@ -436,7 +472,7 @@ Value masternodedebug (const Array& params, bool fHelp) return activeMasternode.GetStatus(); } -Value startmasternode (const Array& params, bool fHelp) +UniValue startmasternode (const UniValue& params, bool fHelp) { std::string strCommand; if (params.size() >= 1) { @@ -479,7 +515,7 @@ Value startmasternode (const Array& params, bool fHelp) " ]\n" "}\n" "\nExamples:\n" + - HelpExampleCli("masternodestart", "\"alias\" \"my_mn\"") + HelpExampleRpc("masternodestart", "\"alias\" \"my_mn\"")); + HelpExampleCli("startmasternode", "\"alias\" \"0\" \"my_mn\"") + HelpExampleRpc("startmasternode", "\"alias\" \"0\" \"my_mn\"")); bool fLock = (params[1].get_str() == "true" ? true : false); @@ -515,7 +551,7 @@ Value startmasternode (const Array& params, bool fHelp) int successful = 0; int failed = 0; - Array resultsObj; + UniValue resultsObj(UniValue::VARR); BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { std::string errorMessage; @@ -532,7 +568,7 @@ Value startmasternode (const Array& params, bool fHelp) bool result = activeMasternode.Register(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage); - Object statusObj; + UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", mne.getAlias())); statusObj.push_back(Pair("result", result ? "success" : "failed")); @@ -549,7 +585,7 @@ Value startmasternode (const Array& params, bool fHelp) if (fLock) pwalletMain->Lock(); - Object returnObj; + UniValue returnObj(UniValue::VOBJ); returnObj.push_back(Pair("overall", strprintf("Successfully started %d masternodes, failed to start %d, total %d", successful, failed, successful + failed))); returnObj.push_back(Pair("detail", resultsObj)); @@ -566,8 +602,8 @@ Value startmasternode (const Array& params, bool fHelp) int successful = 0; int failed = 0; - Array resultsObj; - Object statusObj; + UniValue resultsObj(UniValue::VARR); + UniValue statusObj(UniValue::VOBJ); statusObj.push_back(Pair("alias", alias)); BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { @@ -601,16 +637,16 @@ Value startmasternode (const Array& params, bool fHelp) if (fLock) pwalletMain->Lock(); - Object returnObj; + UniValue returnObj(UniValue::VOBJ); returnObj.push_back(Pair("overall", strprintf("Successfully started %d masternodes, failed to start %d, total %d", successful, failed, successful + failed))); returnObj.push_back(Pair("detail", resultsObj)); return returnObj; } - return Value::null; + return NullUniValue; } -Value createmasternodekey (const Array& params, bool fHelp) +UniValue createmasternodekey (const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0)) throw runtime_error( @@ -628,7 +664,7 @@ Value createmasternodekey (const Array& params, bool fHelp) return CBitcoinSecret(secret).ToString(); } -Value getmasternodeoutputs (const Array& params, bool fHelp) +UniValue getmasternodeoutputs (const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0)) throw runtime_error( @@ -650,9 +686,9 @@ Value getmasternodeoutputs (const Array& params, bool fHelp) // Find possible candidates vector possibleCoins = activeMasternode.SelectCoinsMasternode(); - Array ret; + UniValue ret(UniValue::VARR); BOOST_FOREACH (COutput& out, possibleCoins) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txhash", out.tx->GetHash().ToString())); obj.push_back(Pair("outputidx", out.i)); ret.push_back(obj); @@ -661,7 +697,7 @@ Value getmasternodeoutputs (const Array& params, bool fHelp) return ret; } -Value listmasternodeconf (const Array& params, bool fHelp) +UniValue listmasternodeconf (const UniValue& params, bool fHelp) { std::string strFilter = ""; @@ -694,7 +730,7 @@ Value listmasternodeconf (const Array& params, bool fHelp) std::vector mnEntries; mnEntries = masternodeConfig.getEntries(); - Array ret; + UniValue ret(UniValue::VARR); BOOST_FOREACH (CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { int nIndex; @@ -710,7 +746,7 @@ Value listmasternodeconf (const Array& params, bool fHelp) mne.getTxHash().find(strFilter) == string::npos && strStatus.find(strFilter) == string::npos) continue; - Object mnObj; + UniValue mnObj(UniValue::VOBJ); mnObj.push_back(Pair("alias", mne.getAlias())); mnObj.push_back(Pair("address", mne.getIp())); mnObj.push_back(Pair("privateKey", mne.getPrivKey())); @@ -723,7 +759,7 @@ Value listmasternodeconf (const Array& params, bool fHelp) return ret; } -Value getmasternodestatus (const Array& params, bool fHelp) +UniValue getmasternodestatus (const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0)) throw runtime_error( @@ -748,7 +784,7 @@ Value getmasternodestatus (const Array& params, bool fHelp) CMasternode* pmn = mnodeman.Find(activeMasternode.vin); if (pmn) { - Object mnObj; + UniValue mnObj(UniValue::VOBJ); mnObj.push_back(Pair("txhash", activeMasternode.vin.prevout.hash.ToString())); mnObj.push_back(Pair("outputidx", (uint64_t)activeMasternode.vin.prevout.n)); mnObj.push_back(Pair("netaddr", activeMasternode.service.ToString())); @@ -761,7 +797,7 @@ Value getmasternodestatus (const Array& params, bool fHelp) + activeMasternode.GetStatus()); } -Value getmasternodewinners (const Array& params, bool fHelp) +UniValue getmasternodewinners (const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) throw runtime_error( @@ -818,21 +854,21 @@ Value getmasternodewinners (const Array& params, bool fHelp) if (params.size() == 2) strFilter = params[1].get_str(); - Array ret; + UniValue ret(UniValue::VARR); for (int i = nHeight - nLast; i < nHeight + 20; i++) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("nHeight", i)); std::string strPayment = GetRequiredPaymentsString(i); if (strFilter != "" && strPayment.find(strFilter) == std::string::npos) continue; if (strPayment.find(',') != std::string::npos) { - Array winner; + UniValue winner(UniValue::VARR); boost::char_separator sep(","); boost::tokenizer< boost::char_separator > tokens(strPayment, sep); BOOST_FOREACH (const string& t, tokens) { - Object addr; + UniValue addr(UniValue::VOBJ); std::size_t pos = t.find(":"); std::string strAddress = t.substr(0,pos); uint64_t nVotes = atoi(t.substr(pos+1)); @@ -842,7 +878,7 @@ Value getmasternodewinners (const Array& params, bool fHelp) } obj.push_back(Pair("winner", winner)); } else if (strPayment.find("Unknown") == std::string::npos) { - Object winner; + UniValue winner(UniValue::VOBJ); std::size_t pos = strPayment.find(":"); std::string strAddress = strPayment.substr(0,pos); uint64_t nVotes = atoi(strPayment.substr(pos+1)); @@ -850,7 +886,7 @@ Value getmasternodewinners (const Array& params, bool fHelp) winner.push_back(Pair("nVotes", nVotes)); obj.push_back(Pair("winner", winner)); } else { - Object winner; + UniValue winner(UniValue::VOBJ); winner.push_back(Pair("address", strPayment)); winner.push_back(Pair("nVotes", 0)); obj.push_back(Pair("winner", winner)); @@ -862,7 +898,7 @@ Value getmasternodewinners (const Array& params, bool fHelp) return ret; } -Value getmasternodescores (const Array& params, bool fHelp) +UniValue getmasternodescores (const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -889,7 +925,7 @@ Value getmasternodescores (const Array& params, bool fHelp) throw runtime_error("Exception on param 2"); } } - Object obj; + UniValue obj(UniValue::VOBJ); std::vector vMasternodes = mnodeman.GetFullMasternodeVector(); for (int nHeight = chainActive.Tip()->nHeight - nLast; nHeight < chainActive.Tip()->nHeight + 20; nHeight++) { diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 9e00aef10..de279f303 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -17,6 +17,7 @@ #include "pow.h" #include "rpcserver.h" #include "util.h" +#include "spork.h" #ifdef ENABLE_WALLET #include "db.h" #include "wallet.h" @@ -26,10 +27,8 @@ #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" +#include -using namespace json_spirit; using namespace std; #ifdef ENABLE_WALLET @@ -67,9 +66,9 @@ void ShutdownRPCMining() * or from the last difficulty change if 'lookup' is nonpositive. * If 'height' is nonnegative, compute the estimate at the time when a given block was found. */ -Value GetNetworkHashPS(int lookup, int height) +UniValue GetNetworkHashPS(int lookup, int height) { - CBlockIndex* pb = chainActive.Tip(); + CBlockIndex *pb = chainActive.Tip(); if (height >= 0 && height < chainActive.Height()) pb = chainActive[height]; @@ -105,7 +104,7 @@ Value GetNetworkHashPS(int lookup, int height) return (int64_t)(workDiff.getdouble() / timeDiff); } -Value getnetworkhashps(const Array& params, bool fHelp) +UniValue getnetworkhashps(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( @@ -125,7 +124,7 @@ Value getnetworkhashps(const Array& params, bool fHelp) } #ifdef ENABLE_WALLET -Value getgenerate(const Array& params, bool fHelp) +UniValue getgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -142,7 +141,7 @@ Value getgenerate(const Array& params, bool fHelp) } -Value setgenerate(const Array& params, bool fHelp) +UniValue setgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -192,9 +191,9 @@ Value setgenerate(const Array& params, bool fHelp) nHeightEnd = nHeightStart + nGenerate; } unsigned int nExtraNonce = 0; - Array blockHashes; + UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd) { - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, false)); + unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, false)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); CBlock* pblock = &pblocktemplate->block; @@ -221,10 +220,10 @@ Value setgenerate(const Array& params, bool fHelp) GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); } - return Value::null; + return NullUniValue; } -Value gethashespersec(const Array& params, bool fHelp) +UniValue gethashespersec(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -243,7 +242,7 @@ Value gethashespersec(const Array& params, bool fHelp) #endif -Value getmininginfo(const Array& params, bool fHelp) +UniValue getmininginfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -266,7 +265,7 @@ Value getmininginfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getmininginfo", "") + HelpExampleRpc("getmininginfo", "")); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); @@ -286,7 +285,7 @@ Value getmininginfo(const Array& params, bool fHelp) // NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts -Value prioritisetransaction(const Array& params, bool fHelp) +UniValue prioritisetransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) throw runtime_error( @@ -296,8 +295,8 @@ Value prioritisetransaction(const Array& params, bool fHelp) "1. \"txid\" (string, required) The transaction id.\n" "2. priority delta (numeric, required) The priority to add or subtract.\n" " The transaction selection algorithm considers the tx as it would have a higher priority.\n" - " (priority of a transaction is calculated: coinage * value_in_duffs / txsize) \n" - "3. fee delta (numeric, required) The fee value (in duffs) to add (or subtract, if negative).\n" + " (priority of a transaction is calculated: coinage * value_in_ubwk / txsize) \n" + "3. fee delta (numeric, required) The fee value (in ubwk) to add (or subtract, if negative).\n" " The fee is not actually paid, only the algorithm for selecting transactions into a block\n" " considers the transaction as it would have paid a higher (or lower) fee.\n" "\nResult\n" @@ -315,10 +314,10 @@ Value prioritisetransaction(const Array& params, bool fHelp) // NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller -static Value BIP22ValidationResult(const CValidationState& state) +static UniValue BIP22ValidationResult(const CValidationState& state) { if (state.IsValid()) - return Value::null; + return NullUniValue; std::string strRejectReason = state.GetRejectReason(); if (state.IsError()) @@ -332,8 +331,10 @@ static Value BIP22ValidationResult(const CValidationState& state) return "valid?"; } -Value getblocktemplate(const Array& params, bool fHelp) +UniValue getblocktemplate(const UniValue& params, bool fHelp) { + int lastPoWBlock = IsSporkActive(SPORK_19_POW_ROLLBACK) ? Params().LAST_POW_BLOCK_OLD() : Params().LAST_POW_BLOCK(); + if (fHelp || params.size() > 1) throw runtime_error( "getblocktemplate ( \"jsonrequestobject\" )\n" @@ -364,7 +365,7 @@ Value getblocktemplate(const Array& params, bool fHelp) " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n" " ,...\n" " ],\n" - " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in duffs); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" + " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in ubwk); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" " \"sigops\" : n, (numeric) total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any\n" " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n" " }\n" @@ -373,7 +374,7 @@ Value getblocktemplate(const Array& params, bool fHelp) " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n" " \"flags\" : \"flags\" (string) \n" " },\n" - " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in duffs)\n" + " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in ubwk)\n" " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n" " \"target\" : \"xxxx\", (string) The hash target\n" " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n" @@ -400,22 +401,25 @@ Value getblocktemplate(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getblocktemplate", "") + HelpExampleRpc("getblocktemplate", "")); + if (chainActive.Tip()->nHeight >= lastPoWBlock) + throw JSONRPCError(RPC_GBT_POS_ERROR, "No mining during Proof-of-Stake"); + std::string strMode = "template"; - Value lpval = Value::null; + UniValue lpval = NullUniValue; if (params.size() > 0) { - const Object& oparam = params[0].get_obj(); - const Value& modeval = find_value(oparam, "mode"); - if (modeval.type() == str_type) + const UniValue& oparam = params[0].get_obj(); + const UniValue& modeval = find_value(oparam, "mode"); + if (modeval.isStr()) strMode = modeval.get_str(); - else if (modeval.type() == null_type) { + else if (modeval.isNull()) { /* Do nothing */ } else throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); lpval = find_value(oparam, "longpollid"); if (strMode == "proposal") { - const Value& dataval = find_value(oparam, "data"); - if (dataval.type() != str_type) + const UniValue& dataval = find_value(oparam, "data"); + if (!dataval.isStr()) throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); CBlock block; @@ -454,13 +458,13 @@ Value getblocktemplate(const Array& params, bool fHelp) static unsigned int nTransactionsUpdatedLast; - if (lpval.type() != null_type) { + if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions uint256 hashWatchedChain; boost::system_time checktxtime; unsigned int nTransactionsUpdatedLastLP; - if (lpval.type() == str_type) { + if (lpval.isStr()) { // Format: std::string lpstr = lpval.get_str(); @@ -522,7 +526,7 @@ Value getblocktemplate(const Array& params, bool fHelp) pblocktemplate = NULL; } - CScript scriptDummy = CScript() << OP_TRUE; + CScript scriptDummy = CScript() << OP_TRUE; pblocktemplate = CreateNewBlock(scriptDummy, pwalletMain, false); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); @@ -538,9 +542,9 @@ Value getblocktemplate(const Array& params, bool fHelp) UpdateTime(pblock, pindexPrev); pblock->nNonce = 0; - static const Array aCaps = boost::assign::list_of("proposal"); + UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); - Array transactions; + UniValue transactions(UniValue::VARR); map setTxIndex; int i = 0; BOOST_FOREACH (CTransaction& tx, pblock->vtx) { @@ -550,13 +554,13 @@ Value getblocktemplate(const Array& params, bool fHelp) if (tx.IsCoinBase()) continue; - Object entry; + UniValue entry(UniValue::VOBJ); entry.push_back(Pair("data", EncodeHexTx(tx))); entry.push_back(Pair("hash", txHash.GetHex())); - Array deps; + UniValue deps(UniValue::VARR); BOOST_FOREACH (const CTxIn& in, tx.vin) { if (setTxIndex.count(in.prevout.hash)) deps.push_back(setTxIndex[in.prevout.hash]); @@ -570,7 +574,7 @@ Value getblocktemplate(const Array& params, bool fHelp) transactions.push_back(entry); } - Array coinbasetxn; + UniValue coinbasetxn(UniValue::VARR); map setTxIndex1; int j = 0; BOOST_FOREACH (CTransaction& tx, pblock->vtx) {//Incase if multi coinbase @@ -581,13 +585,13 @@ Value getblocktemplate(const Array& params, bool fHelp) /* if (tx.IsCoinBase()) continue; */ - Object entry; + UniValue entry(UniValue::VOBJ); entry.push_back(Pair("data", EncodeHexTx(tx))); entry.push_back(Pair("hash", txHash.GetHex())); - Array deps; + UniValue deps(UniValue::VARR); BOOST_FOREACH (const CTxIn& in, tx.vin) { if (setTxIndex.count(in.prevout.hash)) deps.push_back(setTxIndex[in.prevout.hash]); @@ -602,21 +606,21 @@ Value getblocktemplate(const Array& params, bool fHelp) } } - Object aux; + UniValue aux(UniValue::VOBJ); aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); uint256 hashTarget = uint256().SetCompact(pblock->nBits); - static Array aMutable; + static UniValue aMutable(UniValue::VARR); if (aMutable.empty()) { aMutable.push_back("time"); aMutable.push_back("transactions"); aMutable.push_back("prevblock"); } - Array aVotes; + UniValue aVotes(UniValue::VARR); - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("capabilities", aCaps)); result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); @@ -629,8 +633,8 @@ Value getblocktemplate(const Array& params, bool fHelp) result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast() + 1)); result.push_back(Pair("mutable", aMutable)); result.push_back(Pair("noncerange", "00000000ffffffff")); - result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); - result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); +// result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); +// result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); result.push_back(Pair("curtime", pblock->GetBlockTime())); result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight + 1))); @@ -673,7 +677,7 @@ class submitblock_StateCatcher : public CValidationInterface }; }; -Value submitblock(const Array& params, bool fHelp) +UniValue submitblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -730,7 +734,7 @@ Value submitblock(const Array& params, bool fHelp) return BIP22ValidationResult(state); } -Value estimatefee(const Array& params, bool fHelp) +UniValue estimatefee(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -748,7 +752,7 @@ Value estimatefee(const Array& params, bool fHelp) "\nExample:\n" + HelpExampleCli("estimatefee", "6")); - RPCTypeCheck(params, boost::assign::list_of(int_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); int nBlocks = params[0].get_int(); if (nBlocks < 1) @@ -761,7 +765,7 @@ Value estimatefee(const Array& params, bool fHelp) return ValueFromAmount(feeRate.GetFeePerK()); } -Value estimatepriority(const Array& params, bool fHelp) +UniValue estimatepriority(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -779,7 +783,7 @@ Value estimatepriority(const Array& params, bool fHelp) "\nExample:\n" + HelpExampleCli("estimatepriority", "6")); - RPCTypeCheck(params, boost::assign::list_of(int_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); int nBlocks = params[0].get_int(); if (nBlocks < 1) diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index e8cdec160..ac7da0723 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -24,13 +24,12 @@ #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" #include +#include + using namespace boost; using namespace boost::assign; -using namespace json_spirit; using namespace std; /** @@ -46,7 +45,7 @@ using namespace std; * * Or alternatively, create a specific query method for the information. **/ -Value getinfo(const Array& params, bool fHelp) +UniValue getinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -57,14 +56,26 @@ Value getinfo(const Array& params, bool fHelp) " \"version\": xxxxx, (numeric) the server version\n" " \"protocolversion\": xxxxx, (numeric) the protocol version\n" " \"walletversion\": xxxxx, (numeric) the wallet version\n" - " \"balance\": xxxxxxx, (numeric) the total bulwark balance of the wallet\n" - " \"obfuscation_balance\": xxxxxx, (numeric) the anonymized bulwark balance of the wallet\n" + " \"balance\": xxxxxxx, (numeric) the total bulwark balance of the wallet (excluding zerocoins)\n" + " \"zerocoinbalance\": xxxxxxx, (numeric) the total zerocoin balance of the wallet\n" " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" " \"timeoffset\": xxxxx, (numeric) the time offset\n" " \"connections\": xxxxx, (numeric) the number of connections\n" " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n" " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" " \"testnet\": true|false, (boolean) if the server is using testnet or not\n" + " \"moneysupply\" : \"supply\" (numeric) The money supply when this block was added to the blockchain\n" + " \"zBWKsupply\" :\n" + " {\n" + " \"1\" : n, (numeric) supply of 1 zBWK denomination\n" + " \"5\" : n, (numeric) supply of 5 zBWK denomination\n" + " \"10\" : n, (numeric) supply of 10 zBWK denomination\n" + " \"50\" : n, (numeric) supply of 50 zBWK denomination\n" + " \"100\" : n, (numeric) supply of 100 zBWK denomination\n" + " \"500\" : n, (numeric) supply of 500 zBWK denomination\n" + " \"1000\" : n, (numeric) supply of 1000 zBWK denomination\n" + " \"total\" : n, (numeric) The total supply of all zBWK denominations\n" + " }\n" " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" @@ -79,23 +90,30 @@ Value getinfo(const Array& params, bool fHelp) proxyType proxy; GetProxy(NET_IPV4, proxy); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); #ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); - if (!fLiteMode) - obj.push_back(Pair("obfuscation_balance", ValueFromAmount(pwalletMain->GetAnonymizedBalance()))); + obj.push_back(Pair("zerocoinbalance", ValueFromAmount(pwalletMain->GetZerocoinBalance(true)))); } #endif obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("connections", (int)vNodes.size())); - obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string()))); + obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); + obj.push_back(Pair("moneysupply",ValueFromAmount(chainActive.Tip()->nMoneySupply))); + UniValue zBWKObj(UniValue::VOBJ); + for (auto denom : libzerocoin::zerocoinDenomList) { + zBWKObj.push_back(Pair(to_string(denom), ValueFromAmount(chainActive.Tip()->mapZerocoinSupply.at(denom) * (denom*COIN)))); + } + zBWKObj.push_back(Pair("total", ValueFromAmount(chainActive.Tip()->GetZerocoinSupply()))); + obj.push_back(Pair("zBWKsupply", zBWKObj)); + #ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); @@ -116,7 +134,7 @@ Value getinfo(const Array& params, bool fHelp) return obj; } -Value mnsync(const Array& params, bool fHelp) +UniValue mnsync(const UniValue& params, bool fHelp) { std::string strMode; if (params.size() == 1) @@ -157,7 +175,7 @@ Value mnsync(const Array& params, bool fHelp) } if (strMode == "status") { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("IsBlockchainSynced", masternodeSync.IsBlockchainSynced())); obj.push_back(Pair("lastMasternodeList", masternodeSync.lastMasternodeList)); @@ -187,7 +205,7 @@ Value mnsync(const Array& params, bool fHelp) } #ifdef ENABLE_WALLET -class DescribeAddressVisitor : public boost::static_visitor +class DescribeAddressVisitor : public boost::static_visitor { private: isminetype mine; @@ -195,11 +213,10 @@ class DescribeAddressVisitor : public boost::static_visitor public: DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {} - Object operator()(const CNoDestination& dest) const { return Object(); } + UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); } - Object operator()(const CKeyID& keyID) const - { - Object obj; + UniValue operator()(const CKeyID &keyID) const { + UniValue obj(UniValue::VOBJ); CPubKey vchPubKey; obj.push_back(Pair("isscript", false)); if (mine == ISMINE_SPENDABLE) { @@ -210,9 +227,8 @@ class DescribeAddressVisitor : public boost::static_visitor return obj; } - Object operator()(const CScriptID& scriptID) const - { - Object obj; + UniValue operator()(const CScriptID &scriptID) const { + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("isscript", true)); if (mine != ISMINE_NO) { CScript subscript; @@ -223,7 +239,7 @@ class DescribeAddressVisitor : public boost::static_visitor ExtractDestinations(subscript, whichType, addresses, nRequired); obj.push_back(Pair("script", GetTxnOutputType(whichType))); obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); - Array a; + UniValue a(UniValue::VARR); BOOST_FOREACH (const CTxDestination& addr, addresses) a.push_back(CBitcoinAddress(addr).ToString()); obj.push_back(Pair("addresses", a)); @@ -238,17 +254,17 @@ class DescribeAddressVisitor : public boost::static_visitor /* Used for updating/reading spork settings on the network */ -Value spork(const Array& params, bool fHelp) +UniValue spork(const UniValue& params, bool fHelp) { if (params.size() == 1 && params[0].get_str() == "show") { - Object ret; + UniValue ret(UniValue::VOBJ); for (int nSporkID = SPORK_START; nSporkID <= SPORK_END; nSporkID++) { if (sporkManager.GetSporkNameByID(nSporkID) != "Unknown") ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), GetSporkValue(nSporkID))); } return ret; } else if (params.size() == 1 && params[0].get_str() == "active") { - Object ret; + UniValue ret(UniValue::VOBJ); for (int nSporkID = SPORK_START; nSporkID <= SPORK_END; nSporkID++) { if (sporkManager.GetSporkNameByID(nSporkID) != "Unknown") ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), IsSporkActive(nSporkID))); @@ -279,7 +295,7 @@ Value spork(const Array& params, bool fHelp) HelpRequiringPassphrase()); } -Value validateaddress(const Array& params, bool fHelp) +UniValue validateaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -303,7 +319,7 @@ Value validateaddress(const Array& params, bool fHelp) CBitcoinAddress address(params[0].get_str()); bool isValid = address.IsValid(); - Object ret; + UniValue ret(UniValue::VOBJ); ret.push_back(Pair("isvalid", isValid)); if (isValid) { CTxDestination dest = address.Get(); @@ -314,8 +330,8 @@ Value validateaddress(const Array& params, bool fHelp) ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false)); if (mine != ISMINE_NO) { ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true : false)); - Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest); - ret.insert(ret.end(), detail.begin(), detail.end()); + UniValue detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest); + ret.pushKVs(detail); } if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); @@ -327,10 +343,10 @@ Value validateaddress(const Array& params, bool fHelp) /** * Used by addmultisigaddress / createmultisig: */ -CScript _createmultisig_redeemScript(const Array& params) +CScript _createmultisig_redeemScript(const UniValue& params) { int nRequired = params[0].get_int(); - const Array& keys = params[1].get_array(); + const UniValue& keys = params[1].get_array(); // Gather public keys if (nRequired < 1) @@ -384,7 +400,7 @@ CScript _createmultisig_redeemScript(const Array& params) return result; } -Value createmultisig(const Array& params, bool fHelp) +UniValue createmultisig(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 2) { string msg = "createmultisig nrequired [\"key\",...]\n" @@ -417,14 +433,14 @@ Value createmultisig(const Array& params, bool fHelp) CScriptID innerID(inner); CBitcoinAddress address(innerID); - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("address", address.ToString())); result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end()))); return result; } -Value verifymessage(const Array& params, bool fHelp) +UniValue verifymessage(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) throw runtime_error( @@ -472,7 +488,7 @@ Value verifymessage(const Array& params, bool fHelp) return (pubkey.GetID() == keyID); } -Value setmocktime(const Array& params, bool fHelp) +UniValue setmocktime(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -485,14 +501,14 @@ Value setmocktime(const Array& params, bool fHelp) if (!Params().MineBlocksOnDemand()) throw runtime_error("setmocktime for regression testing (-regtest mode) only"); - RPCTypeCheck(params, boost::assign::list_of(int_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); SetMockTime(params[0].get_int64()); - return Value::null; + return NullUniValue; } #ifdef ENABLE_WALLET -Value getstakingstatus(const Array& params, bool fHelp) +UniValue getstakingstatus(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -511,7 +527,7 @@ Value getstakingstatus(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getstakingstatus", "") + HelpExampleRpc("getstakingstatus", "")); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("validtime", chainActive.Tip()->nTime > 1471482000)); obj.push_back(Pair("haveconnections", !vNodes.empty())); if (pwalletMain) { diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index b518f2a95..62dae6ba5 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -20,12 +20,11 @@ #include -#include "json/json_spirit_value.h" +#include -using namespace json_spirit; using namespace std; -Value getconnectioncount(const Array& params, bool fHelp) +UniValue getconnectioncount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -40,7 +39,7 @@ Value getconnectioncount(const Array& params, bool fHelp) return (int)vNodes.size(); } -Value ping(const Array& params, bool fHelp) +UniValue ping(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -57,7 +56,7 @@ Value ping(const Array& params, bool fHelp) pNode->fPingQueued = true; } - return Value::null; + return NullUniValue; } static void CopyNodeStats(std::vector& vstats) @@ -73,7 +72,7 @@ static void CopyNodeStats(std::vector& vstats) } } -Value getpeerinfo(const Array& params, bool fHelp) +UniValue getpeerinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -113,10 +112,10 @@ Value getpeerinfo(const Array& params, bool fHelp) vector vstats; CopyNodeStats(vstats); - Array ret; + UniValue ret(UniValue::VARR); BOOST_FOREACH (const CNodeStats& stats, vstats) { - Object obj; + UniValue obj(UniValue::VOBJ); CNodeStateStats statestats; bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); obj.push_back(Pair("id", stats.nodeid)); @@ -143,7 +142,7 @@ Value getpeerinfo(const Array& params, bool fHelp) obj.push_back(Pair("banscore", statestats.nMisbehavior)); obj.push_back(Pair("synced_headers", statestats.nSyncHeight)); obj.push_back(Pair("synced_blocks", statestats.nCommonHeight)); - Array heights; + UniValue heights(UniValue::VARR); BOOST_FOREACH (int height, statestats.vHeightInFlight) { heights.push_back(height); } @@ -157,7 +156,7 @@ Value getpeerinfo(const Array& params, bool fHelp) return ret; } -Value addnode(const Array& params, bool fHelp) +UniValue addnode(const UniValue& params, bool fHelp) { string strCommand; if (params.size() == 2) @@ -179,7 +178,7 @@ Value addnode(const Array& params, bool fHelp) if (strCommand == "onetry") { CAddress addr; OpenNetworkConnection(addr, NULL, strNode.c_str()); - return Value::null; + return NullUniValue; } LOCK(cs_vAddedNodes); @@ -198,10 +197,10 @@ Value addnode(const Array& params, bool fHelp) vAddedNodes.erase(it); } - return Value::null; + return NullUniValue; } -Value getaddednodeinfo(const Array& params, bool fHelp) +UniValue getaddednodeinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -250,10 +249,10 @@ Value getaddednodeinfo(const Array& params, bool fHelp) throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); } - Array ret; + UniValue ret(UniValue::VARR); if (!fDns) { BOOST_FOREACH (string& strAddNode, laddedNodes) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", strAddNode)); ret.push_back(obj); } @@ -266,24 +265,24 @@ Value getaddednodeinfo(const Array& params, bool fHelp) if (Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0)) laddedAddreses.push_back(make_pair(strAddNode, vservNode)); else { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", strAddNode)); obj.push_back(Pair("connected", false)); - Array addresses; + UniValue addresses(UniValue::VARR); obj.push_back(Pair("addresses", addresses)); } } LOCK(cs_vNodes); for (list > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("addednode", it->first)); - Array addresses; + UniValue addresses(UniValue::VARR); bool fConnected = false; BOOST_FOREACH (CService& addrNode, it->second) { bool fFound = false; - Object node; + UniValue node(UniValue::VOBJ); node.push_back(Pair("address", addrNode.ToString())); BOOST_FOREACH (CNode* pnode, vNodes) if (pnode->addr == addrNode) { @@ -304,7 +303,7 @@ Value getaddednodeinfo(const Array& params, bool fHelp) return ret; } -Value getnettotals(const Array& params, bool fHelp) +UniValue getnettotals(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 0) throw runtime_error( @@ -320,33 +319,34 @@ Value getnettotals(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getnettotals", "") + HelpExampleRpc("getnettotals", "")); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv())); obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent())); obj.push_back(Pair("timemillis", GetTimeMillis())); return obj; } -static Array GetNetworksInfo() +static UniValue GetNetworksInfo() { - Array networks; + UniValue networks(UniValue::VARR); for (int n = 0; n < NET_MAX; ++n) { enum Network network = static_cast(n); if (network == NET_UNROUTABLE) continue; proxyType proxy; - Object obj; + UniValue obj(UniValue::VOBJ); GetProxy(network, proxy); obj.push_back(Pair("name", GetNetworkName(network))); obj.push_back(Pair("limited", IsLimited(network))); obj.push_back(Pair("reachable", IsReachable(network))); - obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.ToStringIPPort() : string())); + obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())); + obj.push_back(Pair("proxy_randomize_credentials", proxy.randomize_credentials)); networks.push_back(obj); } return networks; } -Value getnetworkinfo(const Array& params, bool fHelp) +UniValue getnetworkinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -382,7 +382,7 @@ Value getnetworkinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getnetworkinfo", "") + HelpExampleRpc("getnetworkinfo", "")); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("subversion", FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector()))); @@ -392,11 +392,11 @@ Value getnetworkinfo(const Array& params, bool fHelp) obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("networks", GetNetworksInfo())); obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); - Array localAddresses; + UniValue localAddresses(UniValue::VARR); { LOCK(cs_mapLocalHost); BOOST_FOREACH (const PAIRTYPE(CNetAddr, LocalServiceInfo) & item, mapLocalHost) { - Object rec; + UniValue rec(UniValue::VOBJ); rec.push_back(Pair("address", item.first.ToString())); rec.push_back(Pair("port", item.second.nPort)); rec.push_back(Pair("score", item.second.nScore)); @@ -407,7 +407,7 @@ Value getnetworkinfo(const Array& params, bool fHelp) return obj; } -Value setban(const Array& params, bool fHelp) +UniValue setban(const UniValue& params, bool fHelp) { string strCommand; if (params.size() >= 2) @@ -468,10 +468,10 @@ Value setban(const Array& params, bool fHelp) throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed"); } - return Value::null; + return NullUniValue; } -Value listbanned(const Array& params, bool fHelp) +UniValue listbanned(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -485,10 +485,10 @@ Value listbanned(const Array& params, bool fHelp) banmap_t banMap; CNode::GetBanned(banMap); - Array bannedAddresses; + UniValue bannedAddresses(UniValue::VARR); for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++) { - Object rec; + UniValue rec(UniValue::VOBJ); rec.push_back(Pair("address", (*it).first.ToString())); rec.push_back(Pair("banned_untill", (*it).second.nBanUntil)); bannedAddresses.push_back(rec); @@ -497,7 +497,7 @@ Value listbanned(const Array& params, bool fHelp) return bannedAddresses; } -Value clearbanned(const Array& params, bool fHelp) +UniValue clearbanned(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -510,5 +510,5 @@ Value clearbanned(const Array& params, bool fHelp) CNode::ClearBanned(); - return Value::null; + return NullUniValue; } \ No newline at end of file diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp index a00398437..2fed2d953 100644 --- a/src/rpcprotocol.cpp +++ b/src/rpcprotocol.cpp @@ -9,6 +9,7 @@ #include "rpcprotocol.h" #include "clientversion.h" +#include "random.h" #include "tinyformat.h" #include "util.h" #include "utilstrencodings.h" @@ -16,8 +17,8 @@ #include "version.h" #include +#include -#include "json/json_spirit_writer_template.h" #include #include #include @@ -28,10 +29,11 @@ #include #include +#include + using namespace std; using namespace boost; using namespace boost::asio; -using namespace json_spirit; //! Number of bytes to allocate and read at most at once in post data const size_t POST_READ_SIZE = 256 * 1024; @@ -258,20 +260,20 @@ int ReadHTTPMessage(std::basic_istream& stream, map& mapHe * http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx */ -string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id) +string JSONRPCRequest(const string& strMethod, const UniValue& params, const UniValue& id) { - Object request; + UniValue request(UniValue::VOBJ); request.push_back(Pair("method", strMethod)); request.push_back(Pair("params", params)); request.push_back(Pair("id", id)); - return write_string(Value(request), false) + "\n"; + return request.write() + "\n"; } -Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id) +UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id) { - Object reply; - if (error.type() != null_type) - reply.push_back(Pair("result", Value::null)); + UniValue reply(UniValue::VOBJ); + if (!error.isNull()) + reply.push_back(Pair("result", NullUniValue)); else reply.push_back(Pair("result", result)); reply.push_back(Pair("error", error)); @@ -279,16 +281,80 @@ Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id) return reply; } -string JSONRPCReply(const Value& result, const Value& error, const Value& id) +string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id) { - Object reply = JSONRPCReplyObj(result, error, id); - return write_string(Value(reply), false) + "\n"; + UniValue reply = JSONRPCReplyObj(result, error, id); + return reply.write() + "\n"; } -Object JSONRPCError(int code, const string& message) +UniValue JSONRPCError(int code, const string& message) { - Object error; + UniValue error(UniValue::VOBJ); error.push_back(Pair("code", code)); error.push_back(Pair("message", message)); return error; } + +/** Username used when cookie authentication is in use (arbitrary, only for + * recognizability in debugging/logging purposes) + */ +static const std::string COOKIEAUTH_USER = "__cookie__"; +/** Default name for auth cookie file */ +static const std::string COOKIEAUTH_FILE = ".cookie"; + +boost::filesystem::path GetAuthCookieFile() +{ + boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE)); + if (!path.is_complete()) path = GetDataDir() / path; + return path; +} + +bool GenerateAuthCookie(std::string *cookie_out) +{ + unsigned char rand_pwd[32]; + GetRandBytes(rand_pwd, 32); + std::string cookie = COOKIEAUTH_USER + ":" + EncodeBase64(&rand_pwd[0],32); + + /** the umask determines what permissions are used to create this file - + * these are set to 077 in init.cpp unless overridden with -sysperms. + */ + std::ofstream file; + boost::filesystem::path filepath = GetAuthCookieFile(); + file.open(filepath.string().c_str()); + if (!file.is_open()) { + LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string()); + return false; + } + file << cookie; + file.close(); + LogPrintf("Generated RPC authentication cookie %s\n", filepath.string()); + + if (cookie_out) + *cookie_out = cookie; + return true; +} + +bool GetAuthCookie(std::string *cookie_out) +{ + std::ifstream file; + std::string cookie; + boost::filesystem::path filepath = GetAuthCookieFile(); + file.open(filepath.string().c_str()); + if (!file.is_open()) + return false; + std::getline(file, cookie); + file.close(); + + if (cookie_out) + *cookie_out = cookie; + return true; +} + +void DeleteAuthCookie() +{ + try { + boost::filesystem::remove(GetAuthCookieFile()); + } catch (const boost::filesystem::filesystem_error& e) { + LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what()); + } +} diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h index ca493fe84..edc21be70 100644 --- a/src/rpcprotocol.h +++ b/src/rpcprotocol.h @@ -6,18 +6,17 @@ #ifndef BITCOIN_RPCPROTOCOL_H #define BITCOIN_RPCPROTOCOL_H -#include -#include -#include -#include #include #include #include #include +#include +#include +#include +#include +#include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" +#include //! HTTP status codes enum HTTPStatusCode { @@ -52,6 +51,7 @@ enum RPCErrorCode { RPC_VERIFY_REJECTED = -26, //! Transaction or block was rejected by network rules RPC_VERIFY_ALREADY_IN_CHAIN = -27, //! Transaction already in chain RPC_IN_WARMUP = -28, //! Client still warming up + RPC_GBT_POS_ERROR = -29, //! GetBlockTemplate error during PoS period //! Aliases for backward compatibility RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR, @@ -153,9 +153,18 @@ bool ReadHTTPRequestLine(std::basic_istream& stream, int& proto, std::stri int ReadHTTPStatus(std::basic_istream& stream, int& proto); int ReadHTTPHeaders(std::basic_istream& stream, std::map& mapHeadersRet); int ReadHTTPMessage(std::basic_istream& stream, std::map& mapHeadersRet, std::string& strMessageRet, int nProto, size_t max_size); -std::string JSONRPCRequest(const std::string& strMethod, const json_spirit::Array& params, const json_spirit::Value& id); -json_spirit::Object JSONRPCReplyObj(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id); -std::string JSONRPCReply(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id); -json_spirit::Object JSONRPCError(int code, const std::string& message); +std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id); +UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id); +std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id); +UniValue JSONRPCError(int code, const std::string& message); + +/** Get name of RPC authentication cookie file */ +boost::filesystem::path GetAuthCookieFile(); +/** Generate a new RPC authentication cookie and write it to disk */ +bool GenerateAuthCookie(std::string *cookie_out); +/** Read the RPC authentication cookie from disk */ +bool GetAuthCookie(std::string *cookie_out); +/** Delete RPC authentication cookie from disk */ +void DeleteAuthCookie(); #endif // BITCOIN_RPCPROTOCOL_H diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 7f091d986..783e2fc09 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -17,23 +17,24 @@ #include "script/script.h" #include "script/sign.h" #include "script/standard.h" +#include "swifttx.h" #include "uint256.h" +#include "utilmoneystr.h" #ifdef ENABLE_WALLET #include "wallet.h" #endif #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" #include +#include + using namespace boost; using namespace boost::assign; -using namespace json_spirit; using namespace std; -void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex) +void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex) { txnouttype type; vector addresses; @@ -51,26 +52,26 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeH out.push_back(Pair("reqSigs", nRequired)); out.push_back(Pair("type", GetTxnOutputType(type))); - Array a; + UniValue a(UniValue::VARR); BOOST_FOREACH (const CTxDestination& addr, addresses) a.push_back(CBitcoinAddress(addr).ToString()); out.push_back(Pair("addresses", a)); } -void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) +void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) { entry.push_back(Pair("txid", tx.GetHash().GetHex())); entry.push_back(Pair("version", tx.nVersion)); entry.push_back(Pair("locktime", (int64_t)tx.nLockTime)); - Array vin; + UniValue vin(UniValue::VARR); BOOST_FOREACH (const CTxIn& txin, tx.vin) { - Object in; + UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); else { in.push_back(Pair("txid", txin.prevout.hash.GetHex())); in.push_back(Pair("vout", (int64_t)txin.prevout.n)); - Object o; + UniValue o(UniValue::VOBJ); o.push_back(Pair("asm", txin.scriptSig.ToString())); o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); in.push_back(Pair("scriptSig", o)); @@ -79,13 +80,13 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) vin.push_back(in); } entry.push_back(Pair("vin", vin)); - Array vout; + UniValue vout(UniValue::VARR); for (unsigned int i = 0; i < tx.vout.size(); i++) { const CTxOut& txout = tx.vout[i]; - Object out; + UniValue out(UniValue::VOBJ); out.push_back(Pair("value", ValueFromAmount(txout.nValue))); out.push_back(Pair("n", (int64_t)i)); - Object o; + UniValue o(UniValue::VOBJ); ScriptPubKeyToJSON(txout.scriptPubKey, o, true); out.push_back(Pair("scriptPubKey", o)); vout.push_back(out); @@ -107,7 +108,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) } } -Value getrawtransaction(const Array& params, bool fHelp) +UniValue getrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -186,14 +187,14 @@ Value getrawtransaction(const Array& params, bool fHelp) if (!fVerbose) return strHex; - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("hex", strHex)); TxToJSON(tx, hashBlock, result); return result; } #ifdef ENABLE_WALLET -Value listunspent(const Array& params, bool fHelp) +UniValue listunspent(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) throw runtime_error( @@ -228,7 +229,7 @@ Value listunspent(const Array& params, bool fHelp) "\nExamples\n" + HelpExampleCli("listunspent", "") + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")); - RPCTypeCheck(params, list_of(int_type)(int_type)(array_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR)); int nMinDepth = 1; if (params.size() > 0) @@ -240,8 +241,9 @@ Value listunspent(const Array& params, bool fHelp) set setAddress; if (params.size() > 2) { - Array inputs = params[2].get_array(); - BOOST_FOREACH (Value& input, inputs) { + UniValue inputs = params[2].get_array(); + for (unsigned int inx = 0; inx < inputs.size(); inx++) { + const UniValue& input = inputs[inx]; CBitcoinAddress address(input.get_str()); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bulwark address: ") + input.get_str()); @@ -251,7 +253,7 @@ Value listunspent(const Array& params, bool fHelp) } } - Array results; + UniValue results(UniValue::VARR); vector vecOutputs; assert(pwalletMain != NULL); pwalletMain->AvailableCoins(vecOutputs, false); @@ -270,7 +272,7 @@ Value listunspent(const Array& params, bool fHelp) CAmount nValue = out.tx->vout[out.i].nValue; const CScript& pk = out.tx->vout[out.i].scriptPubKey; - Object entry; + UniValue entry(UniValue::VOBJ); entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); entry.push_back(Pair("vout", out.i)); CTxDestination address; @@ -299,7 +301,7 @@ Value listunspent(const Array& params, bool fHelp) } #endif -Value createrawtransaction(const Array& params, bool fHelp) +UniValue createrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) throw runtime_error( @@ -330,20 +332,21 @@ Value createrawtransaction(const Array& params, bool fHelp) "\nExamples\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")); - RPCTypeCheck(params, list_of(array_type)(obj_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)); - Array inputs = params[0].get_array(); - Object sendTo = params[1].get_obj(); + UniValue inputs = params[0].get_array(); + UniValue sendTo = params[1].get_obj(); CMutableTransaction rawTx; - BOOST_FOREACH (const Value& input, inputs) { - const Object& o = input.get_obj(); + for (unsigned int idx = 0; idx < inputs.size(); idx++) { + const UniValue& input = inputs[idx]; + const UniValue& o = input.get_obj(); uint256 txid = ParseHashO(o, "txid"); - const Value& vout_v = find_value(o, "vout"); - if (vout_v.type() != int_type) + const UniValue& vout_v = find_value(o, "vout"); + if (!vout_v.isNum()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); int nOutput = vout_v.get_int(); if (nOutput < 0) @@ -354,17 +357,18 @@ Value createrawtransaction(const Array& params, bool fHelp) } set setAddress; - BOOST_FOREACH (const Pair& s, sendTo) { - CBitcoinAddress address(s.name_); + vector addrList = sendTo.getKeys(); + BOOST_FOREACH(const string& name_, addrList) { + CBitcoinAddress address(name_); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bulwark address: ") + s.name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bulwark address: ")+name_); if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + s.name_); + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); setAddress.insert(address); CScript scriptPubKey = GetScriptForDestination(address.Get()); - CAmount nAmount = AmountFromValue(s.value_); + CAmount nAmount = AmountFromValue(sendTo[name_]); CTxOut out(nAmount, scriptPubKey); rawTx.vout.push_back(out); @@ -373,7 +377,7 @@ Value createrawtransaction(const Array& params, bool fHelp) return EncodeHexTx(rawTx); } -Value decoderawtransaction(const Array& params, bool fHelp) +UniValue decoderawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -422,20 +426,20 @@ Value decoderawtransaction(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("decoderawtransaction", "\"hexstring\"") + HelpExampleRpc("decoderawtransaction", "\"hexstring\"")); - RPCTypeCheck(params, list_of(str_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); CTransaction tx; if (!DecodeHexTx(tx, params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); - Object result; + UniValue result(UniValue::VOBJ); TxToJSON(tx, 0, result); return result; } -Value decodescript(const Array& params, bool fHelp) +UniValue decodescript(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -458,9 +462,9 @@ Value decodescript(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("decodescript", "\"hexstring\"") + HelpExampleRpc("decodescript", "\"hexstring\"")); - RPCTypeCheck(params, list_of(str_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); - Object r; + UniValue r(UniValue::VOBJ); CScript script; if (params[0].get_str().size() > 0) { vector scriptData(ParseHexV(params[0], "argument")); @@ -474,7 +478,7 @@ Value decodescript(const Array& params, bool fHelp) return r; } -Value signrawtransaction(const Array& params, bool fHelp) +UniValue signrawtransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) throw runtime_error( @@ -522,7 +526,7 @@ Value signrawtransaction(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("signrawtransaction", "\"myhex\"") + HelpExampleRpc("signrawtransaction", "\"myhex\"")); - RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true); vector txData(ParseHexV(params[0], "argument 1")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); @@ -565,10 +569,11 @@ Value signrawtransaction(const Array& params, bool fHelp) bool fGivenKeys = false; CBasicKeyStore tempKeystore; - if (params.size() > 2 && params[2].type() != null_type) { + if (params.size() > 2 && !params[2].isNull()) { fGivenKeys = true; - Array keys = params[2].get_array(); - BOOST_FOREACH (Value k, keys) { + UniValue keys = params[2].get_array(); + for (unsigned int idx = 0; idx < keys.size(); idx++) { + UniValue k = keys[idx]; CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(k.get_str()); if (!fGood) @@ -585,15 +590,16 @@ Value signrawtransaction(const Array& params, bool fHelp) #endif // Add previous txouts given in the RPC call: - if (params.size() > 1 && params[1].type() != null_type) { - Array prevTxs = params[1].get_array(); - BOOST_FOREACH (Value& p, prevTxs) { - if (p.type() != obj_type) + if (params.size() > 1 && !params[1].isNull()) { + UniValue prevTxs = params[1].get_array(); + for (unsigned int idx = 0; idx < prevTxs.size(); idx++) { + const UniValue& p = prevTxs[idx]; + if (!p.isObject()) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); - Object prevOut = p.get_obj(); + UniValue prevOut = p.get_obj(); - RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)); + RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)); uint256 txid = ParseHashO(prevOut, "txid"); @@ -621,9 +627,9 @@ Value signrawtransaction(const Array& params, bool fHelp) // if redeemScript given and not using the local wallet (private keys // given), add redeemScript to the tempKeystore so it can be signed: if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) { - RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript", str_type)); - Value v = find_value(prevOut, "redeemScript"); - if (!(v == Value::null)) { + RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript",UniValue::VSTR)); + UniValue v = find_value(prevOut, "redeemScript"); + if (!v.isNull()) { vector rsData(ParseHexV(v, "redeemScript")); CScript redeemScript(rsData.begin(), rsData.end()); tempKeystore.AddCScript(redeemScript); @@ -639,7 +645,7 @@ Value signrawtransaction(const Array& params, bool fHelp) #endif int nHashType = SIGHASH_ALL; - if (params.size() > 3 && params[3].type() != null_type) { + if (params.size() > 3 && !params[3].isNull()) { static map mapSigHashValues = boost::assign::map_list_of(string("ALL"), int(SIGHASH_ALL))(string("ALL|ANYONECANPAY"), int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))(string("NONE"), int(SIGHASH_NONE))(string("NONE|ANYONECANPAY"), int(SIGHASH_NONE | SIGHASH_ANYONECANPAY))(string("SINGLE"), int(SIGHASH_SINGLE))(string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY)); string strHashType = params[3].get_str(); @@ -674,16 +680,16 @@ Value signrawtransaction(const Array& params, bool fHelp) fComplete = false; } - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("hex", EncodeHexTx(mergedTx))); result.push_back(Pair("complete", fComplete)); return result; } -Value sendrawtransaction(const Array& params, bool fHelp) +UniValue sendrawtransaction(const UniValue& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( "sendrawtransaction \"hexstring\" ( allowhighfees )\n" "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" @@ -691,6 +697,7 @@ Value sendrawtransaction(const Array& params, bool fHelp) "\nArguments:\n" "1. \"hexstring\" (string, required) The hex string of the raw transaction)\n" "2. allowhighfees (boolean, optional, default=false) Allow high fees\n" + "3. swiftx (boolean, optional, default=false) Use SwiftX to send this transaction\n" "\nResult:\n" "\"hex\" (string) The transaction hash in hex\n" "\nExamples:\n" @@ -700,7 +707,7 @@ Value sendrawtransaction(const Array& params, bool fHelp) "\nSend the transaction (signed hex)\n" + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + "\nAs a json rpc call\n" + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")); - RPCTypeCheck(params, list_of(str_type)(bool_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL)); // parse hex string from parameter CTransaction tx; @@ -712,12 +719,21 @@ Value sendrawtransaction(const Array& params, bool fHelp) if (params.size() > 1) fOverrideFees = params[1].get_bool(); + bool fSwiftTX = false; + if (params.size() > 2) + fSwiftTX = params[2].get_bool(); + CCoinsViewCache& view = *pcoinsTip; const CCoins* existingCoins = view.AccessCoins(hashTx); bool fHaveMempool = mempool.exists(hashTx); bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets + if (fSwiftTX) { + mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); + CreateNewLock(tx); + RelayTransactionLockReq(tx, true); + } CValidationState state; if (!AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees)) { if (state.IsInvalid()) @@ -732,3 +748,39 @@ Value sendrawtransaction(const Array& params, bool fHelp) return hashTx.GetHex(); } + +UniValue getspentzerocoinamount(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "getspentzerocoinamount hexstring index\n" + "\nReturns value of spent zerocoin output designated by transaction hash and input index.\n" + "\nArguments:\n" + "1. hash (hexstring) Transaction hash\n" + "2. index (int) Input index\n" + "\nResult:\n" + "\"value\" (int) Spent output value, -1 if error\n" + "\nExamples:\n" + + HelpExampleCli("getspentzerocoinamount", "78021ebf92a80dfccef1413067f1222e37535399797cce029bb40ad981131706 0")); + + uint256 txHash = ParseHashV(params[0], "parameter 1"); + int inputIndex = params[1].get_int(); + if (inputIndex < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter for transaction input"); + + CTransaction tx; + uint256 hashBlock = 0; + if (!GetTransaction(txHash, tx, hashBlock, true)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); + + if (inputIndex >= (int)tx.vin.size()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter for transaction input"); + + const CTxIn& input = tx.vin[inputIndex]; + if (!input.scriptSig.IsZerocoinSpend()) + return -1; + + libzerocoin::CoinSpend spend = TxInToZerocoinSpend(input); + CAmount nValue = libzerocoin::ZerocoinDenominationToAmount(spend.getDenomination()); + return FormatMoney(nValue); +} diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index a0eac01e0..06e224274 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -17,7 +17,6 @@ #include "wallet.h" #endif -#include "json/json_spirit_writer_template.h" #include #include #include @@ -29,9 +28,10 @@ #include #include +#include + using namespace boost; using namespace boost::asio; -using namespace json_spirit; using namespace std; static std::string strRPCUserColonPass; @@ -50,37 +50,37 @@ static boost::asio::io_service::work* rpc_dummy_work = NULL; static std::vector rpc_allow_subnets; //!< List of subnets to allow RPC connections from static std::vector > rpc_acceptors; -void RPCTypeCheck(const Array& params, - const list& typesExpected, - bool fAllowNull) +void RPCTypeCheck(const UniValue& params, + const list& typesExpected, + bool fAllowNull) { unsigned int i = 0; - BOOST_FOREACH (Value_type t, typesExpected) { + BOOST_FOREACH(UniValue::VType t, typesExpected) { if (params.size() <= i) break; - const Value& v = params[i]; - if (!((v.type() == t) || (fAllowNull && (v.type() == null_type)))) { + const UniValue& v = params[i]; + if (!((v.type() == t) || (fAllowNull && (v.isNull())))) { string err = strprintf("Expected type %s, got %s", - Value_type_name[t], Value_type_name[v.type()]); + uvTypeName(t), uvTypeName(v.type())); throw JSONRPCError(RPC_TYPE_ERROR, err); } i++; } } -void RPCTypeCheck(const Object& o, - const map& typesExpected, - bool fAllowNull) +void RPCTypeCheckObj(const UniValue& o, + const map& typesExpected, + bool fAllowNull) { - BOOST_FOREACH (const PAIRTYPE(string, Value_type) & t, typesExpected) { - const Value& v = find_value(o, t.first); - if (!fAllowNull && v.type() == null_type) + BOOST_FOREACH(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)); - if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type)))) { + if (!((v.type() == t.second) || (fAllowNull && (v.isNull())))) { string err = strprintf("Expected type %s for %s, got %s", - Value_type_name[t.second], t.first, Value_type_name[v.type()]); + uvTypeName(t.second), t.first, uvTypeName(v.type())); throw JSONRPCError(RPC_TYPE_ERROR, err); } } @@ -91,7 +91,7 @@ static inline int64_t roundint64(double d) return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); } -CAmount AmountFromValue(const Value& value) +CAmount AmountFromValue(const UniValue& value) { double dAmount = value.get_real(); if (dAmount <= 0.0 || dAmount > 21000000.0) @@ -102,15 +102,20 @@ CAmount AmountFromValue(const Value& value) return nAmount; } -Value ValueFromAmount(const CAmount& amount) +UniValue ValueFromAmount(const CAmount& amount) { - return (double)amount / (double)COIN; + bool sign = amount < 0; + int64_t n_abs = (sign ? -amount : amount); + int64_t quotient = n_abs / COIN; + int64_t remainder = n_abs % COIN; + return UniValue(UniValue::VNUM, + strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder)); } -uint256 ParseHashV(const Value& v, string strName) +uint256 ParseHashV(const UniValue& v, string strName) { string strHex; - if (v.type() == str_type) + if (v.isStr()) strHex = v.get_str(); if (!IsHex(strHex)) // Note: IsHex("") is false throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be hexadecimal string (not '" + strHex + "')"); @@ -118,24 +123,42 @@ uint256 ParseHashV(const Value& v, string strName) result.SetHex(strHex); return result; } -uint256 ParseHashO(const Object& o, string strKey) +uint256 ParseHashO(const UniValue& o, string strKey) { return ParseHashV(find_value(o, strKey), strKey); } -vector ParseHexV(const Value& v, string strName) +vector ParseHexV(const UniValue& v, string strName) { string strHex; - if (v.type() == str_type) + if (v.isStr()) strHex = v.get_str(); if (!IsHex(strHex)) throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be hexadecimal string (not '" + strHex + "')"); return ParseHex(strHex); } -vector ParseHexO(const Object& o, string strKey) +vector ParseHexO(const UniValue& o, string strKey) { return ParseHexV(find_value(o, strKey), strKey); } +int ParseInt(const UniValue& o, string strKey) +{ + const UniValue& v = find_value(o, strKey); + if (v.isNum()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, " + strKey + "is not an int"); + + return v.get_int(); +} + +bool ParseBool(const UniValue& o, string strKey) +{ + const UniValue& v = find_value(o, strKey); + if (v.isBool()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, " + strKey + "is not a bool"); + + return v.get_bool(); +} + /** * Note: This interface may still be subject to change. @@ -166,7 +189,7 @@ string CRPCTable::help(string strCommand) const #endif try { - Array params; + UniValue params; rpcfn_type pfn = pcmd->actor; if (setDone.insert(pfn).second) (*pfn)(params, true); @@ -195,7 +218,7 @@ string CRPCTable::help(string strCommand) const return strRet; } -Value help(const Array& params, bool fHelp) +UniValue help(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -214,7 +237,7 @@ Value help(const Array& params, bool fHelp) } -Value stop(const Array& params, bool fHelp) +UniValue stop(const UniValue& params, bool fHelp) { // Accept the deprecated and ignored 'detach' boolean argument if (fHelp || params.size() > 1) @@ -252,6 +275,7 @@ static const CRPCCommand vRPCCommands[] = {"network", "clearbanned", &clearbanned, true, false, false}, /* Block chain and UTXO */ + {"blockchain", "findserial", &findserial, true, false, false}, {"blockchain", "getblockchaininfo", &getblockchaininfo, true, false, false}, {"blockchain", "getbestblockhash", &getbestblockhash, true, false, false}, {"blockchain", "getblockcount", &getblockcount, true, false, false}, @@ -260,13 +284,14 @@ static const CRPCCommand vRPCCommands[] = {"blockchain", "getblockheader", &getblockheader, false, false, false}, {"blockchain", "getchaintips", &getchaintips, true, false, false}, {"blockchain", "getdifficulty", &getdifficulty, true, false, false}, + {"blockchain", "getfeeinfo", &getfeeinfo, true, false, false}, {"blockchain", "getmempoolinfo", &getmempoolinfo, true, true, false}, {"blockchain", "getrawmempool", &getrawmempool, true, false, false}, {"blockchain", "gettxout", &gettxout, true, false, false}, {"blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false}, - {"blockchain", "verifychain", &verifychain, true, false, false}, {"blockchain", "invalidateblock", &invalidateblock, true, true, false}, {"blockchain", "reconsiderblock", &reconsiderblock, true, true, false}, + {"blockchain", "verifychain", &verifychain, true, false, false}, /* Mining */ {"mining", "getblocktemplate", &getblocktemplate, true, false, false}, @@ -382,6 +407,21 @@ static const CRPCCommand vRPCCommands[] = {"wallet", "walletlock", &walletlock, true, false, true}, {"wallet", "walletpassphrasechange", &walletpassphrasechange, true, false, true}, {"wallet", "walletpassphrase", &walletpassphrase, true, false, true}, + + {"zerocoin", "getzerocoinbalance", &getzerocoinbalance, false, false, true}, + {"zerocoin", "listmintedzerocoins", &listmintedzerocoins, false, false, true}, + {"zerocoin", "listspentzerocoins", &listspentzerocoins, false, false, true}, + {"zerocoin", "listzerocoinamounts", &listzerocoinamounts, false, false, true}, + {"zerocoin", "mintzerocoin", &mintzerocoin, false, false, true}, + {"zerocoin", "spendzerocoin", &spendzerocoin, false, false, true}, + {"zerocoin", "resetmintzerocoin", &resetmintzerocoin, false, false, true}, + {"zerocoin", "resetspentzerocoin", &resetspentzerocoin, false, false, true}, + {"zerocoin", "getarchivedzerocoin", &getarchivedzerocoin, false, false, true}, + {"zerocoin", "importzerocoins", &importzerocoins, false, false, true}, + {"zerocoin", "exportzerocoins", &exportzerocoins, false, false, true}, + {"zerocoin", "reconsiderzerocoins", &reconsiderzerocoins, false, false, true}, + {"zerocoin", "getspentzerocoinamount", &getspentzerocoinamount, false, false, false} + #endif // ENABLE_WALLET }; @@ -416,7 +456,7 @@ bool HTTPAuthorized(map& mapHeaders) return TimingResistantEqual(strUserPass, strRPCUserColonPass); } -void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) +void ErrorReply(std::ostream& stream, const UniValue& objError, const UniValue& id) { // Send error reply from json-rpc error object int nStatus = HTTP_INTERNAL_SERVER_ERROR; @@ -425,7 +465,7 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) nStatus = HTTP_BAD_REQUEST; else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND; - string strReply = JSONRPCReply(Value::null, objError, id); + string strReply = JSONRPCReply(NullUniValue, objError, id); stream << HTTPReply(nStatus, strReply, false) << std::flush; } @@ -590,28 +630,17 @@ void StartRPCThreads() strAllowed += subnet.ToString() + " "; LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed); - strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; - if (((mapArgs["-rpcpassword"] == "") || - (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && - Params().RequireRPCPassword()) { - unsigned char rand_pwd[32]; - GetRandBytes(rand_pwd, 32); - uiInterface.ThreadSafeMessageBox(strprintf( - _("To use bulwarkd, or the -server option to bulwark-qt, you must set an rpcpassword in the configuration file:\n" - "%s\n" - "It is recommended you use the following random password:\n" - "rpcuser=bulwarkrpc\n" - "rpcpassword=%s\n" - "(you do not need to remember this password)\n" - "The username and password MUST NOT be the same.\n" - "If the file does not exist, create it with owner-readable-only file permissions.\n" - "It is also recommended to set alertnotify so you are notified of problems;\n" - "for example: alertnotify=echo %%s | mail -s \"Bulwark Alert\" admin@foo.com\n"), - GetConfigFile().string(), - EncodeBase58(&rand_pwd[0], &rand_pwd[0] + 32)), - "", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE); - StartShutdown(); - return; + if (mapArgs["-rpcpassword"] == "") { + LogPrintf("No rpcpassword set - using random cookie authentication\n"); + if (!GenerateAuthCookie(&strRPCUserColonPass)) { + uiInterface.ThreadSafeMessageBox( + _("Error: A fatal internal error occured, see debug.log for details"), // Same message as AbortNode + "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return; + } + } else { + strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; } assert(rpc_io_service == NULL); @@ -756,6 +785,8 @@ void StopRPCThreads() } deadlineTimers.clear(); + DeleteAuthCookie(); + rpc_io_service->stop(); cvBlockChange.notify_all(); if (rpc_worker_group != NULL) @@ -817,72 +848,72 @@ void RPCRunLater(const std::string& name, boost::function func, int6 class JSONRequest { public: - Value id; + UniValue id; string strMethod; - Array params; + UniValue params; - JSONRequest() { id = Value::null; } - void parse(const Value& valRequest); + JSONRequest() { id = NullUniValue; } + void parse(const UniValue& valRequest); }; -void JSONRequest::parse(const Value& valRequest) +void JSONRequest::parse(const UniValue& valRequest) { // Parse request - if (valRequest.type() != obj_type) + if (!valRequest.isObject()) throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object"); - const Object& request = valRequest.get_obj(); + const UniValue& request = valRequest.get_obj(); // Parse id now so errors from here on will have the id id = find_value(request, "id"); // Parse method - Value valMethod = find_value(request, "method"); - if (valMethod.type() == null_type) + UniValue valMethod = find_value(request, "method"); + if (valMethod.isNull()) throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method"); - if (valMethod.type() != str_type) + if (!valMethod.isStr()) throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string"); strMethod = valMethod.get_str(); if (strMethod != "getblocktemplate") LogPrint("rpc", "ThreadRPCServer method=%s\n", SanitizeString(strMethod)); // Parse params - Value valParams = find_value(request, "params"); - if (valParams.type() == array_type) + UniValue valParams = find_value(request, "params"); + if (valParams.isArray()) params = valParams.get_array(); - else if (valParams.type() == null_type) - params = Array(); + else if (valParams.isNull()) + params = UniValue(UniValue::VARR); else throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array"); } -static Object JSONRPCExecOne(const Value& req) +static UniValue JSONRPCExecOne(const UniValue& req) { - Object rpc_result; + UniValue rpc_result(UniValue::VOBJ); JSONRequest jreq; try { jreq.parse(req); - Value result = tableRPC.execute(jreq.strMethod, jreq.params); - rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id); - } catch (Object& objError) { - rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id); + UniValue result = tableRPC.execute(jreq.strMethod, jreq.params); + rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id); + } catch (const UniValue& objError) { + rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id); } catch (std::exception& e) { - rpc_result = JSONRPCReplyObj(Value::null, + rpc_result = JSONRPCReplyObj(NullUniValue, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); } return rpc_result; } -static string JSONRPCExecBatch(const Array& vReq) +static string JSONRPCExecBatch(const UniValue& vReq) { - Array ret; + UniValue ret(UniValue::VARR); for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++) ret.push_back(JSONRPCExecOne(vReq[reqIdx])); - return write_string(Value(ret), false) + "\n"; + return ret.write() + "\n"; } static bool HTTPReq_JSONRPC(AcceptedConnection* conn, @@ -910,8 +941,8 @@ static bool HTTPReq_JSONRPC(AcceptedConnection* conn, JSONRequest jreq; try { // Parse request - Value valRequest; - if (!read_string(strRequest, valRequest)) + UniValue valRequest; + if (!valRequest.read(strRequest)) throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); // Return immediately if in warmup @@ -924,22 +955,22 @@ static bool HTTPReq_JSONRPC(AcceptedConnection* conn, string strReply; // singleton request - if (valRequest.type() == obj_type) { + if (valRequest.isObject()) { jreq.parse(valRequest); - Value result = tableRPC.execute(jreq.strMethod, jreq.params); + UniValue result = tableRPC.execute(jreq.strMethod, jreq.params); // Send reply - strReply = JSONRPCReply(result, Value::null, jreq.id); + strReply = JSONRPCReply(result, NullUniValue, jreq.id); - // array of requests - } else if (valRequest.type() == array_type) + // array of requests + } else if (valRequest.isArray()) strReply = JSONRPCExecBatch(valRequest.get_array()); else throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, strReply.size()) << strReply << std::flush; - } catch (Object& objError) { + } catch (const UniValue& objError) { ErrorReply(conn->stream(), objError, jreq.id); return false; } catch (std::exception& e) { @@ -985,7 +1016,7 @@ void ServiceConnection(AcceptedConnection* conn) } } -json_spirit::Value CRPCTable::execute(const std::string& strMethod, const json_spirit::Array& params) const +UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms) const { // Find method const CRPCCommand* pcmd = tableRPC[strMethod]; @@ -1004,7 +1035,7 @@ json_spirit::Value CRPCTable::execute(const std::string& strMethod, const json_s try { // Execute - Value result; + UniValue result; { if (pcmd->threadSafe) result = pcmd->actor(params, false); diff --git a/src/rpcserver.h b/src/rpcserver.h index 36bce6e50..3c6b8e7d9 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -1,5 +1,6 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2015-2017 The PIVX developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,9 +16,10 @@ #include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" +#include + +#include + class CBlockIndex; class CNetAddr; @@ -61,16 +63,15 @@ bool RPCIsInWarmup(std::string* statusOut); * the right number of arguments are passed, just that any passed are the correct type. * Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type)); */ -void RPCTypeCheck(const json_spirit::Array& params, - const std::list& typesExpected, - bool fAllowNull = false); +void RPCTypeCheck(const UniValue& params, + const std::list& typesExpected, bool fAllowNull=false); + /** * Check for expected keys/value types in an Object. - * Use like: RPCTypeCheck(object, boost::assign::map_list_of("name", str_type)("value", int_type)); + * Use like: RPCTypeCheckObj(object, boost::assign::map_list_of("name", str_type)("value", int_type)); */ -void RPCTypeCheck(const json_spirit::Object& o, - const std::map& typesExpected, - bool fAllowNull = false); +void RPCTypeCheckObj(const UniValue& o, + const std::map& typesExpected, bool fAllowNull=false); /** * Run func nSeconds from now. Uses boost deadline timers. @@ -81,7 +82,7 @@ void RPCRunLater(const std::string& name, boost::function func, int6 //! Convert boost::asio address to CNetAddr extern CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address); -typedef json_spirit::Value (*rpcfn_type)(const json_spirit::Array& params, bool fHelp); +typedef UniValue(*rpcfn_type)(const UniValue& params, bool fHelp); class CRPCCommand { @@ -110,11 +111,11 @@ class CRPCTable /** * Execute a method. * @param method Method to execute - * @param params Array of arguments (JSON objects) + * @param params UniValue Array of arguments (JSON objects) * @returns Result of the call. - * @throws an exception (json_spirit::Value) when an error happens. + * @throws an exception (UniValue) when an error happens. */ - json_spirit::Value execute(const std::string& method, const json_spirit::Array& params) const; + UniValue execute(const std::string &method, const UniValue ¶ms) const; /** * Returns a list of registered commands @@ -129,17 +130,19 @@ extern const CRPCTable tableRPC; * Utilities: convert hex-encoded Values * (throws error if not hex). */ -extern uint256 ParseHashV(const json_spirit::Value& v, std::string strName); -extern uint256 ParseHashO(const json_spirit::Object& o, std::string strKey); -extern std::vector ParseHexV(const json_spirit::Value& v, std::string strName); -extern std::vector ParseHexO(const json_spirit::Object& o, std::string strKey); +extern uint256 ParseHashV(const UniValue& v, std::string strName); +extern uint256 ParseHashO(const UniValue& o, std::string strKey); +extern std::vector ParseHexV(const UniValue& v, std::string strName); +extern std::vector ParseHexO(const UniValue& o, std::string strKey); +extern int ParseInt(const UniValue& o, std::string strKey); +extern bool ParseBool(const UniValue& o, std::string strKey); extern void InitRPCMining(); extern void ShutdownRPCMining(); extern int64_t nWalletUnlockTime; -extern CAmount AmountFromValue(const json_spirit::Value& value); -extern json_spirit::Value ValueFromAmount(const CAmount& amount); +extern CAmount AmountFromValue(const UniValue& value); +extern UniValue ValueFromAmount(const CAmount& amount); extern double GetDifficulty(const CBlockIndex* blockindex = NULL); extern std::string HelpRequiringPassphrase(); extern std::string HelpExampleCli(std::string methodname, std::string args); @@ -147,136 +150,151 @@ extern std::string HelpExampleRpc(std::string methodname, std::string args); extern void EnsureWalletIsUnlocked(); -extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, bool fHelp); // in rpcnet.cpp -extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value ping(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getnettotals(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value setban(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listbanned(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value clearbanned(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp -extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value importaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value bip38encrypt(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value bip38decrypt(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp -extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value gethashespersec(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value estimatefee(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value estimatepriority(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp -extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getrawchangeaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value setaccount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getaccount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getaddressesbyaccount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value sendtoaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value sendtoaddressix(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value signmessage(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getreceivedbyaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getreceivedbyaccount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getbalance(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getunconfirmedbalance(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value movecmd(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value sendfrom(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value sendmany(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value addmultisigaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listreceivedbyaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listreceivedbyaccount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listtransactions(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listaddressgroupings(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listaccounts(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listsinceblock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value gettransaction(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value backupwallet(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value keypoolrefill(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value walletpassphrase(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value walletpassphrasechange(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value walletlock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value encryptwallet(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getwalletinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getblockchaininfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getnetworkinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value reservebalance(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value setstakesplitthreshold(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getstakesplitthreshold(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value multisend(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value autocombinerewards(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp -extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value lockunspent(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listlockunspent(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value decodescript(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp -extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getdifficulty(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getmempoolinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getblockheader(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getchaintips(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value invalidateblock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value reconsiderblock(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value obfuscation(const json_spirit::Array& params, bool fHelp); // in rpcmasternode.cpp -extern json_spirit::Value getpoolinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value masternode(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listmasternodes(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getmasternodecount(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value masternodeconnect(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value masternodecurrent(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value masternodedebug(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value startmasternode(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value createmasternodekey(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getmasternodeoutputs(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value listmasternodeconf(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getmasternodestatus(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getmasternodewinners(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getmasternodescores(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value mnbudget(const json_spirit::Array& params, bool fHelp); // in rpcmasternode-budget.cpp -extern json_spirit::Value preparebudget(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value submitbudget(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value mnbudgetvote(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getbudgetvotes(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getnextsuperblock(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getbudgetprojection(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getbudgetinfo(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value mnbudgetrawvote(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value mnfinalbudget(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value checkbudgets(const json_spirit::Array& params, bool fHelp); - -extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp); // in rpcmisc.cpp -extern json_spirit::Value mnsync(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value spork(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value validateaddress(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value createmultisig(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value verifymessage(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value setmocktime(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value getstakingstatus(const json_spirit::Array& params, bool fHelp); +extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp +extern UniValue getpeerinfo(const UniValue& params, bool fHelp); +extern UniValue ping(const UniValue& params, bool fHelp); +extern UniValue addnode(const UniValue& params, bool fHelp); +extern UniValue getaddednodeinfo(const UniValue& params, bool fHelp); +extern UniValue getnettotals(const UniValue& params, bool fHelp); +extern UniValue setban(const UniValue& params, bool fHelp); +extern UniValue listbanned(const UniValue& params, bool fHelp); +extern UniValue clearbanned(const UniValue& params, bool fHelp); + +extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp +extern UniValue importprivkey(const UniValue& params, bool fHelp); +extern UniValue importaddress(const UniValue& params, bool fHelp); +extern UniValue dumpwallet(const UniValue& params, bool fHelp); +extern UniValue importwallet(const UniValue& params, bool fHelp); +extern UniValue bip38encrypt(const UniValue& params, bool fHelp); +extern UniValue bip38decrypt(const UniValue& params, bool fHelp); + +extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp +extern UniValue setgenerate(const UniValue& params, bool fHelp); +extern UniValue getnetworkhashps(const UniValue& params, bool fHelp); +extern UniValue gethashespersec(const UniValue& params, bool fHelp); +extern UniValue getmininginfo(const UniValue& params, bool fHelp); +extern UniValue prioritisetransaction(const UniValue& params, bool fHelp); +extern UniValue getblocktemplate(const UniValue& params, bool fHelp); +extern UniValue submitblock(const UniValue& params, bool fHelp); +extern UniValue estimatefee(const UniValue& params, bool fHelp); +extern UniValue estimatepriority(const UniValue& params, bool fHelp); + +extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp +extern UniValue getaccountaddress(const UniValue& params, bool fHelp); +extern UniValue getrawchangeaddress(const UniValue& params, bool fHelp); +extern UniValue setaccount(const UniValue& params, bool fHelp); +extern UniValue getaccount(const UniValue& params, bool fHelp); +extern UniValue getaddressesbyaccount(const UniValue& params, bool fHelp); +extern UniValue sendtoaddress(const UniValue& params, bool fHelp); +extern UniValue sendtoaddressix(const UniValue& params, bool fHelp); +extern UniValue signmessage(const UniValue& params, bool fHelp); +extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp); +extern UniValue getreceivedbyaccount(const UniValue& params, bool fHelp); +extern UniValue getbalance(const UniValue& params, bool fHelp); +extern UniValue getunconfirmedbalance(const UniValue& params, bool fHelp); +extern UniValue movecmd(const UniValue& params, bool fHelp); +extern UniValue sendfrom(const UniValue& params, bool fHelp); +extern UniValue sendmany(const UniValue& params, bool fHelp); +extern UniValue addmultisigaddress(const UniValue& params, bool fHelp); +extern UniValue listreceivedbyaddress(const UniValue& params, bool fHelp); +extern UniValue listreceivedbyaccount(const UniValue& params, bool fHelp); +extern UniValue listtransactions(const UniValue& params, bool fHelp); +extern UniValue listaddressgroupings(const UniValue& params, bool fHelp); +extern UniValue listaccounts(const UniValue& params, bool fHelp); +extern UniValue listsinceblock(const UniValue& params, bool fHelp); +extern UniValue gettransaction(const UniValue& params, bool fHelp); +extern UniValue backupwallet(const UniValue& params, bool fHelp); +extern UniValue keypoolrefill(const UniValue& params, bool fHelp); +extern UniValue walletpassphrase(const UniValue& params, bool fHelp); +extern UniValue walletpassphrasechange(const UniValue& params, bool fHelp); +extern UniValue walletlock(const UniValue& params, bool fHelp); +extern UniValue encryptwallet(const UniValue& params, bool fHelp); +extern UniValue getwalletinfo(const UniValue& params, bool fHelp); +extern UniValue getblockchaininfo(const UniValue& params, bool fHelp); +extern UniValue getnetworkinfo(const UniValue& params, bool fHelp); +extern UniValue reservebalance(const UniValue& params, bool fHelp); +extern UniValue setstakesplitthreshold(const UniValue& params, bool fHelp); +extern UniValue getstakesplitthreshold(const UniValue& params, bool fHelp); +extern UniValue multisend(const UniValue& params, bool fHelp); +extern UniValue autocombinerewards(const UniValue& params, bool fHelp); +extern UniValue getzerocoinbalance(const UniValue& params, bool fHelp); +extern UniValue listmintedzerocoins(const UniValue& params, bool fHelp); +extern UniValue listspentzerocoins(const UniValue& params, bool fHelp); +extern UniValue listzerocoinamounts(const UniValue& params, bool fHelp); +extern UniValue mintzerocoin(const UniValue& params, bool fHelp); +extern UniValue spendzerocoin(const UniValue& params, bool fHelp); +extern UniValue resetmintzerocoin(const UniValue& params, bool fHelp); +extern UniValue resetspentzerocoin(const UniValue& params, bool fHelp); +extern UniValue getarchivedzerocoin(const UniValue& params, bool fHelp); +extern UniValue importzerocoins(const UniValue& params, bool fHelp); +extern UniValue exportzerocoins(const UniValue& params, bool fHelp); +extern UniValue reconsiderzerocoins(const UniValue& params, bool fHelp); +extern UniValue getspentzerocoinamount(const UniValue& params, bool fHelp); + +extern UniValue getrawtransaction(const UniValue& params, bool fHelp); // in rcprawtransaction.cpp +extern UniValue listunspent(const UniValue& params, bool fHelp); +extern UniValue lockunspent(const UniValue& params, bool fHelp); +extern UniValue listlockunspent(const UniValue& params, bool fHelp); +extern UniValue createrawtransaction(const UniValue& params, bool fHelp); +extern UniValue decoderawtransaction(const UniValue& params, bool fHelp); +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 findserial(const UniValue& params, bool fHelp); // in rpcblockchain.cpp +extern UniValue getblockcount(const UniValue& params, bool fHelp); +extern UniValue getbestblockhash(const UniValue& params, bool fHelp); +extern UniValue getdifficulty(const UniValue& params, bool fHelp); +extern UniValue settxfee(const UniValue& params, bool fHelp); +extern UniValue getmempoolinfo(const UniValue& params, bool fHelp); +extern UniValue getrawmempool(const UniValue& params, bool fHelp); +extern UniValue getblockhash(const UniValue& params, bool fHelp); +extern UniValue getblock(const UniValue& params, bool fHelp); +extern UniValue getblockheader(const UniValue& params, bool fHelp); +extern UniValue getfeeinfo(const UniValue& params, bool fHelp); +extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp); +extern UniValue gettxout(const UniValue& params, bool fHelp); +extern UniValue verifychain(const UniValue& params, bool fHelp); +extern UniValue getchaintips(const UniValue& params, bool fHelp); +extern UniValue invalidateblock(const UniValue& params, bool fHelp); +extern UniValue reconsiderblock(const UniValue& params, bool fHelp); + +extern UniValue obfuscation(const UniValue& params, bool fHelp); // in rpcmasternode.cpp +extern UniValue getpoolinfo(const UniValue& params, bool fHelp); +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 masternodeconnect(const UniValue& params, bool fHelp); +extern UniValue masternodecurrent(const UniValue& params, bool fHelp); +extern UniValue masternodedebug(const UniValue& params, bool fHelp); +extern UniValue startmasternode(const UniValue& params, bool fHelp); +extern UniValue createmasternodekey(const UniValue& params, bool fHelp); +extern UniValue getmasternodeoutputs(const UniValue& params, bool fHelp); +extern UniValue listmasternodeconf(const UniValue& params, bool fHelp); +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 rpcmasternode-budget.cpp +extern UniValue preparebudget(const UniValue& params, bool fHelp); +extern UniValue submitbudget(const UniValue& params, bool fHelp); +extern UniValue mnbudgetvote(const UniValue& params, bool fHelp); +extern UniValue getbudgetvotes(const UniValue& params, bool fHelp); +extern UniValue getnextsuperblock(const UniValue& params, bool fHelp); +extern UniValue getbudgetprojection(const UniValue& params, bool fHelp); +extern UniValue getbudgetinfo(const UniValue& params, bool fHelp); +extern UniValue mnbudgetrawvote(const UniValue& params, bool fHelp); +extern UniValue mnfinalbudget(const UniValue& params, bool fHelp); +extern UniValue checkbudgets(const UniValue& params, bool fHelp); + +extern UniValue getinfo(const UniValue& params, bool fHelp); // in rpcmisc.cpp +extern UniValue mnsync(const UniValue& params, bool fHelp); +extern UniValue spork(const UniValue& params, bool fHelp); +extern UniValue validateaddress(const UniValue& params, bool fHelp); +extern UniValue createmultisig(const UniValue& params, bool fHelp); +extern UniValue verifymessage(const UniValue& params, bool fHelp); +extern UniValue setmocktime(const UniValue& params, bool fHelp); +extern UniValue getstakingstatus(const UniValue& params, bool fHelp); // in rest.cpp extern bool HTTPReq_REST(AcceptedConnection* conn, diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 4104f80e4..cb07d68dd 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -21,14 +21,15 @@ #include -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" +#include "libzerocoin/Coin.h" +#include "spork.h" #include +#include + using namespace std; using namespace boost; using namespace boost::assign; -using namespace json_spirit; int64_t nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -44,7 +45,7 @@ void EnsureWalletIsUnlocked() throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); } -void WalletTxToJSON(const CWalletTx& wtx, Object& entry) +void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) { int confirms = wtx.GetDepthInMainChain(false); int confirmsTotal = GetIXConfirmations(wtx.GetHash()) + confirms; @@ -59,7 +60,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) } uint256 hash = wtx.GetHash(); entry.push_back(Pair("txid", hash.GetHex())); - Array conflicts; + UniValue conflicts(UniValue::VARR); BOOST_FOREACH (const uint256& conflict, wtx.GetConflicts()) conflicts.push_back(conflict.GetHex()); entry.push_back(Pair("walletconflicts", conflicts)); @@ -69,7 +70,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) entry.push_back(Pair(item.first, item.second)); } -string AccountFromValue(const Value& value) +string AccountFromValue(const UniValue& value) { string strAccount = value.get_str(); if (strAccount == "*") @@ -77,7 +78,7 @@ string AccountFromValue(const Value& value) return strAccount; } -Value getnewaddress(const Array& params, bool fHelp) +UniValue getnewaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -146,7 +147,7 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew = false) return CBitcoinAddress(account.vchPubKey.GetID()); } -Value getaccountaddress(const Array& params, bool fHelp) +UniValue getaccountaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -162,7 +163,7 @@ Value getaccountaddress(const Array& params, bool fHelp) // Parse the account first so we don't generate a key if there's an error string strAccount = AccountFromValue(params[0]); - Value ret; + UniValue ret(UniValue::VSTR); ret = GetAccountAddress(strAccount).ToString(); @@ -170,7 +171,7 @@ Value getaccountaddress(const Array& params, bool fHelp) } -Value getrawchangeaddress(const Array& params, bool fHelp) +UniValue getrawchangeaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -198,7 +199,7 @@ Value getrawchangeaddress(const Array& params, bool fHelp) } -Value setaccount(const Array& params, bool fHelp) +UniValue setaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -231,11 +232,11 @@ Value setaccount(const Array& params, bool fHelp) } else throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address"); - return Value::null; + return NullUniValue; } -Value getaccount(const Array& params, bool fHelp) +UniValue getaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -260,7 +261,7 @@ Value getaccount(const Array& params, bool fHelp) } -Value getaddressesbyaccount(const Array& params, bool fHelp) +UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -279,7 +280,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp) string strAccount = AccountFromValue(params[0]); // Find all addresses that have the given account - Array ret; + UniValue ret(UniValue::VARR); BOOST_FOREACH (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item, pwalletMain->mapAddressBook) { const CBitcoinAddress& address = item.first; const string& strName = item.second.name; @@ -321,7 +322,7 @@ void SendMoney(const CTxDestination& address, CAmount nValue, CWalletTx& wtxNew, throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); } -Value sendtoaddress(const Array& params, bool fHelp) +UniValue sendtoaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) throw runtime_error( @@ -350,9 +351,9 @@ Value sendtoaddress(const Array& params, bool fHelp) // Wallet comments CWalletTx wtx; - if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty()) + if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty()) wtx.mapValue["comment"] = params[2].get_str(); - if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) + if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty()) wtx.mapValue["to"] = params[3].get_str(); EnsureWalletIsUnlocked(); @@ -362,7 +363,7 @@ Value sendtoaddress(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } -Value sendtoaddressix(const Array& params, bool fHelp) +UniValue sendtoaddressix(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) throw runtime_error( @@ -391,9 +392,9 @@ Value sendtoaddressix(const Array& params, bool fHelp) // Wallet comments CWalletTx wtx; - if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty()) + if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty()) wtx.mapValue["comment"] = params[2].get_str(); - if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) + if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty()) wtx.mapValue["to"] = params[3].get_str(); EnsureWalletIsUnlocked(); @@ -402,7 +403,8 @@ Value sendtoaddressix(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } -Value listaddressgroupings(const Array& params, bool fHelp) + +UniValue listaddressgroupings(const UniValue& params, bool fHelp) { if (fHelp) throw runtime_error( @@ -425,12 +427,12 @@ Value listaddressgroupings(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("listaddressgroupings", "") + HelpExampleRpc("listaddressgroupings", "")); - Array jsonGroupings; + UniValue jsonGroupings(UniValue::VARR); map balances = pwalletMain->GetAddressBalances(); BOOST_FOREACH (set grouping, pwalletMain->GetAddressGroupings()) { - Array jsonGrouping; + UniValue jsonGrouping(UniValue::VARR); BOOST_FOREACH (CTxDestination address, grouping) { - Array addressInfo; + UniValue addressInfo(UniValue::VARR); addressInfo.push_back(CBitcoinAddress(address).ToString()); addressInfo.push_back(ValueFromAmount(balances[address])); { @@ -445,7 +447,7 @@ Value listaddressgroupings(const Array& params, bool fHelp) return jsonGroupings; } -Value signmessage(const Array& params, bool fHelp) +UniValue signmessage(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) throw runtime_error( @@ -492,7 +494,7 @@ Value signmessage(const Array& params, bool fHelp) return EncodeBase64(&vchSig[0], vchSig.size()); } -Value getreceivedbyaddress(const Array& params, bool fHelp) +UniValue getreceivedbyaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -540,7 +542,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) } -Value getreceivedbyaccount(const Array& params, bool fHelp) +UniValue getreceivedbyaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -617,12 +619,12 @@ CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminef } -Value getbalance(const Array& params, bool fHelp) +UniValue getbalance(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) throw runtime_error( "getbalance ( \"account\" minconf includeWatchonly )\n" - "\nIf account is not specified, returns the server's total available balance.\n" + "\nIf account is not specified, returns the server's total available balance (excluding zerocoins).\n" "If account is specified, returns the balance in the account.\n" "Note that the account \"\" is not the same as leaving the parameter out.\n" "The server total may be different to the balance in the default \"\" account.\n" @@ -684,7 +686,7 @@ Value getbalance(const Array& params, bool fHelp) return ValueFromAmount(nBalance); } -Value getunconfirmedbalance(const Array& params, bool fHelp) +UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp) { if (fHelp || params.size() > 0) throw runtime_error( @@ -694,7 +696,7 @@ Value getunconfirmedbalance(const Array& params, bool fHelp) } -Value movecmd(const Array& params, bool fHelp) +UniValue movecmd(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 3 || params.size() > 5) throw runtime_error( @@ -756,7 +758,7 @@ Value movecmd(const Array& params, bool fHelp) } -Value sendfrom(const Array& params, bool fHelp) +UniValue sendfrom(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 3 || params.size() > 6) throw runtime_error( @@ -793,9 +795,9 @@ Value sendfrom(const Array& params, bool fHelp) CWalletTx wtx; wtx.strFromAccount = strAccount; - if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty()) + if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty()) wtx.mapValue["comment"] = params[4].get_str(); - if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty()) + if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty()) wtx.mapValue["to"] = params[5].get_str(); EnsureWalletIsUnlocked(); @@ -811,7 +813,7 @@ Value sendfrom(const Array& params, bool fHelp) } -Value sendmany(const Array& params, bool fHelp) +UniValue sendmany(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) throw runtime_error( @@ -837,31 +839,32 @@ Value sendmany(const Array& params, bool fHelp) "\nAs a json rpc call\n" + HelpExampleRpc("sendmany", "\"tabby\", \"{\\\"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwg\\\":0.01,\\\"XuQQkwA4FYkq2XERzMY2CiAZhJTEDAbtcg\\\":0.02}\", 6, \"testing\"")); string strAccount = AccountFromValue(params[0]); - Object sendTo = params[1].get_obj(); + UniValue sendTo = params[1].get_obj(); int nMinDepth = 1; if (params.size() > 2) nMinDepth = params[2].get_int(); CWalletTx wtx; wtx.strFromAccount = strAccount; - if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) + if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty()) wtx.mapValue["comment"] = params[3].get_str(); set setAddress; vector > vecSend; CAmount totalAmount = 0; - BOOST_FOREACH (const Pair& s, sendTo) { - CBitcoinAddress address(s.name_); + vector keys = sendTo.getKeys(); + BOOST_FOREACH(const string& name_, keys) { + CBitcoinAddress address(name_); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bulwark address: ") + s.name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bulwark address: ")+name_); if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + s.name_); + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); setAddress.insert(address); CScript scriptPubKey = GetScriptForDestination(address.Get()); - CAmount nAmount = AmountFromValue(s.value_); + CAmount nAmount = AmountFromValue(sendTo[name_]); totalAmount += nAmount; vecSend.push_back(make_pair(scriptPubKey, nAmount)); @@ -888,9 +891,9 @@ Value sendmany(const Array& params, bool fHelp) } // Defined in rpcmisc.cpp -extern CScript _createmultisig_redeemScript(const Array& params); +extern CScript _createmultisig_redeemScript(const UniValue& params); -Value addmultisigaddress(const Array& params, bool fHelp) +UniValue addmultisigaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) { string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" @@ -946,7 +949,7 @@ struct tallyitem { } }; -Value ListReceived(const Array& params, bool fByAccounts) +UniValue ListReceived(const UniValue& params, bool fByAccounts) { // Minimum confirmations int nMinDepth = 1; @@ -996,7 +999,7 @@ Value ListReceived(const Array& params, bool fByAccounts) } // Reply - Array ret; + UniValue ret(UniValue::VARR); map mapAccountTally; BOOST_FOREACH (const PAIRTYPE(CBitcoinAddress, CAddressBookData) & item, pwalletMain->mapAddressBook) { const CBitcoinAddress& address = item.first; @@ -1023,7 +1026,7 @@ Value ListReceived(const Array& params, bool fByAccounts) item.nBCConf = min(item.nBCConf, nBCConf); item.fIsWatchonly = fIsWatchonly; } else { - Object obj; + UniValue obj(UniValue::VOBJ); if (fIsWatchonly) obj.push_back(Pair("involvesWatchonly", true)); obj.push_back(Pair("address", address.ToString())); @@ -1031,7 +1034,7 @@ Value ListReceived(const Array& params, bool fByAccounts) obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("confirmations", (nConf == std::numeric_limits::max() ? 0 : nConf))); obj.push_back(Pair("bcconfirmations", (nBCConf == std::numeric_limits::max() ? 0 : nBCConf))); - Array transactions; + UniValue transactions(UniValue::VARR); if (it != mapTally.end()) { BOOST_FOREACH (const uint256& item, (*it).second.txids) { transactions.push_back(item.GetHex()); @@ -1047,7 +1050,7 @@ Value ListReceived(const Array& params, bool fByAccounts) CAmount nAmount = (*it).second.nAmount; int nConf = (*it).second.nConf; int nBCConf = (*it).second.nBCConf; - Object obj; + UniValue obj(UniValue::VOBJ); if ((*it).second.fIsWatchonly) obj.push_back(Pair("involvesWatchonly", true)); obj.push_back(Pair("account", (*it).first)); @@ -1061,7 +1064,7 @@ Value ListReceived(const Array& params, bool fByAccounts) return ret; } -Value listreceivedbyaddress(const Array& params, bool fHelp) +UniValue listreceivedbyaddress(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) throw runtime_error( @@ -1091,7 +1094,7 @@ Value listreceivedbyaddress(const Array& params, bool fHelp) return ListReceived(params, false); } -Value listreceivedbyaccount(const Array& params, bool fHelp) +UniValue listreceivedbyaccount(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 3) throw runtime_error( @@ -1120,14 +1123,14 @@ Value listreceivedbyaccount(const Array& params, bool fHelp) return ListReceived(params, true); } -static void MaybePushAddress(Object& entry, const CTxDestination& dest) +static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) { CBitcoinAddress addr; if (addr.Set(dest)) entry.push_back(Pair("address", addr.ToString())); } -void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter) +void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) { CAmount nFee; string strSentAccount; @@ -1142,7 +1145,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) { - Object entry; + UniValue entry(UniValue::VOBJ); if (involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY)) entry.push_back(Pair("involvesWatchonly", true)); entry.push_back(Pair("account", strSentAccount)); @@ -1165,7 +1168,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe if (pwalletMain->mapAddressBook.count(r.destination)) account = pwalletMain->mapAddressBook[r.destination].name; if (fAllAccounts || (account == strAccount)) { - Object entry; + UniValue entry(UniValue::VOBJ); if (involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY)) entry.push_back(Pair("involvesWatchonly", true)); entry.push_back(Pair("account", account)); @@ -1190,12 +1193,12 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe } } -void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret) +void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret) { bool fAllAccounts = (strAccount == string("*")); if (fAllAccounts || acentry.strAccount == strAccount) { - Object entry; + UniValue entry(UniValue::VOBJ); entry.push_back(Pair("account", acentry.strAccount)); entry.push_back(Pair("category", "move")); entry.push_back(Pair("time", acentry.nTime)); @@ -1206,7 +1209,7 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar } } -Value listtransactions(const Array& params, bool fHelp) +UniValue listtransactions(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 4) throw runtime_error( @@ -1280,7 +1283,7 @@ Value listtransactions(const Array& params, bool fHelp) if (nFrom < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from"); - Array ret; + UniValue ret(UniValue::VARR); std::list acentries; CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); @@ -1302,20 +1305,27 @@ Value listtransactions(const Array& params, bool fHelp) nFrom = ret.size(); if ((nFrom + nCount) > (int)ret.size()) nCount = ret.size() - nFrom; - Array::iterator first = ret.begin(); + + vector arrTmp = ret.getValues(); + + vector::iterator first = arrTmp.begin(); std::advance(first, nFrom); - Array::iterator last = ret.begin(); - std::advance(last, nFrom + nCount); + vector::iterator last = arrTmp.begin(); + std::advance(last, nFrom+nCount); + + if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end()); + if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first); - if (last != ret.end()) ret.erase(last, ret.end()); - if (first != ret.begin()) ret.erase(ret.begin(), first); + std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest - std::reverse(ret.begin(), ret.end()); // Return oldest to newest + ret.clear(); + ret.setArray(); + ret.push_backV(arrTmp); return ret; } -Value listaccounts(const Array& params, bool fHelp) +UniValue listaccounts(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( @@ -1377,14 +1387,14 @@ Value listaccounts(const Array& params, bool fHelp) BOOST_FOREACH (const CAccountingEntry& entry, acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; - Object ret; + UniValue ret(UniValue::VOBJ); BOOST_FOREACH (const PAIRTYPE(string, CAmount) & accountBalance, mapAccountBalances) { ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); } return ret; } -Value listsinceblock(const Array& params, bool fHelp) +UniValue listsinceblock(const UniValue& params, bool fHelp) { if (fHelp) throw runtime_error( @@ -1446,7 +1456,7 @@ Value listsinceblock(const Array& params, bool fHelp) int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1; - Array transactions; + UniValue transactions(UniValue::VARR); for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { CWalletTx tx = (*it).second; @@ -1458,14 +1468,14 @@ Value listsinceblock(const Array& params, bool fHelp) CBlockIndex* pblockLast = chainActive[chainActive.Height() + 1 - target_confirms]; uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : 0; - Object ret; + UniValue ret(UniValue::VOBJ); ret.push_back(Pair("transactions", transactions)); ret.push_back(Pair("lastblock", lastblock.GetHex())); return ret; } -Value gettransaction(const Array& params, bool fHelp) +UniValue gettransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -1509,7 +1519,7 @@ Value gettransaction(const Array& params, bool fHelp) if (params[1].get_bool()) filter = filter | ISMINE_WATCH_ONLY; - Object entry; + UniValue entry(UniValue::VOBJ); if (!pwalletMain->mapWallet.count(hash)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); const CWalletTx& wtx = pwalletMain->mapWallet[hash]; @@ -1525,7 +1535,7 @@ Value gettransaction(const Array& params, bool fHelp) WalletTxToJSON(wtx, entry); - Array details; + UniValue details(UniValue::VARR); ListTransactions(wtx, "*", 0, false, details, filter); entry.push_back(Pair("details", details)); @@ -1536,7 +1546,7 @@ Value gettransaction(const Array& params, bool fHelp) } -Value backupwallet(const Array& params, bool fHelp) +UniValue backupwallet(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -1551,11 +1561,11 @@ Value backupwallet(const Array& params, bool fHelp) if (!BackupWallet(*pwalletMain, strDest)) throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); - return Value::null; + return NullUniValue; } -Value keypoolrefill(const Array& params, bool fHelp) +UniValue keypoolrefill(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -1581,7 +1591,7 @@ Value keypoolrefill(const Array& params, bool fHelp) if (pwalletMain->GetKeyPoolSize() < kpSize) throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool."); - return Value::null; + return NullUniValue; } @@ -1593,7 +1603,7 @@ static void LockWallet(CWallet* pWallet) pWallet->Lock(); } -Value walletpassphrase(const Array& params, bool fHelp) +UniValue walletpassphrase(const UniValue& params, bool fHelp) { if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 3)) throw runtime_error( @@ -1647,11 +1657,11 @@ Value walletpassphrase(const Array& params, bool fHelp) RPCRunLater ("lockwallet", boost::bind (LockWallet, pwalletMain), nSleepTime); } - return Value::null; + return NullUniValue; } -Value walletpassphrasechange(const Array& params, bool fHelp) +UniValue walletpassphrasechange(const UniValue& params, bool fHelp) { if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2)) throw runtime_error( @@ -1686,11 +1696,11 @@ Value walletpassphrasechange(const Array& params, bool fHelp) if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); - return Value::null; + return NullUniValue; } -Value walletlock(const Array& params, bool fHelp) +UniValue walletlock(const UniValue& params, bool fHelp) { if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0)) throw runtime_error( @@ -1716,11 +1726,11 @@ Value walletlock(const Array& params, bool fHelp) nWalletUnlockTime = 0; } - return Value::null; + return NullUniValue; } -Value encryptwallet(const Array& params, bool fHelp) +UniValue encryptwallet(const UniValue& params, bool fHelp) { if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1)) throw runtime_error( @@ -1767,7 +1777,7 @@ Value encryptwallet(const Array& params, bool fHelp) return "wallet encrypted; bulwark server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup."; } -Value lockunspent(const Array& params, bool fHelp) +UniValue lockunspent(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -1801,9 +1811,9 @@ Value lockunspent(const Array& params, bool fHelp) "\nAs a json rpc call\n" + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")); if (params.size() == 1) - RPCTypeCheck(params, list_of(bool_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)); else - RPCTypeCheck(params, list_of(bool_type)(array_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR)); bool fUnlock = params[0].get_bool(); @@ -1813,13 +1823,14 @@ Value lockunspent(const Array& params, bool fHelp) return true; } - Array outputs = params[1].get_array(); - BOOST_FOREACH (Value& output, outputs) { - if (output.type() != obj_type) + UniValue outputs = params[1].get_array(); + for (unsigned int idx = 0; idx < outputs.size(); idx++) { + const UniValue& output = outputs[idx]; + if (!output.isObject()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object"); - const Object& o = output.get_obj(); + const UniValue& o = output.get_obj(); - RPCTypeCheck(o, map_list_of("txid", str_type)("vout", int_type)); + RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)); string txid = find_value(o, "txid").get_str(); if (!IsHex(txid)) @@ -1840,7 +1851,7 @@ Value lockunspent(const Array& params, bool fHelp) return true; } -Value listlockunspent(const Array& params, bool fHelp) +UniValue listlockunspent(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 0) throw runtime_error( @@ -1866,10 +1877,10 @@ Value listlockunspent(const Array& params, bool fHelp) vector vOutpts; pwalletMain->ListLockedCoins(vOutpts); - Array ret; + UniValue ret(UniValue::VARR); BOOST_FOREACH (COutPoint& outpt, vOutpts) { - Object o; + UniValue o(UniValue::VOBJ); o.push_back(Pair("txid", outpt.hash.GetHex())); o.push_back(Pair("vout", (int)outpt.n)); @@ -1879,7 +1890,7 @@ Value listlockunspent(const Array& params, bool fHelp) return ret; } -Value settxfee(const Array& params, bool fHelp) +UniValue settxfee(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 1) throw runtime_error( @@ -1901,7 +1912,7 @@ Value settxfee(const Array& params, bool fHelp) return true; } -Value getwalletinfo(const Array& params, bool fHelp) +UniValue getwalletinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -1919,7 +1930,7 @@ Value getwalletinfo(const Array& params, bool fHelp) "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") + HelpExampleRpc("getwalletinfo", "")); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size())); @@ -1931,7 +1942,7 @@ Value getwalletinfo(const Array& params, bool fHelp) } // ppcoin: reserve balance from being staked for network protection -Value reservebalance(const Array& params, bool fHelp) +UniValue reservebalance(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( @@ -1967,14 +1978,14 @@ Value reservebalance(const Array& params, bool fHelp) } } - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("reserve", (nReserveBalance > 0))); result.push_back(Pair("amount", ValueFromAmount(nReserveBalance))); return result; } // presstab HyperStake -Value setstakesplitthreshold(const Array& params, bool fHelp) +UniValue setstakesplitthreshold(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -1982,7 +1993,7 @@ Value setstakesplitthreshold(const Array& params, bool fHelp) "\nThis will set the output size of your stakes to never be below this number\n" "\nArguments:\n" - "1. value (numeric, required) Threshold value between 1 and 999999\n" + "1. value (numeric, required) Threshold value between 100 and 999999\n" "\nResult:\n" "{\n" " \"threshold\": n, (numeric) Threshold value set\n" @@ -1994,15 +2005,15 @@ Value setstakesplitthreshold(const Array& params, bool fHelp) uint64_t nStakeSplitThreshold = params[0].get_int(); if (pwalletMain->IsLocked()) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Unlock wallet to use this feature"); - if (nStakeSplitThreshold > 999999) - throw runtime_error("Value out of range, max allowed is 999999"); + if (nStakeSplitThreshold < 100 || nStakeSplitThreshold > 999999) + throw runtime_error("Value out of range, min allowed is 100 and max allowed is 999999"); CWalletDB walletdb(pwalletMain->strWalletFile); LOCK(pwalletMain->cs_wallet); { bool fFileBacked = pwalletMain->fFileBacked; - Object result; + UniValue result(UniValue::VOBJ); pwalletMain->nStakeSplitThreshold = nStakeSplitThreshold; result.push_back(Pair("threshold", int(pwalletMain->nStakeSplitThreshold))); if (fFileBacked) { @@ -2016,7 +2027,7 @@ Value setstakesplitthreshold(const Array& params, bool fHelp) } // presstab HyperStake -Value getstakesplitthreshold(const Array& params, bool fHelp) +UniValue getstakesplitthreshold(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -2030,7 +2041,7 @@ Value getstakesplitthreshold(const Array& params, bool fHelp) return int(pwalletMain->nStakeSplitThreshold); } -Value autocombinerewards(const Array& params, bool fHelp) +UniValue autocombinerewards(const UniValue& params, bool fHelp) { bool fEnable; if (params.size() >= 1) @@ -2060,19 +2071,19 @@ Value autocombinerewards(const Array& params, bool fHelp) if (!walletdb.WriteAutoCombineSettings(fEnable, nThreshold)) throw runtime_error("Changed settings in wallet but failed to save to database\n"); - return Value::null; + return NullUniValue; } -Array printMultiSend() +UniValue printMultiSend() { - Array ret; - Object act; + UniValue ret(UniValue::VARR); + UniValue act(UniValue::VOBJ); act.push_back(Pair("MultiSendStake Activated?", pwalletMain->fMultiSendStake)); act.push_back(Pair("MultiSendMasternode Activated?", pwalletMain->fMultiSendMasternodeReward)); ret.push_back(act); if (pwalletMain->vDisabledAddresses.size() >= 1) { - Object disAdd; + UniValue disAdd(UniValue::VOBJ); for (unsigned int i = 0; i < pwalletMain->vDisabledAddresses.size(); i++) { disAdd.push_back(Pair("Disabled From Sending", pwalletMain->vDisabledAddresses[i])); } @@ -2081,19 +2092,19 @@ Array printMultiSend() ret.push_back("MultiSend Addresses to Send To:"); - Object vMS; - for (unsigned int j = 0; j < pwalletMain->vMultiSend.size(); j++) { - for (unsigned int i = 0; i < pwalletMain->vMultiSend[j].second.size(); i++) { - vMS.push_back(Pair("Address " + boost::lexical_cast(i), pwalletMain->vMultiSend[1].second[i].first)); - vMS.push_back(Pair("Percent", pwalletMain->vMultiSend[i].second[i].second)); - } - } + UniValue vMS(UniValue::VOBJ); + for (unsigned int j = 0; j < pwalletMain->vMultiSend.size(); j++) { + for (unsigned int i = 0; i < pwalletMain->vMultiSend[j].second.size(); i++) { + vMS.push_back(Pair("Address " + boost::lexical_cast(i), pwalletMain->vMultiSend[1].second[i].first)); + vMS.push_back(Pair("Percent", pwalletMain->vMultiSend[i].second[i].second)); + } + } ret.push_back(vMS); return ret; } -Array printAddresses() +UniValue printAddresses() { std::vector vCoins; pwalletMain->AvailableCoins(vCoins); @@ -2109,9 +2120,9 @@ Array printAddresses() mapAddresses[strAdd] += (double)out.tx->vout[out.i].nValue / (double)COIN; } - Array ret; + UniValue ret(UniValue::VARR); for (map::const_iterator it = mapAddresses.begin(); it != mapAddresses.end(); ++it) { - Object obj; + UniValue obj(UniValue::VOBJ); const std::string* strAdd = &(*it).first; const double* nBalance = &(*it).second; obj.push_back(Pair("Address ", *strAdd)); @@ -2130,14 +2141,14 @@ unsigned int sumMultiSend() return sum; } -Value multisend(const Array& params, bool fHelp) +UniValue multisend(const UniValue& params, bool fHelp) { CWalletDB walletdb(pwalletMain->strWalletFile); bool fFileBacked; //MultiSend Commands if (params.size() == 1) { string strCommand = params[0].get_str(); - Object ret; + UniValue ret(UniValue::VOBJ); if (strCommand == "print") { return printMultiSend(); } else if (strCommand == "printaddress" || strCommand == "printaddresses") { @@ -2154,7 +2165,7 @@ Value multisend(const Array& params, bool fHelp) pwalletMain->vMultiSend.clear(); pwalletMain->setMultiSendDisabled(); - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("Erased from database", erased)); obj.push_back(Pair("Erased from RAM", true)); @@ -2167,9 +2178,9 @@ Value multisend(const Array& params, bool fHelp) if (CBitcoinAddress(pwalletMain->vMultiSend[0].first).IsValid()) { pwalletMain->fMultiSendStake = true; if (!walletdb.WriteMSettings(true, pwalletMain->fMultiSendMasternodeReward, pwalletMain->nLastMultiSendHeight)) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("error", "MultiSend activated but writing settings to DB failed")); - Array arr; + UniValue arr(UniValue::VARR); arr.push_back(obj); arr.push_back(printMultiSend()); return arr; @@ -2186,9 +2197,9 @@ Value multisend(const Array& params, bool fHelp) pwalletMain->fMultiSendMasternodeReward = true; if (!walletdb.WriteMSettings(pwalletMain->fMultiSendStake, true, pwalletMain->nLastMultiSendHeight)) { - Object obj; + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("error", "MultiSend activated but writing settings to DB failed")); - Array arr; + UniValue arr(UniValue::VARR); arr.push_back(obj); arr.push_back(printMultiSend()); return arr; @@ -2249,7 +2260,7 @@ Value multisend(const Array& params, bool fHelp) "The MultiSend transaction is sent when the staked coins mature (100 confirmations)\n" "****************************************************************\n" "TO CREATE OR ADD TO THE MULTISEND VECTOR:\n" - "multisend
\n" + "multisend
\n" "This will add a new address to the MultiSend vector\n" "Percent is a whole number 1 to 100.\n" "****************************************************************\n" @@ -2266,9 +2277,9 @@ Value multisend(const Array& params, bool fHelp) //if the user is entering a new MultiSend item string strAddress = params[0].get_str(); - string strSendAddress = params[1].get_str(); + string strSendAddress = params[1].get_str(); CBitcoinAddress address(strAddress); - CBitcoinAddress sendAddress(strSendAddress); + CBitcoinAddress sendAddress(strSendAddress); if (!(address.IsValid() || sendAddress.IsValid())) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid BWK address"); if (boost::lexical_cast(params[2].get_str()) < 0) @@ -2288,7 +2299,7 @@ Value multisend(const Array& params, bool fHelp) //MultiSend can only send 100% of your stake if (nPercent + sumMultiSend() > 100) throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to add to MultiSend vector, the sum of your MultiSend is greater than 100%"); - /* + /* for (unsigned int i = 0; i < pwalletMain->vMultiSend.size(); i++) { if (pwalletMain->vMultiSend[i].first == strAddress) throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to add to MultiSend vector, cannot use the same address twice"); @@ -2305,7 +2316,518 @@ Value multisend(const Array& params, bool fHelp) if (!walletdb.WriteMultiSend(pwalletMain->vMultiSend)) throw JSONRPCError(RPC_DATABASE_ERROR, "walletdb WriteMultiSend failed!"); } - */ + */ } return printMultiSend(); } +UniValue getzerocoinbalance(const UniValue& params, bool fHelp) +{ + + if (fHelp || params.size() != 0) + throw runtime_error( + "getzerocoinbalance\n" + + HelpRequiringPassphrase()); + + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + return ValueFromAmount(pwalletMain->GetZerocoinBalance(true)); + +} +UniValue listmintedzerocoins(const UniValue& params, bool fHelp) +{ + + if (fHelp || params.size() != 0) + throw runtime_error( + "listmintedzerocoins\n" + + HelpRequiringPassphrase()); + + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + CWalletDB walletdb(pwalletMain->strWalletFile); + list listPubCoin = walletdb.ListMintedCoins(true, false, true); + + UniValue jsonList(UniValue::VARR); + for (const CZerocoinMint& pubCoinItem : listPubCoin) { + jsonList.push_back(pubCoinItem.GetValue().GetHex()); + } + + return jsonList; +} + +UniValue listzerocoinamounts(const UniValue& params, bool fHelp) +{ + + if (fHelp || params.size() != 0) + throw runtime_error( + "listzerocoinamounts\n" + + HelpRequiringPassphrase()); + + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + CWalletDB walletdb(pwalletMain->strWalletFile); + list listPubCoin = walletdb.ListMintedCoins(true, true, true); + + std::map spread; + for (const auto& denom : libzerocoin::zerocoinDenomList) + spread.insert(std::pair(denom, 0)); + for (auto& mint : listPubCoin) spread.at(mint.GetDenomination())++; + + + UniValue jsonList(UniValue::VARR); + UniValue val(UniValue::VOBJ); + for (const auto& m : libzerocoin::zerocoinDenomList) { + stringstream s1; + s1 << "Denomination Value " << libzerocoin::ZerocoinDenominationToInt(m); + stringstream s2; + s2 << spread.at(m) << " coins"; + val.push_back(Pair(s1.str(),s2.str())); + } + jsonList.push_back(val); + return jsonList; +} + +UniValue listspentzerocoins(const UniValue& params, bool fHelp) +{ + + if (fHelp || params.size() != 0) + throw runtime_error( + "listspentzerocoins\n" + + HelpRequiringPassphrase()); + + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + CWalletDB walletdb(pwalletMain->strWalletFile); + list listPubCoin = walletdb.ListSpentCoinsSerial(); + + UniValue jsonList(UniValue::VARR); + for (const CBigNum& pubCoinItem : listPubCoin) { + jsonList.push_back(pubCoinItem.GetHex()); + } + + return jsonList; +} + +UniValue mintzerocoin(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "mintzerocoin \n" + "Usage: Enter an amount of BWK to convert to zBWK" + + HelpRequiringPassphrase()); + + int64_t nTime = GetTimeMillis(); + + if (GetAdjustedTime() < GetSporkValue(SPORK_21_ENABLE_ZEROCOIN)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error: Zerocoin functionality is not enabled on the Bulwark network yet."); + + if(GetAdjustedTime() > GetSporkValue(SPORK_22_ZEROCOIN_MAINTENANCE_MODE)) + throw JSONRPCError(RPC_WALLET_ERROR, "zBWK is currently disabled due to maintenance."); + + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + CAmount nAmount = params[0].get_int() * COIN; + + CWalletTx wtx; + vector vMints; + string strError = pwalletMain->MintZerocoin(nAmount, wtx, vMints); + + if (strError != "") + throw JSONRPCError(RPC_WALLET_ERROR, strError); + + UniValue arrMints(UniValue::VARR); + for (CZerocoinMint mint : vMints) { + UniValue m(UniValue::VOBJ); + m.push_back(Pair("txid", wtx.GetHash().ToString())); + m.push_back(Pair("value", ValueFromAmount(libzerocoin::ZerocoinDenominationToAmount(mint.GetDenomination())))); + m.push_back(Pair("pubcoin", mint.GetValue().GetHex())); + m.push_back(Pair("randomness", mint.GetRandomness().GetHex())); + m.push_back(Pair("serial", mint.GetSerialNumber().GetHex())); + m.push_back(Pair("time", GetTimeMillis() - nTime)); + arrMints.push_back(m); + } + + return arrMints; +} + +UniValue spendzerocoin(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 5 || params.size() < 4) + throw runtime_error( + "spendzerocoin
\n" + "Overview: Convert zBWK (zerocoins) into BWK. \n" + "amount: amount to spend\n" + "mintchange: if there is left over BWK (change), the wallet can convert it automatically back to zerocoins [true]\n" + "minimizechange: try to minimize the returning change [false]\n" + "security level: the amount of checkpoints to add to the accumulator. A checkpoint contains 10 blocks worth of zerocoinmints." + "The more checkpoints that are added, the more untraceable the transaction will be. Use [100] to add the maximum amount" + "of checkpoints available. Tip: adding more checkpoints makes the minting process take longer\n" + "address: Send straight to an address or leave the address blank and the wallet will send to a change address. If there is change then" + "an address is required" + + HelpRequiringPassphrase()); + + if (GetAdjustedTime() < GetSporkValue(SPORK_21_ENABLE_ZEROCOIN)) + throw JSONRPCError(RPC_WALLET_ERROR, "Error: Zerocoin functionality is not enabled on the Bulwark network yet."); + + if(GetAdjustedTime() > GetSporkValue(SPORK_22_ZEROCOIN_MAINTENANCE_MODE)) + throw JSONRPCError(RPC_WALLET_ERROR, "zBWK is currently disabled due to maintenance."); + + int64_t nTimeStart = GetTimeMillis(); + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + CAmount nAmount = AmountFromValue(params[0]); // Spending amount + bool fMintChange = params[1].get_bool(); // Mint change to zBWK + bool fMinimizeChange = params[2].get_bool(); // Minimize change + int nSecurityLevel = params[3].get_int(); // Security level + + CBitcoinAddress address = CBitcoinAddress(); // Optional sending address. Dummy initialization here. + if (params.size() == 5) { + // Destination address was supplied as params[4]. Optional parameters MUST be at the end + // to avoid type confusion from the JSON interpreter + address = CBitcoinAddress(params[4].get_str()); + if(!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bulwark address"); + } + + CWalletTx wtx; + vector vMintsSelected; + CZerocoinSpendReceipt receipt; + bool fSuccess; + + if(params.size() == 5) // Spend to supplied destination address + fSuccess = pwalletMain->SpendZerocoin(nAmount, nSecurityLevel, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange, &address); + else // Spend to newly generated local address + fSuccess = pwalletMain->SpendZerocoin(nAmount, nSecurityLevel, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange); + + if (!fSuccess) + throw JSONRPCError(RPC_WALLET_ERROR, receipt.GetStatusMessage()); + + CAmount nValueIn = 0; + UniValue arrSpends(UniValue::VARR); + for (CZerocoinSpend spend : receipt.GetSpends()) { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("denomination", spend.GetDenomination())); + obj.push_back(Pair("pubcoin", spend.GetPubCoin().GetHex())); + obj.push_back(Pair("serial", spend.GetSerial().GetHex())); + uint32_t nChecksum = spend.GetAccumulatorChecksum(); + obj.push_back(Pair("acc_checksum", HexStr(BEGIN(nChecksum), END(nChecksum)))); + arrSpends.push_back(obj); + nValueIn += libzerocoin::ZerocoinDenominationToAmount(spend.GetDenomination()); + } + + CAmount nValueOut = 0; + UniValue vout(UniValue::VARR); + for (unsigned int i = 0; i < wtx.vout.size(); i++) { + const CTxOut& txout = wtx.vout[i]; + UniValue out(UniValue::VOBJ); + out.push_back(Pair("value", ValueFromAmount(txout.nValue))); + nValueOut += txout.nValue; + + CTxDestination dest; + if(txout.scriptPubKey.IsZerocoinMint()) + out.push_back(Pair("address", "zerocoinmint")); + else if(ExtractDestination(txout.scriptPubKey, dest)) + out.push_back(Pair("address", CBitcoinAddress(dest).ToString())); + vout.push_back(out); + } + + //construct JSON to return + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("txid", wtx.GetHash().ToString())); + ret.push_back(Pair("bytes", (int64_t)wtx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION))); + ret.push_back(Pair("fee", ValueFromAmount(nValueIn - nValueOut))); + ret.push_back(Pair("duration_millis", (GetTimeMillis() - nTimeStart))); + ret.push_back(Pair("spends", arrSpends)); + ret.push_back(Pair("outputs", vout)); + + return ret; +} + +UniValue resetmintzerocoin(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "resetmintzerocoin \n" + "Scan the blockchain for all of the zerocoins that are held in the wallet.dat. Update any meta-data that is incorrect.\n" + "Archive any mints that are not able to be found." + + "\nArguments:\n" + "1. \"extended_search\" (bool, optional) Rescan each block of the blockchain looking for your mints. WARNING - may take 30+ minutes!\n" + + + HelpRequiringPassphrase()); + + bool fExtendedSearch = false; + if (params.size() == 1) + fExtendedSearch = params[0].get_bool(); + + CWalletDB walletdb(pwalletMain->strWalletFile); + list listMints = walletdb.ListMintedCoins(false, false, true); + vector vMintsToFind{ std::make_move_iterator(std::begin(listMints)), std::make_move_iterator(std::end(listMints)) }; + vector vMintsMissing; + vector vMintsToUpdate; + + // search all of our available data for these mints + FindMints(vMintsToFind, vMintsToUpdate, vMintsMissing, fExtendedSearch); + + // update the meta data of mints that were marked for updating + UniValue arrUpdated(UniValue::VARR); + for (CZerocoinMint mint : vMintsToUpdate) { + walletdb.WriteZerocoinMint(mint); + arrUpdated.push_back(mint.GetValue().GetHex()); + } + + // delete any mints that were unable to be located on the blockchain + UniValue arrDeleted(UniValue::VARR); + for (CZerocoinMint mint : vMintsMissing) { + arrDeleted.push_back(mint.GetValue().GetHex()); + walletdb.ArchiveMintOrphan(mint); + } + + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("updated", arrUpdated)); + obj.push_back(Pair("archived", arrDeleted)); + return obj; +} + +UniValue resetspentzerocoin(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "resetspentzerocoin\n" + "Scan the blockchain for all of the zerocoins that are held in the wallet.dat. Reset mints that are considered spent that did not make it into the blockchain." + + HelpRequiringPassphrase()); + + CWalletDB walletdb(pwalletMain->strWalletFile); + list listMints = walletdb.ListMintedCoins(false, false, false); + list listSpends = walletdb.ListSpentCoins(); + list listUnconfirmedSpends; + + for (CZerocoinSpend spend : listSpends) { + CTransaction tx; + uint256 hashBlock = 0; + if (!GetTransaction(spend.GetTxHash(), tx, hashBlock)) { + listUnconfirmedSpends.push_back(spend); + continue; + } + + //no confirmations + if (hashBlock == 0) + listUnconfirmedSpends.push_back(spend); + } + + UniValue objRet(UniValue::VOBJ); + UniValue arrRestored(UniValue::VARR); + for (CZerocoinSpend spend : listUnconfirmedSpends) { + for (CZerocoinMint mint : listMints) { + if (mint.GetSerialNumber() == spend.GetSerial()) { + mint.SetUsed(false); + walletdb.WriteZerocoinMint(mint); + walletdb.EraseZerocoinSpendSerialEntry(spend.GetSerial()); + RemoveSerialFromDB(spend.GetSerial()); + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("serial", spend.GetSerial().GetHex())); + arrRestored.push_back(obj); + continue; + } + } + } + + objRet.push_back(Pair("restored", arrRestored)); + return objRet; +} + +UniValue getarchivedzerocoin(const UniValue& params, bool fHelp) +{ + if(fHelp || params.size() != 0) + throw runtime_error( + "getarchivedzerocoin\n" + "Display zerocoins that were archived because they were believed to be orphans." + "Provides enough information to recover mint if it was incorrectly archived." + + HelpRequiringPassphrase()); + + CWalletDB walletdb(pwalletMain->strWalletFile); + list listMints = walletdb.ListArchivedZerocoins(); + + UniValue arrRet(UniValue::VARR); + for (const CZerocoinMint mint : listMints) { + UniValue objMint(UniValue::VOBJ); + objMint.push_back(Pair("txid", mint.GetTxHash().GetHex())); + objMint.push_back(Pair("denomination", FormatMoney(mint.GetDenominationAsAmount()))); + objMint.push_back(Pair("serial", mint.GetSerialNumber().GetHex())); + objMint.push_back(Pair("randomness", mint.GetRandomness().GetHex())); + objMint.push_back(Pair("pubcoin", mint.GetValue().GetHex())); + arrRet.push_back(objMint); + } + + return arrRet; +} + +UniValue exportzerocoins(const UniValue& params, bool fHelp) +{ + if(fHelp || params.empty() || params.size() > 2) + throw runtime_error( + "exportzerocoins include_spent ( denomination )\n" + "Exports zerocoin mints that are held by this wallet.dat\n" + + "\nArguments:\n" + "1. \"include_spent\" (bool, required) Include mints that have already been spent\n" + "2. \"denomination\" (integer, optional) Export a specific denomination of zBWK\n" + + "\nResult\n" + "[ (array of json object)\n" + " {\n" + " \"d\" : n, (numeric) the mint's zerocoin denomination \n" + " \"p\" : \"pubcoin\", (string) The public coin\n" + " \"s\" : \"serial\", (string) The secret serial number\n" + " \"r\" : \"random\", (string) The secret random number\n" + " \"t\" : \"txid\", (string) The txid that the coin was minted in\n" + " \"h\" : n, (numeric) The height the tx was added to the blockchain\n" + " \"u\" : used (boolean) Whether the mint has been spent\n" + " }\n" + " ,...\n" + "]\n" + + "\nExamples\n" + + HelpExampleCli("exportzerocoins", "false 5") + HelpExampleRpc("exportzerocoins", "false 5")); + + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + CWalletDB walletdb(pwalletMain->strWalletFile); + + bool fIncludeSpent = params[0].get_bool(); + libzerocoin::CoinDenomination denomination = libzerocoin::ZQ_ERROR; + if (params.size() == 2) + denomination = libzerocoin::IntToZerocoinDenomination(params[1].get_int()); + list listMints = walletdb.ListMintedCoins(!fIncludeSpent, false, false); + + UniValue jsonList(UniValue::VARR); + for (const CZerocoinMint mint : listMints) { + if (denomination != libzerocoin::ZQ_ERROR && denomination != mint.GetDenomination()) + continue; + + UniValue objMint(UniValue::VOBJ); + objMint.push_back(Pair("d", mint.GetDenomination())); + objMint.push_back(Pair("p", mint.GetValue().GetHex())); + objMint.push_back(Pair("s", mint.GetSerialNumber().GetHex())); + objMint.push_back(Pair("r", mint.GetRandomness().GetHex())); + objMint.push_back(Pair("t", mint.GetTxHash().GetHex())); + objMint.push_back(Pair("h", mint.GetHeight())); + objMint.push_back(Pair("u", mint.IsUsed())); + jsonList.push_back(objMint); + } + + return jsonList; +} + +UniValue importzerocoins(const UniValue& params, bool fHelp) +{ + if(fHelp || params.size() == 0) + throw runtime_error( + "importzerocoins importdata \n" + "[{\"d\":denomination,\"p\":\"pubcoin_hex\",\"s\":\"serial_hex\",\"r\":\"randomness_hex\",\"t\":\"txid\",\"h\":height, \"u\":used},{\"d\":...}]\n" + "\nImport zerocoin mints.\n" + "Adds raw zerocoin mints to the wallet.dat\n" + "Note it is recommended to use the json export created from the exportzerocoins RPC call\n" + + "\nArguments:\n" + "1. \"importdata\" (string, required) A json array of json objects containing zerocoin mints\n" + + "\nResult:\n" + "\"added\" (int) the quantity of zerocoin mints that were added\n" + "\"value\" (string) the total zBWK value of zerocoin mints that were added\n" + + "\nExamples\n" + + HelpExampleCli("importzerocoins", "\'[{\"d\":100,\"p\":\"mypubcoin\",\"s\":\"myserial\",\"r\":\"randomness_hex\",\"t\":\"mytxid\",\"h\":104923, \"u\":false},{\"d\":5,...}]\'") + + HelpExampleRpc("importzerocoins", "[{\"d\":100,\"p\":\"mypubcoin\",\"s\":\"myserial\",\"r\":\"randomness_hex\",\"t\":\"mytxid\",\"h\":104923, \"u\":false},{\"d\":5,...}]")); + + if(pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + RPCTypeCheck(params, list_of(UniValue::VARR)(UniValue::VOBJ)); + UniValue arrMints = params[0].get_array(); + CWalletDB walletdb(pwalletMain->strWalletFile); + + int count = 0; + CAmount nValue = 0; + for (unsigned int idx = 0; idx < arrMints.size(); idx++) { + const UniValue &val = arrMints[idx]; + const UniValue &o = val.get_obj(); + + const UniValue& vDenom = find_value(o, "d"); + if (!vDenom.isNum()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing d key"); + int d = vDenom.get_int(); + if (d < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, d must be positive"); + + libzerocoin::CoinDenomination denom = libzerocoin::IntToZerocoinDenomination(d); + CBigNum bnValue = CBigNum(find_value(o, "p").get_str()); + CBigNum bnSerial = CBigNum(find_value(o, "s").get_str()); + CBigNum bnRandom = CBigNum(find_value(o, "r").get_str()); + uint256 txid(find_value(o, "t").get_str()); + + int nHeight = find_value(o, "h").get_int(); + if (nHeight < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, h must be positive"); + + bool fUsed = find_value(o, "u").get_bool(); + CZerocoinMint mint(denom, bnValue, bnRandom, bnSerial, fUsed); + mint.SetTxHash(txid); + mint.SetHeight(nHeight); + walletdb.WriteZerocoinMint(mint); + count++; + nValue += libzerocoin::ZerocoinDenominationToAmount(denom); + } + + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("added", count)); + ret.push_back(Pair("value", FormatMoney(nValue))); + return ret; +} + +UniValue reconsiderzerocoins(const UniValue& params, bool fHelp) +{ + if(fHelp || !params.empty()) + throw runtime_error( + "reconsiderzerocoins\n" + "\nCheck archived zBWK list to see if any mints were added to the blockchain.\n" + + "\nResult\n" + "[ (array of json objects)\n" + " {\n" + " \"txid\" : txid, (numeric) the mint's zerocoin denomination \n" + " \"denomination\" : \"denom\", (numeric) the mint's zerocoin denomination\n" + " \"pubcoin\" : \"pubcoin\", (string) The mint's public identifier\n" + " \"height\" : n, (numeric) The height the tx was added to the blockchain\n" + " }\n" + " ,...\n" + "]\n" + + "\nExamples\n" + + HelpExampleCli("reconsiderzerocoins", "") + HelpExampleRpc("reconsiderzerocoins", "")); + + if(pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, + "Error: Please enter the wallet passphrase with walletpassphrase first."); + + list listMints; + pwalletMain->ReconsiderZerocoins(listMints); + + UniValue arrRet(UniValue::VARR); + for (const CZerocoinMint mint : listMints) { + UniValue objMint(UniValue::VOBJ); + objMint.push_back(Pair("txid", mint.GetTxHash().GetHex())); + objMint.push_back(Pair("denomination", FormatMoney(mint.GetDenominationAsAmount()))); + objMint.push_back(Pair("pubcoin", mint.GetValue().GetHex())); + objMint.push_back(Pair("height", mint.GetHeight())); + arrRet.push_back(objMint); + } + + return arrRet; +} diff --git a/src/script/script.cpp b/src/script/script.cpp index b77415b12..9adf5806a 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -150,6 +150,10 @@ const char* GetOpName(opcodetype opcode) case OP_NOP9 : return "OP_NOP9"; case OP_NOP10 : return "OP_NOP10"; + // zerocoin + case OP_ZEROCOINMINT : return "OP_ZEROCOINMINT"; + case OP_ZEROCOINSPEND : return "OP_ZEROCOINSPEND"; + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; // Note: @@ -243,6 +247,19 @@ bool CScript::IsPayToScriptHash() const this->at(22) == OP_EQUAL); } +bool CScript::IsZerocoinMint() const +{ + //fast test for Zerocoin Mint CScripts + return (this->size() > 0 && + this->at(0) == OP_ZEROCOINMINT); +} + +bool CScript::IsZerocoinSpend() const +{ + return (this->size() > 0 && + this->at(0) == OP_ZEROCOINSPEND); +} + bool CScript::IsPushOnly(const_iterator pc) const { while (pc < end()) @@ -280,10 +297,16 @@ std::string CScript::ToString() const str += "[error]"; return str; } - if (0 <= opcode && opcode <= OP_PUSHDATA4) + if (0 <= opcode && opcode <= OP_PUSHDATA4) { str += ValueString(vch); - else + } else { str += GetOpName(opcode); + if (opcode == OP_ZEROCOINSPEND) { + //Zerocoinspend has no further op codes. + break; + } + } + } return str; } diff --git a/src/script/script.h b/src/script/script.h index e2cd45e6e..69c8bb4ec 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -161,6 +161,9 @@ enum opcodetype OP_NOP9 = 0xb8, OP_NOP10 = 0xb9, + // zerocoin + OP_ZEROCOINMINT = 0xc1, + OP_ZEROCOINSPEND = 0xc2, // template matching params OP_SMALLINTEGER = 0xfa, @@ -587,6 +590,8 @@ class CScript : public std::vector bool IsNormalPaymentScript() const; bool IsPayToScriptHash() const; + bool IsZerocoinMint() const; + bool IsZerocoinSpend() const; /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly() const; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 8215031da..65a94991b 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -74,6 +74,8 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash LogPrintf("*** null data \n"); return false; } + case TX_ZEROCOINMINT: + return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); if(!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) @@ -223,6 +225,7 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction { case TX_NONSTANDARD: case TX_NULL_DATA: + case TX_ZEROCOINMINT: // Don't know anything about this, assume bigger one is correct: if (sigs1.size() >= sigs2.size()) return PushAll(sigs1); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 306fa82a2..0f5be297d 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -30,6 +30,7 @@ const char* GetTxnOutputType(txnouttype t) case TX_SCRIPTHASH: return "scripthash"; case TX_MULTISIG: return "multisig"; case TX_NULL_DATA: return "nulldata"; + case TX_ZEROCOINMINT: return "zerocoinmint"; } return NULL; } @@ -63,6 +64,15 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector 150) return false; + vector hashBytes(scriptPubKey.begin()+2, scriptPubKey.end()); + vSolutionsRet.push_back(hashBytes); + return true; + } + // Provably prunable, data-carrying output // // So long as script passes the IsUnspendable() test and all but the first @@ -164,6 +174,7 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector #include #include +#include "libzerocoin/Denominations.h" class CScript; @@ -273,6 +275,8 @@ inline void Serialize(Stream& s, bool a, int, int = 0) char f = a; WRITEDATA(s, f); } + + template inline void Unserialize(Stream& s, bool& a, int, int = 0) { @@ -280,6 +284,23 @@ inline void Unserialize(Stream& s, bool& a, int, int = 0) READDATA(s, f); a = f; } +// Serializatin for libzerocoin::CoinDenomination +inline unsigned int GetSerializeSize(libzerocoin::CoinDenomination a, int, int = 0) { return sizeof(libzerocoin::CoinDenomination); } +template +inline void Serialize(Stream& s, libzerocoin::CoinDenomination a, int, int = 0) +{ + int f = libzerocoin::ZerocoinDenominationToInt(a); + WRITEDATA(s, f); +} + +template +inline void Unserialize(Stream& s, libzerocoin::CoinDenomination& a, int, int = 0) +{ + int f=0; + READDATA(s, f); + a = libzerocoin::IntToZerocoinDenomination(f); +} + /** diff --git a/src/spork.cpp b/src/spork.cpp index a54ff3be9..1a9f27fe5 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -1,5 +1,8 @@ - - +// Copyright (c) 2014-2016 The Dash developers +// Copyright (c) 2016-2017 The PIVX developers +// Copyright (c) 2017-2018 The Bulwark developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "spork.h" #include "base58.h" @@ -9,6 +12,7 @@ #include "net.h" #include "protocol.h" #include "sync.h" +#include "sporkdb.h" #include "util.h" #include @@ -23,6 +27,36 @@ CSporkManager sporkManager; std::map mapSporks; std::map mapSporksActive; +// Bulwark: on startup load spork values from previous session if they exist in the sporkDB +void LoadSporksFromDB() +{ + for (int i = SPORK_START; i <= SPORK_END; ++i) { + // Since not all spork IDs are in use, we have to exclude undefined IDs + std::string strSpork = sporkManager.GetSporkNameByID(i); + if (strSpork == "Unknown") continue; + + // attempt to read spork from sporkDB + CSporkMessage spork; + if (!pSporkDB->ReadSpork(i, spork)) { + LogPrintf("%s : no previous value for %s found in database\n", __func__, strSpork); + continue; + } + + // add spork to memory + mapSporks[spork.GetHash()] = spork; + mapSporksActive[spork.nSporkID] = spork; + std::time_t result = spork.nValue; + // If SPORK Value is greater than 1,000,000 assume it's actually a Date and then convert to a more readable format + if (spork.nValue > 1000000) { + LogPrintf("%s : loaded spork %s with value %d : %s", __func__, + sporkManager.GetSporkNameByID(spork.nSporkID), spork.nValue, + std::ctime(&result)); + } else { + LogPrintf("%s : loaded spork %s with value %d\n", __func__, + sporkManager.GetSporkNameByID(spork.nSporkID), spork.nValue); + } + } +} void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) { @@ -36,6 +70,10 @@ void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) if (chainActive.Tip() == NULL) return; + // Ignore spork messages about unknown/deleted sporks + std::string strSpork = sporkManager.GetSporkNameByID(spork.nSporkID); + if (strSpork == "Unknown") return; + uint256 hash = spork.GetHash(); if (mapSporksActive.count(spork.nSporkID)) { if (mapSporksActive[spork.nSporkID].nTimeSigned >= spork.nTimeSigned) { @@ -60,6 +98,9 @@ void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) //does a task if needed ExecuteSpork(spork.nSporkID, spork.nValue); + + // Bulwark: add to spork database. + pSporkDB->WriteSpork(spork.nSporkID, spork); } if (strCommand == "getsporks") { std::map::iterator it = mapSporksActive.begin(); @@ -70,40 +111,6 @@ void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) } } } - -// grab the spork, otherwise say it's off -bool IsSporkActive(int nSporkID) -{ - int64_t r = -1; - - if (mapSporksActive.count(nSporkID)) { - r = mapSporksActive[nSporkID].nValue; - } else { - if (nSporkID == SPORK_2_SWIFTTX) r = SPORK_2_SWIFTTX_DEFAULT; - if (nSporkID == SPORK_3_SWIFTTX_BLOCK_FILTERING) r = SPORK_3_SWIFTTX_BLOCK_FILTERING_DEFAULT; - if (nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT; - if (nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING_DEFAULT; - if (nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT; - if (nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT; - if (nSporkID == SPORK_10_MASTERNODE_PAY_UPDATED_NODES) r = SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT; - if (nSporkID == SPORK_11_RESET_BUDGET) r = SPORK_11_RESET_BUDGET_DEFAULT; - if (nSporkID == SPORK_12_RECONSIDER_BLOCKS) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT; - if (nSporkID == SPORK_13_ENABLE_SUPERBLOCKS) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT; - if (nSporkID == SPORK_14_NEW_PROTOCOL_ENFORCEMENT) r = SPORK_14_NEW_PROTOCOL_ENFORCEMENT_DEFAULT; - if (nSporkID == SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) r = SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2_DEFAULT; - if (nSporkID == SPORK_16_MN_WINNER_MINIMUM_AGE) r = SPORK_16_MN_WINNER_MINIMUM_AGE_DEFAULT; - if (nSporkID == SPORK_17_NEW_PROTOCOL_ENFORCEMENT_3) r = SPORK_17_NEW_PROTOCOL_ENFORCEMENT_3_DEFAULT; - if (nSporkID == SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4) r = SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4_DEFAULT; - if (nSporkID == SPORK_19_POW_ROLLBACK) r = SPORK_19_POW_ROLLBACK_DEFAULT; - if (nSporkID == SPORK_20_NEW_PROTOCOL_DYNAMIC) r = SPORK_20_NEW_PROTOCOL_DYNAMIC_DEFAULT; - - if (r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID); - } - if (r == -1) r = 4070908800; //return 2099-1-1 by default - - return r < GetTime(); -} - // grab the value of the spork on the network, or the default int64_t GetSporkValue(int nSporkID) { @@ -129,6 +136,8 @@ int64_t GetSporkValue(int nSporkID) if (nSporkID == SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4) r = SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4_DEFAULT; if (nSporkID == SPORK_19_POW_ROLLBACK) r = SPORK_19_POW_ROLLBACK_DEFAULT; if (nSporkID == SPORK_20_NEW_PROTOCOL_DYNAMIC) r = SPORK_20_NEW_PROTOCOL_DYNAMIC_DEFAULT; + if (nSporkID == SPORK_21_ENABLE_ZEROCOIN) r = SPORK_21_ENABLE_ZEROCOIN_DEFAULT; + if (nSporkID == SPORK_22_ZEROCOIN_MAINTENANCE_MODE) r = SPORK_22_ZEROCOIN_MAINTENANCE_MODE_DEFAULT; if (r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID); } @@ -136,6 +145,14 @@ int64_t GetSporkValue(int nSporkID) return r; } +// grab the spork value, and see if it's off +bool IsSporkActive(int nSporkID) +{ + int64_t r = GetSporkValue(nSporkID); + if (r == -1) return false; + return r < GetTime(); +} + void ExecuteSpork(int nSporkID, int nValue) { if (nSporkID == SPORK_11_RESET_BUDGET && nValue == 1) { @@ -181,19 +198,17 @@ void ReprocessBlocks(int nBlocks) } } - bool CSporkManager::CheckSignature(CSporkMessage& spork) { //note: need to investigate why this is failing std::string strMessage = boost::lexical_cast(spork.nSporkID) + boost::lexical_cast(spork.nValue) + boost::lexical_cast(spork.nTimeSigned); - CPubKey pubkey(ParseHex(Params().SporkKey())); - + CPubKey pubkeynew(ParseHex(Params().SporkKey())); std::string errorMessage = ""; - if (!obfuScationSigner.VerifyMessage(pubkey, spork.vchSig, strMessage, errorMessage)) { - return false; + if (obfuScationSigner.VerifyMessage(pubkeynew, spork.vchSig, strMessage, errorMessage)) { + return true; } - return true; + return false; } bool CSporkManager::Sign(CSporkMessage& spork) @@ -281,9 +296,11 @@ int CSporkManager::GetSporkIDByName(std::string strName) if (strName == "SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4") return SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4; if (strName == "SPORK_19_POW_ROLLBACK") return SPORK_19_POW_ROLLBACK; if (strName == "SPORK_20_NEW_PROTOCOL_DYNAMIC") return SPORK_20_NEW_PROTOCOL_DYNAMIC; + if (strName == "SPORK_21_ENABLE_ZEROCOIN") return SPORK_21_ENABLE_ZEROCOIN; + if (strName == "SPORK_22_ZEROCOIN_MAINTENANCE_MODE") return SPORK_22_ZEROCOIN_MAINTENANCE_MODE; return -1; -} +} std::string CSporkManager::GetSporkNameByID(int id) { @@ -301,9 +318,11 @@ std::string CSporkManager::GetSporkNameByID(int id) if (id == SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) return "SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2"; if (id == SPORK_16_MN_WINNER_MINIMUM_AGE) return "SPORK_16_MN_WINNER_MINIMUM_AGE"; if (id == SPORK_17_NEW_PROTOCOL_ENFORCEMENT_3) return "SPORK_17_NEW_PROTOCOL_ENFORCEMENT_3"; - if (id == SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4) return "SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4"; + if (id == SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4) return "SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4"; if (id == SPORK_19_POW_ROLLBACK) return "SPORK_19_POW_ROLLBACK"; if (id == SPORK_20_NEW_PROTOCOL_DYNAMIC) return "SPORK_20_NEW_PROTOCOL_DYNAMIC"; + if (id == SPORK_21_ENABLE_ZEROCOIN) return "SPORK_21_ENABLE_ZEROCOIN"; + if (id == SPORK_22_ZEROCOIN_MAINTENANCE_MODE) return "SPORK_22_ZEROCOIN_MAINTENANCE_MODE"; return "Unknown"; } diff --git a/src/spork.h b/src/spork.h index d53c158fd..49727824d 100644 --- a/src/spork.h +++ b/src/spork.h @@ -1,9 +1,9 @@ - -// Copyright (c) 2009-2012 The Dash developers -// Copyright (c) 2015-2017 The PIVX developers +// Copyright (c) 2014-2016 The Dash developers +// Copyright (c) 2016-2017 The PIVX developers // Copyright (c) 2017-2018 The Bulwark developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef SPORK_H #define SPORK_H @@ -26,7 +26,7 @@ using namespace boost; - This would result in old clients getting confused about which spork is for what */ #define SPORK_START 10001 -#define SPORK_END 10019 +#define SPORK_END 10021 #define SPORK_2_SWIFTTX 10001 #define SPORK_3_SWIFTTX_BLOCK_FILTERING 10002 @@ -45,14 +45,16 @@ using namespace boost; #define SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4 10017 #define SPORK_19_POW_ROLLBACK 10018 #define SPORK_20_NEW_PROTOCOL_DYNAMIC 10019 +#define SPORK_21_ENABLE_ZEROCOIN 10020 +#define SPORK_22_ZEROCOIN_MAINTENANCE_MODE 10021 #define SPORK_2_SWIFTTX_DEFAULT 978307200 //2001-1-1 #define SPORK_3_SWIFTTX_BLOCK_FILTERING_DEFAULT 1424217600 //2015-2-18 -#define SPORK_5_MAX_VALUE_DEFAULT 1000 //1000 BWK +#define SPORK_5_MAX_VALUE_DEFAULT 1000 //1000 PIV #define SPORK_7_MASTERNODE_SCANNING_DEFAULT 978307200 //2001-1-1 -#define SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT 4070908800 //OFF +#define SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT 1531526400 //2018-7-14 #define SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT 4070908800 //OFF -#define SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT 1529804022 //ON +#define SPORK_10_MASTERNODE_PAY_UPDATED_NODES_DEFAULT 1529804022 //2018-6-24 #define SPORK_11_RESET_BUDGET_DEFAULT 0 #define SPORK_12_RECONSIDER_BLOCKS_DEFAULT 0 #define SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT 4070908800 //OFF @@ -62,12 +64,14 @@ using namespace boost; // misconfigured new nodes in the list. // Set this to zero to emulate classic behaviour #define SPORK_17_NEW_PROTOCOL_ENFORCEMENT_3_DEFAULT 1529303404 //ON -#define SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4_DEFAULT 4070908800 //OFF +#define SPORK_18_NEW_PROTOCOL_ENFORCEMENT_4_DEFAULT 1529303404 //ON #define SPORK_19_POW_ROLLBACK_DEFAULT 4070908800 //OFF #define SPORK_20_NEW_PROTOCOL_DYNAMIC_DEFAULT 4070908800 //OFF // Will be whatever value is provided during spork update. // Example `spork SPORK_20_NEW_PROTOCOL_DYNAMIC 70850` will set active // protocol version to `70850`. +#define SPORK_21_ENABLE_ZEROCOIN_DEFAULT 4070908800 //OFF +#define SPORK_22_ZEROCOIN_MAINTENANCE_MODE_DEFAULT 4070908800 //OFF class CSporkMessage; class CSporkManager; @@ -76,6 +80,7 @@ extern std::map mapSporks; extern std::map mapSporksActive; extern CSporkManager sporkManager; +void LoadSporksFromDB(); void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); int64_t GetSporkValue(int nSporkID); bool IsSporkActive(int nSporkID); diff --git a/src/sporkdb.cpp b/src/sporkdb.cpp new file mode 100644 index 000000000..79be1dc7a --- /dev/null +++ b/src/sporkdb.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2017 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 "sporkdb.h" +#include "spork.h" + +CSporkDB::CSporkDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "sporks", nCacheSize, fMemory, fWipe) {} + +bool CSporkDB::WriteSpork(const int nSporkId, const CSporkMessage& spork) +{ + LogPrintf("Wrote spork %s to database\n", sporkManager.GetSporkNameByID(nSporkId)); + return Write(nSporkId, spork); + +} + +bool CSporkDB::ReadSpork(const int nSporkId, CSporkMessage& spork) +{ + return Read(nSporkId, spork); +} + +bool CSporkDB::SporkExists(const int nSporkId) +{ + return Exists(nSporkId); +} diff --git a/src/sporkdb.h b/src/sporkdb.h new file mode 100644 index 000000000..53922dfeb --- /dev/null +++ b/src/sporkdb.h @@ -0,0 +1,28 @@ +// Copyright (c) 2017 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 BULWARK_CSPORKDB_H +#define BULWARK_CSPORKDB_H + +#include +#include "leveldbwrapper.h" +#include "spork.h" + +class CSporkDB : public CLevelDBWrapper +{ +public: + CSporkDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); + +private: + CSporkDB(const CSporkDB&); + void operator=(const CSporkDB&); + +public: + bool WriteSpork(const int nSporkId, const CSporkMessage& spork); + bool ReadSpork(const int nSporkId, CSporkMessage& spork); + bool SporkExists(const int nSporkId); +}; + + +#endif //BULWARK_CSPORKDB_H diff --git a/src/swifttx.cpp b/src/swifttx.cpp index 58b71fd4b..df6d4b3af 100644 --- a/src/swifttx.cpp +++ b/src/swifttx.cpp @@ -1,5 +1,7 @@ - - +// Copyright (c) 2014-2016 The Dash developers +// Copyright (c) 2016-2017 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 "swifttx.h" #include "activemasternode.h" @@ -119,7 +121,7 @@ void ProcessMessageSwiftTX(CNode* pfrom, std::string& strCommand, CDataStream& v return; } - } else if (strCommand == "txlvote") //SwiftTX Lock Consensus Votes + } else if (strCommand == "txlvote") // SwiftX Lock Consensus Votes { CConsensusVote ctx; vRecv >> ctx; @@ -187,12 +189,12 @@ bool IsIXTXValid(const CTransaction& txCollateral) } if (nValueOut > GetSporkValue(SPORK_5_MAX_VALUE) * COIN) { - LogPrint("swifttx", "IsIXTXValid - Transaction value too high - %s\n", txCollateral.ToString().c_str()); + LogPrint("swiftx", "IsIXTXValid - Transaction value too high - %s\n", txCollateral.ToString().c_str()); return false; } if (missingTx) { - LogPrint("swifttx", "IsIXTXValid - Unknown inputs in IX transaction - %s\n", txCollateral.ToString().c_str()); + LogPrint("swiftx", "IsIXTXValid - Unknown inputs in IX transaction - %s\n", txCollateral.ToString().c_str()); /* This happens sometimes for an unknown reason, so we'll return that it's a valid transaction. If someone submits an invalid transaction it will be rejected by the network anyway and this isn't @@ -202,7 +204,7 @@ bool IsIXTXValid(const CTransaction& txCollateral) } if (nValueIn - nValueOut < COIN * 0.01) { - LogPrint("swifttx", "IsIXTXValid - did not include enough fees in transaction %d\n%s\n", nValueOut - nValueIn, txCollateral.ToString().c_str()); + LogPrint("swiftx", "IsIXTXValid - did not include enough fees in transaction %d\n%s\n", nValueOut - nValueIn, txCollateral.ToString().c_str()); return false; } @@ -239,7 +241,7 @@ int64_t CreateNewLock(CTransaction tx) mapTxLocks.insert(make_pair(tx.GetHash(), newLock)); } else { mapTxLocks[tx.GetHash()].nBlockHeight = nBlockHeight; - LogPrint("swifttx", "CreateNewLock - Transaction Lock Exists %s !\n", tx.GetHash().ToString().c_str()); + LogPrint("swiftx", "CreateNewLock - Transaction Lock Exists %s !\n", tx.GetHash().ToString().c_str()); } @@ -254,30 +256,30 @@ void DoConsensusVote(CTransaction& tx, int64_t nBlockHeight) int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight, MIN_SWIFTTX_PROTO_VERSION); if (n == -1) { - LogPrint("swifttx", "SwiftTX::DoConsensusVote - Unknown Masternode\n"); + LogPrint("swiftx", "SwiftX::DoConsensusVote - Unknown Masternode\n"); return; } if (n > SWIFTTX_SIGNATURES_TOTAL) { - LogPrint("swifttx", "SwiftTX::DoConsensusVote - Masternode not in the top %d (%d)\n", SWIFTTX_SIGNATURES_TOTAL, n); + LogPrint("swiftx", "SwiftX::DoConsensusVote - Masternode not in the top %d (%d)\n", SWIFTTX_SIGNATURES_TOTAL, n); return; } /* nBlockHeight calculated from the transaction is the authoritive source */ - LogPrint("swifttx", "SwiftTX::DoConsensusVote - In the top %d (%d)\n", SWIFTTX_SIGNATURES_TOTAL, n); + LogPrint("swiftx", "SwiftX::DoConsensusVote - In the top %d (%d)\n", SWIFTTX_SIGNATURES_TOTAL, n); CConsensusVote ctx; ctx.vinMasternode = activeMasternode.vin; ctx.txHash = tx.GetHash(); ctx.nBlockHeight = nBlockHeight; if (!ctx.Sign()) { - LogPrintf("SwiftTX::DoConsensusVote - Failed to sign consensus vote\n"); + LogPrintf("SwiftX::DoConsensusVote - Failed to sign consensus vote\n"); return; } if (!ctx.SignatureValid()) { - LogPrintf("SwiftTX::DoConsensusVote - Signature invalid\n"); + LogPrintf("SwiftX::DoConsensusVote - Signature invalid\n"); return; } @@ -294,29 +296,29 @@ bool ProcessConsensusVote(CNode* pnode, CConsensusVote& ctx) CMasternode* pmn = mnodeman.Find(ctx.vinMasternode); if (pmn != NULL) - LogPrint("swifttx", "SwiftTX::ProcessConsensusVote - Masternode ADDR %s %d\n", pmn->addr.ToString().c_str(), n); + LogPrint("swiftx", "SwiftX::ProcessConsensusVote - Masternode ADDR %s %d\n", pmn->addr.ToString().c_str(), n); if (n == -1) { //can be caused by past versions trying to vote with an invalid protocol - LogPrint("swifttx", "SwiftTX::ProcessConsensusVote - Unknown Masternode\n"); + LogPrint("swiftx", "SwiftX::ProcessConsensusVote - Unknown Masternode\n"); mnodeman.AskForMN(pnode, ctx.vinMasternode); return false; } if (n > SWIFTTX_SIGNATURES_TOTAL) { - LogPrint("swifttx", "SwiftTX::ProcessConsensusVote - Masternode not in the top %d (%d) - %s\n", SWIFTTX_SIGNATURES_TOTAL, n, ctx.GetHash().ToString().c_str()); + LogPrint("swiftx", "SwiftX::ProcessConsensusVote - Masternode not in the top %d (%d) - %s\n", SWIFTTX_SIGNATURES_TOTAL, n, ctx.GetHash().ToString().c_str()); return false; } if (!ctx.SignatureValid()) { - LogPrintf("SwiftTX::ProcessConsensusVote - Signature invalid\n"); + LogPrintf("SwiftX::ProcessConsensusVote - Signature invalid\n"); // don't ban, it could just be a non-synced masternode mnodeman.AskForMN(pnode, ctx.vinMasternode); return false; } if (!mapTxLocks.count(ctx.txHash)) { - LogPrintf("SwiftTX::ProcessConsensusVote - New Transaction Lock %s !\n", ctx.txHash.ToString().c_str()); + LogPrintf("SwiftX::ProcessConsensusVote - New Transaction Lock %s !\n", ctx.txHash.ToString().c_str()); CTransactionLock newLock; newLock.nBlockHeight = 0; @@ -325,7 +327,7 @@ bool ProcessConsensusVote(CNode* pnode, CConsensusVote& ctx) newLock.txHash = ctx.txHash; mapTxLocks.insert(make_pair(ctx.txHash, newLock)); } else - LogPrint("swifttx", "SwiftTX::ProcessConsensusVote - Transaction Lock Exists %s !\n", ctx.txHash.ToString().c_str()); + LogPrint("swiftx", "SwiftX::ProcessConsensusVote - Transaction Lock Exists %s !\n", ctx.txHash.ToString().c_str()); //compile consessus vote std::map::iterator i = mapTxLocks.find(ctx.txHash); @@ -340,10 +342,10 @@ bool ProcessConsensusVote(CNode* pnode, CConsensusVote& ctx) } #endif - LogPrint("swifttx", "SwiftTX::ProcessConsensusVote - Transaction Lock Votes %d - %s !\n", (*i).second.CountSignatures(), ctx.GetHash().ToString().c_str()); + LogPrint("swiftx", "SwiftX::ProcessConsensusVote - Transaction Lock Votes %d - %s !\n", (*i).second.CountSignatures(), ctx.GetHash().ToString().c_str()); if ((*i).second.CountSignatures() >= SWIFTTX_SIGNATURES_REQUIRED) { - LogPrint("swifttx", "SwiftTX::ProcessConsensusVote - Transaction Lock Is Complete %s !\n", (*i).second.GetHash().ToString().c_str()); + LogPrint("swiftx", "SwiftX::ProcessConsensusVote - Transaction Lock Is Complete %s !\n", (*i).second.GetHash().ToString().c_str()); CTransaction& tx = mapTxLockReq[ctx.txHash]; if (!CheckForConflictingLocks(tx)) { @@ -391,7 +393,7 @@ bool CheckForConflictingLocks(CTransaction& tx) BOOST_FOREACH (const CTxIn& in, tx.vin) { if (mapLockedInputs.count(in.prevout)) { if (mapLockedInputs[in.prevout] != tx.GetHash()) { - LogPrintf("SwiftTX::CheckForConflictingLocks - found two complete conflicting locks - removing both. %s %s", tx.GetHash().ToString().c_str(), mapLockedInputs[in.prevout].ToString().c_str()); + LogPrintf("SwiftX::CheckForConflictingLocks - found two complete conflicting locks - removing both. %s %s", tx.GetHash().ToString().c_str(), mapLockedInputs[in.prevout].ToString().c_str()); if (mapTxLocks.count(tx.GetHash())) mapTxLocks[tx.GetHash()].nExpiration = GetTime(); if (mapTxLocks.count(mapLockedInputs[in.prevout])) mapTxLocks[mapLockedInputs[in.prevout]].nExpiration = GetTime(); return true; @@ -462,12 +464,12 @@ bool CConsensusVote::SignatureValid() CMasternode* pmn = mnodeman.Find(vinMasternode); if (pmn == NULL) { - LogPrintf("SwiftTX::CConsensusVote::SignatureValid() - Unknown Masternode\n"); + LogPrintf("SwiftX::CConsensusVote::SignatureValid() - Unknown Masternode\n"); return false; } if (!obfuScationSigner.VerifyMessage(pmn->pubKeyMasternode, vchMasterNodeSignature, strMessage, errorMessage)) { - LogPrintf("SwiftTX::CConsensusVote::SignatureValid() - Verify message failed\n"); + LogPrintf("SwiftX::CConsensusVote::SignatureValid() - Verify message failed\n"); return false; } diff --git a/src/swifttx.h b/src/swifttx.h index 4e2039fd8..d89e83667 100644 --- a/src/swifttx.h +++ b/src/swifttx.h @@ -1,9 +1,9 @@ - // Copyright (c) 2009-2012 The Dash developers // Copyright (c) 2015-2017 The PIVX developers // Copyright (c) 2017-2018 The Bulwark developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. + #ifndef SWIFTTX_H #define SWIFTTX_H @@ -17,7 +17,7 @@ /* At 15 signatures, 1/2 of the masternode network can be owned by - one party without comprimising the security of SwiftTX + one party without comprimising the security of SwiftX (1000/2150.0)**10 = 0.00047382219560689856 (1000/2900.0)**10 = 2.3769498616783657e-05 diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index e495435b8..3b997d039 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -16,23 +16,20 @@ #include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" -using namespace json_spirit; -extern Array read_json(const std::string& jsondata); +#include + +extern UniValue read_json(const std::string& jsondata); BOOST_AUTO_TEST_SUITE(base58_tests) // Goal: test low-level base58 encoding functionality BOOST_AUTO_TEST_CASE(base58_EncodeBase58) { - Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode))); - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode))); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 2) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -49,13 +46,12 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58) // Goal: test low-level base58 decoding functionality BOOST_AUTO_TEST_CASE(base58_DecodeBase58) { - Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode))); + UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode))); std::vector result; - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 2) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -123,15 +119,14 @@ class TestPayloadVisitor : public boost::static_visitor // Goal: check that parsed keys match test payload BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) { - Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); + UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); std::vector result; CBitcoinSecret secret; CBitcoinAddress addr; - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 3) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -139,7 +134,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) } std::string exp_base58string = test[0].get_str(); std::vector exp_payload = ParseHex(test[1].get_str()); - const Object &metadata = test[2].get_obj(); + const UniValue &metadata = test[2].get_obj(); bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); bool isTestnet = find_value(metadata, "isTestnet").get_bool(); if (isTestnet) @@ -182,12 +177,12 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) // Goal: check that generated keys match test vectors BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) { - Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); + UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid))); std::vector result; - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + + for (unsigned int idx = 0; idx < tests.size(); idx++) { + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 3) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -195,7 +190,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) } std::string exp_base58string = test[0].get_str(); std::vector exp_payload = ParseHex(test[1].get_str()); - const Object &metadata = test[2].get_obj(); + const UniValue &metadata = test[2].get_obj(); bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); bool isTestnet = find_value(metadata, "isTestnet").get_bool(); if (isTestnet) @@ -250,15 +245,14 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) // Goal: check that base58 parsing code is robust against a variety of corrupted data BOOST_AUTO_TEST_CASE(base58_keys_invalid) { - Array tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases + UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases std::vector result; CBitcoinSecret secret; CBitcoinAddress addr; - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 1) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); diff --git a/src/test/benchmark_zerocoin.cpp b/src/test/benchmark_zerocoin.cpp new file mode 100644 index 000000000..9899b2071 --- /dev/null +++ b/src/test/benchmark_zerocoin.cpp @@ -0,0 +1,414 @@ +/** + * @file Benchmark.cpp + * + * @brief Benchmarking tests for Zerocoin. + * + * @author Ian Miers, Christina Garman and Matthew Green + * @date June 2013 + * + * @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green + * @license This project is released under the MIT license. + **/ + + +#include +#include +#include +#include +// #include +#include +#include +#include +#include "streams.h" +#include "libzerocoin/ParamGeneration.h" +#include "libzerocoin/Denominations.h" +#include "libzerocoin/Coin.h" +#include "libzerocoin/CoinSpend.h" +#include "libzerocoin/Accumulator.h" + +using namespace std; +using namespace libzerocoin; + +#define COLOR_STR_GREEN "\033[32m" +#define COLOR_STR_NORMAL "\033[0m" +#define COLOR_STR_RED "\033[31m" + +#define TESTS_COINS_TO_ACCUMULATE 50 + +// Global test counters +uint32_t ggNumTests = 0; +uint32_t ggSuccessfulTests = 0; + +// Global coin array +PrivateCoin *ggCoins[TESTS_COINS_TO_ACCUMULATE]; + +// Global params +ZerocoinParams *gg_Params; + +////////// +// Utility routines +////////// + +class Timer +{ + timeval timer[2]; + +public: + + timeval start() + { + gettimeofday(&this->timer[0], NULL); + return this->timer[0]; + } + + timeval stop() + { + gettimeofday(&this->timer[1], NULL); + return this->timer[1]; + } + + int duration() const + { + int secs(this->timer[1].tv_sec - this->timer[0].tv_sec); + int usecs(this->timer[1].tv_usec - this->timer[0].tv_usec); + + if(usecs < 0) + { + --secs; + usecs += 1000000; + } + + return static_cast(secs * 1000 + usecs / 1000.0 + 0.5); + } +}; + +// Global timer +Timer timer; + +void +gLogTestResult(string testName, bool (*testPtr)()) +{ + string colorGreen(COLOR_STR_GREEN); + string colorNormal(COLOR_STR_NORMAL); + string colorRed(COLOR_STR_RED); + + cout << "Testing if " << testName << "..." << endl; + + bool testResult = testPtr(); + + if (testResult == true) { + cout << "\t" << colorGreen << "[PASS]" << colorNormal << endl; + ggSuccessfulTests++; + } else { + cout << colorRed << "\t[FAIL]" << colorNormal << endl; + } + + ggNumTests++; +} + +CBigNum +gGetTestModulus() +{ + static CBigNum testModulus(0); + + // TODO: should use a hard-coded RSA modulus for testing + if (!testModulus) { + CBigNum p, q; + p = CBigNum::generatePrime(1024, false); + q = CBigNum::generatePrime(1024, false); + testModulus = p * q; + } + + return testModulus; +} + +////////// +// Test routines +////////// + + +bool +Testb_GenRSAModulus() +{ + CBigNum result = gGetTestModulus(); + + if (!result) { + return false; + } + else { + return true; + } +} + +bool +Testb_CalcParamSizes() +{ + 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; + } +#endif + + return result; +} + +bool +Testb_GenerateGroupParams() +{ + uint32_t pLen = 1024, qLen = 256, count; + IntegerGroupParams group; + + for (count = 0; count < 1; count++) { + + try { + group = deriveIntegerGroupParams(calculateSeed(gGetTestModulus(), "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; + } + + 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; + } + + return true; +} + +bool +Testb_ParamGen() +{ + bool result = true; + + try { + timer.start(); + // Instantiating testParams runs the parameter generation code + ZerocoinParams testParams(gGetTestModulus(),ZEROCOIN_DEFAULT_SECURITYLEVEL); + timer.stop(); + + cout << "\tPARAMGEN ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; + } catch (runtime_error e) { + cout << e.what() << endl; + result = false; + } + + return result; +} + +bool +Testb_Accumulator() +{ + // This test assumes a list of coins were generated during + // the Testb_MintCoin() test. + if (ggCoins[0] == NULL) { + return false; + } + try { + // Accumulate the coin list from first to last into one accumulator + Accumulator accOne(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE); + Accumulator accTwo(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE); + Accumulator accThree(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE); + Accumulator accFour(&gg_Params->accumulatorParams,libzerocoin::CoinDenomination::ZQ_ONE); + AccumulatorWitness wThree(gg_Params, accThree, ggCoins[0]->getPublicCoin()); + + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + accOne += ggCoins[i]->getPublicCoin(); + accTwo += ggCoins[TESTS_COINS_TO_ACCUMULATE - (i+1)]->getPublicCoin(); + accThree += ggCoins[i]->getPublicCoin(); + wThree += ggCoins[i]->getPublicCoin(); + if(i != 0) { + accFour += ggCoins[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, ggCoins[0]->getPublicCoin()) ) { + cout << "Witness not valid" << endl; + return false; + } + + } catch (runtime_error e) { + cout << e.what() << endl; + return false; + } + + return true; +} + +bool +Testb_MintCoin() +{ + try { + // Generate a list of coins + timer.start(); + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + ggCoins[i] = new PrivateCoin(gg_Params,CoinDenomination::ZQ_ONE); + } + timer.stop(); + } catch (exception &e) { + return false; + } + + cout << "\tMINT ELAPSED TIME:\n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Coin: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl; + + return true; +} + +bool +Testb_MintAndSpend() +{ + try { + // This test assumes a list of coins were generated in Testb_MintCoin() + if (ggCoins[0] == NULL) + { + // No coins: mint some. + Testb_MintCoin(); + if (ggCoins[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(&gg_Params->accumulatorParams,CoinDenomination::ZQ_ONE); + AccumulatorWitness wAcc(gg_Params, acc, ggCoins[0]->getPublicCoin()); + + timer.start(); + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + acc += ggCoins[i]->getPublicCoin(); + } + timer.stop(); + + cout << "\tACCUMULATOR ELAPSED TIME:\n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Element: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl; + + timer.start(); + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + wAcc +=ggCoins[i]->getPublicCoin(); + } + timer.stop(); + + cout << "\tWITNESS ELAPSED TIME: \n\t\tTotal: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s\n\t\tPer Element: " << timer.duration()/TESTS_COINS_TO_ACCUMULATE << " ms\t" << (timer.duration()/TESTS_COINS_TO_ACCUMULATE)*0.001 << " s" << endl; + + // Now spend the coin + timer.start(); + CoinSpend spend(gg_Params, *(ggCoins[0]), acc, 0, wAcc, 0); //(0) presstab + timer.stop(); + + cout << "\tSPEND ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; + + // Serialize the proof and deserialize into newSpend + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + + timer.start(); + ss << spend; + timer.stop(); + + CoinSpend newSpend(gg_Params, ss); + + cout << "\tSERIALIZE ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; + + // Finally, see if we can verify the deserialized proof (return our result) + timer.start(); + bool ret = newSpend.Verify(acc); + timer.stop(); + + cout << "\tSPEND VERIFY ELAPSED TIME: " << timer.duration() << " ms\t" << timer.duration()*0.001 << " s" << endl; + + return ret; + } catch (runtime_error &e) { + cout << e.what() << endl; + return false; + } + + return false; +} + +void +Testb_RunAllTests() +{ + // Make a new set of parameters from a random RSA modulus + gg_Params = new ZerocoinParams(gGetTestModulus()); + + ggNumTests = ggSuccessfulTests = 0; + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + ggCoins[i] = NULL; + } + + // Run through all of the Zerocoin tests + gLogTestResult("an RSA modulus can be generated", Testb_GenRSAModulus); + gLogTestResult("parameter sizes are correct", Testb_CalcParamSizes); + gLogTestResult("group/field parameters can be generated", Testb_GenerateGroupParams); + gLogTestResult("parameter generation is correct", Testb_ParamGen); + gLogTestResult("coins can be minted", Testb_MintCoin); + gLogTestResult("the accumulator works", Testb_Accumulator); + gLogTestResult("a minted coin can be spent", Testb_MintAndSpend); + + // Summarize test results + if (ggSuccessfulTests < ggNumTests) { + cout << endl << "ERROR: SOME TESTS FAILED" << endl; + } + + // Clear any generated coins + for (uint32_t i = 0; i < TESTS_COINS_TO_ACCUMULATE; i++) { + delete ggCoins[i]; + } + + cout << ggSuccessfulTests << " out of " << ggNumTests << " tests passed." << endl << endl; + delete gg_Params; +} +BOOST_AUTO_TEST_SUITE(benchmark_zerocoin) + +BOOST_AUTO_TEST_CASE(benchmark_test) +{ + cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " benchmark utility." << endl << endl; + + Testb_RunAllTests(); +} +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/test/libzerocoin_tests.cpp b/src/test/libzerocoin_tests.cpp new file mode 100644 index 000000000..b8ae55c82 --- /dev/null +++ b/src/test/libzerocoin_tests.cpp @@ -0,0 +1,492 @@ +/** +* @file Tests.cpp +* +* @brief Test routines for Zerocoin. +* +* @author Ian Miers, Christina Garman and Matthew Green +* @date June 2013 +* +* @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green +* @license This project is released under the MIT license. +**/ + +#include +#include +#include +#include +#include +// #include +#include +#include "streams.h" +#include "libzerocoin/ParamGeneration.h" +#include "libzerocoin/Denominations.h" +#include "libzerocoin/Coin.h" +#include "libzerocoin/CoinSpend.h" +#include "libzerocoin/Accumulator.h" + +using namespace std; +using namespace libzerocoin; + +#define COLOR_STR_GREEN "\033[32m" +#define COLOR_STR_NORMAL "\033[0m" +#define COLOR_STR_RED "\033[31m" + +#define TESTS_COINS_TO_ACCUMULATE 10 +#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; + +// Global coin array +PrivateCoin *gCoins[TESTS_COINS_TO_ACCUMULATE]; + +// Global params +ZerocoinParams *g_Params; + +////////// +// Utility routines +////////// + +void +LogTestResult(string testName, bool (*testPtr)()) +{ + string colorGreen(COLOR_STR_GREEN); + string colorNormal(COLOR_STR_NORMAL); + string colorRed(COLOR_STR_RED); + + cout << "Testing if " << testName << "..." << endl; + + bool testResult = testPtr(); + + if (testResult == true) { + cout << "\t" << colorGreen << "[PASS]" << colorNormal << endl; + gSuccessfulTests++; + } else { + cout << colorRed << "\t[FAIL]" << colorNormal << endl; + } + + gNumTests++; +} + +CBigNum +GetTestModulus() +{ + static CBigNum testModulus(0); + + // 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; + } + + return testModulus; +} + +////////// +// Test routines +////////// + +bool +Test_GenRSAModulus() +{ + CBigNum result = GetTestModulus(); + + if (!result) { + return false; + } + else { + return true; + } +} + +bool +Test_CalcParamSizes() +{ + 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; + } +#endif + + return result; +} + +bool +Test_GenerateGroupParams() +{ + uint32_t pLen = 1024, qLen = 256, count; + IntegerGroupParams group; + + 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; + } + + // 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; + + // Try at multiple parameter sizes + pLen = pLen * 1.5; + qLen = qLen * 1.5; + } + + return true; +} + +bool +Test_ParamGen() +{ + 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; + } + + 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 + 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; +} + +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; +} + +bool +Test_MintCoin() +{ + gCoinSize = 0; + + 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(); + } + + gCoinSize /= TESTS_COINS_TO_ACCUMULATE; + + } catch (exception &e) { + return false; + } + + 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; +} + +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. + Accumulator acc(&g_Params->accumulatorParams,CoinDenomination::ZQ_ONE); + 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(); + } + + // 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, myCoin, acc, 0, wAcc, 0); + + // Serialize the proof and deserialize into newSpend + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << spend; + gProofSize = ss.size(); + CoinSpend newSpend(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; +} + +BOOST_AUTO_TEST_SUITE(libzerocoin) +BOOST_AUTO_TEST_CASE(libzerocoin_tests) +{ + cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " test utility." << endl << endl; + + Test_RunAllTests(); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 0e65e1dbb..11a3e88b5 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -11,36 +11,36 @@ #include #include +#include + using namespace std; -using namespace json_spirit; -Array +UniValue createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL) { - Array result; + UniValue result(UniValue::VARR); result.push_back(nRequired); - Array addresses; + UniValue addresses(UniValue::VARR); if (address1) addresses.push_back(address1); if (address2) addresses.push_back(address2); result.push_back(addresses); return result; } -Value CallRPC(string args) +UniValue CallRPC(string args) { vector vArgs; boost::split(vArgs, args, boost::is_any_of(" \t")); string strMethod = vArgs[0]; vArgs.erase(vArgs.begin()); - Array params = RPCConvertValues(strMethod, vArgs); + UniValue params = RPCConvertValues(strMethod, vArgs); rpcfn_type method = tableRPC[strMethod]->actor; try { - Value result = (*method)(params, false); + UniValue result = (*method)(params, false); return result; } - catch (Object& objError) - { + catch (const UniValue& objError) { throw runtime_error(find_value(objError, "message").get_str()); } } @@ -51,7 +51,7 @@ BOOST_AUTO_TEST_SUITE(rpc_tests) BOOST_AUTO_TEST_CASE(rpc_rawparams) { // Test raw transaction API argument handling - Value r; + UniValue r; BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error); BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error); @@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams) BOOST_AUTO_TEST_CASE(rpc_rawsign) { - Value r; + UniValue r; // input is a 1-of-2 multisig (so is output): string prevout = "[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\"," @@ -110,20 +110,43 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) BOOST_AUTO_TEST_CASE(rpc_format_monetary_values) { - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(0LL), false), "0.00000000"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(1LL), false), "0.00000001"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(17622195LL), false), "0.17622195"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(50000000LL), false), "0.50000000"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(89898989LL), false), "0.89898989"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(100000000LL), false), "1.00000000"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999990LL), false), "20999999.99999990"); - BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999999LL), false), "20999999.99999999"); + BOOST_CHECK(ValueFromAmount(0LL).write() == "0.00000000"); + BOOST_CHECK(ValueFromAmount(1LL).write() == "0.00000001"); + BOOST_CHECK(ValueFromAmount(17622195LL).write() == "0.17622195"); + BOOST_CHECK(ValueFromAmount(50000000LL).write() == "0.50000000"); + BOOST_CHECK(ValueFromAmount(89898989LL).write() == "0.89898989"); + BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000"); + BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990"); + BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999"); + + BOOST_CHECK_EQUAL(ValueFromAmount(0).write(), "0.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount((COIN/10000)*123456789).write(), "12345.67890000"); + BOOST_CHECK_EQUAL(ValueFromAmount(-COIN).write(), "-1.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(-COIN/10).write(), "-0.10000000"); + + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000000).write(), "100000000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000000).write(), "10000000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000000).write(), "1000000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000).write(), "100000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000).write(), "10000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000).write(), "1000.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100).write(), "100.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10).write(), "10.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN).write(), "1.00000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10).write(), "0.10000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100).write(), "0.01000000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000).write(), "0.00100000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000).write(), "0.00010000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000).write(), "0.00001000"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000000).write(), "0.00000100"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000000).write(), "0.00000010"); + BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000000).write(), "0.00000001"); } -static Value ValueFromString(const std::string &str) +static UniValue ValueFromString(const std::string &str) { - Value value; - BOOST_CHECK(read_string(str, value)); + UniValue value; + BOOST_CHECK(value.setNumStr(str)); return value; } @@ -141,20 +164,20 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values) BOOST_AUTO_TEST_CASE(json_parse_errors) { - Value value; // Valid - BOOST_CHECK_EQUAL(read_string(std::string("1.0"), value), true); - // Valid, with trailing whitespace - BOOST_CHECK_EQUAL(read_string(std::string("1.0 "), value), true); + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0); + // Valid, with leading or trailing whitespace + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0); + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0); // Invalid, initial garbage - BOOST_CHECK_EQUAL(read_string(std::string("[1.0"), value), false); - BOOST_CHECK_EQUAL(read_string(std::string("a1.0"), value), false); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error); // Invalid, trailing garbage - BOOST_CHECK_EQUAL(read_string(std::string("1.0sds"), value), false); - BOOST_CHECK_EQUAL(read_string(std::string("1.0]"), value), false); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error); // BTC addresses should fail parsing - BOOST_CHECK_EQUAL(read_string(std::string("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), value), false); - BOOST_CHECK_EQUAL(read_string(std::string("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), value), false); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error); } BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr) diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 91da0c442..f4c4c5a85 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -11,11 +11,12 @@ #include #include +#include + using namespace std; -using namespace json_spirit; -extern Array createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL); -extern Value CallRPC(string args); +extern UniValue createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL); +extern UniValue CallRPC(string args); extern CWallet* pwalletMain; @@ -32,7 +33,7 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig) // new, compressed: const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4"; - Value v; + UniValue v; CBitcoinAddress address; BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false)); address.SetString(v.get_str()); @@ -63,13 +64,13 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig) BOOST_AUTO_TEST_CASE(rpc_wallet) { // Test RPC calls for various wallet statistics - Value r; + UniValue r; LOCK2(cs_main, pwalletMain->cs_wallet); CPubKey demoPubkey = pwalletMain->GenerateNewKey(); CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID())); - Value retValue; + UniValue retValue; string strAccount = "walletDemoAccount"; string strPurpose = "receive"; BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */ @@ -174,10 +175,9 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) *********************************/ BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error); BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount)); - Array arr = retValue.get_array(); + UniValue arr = retValue.get_array(); BOOST_CHECK(arr.size() > 0); BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get()); } - BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index a084a145c..6fbedad2b 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -31,12 +31,10 @@ #include #include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" + +#include using namespace std; -using namespace json_spirit; using namespace boost::algorithm; // Uncomment if you want to output updated JSON tests. @@ -47,15 +45,15 @@ static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; unsigned int ParseScriptFlags(string strFlags); string FormatScriptFlags(unsigned int flags); -Array +UniValue read_json(const std::string& jsondata) { - Value v; + UniValue v; - if (!read_string(jsondata, v) || v.type() != array_type) + if (!v.read(jsondata) || !v.isArray()) { BOOST_ERROR("Parse error."); - return Array(); + return UniValue(UniValue::VARR); } return v.get_array(); } @@ -303,10 +301,10 @@ class TestBuilder return *this; } - Array GetJSON() + UniValue GetJSON() { DoPush(); - Array array; + UniValue array(UniValue::VARR); array.push_back(FormatScript(spendTx.vin[0].scriptSig)); array.push_back(FormatScript(creditTx.vout[0].scriptPubKey)); array.push_back(FormatScriptFlags(flags)); @@ -568,14 +566,16 @@ BOOST_AUTO_TEST_CASE(script_build) std::set tests_bad; { - Array json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid))); - Array json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); + UniValue json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid))); + UniValue json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); - BOOST_FOREACH(Value& tv, json_good) { - tests_good.insert(write_string(Value(tv.get_array()), true)); + for (unsigned int idx = 0; idx < json_good.size(); idx++) { + const UniValue& tv = json_good[idx]; + tests_good.insert(tv.get_array().write()); } - BOOST_FOREACH(Value& tv, json_bad) { - tests_bad.insert(write_string(Value(tv.get_array()), true)); + for (unsigned int idx = 0; idx < json_bad.size(); idx++) { + const UniValue& tv = json_bad[idx]; + tests_bad.insert(tv.get_array().write()); } } @@ -584,7 +584,7 @@ BOOST_AUTO_TEST_CASE(script_build) BOOST_FOREACH(TestBuilder& test, good) { test.Test(true); - std::string str = write_string(Value(test.GetJSON()), true); + std::string str = test.GetJSON().write(); #ifndef UPDATE_JSON_TESTS if (tests_good.count(str) == 0) { BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment()); @@ -594,7 +594,7 @@ BOOST_AUTO_TEST_CASE(script_build) } BOOST_FOREACH(TestBuilder& test, bad) { test.Test(false); - std::string str = write_string(Value(test.GetJSON()), true); + std::string str = test.GetJSON().write(); #ifndef UPDATE_JSON_TESTS if (tests_bad.count(str) == 0) { BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment()); @@ -620,12 +620,11 @@ BOOST_AUTO_TEST_CASE(script_valid) // Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ] // ... where scriptSig and scriptPubKey are stringified // scripts. - Array tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid))); + UniValue tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid))); - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + UniValue test = tests[idx]; + string strTest = test.write(); if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments) { if (test.size() != 1) { @@ -646,12 +645,11 @@ BOOST_AUTO_TEST_CASE(script_valid) BOOST_AUTO_TEST_CASE(script_invalid) { // Scripts that should evaluate as invalid - Array tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); + UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + UniValue test = tests[idx]; + string strTest = test.write(); if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments) { if (test.size() != 1) { diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp index 5621e1272..ddb4cc45e 100644 --- a/src/test/scriptnum_tests.cpp +++ b/src/test/scriptnum_tests.cpp @@ -2,23 +2,23 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "bignum.h" +#include "libzerocoin/bignum.h" #include "script/script.h" #include #include #include BOOST_AUTO_TEST_SUITE(scriptnum_tests) -static const int64_t values[] = \ +static const long values[] = \ { 0, 1, CHAR_MIN, CHAR_MAX, UCHAR_MAX, SHRT_MIN, USHRT_MAX, INT_MIN, INT_MAX, UINT_MAX, LONG_MIN, LONG_MAX }; -static const int64_t offsets[] = { 1, 0x79, 0x80, 0x81, 0xFF, 0x7FFF, 0x8000, 0xFFFF, 0x10000}; +static const long offsets[] = { 1, 0x79, 0x80, 0x81, 0xFF, 0x7FFF, 0x8000, 0xFFFF, 0x10000}; static bool verify(const CBigNum& bignum, const CScriptNum& scriptnum) { return bignum.getvch() == scriptnum.getvch() && bignum.getint() == scriptnum.getint(); } -static void CheckCreateVch(const int64_t& num) +static void CheckCreateVch(const long& num) { CBigNum bignum(num); CScriptNum scriptnum(num); @@ -33,7 +33,7 @@ static void CheckCreateVch(const int64_t& num) BOOST_CHECK(verify(bignum3, scriptnum3)); } -static void CheckCreateInt(const int64_t& num) +static void CheckCreateInt(const long& num) { CBigNum bignum(num); CScriptNum scriptnum(num); @@ -44,7 +44,7 @@ static void CheckCreateInt(const int64_t& num) } -static void CheckAdd(const int64_t& num1, const int64_t& num2) +static void CheckAdd(const long& num1, const long& num2) { const CBigNum bignum1(num1); const CBigNum bignum2(num2); @@ -56,8 +56,8 @@ static void CheckAdd(const int64_t& num1, const int64_t& num2) CScriptNum scriptnum4(num1); // int64_t overflow is undefined. - bool invalid = (((num2 > 0) && (num1 > (std::numeric_limits::max() - num2))) || - ((num2 < 0) && (num1 < (std::numeric_limits::min() - num2)))); + bool invalid = (((num2 > 0) && (num1 > (std::numeric_limits::max() - num2))) || + ((num2 < 0) && (num1 < (std::numeric_limits::min() - num2)))); if (!invalid) { BOOST_CHECK(verify(bignum1 + bignum2, scriptnum1 + scriptnum2)); @@ -66,17 +66,17 @@ static void CheckAdd(const int64_t& num1, const int64_t& num2) } } -static void CheckNegate(const int64_t& num) +static void CheckNegate(const long& num) { const CBigNum bignum(num); const CScriptNum scriptnum(num); // -INT64_MIN is undefined - if (num != std::numeric_limits::min()) + if (num != std::numeric_limits::min()) BOOST_CHECK(verify(-bignum, -scriptnum)); } -static void CheckSubtract(const int64_t& num1, const int64_t& num2) +static void CheckSubtract(const long& num1, const long& num2) { const CBigNum bignum1(num1); const CBigNum bignum2(num2); @@ -85,16 +85,16 @@ static void CheckSubtract(const int64_t& num1, const int64_t& num2) bool invalid = false; // int64_t overflow is undefined. - invalid = ((num2 > 0 && num1 < std::numeric_limits::min() + num2) || - (num2 < 0 && num1 > std::numeric_limits::max() + num2)); + invalid = ((num2 > 0 && num1 < std::numeric_limits::min() + num2) || + (num2 < 0 && num1 > std::numeric_limits::max() + num2)); if (!invalid) { BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - scriptnum2)); BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - num2)); } - invalid = ((num1 > 0 && num2 < std::numeric_limits::min() + num1) || - (num1 < 0 && num2 > std::numeric_limits::max() + num1)); + invalid = ((num1 > 0 && num2 < std::numeric_limits::min() + num1) || + (num1 < 0 && num2 > std::numeric_limits::max() + num1)); if (!invalid) { BOOST_CHECK(verify(bignum2 - bignum1, scriptnum2 - scriptnum1)); @@ -102,7 +102,7 @@ static void CheckSubtract(const int64_t& num1, const int64_t& num2) } } -static void CheckCompare(const int64_t& num1, const int64_t& num2) +static void CheckCompare(const long& num1, const long& num2) { const CBigNum bignum1(num1); const CBigNum bignum2(num2); @@ -138,7 +138,7 @@ static void CheckCompare(const int64_t& num1, const int64_t& num2) BOOST_CHECK((bignum1 <= bignum2) == (scriptnum1 <= num2)); } -static void RunCreate(const int64_t& num) +static void RunCreate(const long& num) { CheckCreateInt(num); CScriptNum scriptnum(num); @@ -150,7 +150,7 @@ static void RunCreate(const int64_t& num) } } -static void RunOperators(const int64_t& num1, const int64_t& num2) +static void RunOperators(const long& num1, const int64_t& num2) { CheckAdd(num1, num2); CheckSubtract(num1, num2); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 8abde887c..b6a1b8b33 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -14,12 +14,10 @@ #include #include -#include "json/json_spirit_reader_template.h" -#include "json/json_spirit_utils.h" -#include "json/json_spirit_writer_template.h" -using namespace json_spirit; -extern Array read_json(const std::string& jsondata); +#include + +extern UniValue read_json(const std::string& jsondata); // Old script.cpp SignatureHash function uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) @@ -165,12 +163,11 @@ BOOST_AUTO_TEST_CASE(sighash_test) // Goal: check that SignatureHash generates correct hash BOOST_AUTO_TEST_CASE(sighash_from_data) { - Array tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash))); + UniValue tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash))); - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - std::string strTest = write_string(tv, false); + for (unsigned int idx = 0; idx < tests.size(); idx++) { + UniValue test = tests[idx]; + std::string strTest = test.write(); if (test.size() < 1) // Allow for extra stuff (useful for comments) { BOOST_ERROR("Bad test: " << strTest); @@ -197,7 +194,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data) stream >> tx; CValidationState state; - BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); + BOOST_CHECK_MESSAGE(CheckTransaction(tx, false, false, state), strTest); BOOST_CHECK(state.IsValid()); std::vector raw = ParseHex(raw_script); diff --git a/src/test/test_zerocoin.cpp b/src/test/test_zerocoin.cpp new file mode 100644 index 000000000..0d1159aa4 --- /dev/null +++ b/src/test/test_zerocoin.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2012-2014 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. +#define BOOST_TEST_MODULE Zerocoin Test Suite +#define BOOST_TEST_MAIN + +#include "libzerocoin/Denominations.h" +#include "amount.h" +#include "chainparams.h" +#include "main.h" +#include "txdb.h" + +#include +#include + +struct ZeroSetup { + ZeroSetup() { + std::cout << "global setup\n"; + } + ~ZeroSetup() + { + std::cout << "global teardown\n"; + } +}; + +BOOST_GLOBAL_FIXTURE(ZeroSetup); + diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 519ce6c31..6949e4148 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -18,16 +18,17 @@ #include #include +#include #include #include -#include "json/json_spirit_writer_template.h" + +#include using namespace std; -using namespace json_spirit; using namespace boost::algorithm; // In script_tests.cpp -extern Array read_json(const std::string& jsondata); +extern UniValue read_json(const std::string& jsondata); static std::map mapFlagNames = boost::assign::map_list_of (string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE) @@ -86,32 +87,31 @@ BOOST_AUTO_TEST_CASE(tx_valid) // ... where all scripts are stringified scripts. // // verifyFlags is a comma separated list of script verification flags to apply, or "NONE" - Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); + UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); ScriptError err; - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - string strTest = write_string(tv, false); - if (test[0].type() == array_type) + for (unsigned int idx = 0; idx < tests.size(); idx++) { + UniValue test = tests[idx]; + string strTest = test.write(); + if (test[0].isArray()) { - if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type) + if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) { BOOST_ERROR("Bad test: " << strTest); continue; } map mapprevOutScriptPubKeys; - Array inputs = test[0].get_array(); + UniValue inputs = test[0].get_array(); bool fValid = true; - BOOST_FOREACH(Value& input, inputs) - { - if (input.type() != array_type) + for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { + const UniValue& input = inputs[inpIdx]; + if (!input.isArray()) { fValid = false; break; } - Array vinput = input.get_array(); + UniValue vinput = input.get_array(); if (vinput.size() != 3) { fValid = false; @@ -132,7 +132,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) stream >> tx; CValidationState state; - BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); + BOOST_CHECK_MESSAGE(CheckTransaction(tx, false, false, state), strTest); BOOST_CHECK(state.IsValid()); for (unsigned int i = 0; i < tx.vin.size(); i++) @@ -162,32 +162,31 @@ BOOST_AUTO_TEST_CASE(tx_invalid) // ... where all scripts are stringified scripts. // // verifyFlags is a comma separated list of script verification flags to apply, or "NONE" - Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid))); + UniValue tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid))); ScriptError err; - BOOST_FOREACH(Value& tv, tests) - { - Array test = tv.get_array(); - string strTest = write_string(tv, false); - if (test[0].type() == array_type) + for (unsigned int idx = 0; idx < tests.size(); idx++) { + UniValue test = tests[idx]; + string strTest = test.write(); + if (test[0].isArray()) { - if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type) + if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) { BOOST_ERROR("Bad test: " << strTest); continue; } map mapprevOutScriptPubKeys; - Array inputs = test[0].get_array(); + UniValue inputs = test[0].get_array(); bool fValid = true; - BOOST_FOREACH(Value& input, inputs) - { - if (input.type() != array_type) + for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { + const UniValue& input = inputs[inpIdx]; + if (!input.isArray()) { fValid = false; break; } - Array vinput = input.get_array(); + UniValue vinput = input.get_array(); if (vinput.size() != 3) { fValid = false; @@ -208,7 +207,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) stream >> tx; CValidationState state; - fValid = CheckTransaction(tx, state) && state.IsValid(); + fValid = CheckTransaction(tx, false, false, state) && state.IsValid(); for (unsigned int i = 0; i < tx.vin.size() && fValid; i++) { @@ -237,11 +236,11 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) CMutableTransaction tx; stream >> tx; CValidationState state; - BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid."); + BOOST_CHECK_MESSAGE(CheckTransaction(tx, false, false, state) && state.IsValid(), "Simple deserialized transaction should be valid."); // Check that duplicate txins fail tx.vin.push_back(tx.vin[0]); - BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid."); + BOOST_CHECK_MESSAGE(!CheckTransaction(tx, false, false, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid."); } // diff --git a/src/test/tutorial_zerocoin.cpp b/src/test/tutorial_zerocoin.cpp new file mode 100644 index 000000000..de70c5aca --- /dev/null +++ b/src/test/tutorial_zerocoin.cpp @@ -0,0 +1,283 @@ +/** +* @file tutorial.cpp +* +* @brief Simple tutorial program to illustrate Zerocoin usage. +* +* @author Ian Miers, Christina Garman and Matthew Green +* @date June 2013 +* +* @copyright Copyright 2013 Ian Miers, Christina Garman and Matthew Green +* @license This project is released under the MIT license. +**/ + + +#include +#include +#include +#include +// #include +#include +#include "streams.h" +#include "libzerocoin/bignum.h" +#include "libzerocoin/ParamGeneration.h" +#include "libzerocoin/Denominations.h" +#include "libzerocoin/Coin.h" +#include "libzerocoin/CoinSpend.h" +#include "libzerocoin/Accumulator.h" + +using namespace std; + +#define COINS_TO_ACCUMULATE 5 +#define DUMMY_TRANSACTION_HASH 0 // in real life these would be uint256 hashes +#define DUMMY_ACCUMULATOR_ID 0 // in real life these would be uint256 hashes + +// +// We generated this for testing only. Don't use it in production! +// +#define TUTORIAL_TEST_MODULUS "a8852ebf7c49f01cd196e35394f3b74dd86283a07f57e0a262928e7493d4a3961d93d93c90ea3369719641d626d28b9cddc6d9307b9aabdbffc40b6d6da2e329d079b4187ff784b2893d9f53e9ab913a04ff02668114695b07d8ce877c4c8cac1b12b9beff3c51294ebe349eca41c24cd32a6d09dd1579d3947e5c4dcc30b2090b0454edb98c6336e7571db09e0fdafbd68d8f0470223836e90666a5b143b73b9cd71547c917bf24c0efc86af2eba046ed781d9acb05c80f007ef5a0a5dfca23236f37e698e8728def12554bc80f294f71c040a88eff144d130b24211016a97ce0f5fe520f477e555c9997683d762aff8bd1402ae6938dd5c994780b1bf6aa7239e9d8101630ecfeaa730d2bbc97d39beb057f016db2e28bf12fab4989c0170c2593383fd04660b5229adcd8486ba78f6cc1b558bcd92f344100dff239a8c00dbc4c2825277f24bdd04475bcc9a8c39fd895eff97c1967e434effcb9bd394e0577f4cf98c30d9e6b54cd47d6e447dcf34d67e48e4421691dbe4a7d9bd503abb9" + +// +// The following routine exercises most of the core functions of +// the library. We've commented it as well as possible to give +// you the flavor of how libzerocoin works. +// +// For details on Zerocoin integration, see the libzerocoin wiki +// at: https://github.com/Zerocoin/libzerocoin/wiki +// + +bool +ZerocoinTutorial() +{ + // The following simple code illustrates the call flow for Zerocoin + // applications. In a real currency network these operations would + // be split between individual payers/payees, network nodes and miners. + // + // For each call we specify the participant who would use it. + + // Zerocoin uses exceptions (based on the runtime_error class) + // to indicate all sorts of problems. Always remember to catch them! + + try { + + /********************************************************************/ + // What is it: Parameter loading + // Who does it: ALL ZEROCOIN PARTICIPANTS + // What it does: Loads a trusted Zerocoin modulus "N" and + // generates all associated parameters from it. + // We use a hardcoded "N" that we generated using + // the included 'paramgen' utility. + /********************************************************************/ + + // Load a test modulus from our hardcoded string (above) + CBigNum testModulus; + testModulus.SetHex(std::string(TUTORIAL_TEST_MODULUS)); + + // Set up the Zerocoin Params object + libzerocoin::ZerocoinParams* params = new libzerocoin::ZerocoinParams(testModulus); + + cout << "Successfully loaded parameters." << endl; + + /********************************************************************/ + // What is it: Coin generation + // Who does it: ZEROCOIN CLIENTS + // What it does: Generates a new 'zerocoin' coin using the + // public parameters. Once generated, the client + // will transmit the public portion of this coin + // in a ZEROCOIN_MINT transaction. The inputs + // to this transaction must add up to the zerocoin + // denomination plus any transaction fees. + /********************************************************************/ + + // The following constructor does all the work of minting a brand + // new zerocoin. It stores all the private values inside the + // PrivateCoin object. This includes the coin secrets, which must be + // stored in a secure location (wallet) at the client. + libzerocoin::PrivateCoin newCoin(params, libzerocoin::CoinDenomination::ZQ_ONE); + + // Get a copy of the 'public' portion of the coin. You should + // embed this into a Zerocoin 'MINT' transaction along with a series + // of currency inputs totaling the assigned value of one zerocoin. + libzerocoin::PublicCoin pubCoin = newCoin.getPublicCoin(); + + cout << "Successfully minted a zerocoin." << endl; + + // Serialize the public coin to a CDataStream object. + CDataStream serializedCoin(SER_NETWORK, PROTOCOL_VERSION); + serializedCoin << pubCoin; + + /********************************************************************/ + // What is it: Coin verification + // Who does it: TRANSACTION VERIFIERS + // What it does: Verifies the structure of a zerocoin obtained from + // a ZEROCOIN_MINT transaction. All coins must be + // verified before you operate on them. + // Note that this is only part of the transaction + // verification process! The client must also check + // that (1) the inputs to the transaction are valid + // and add up to the value of one zerocoin, (2) that + // this particular zerocoin has not been minted before. + /********************************************************************/ + + // Deserialize the public coin into a fresh object. + libzerocoin::PublicCoin pubCoinNew(params, serializedCoin); + + // Now make sure the coin is valid. + if (!pubCoinNew.validate()) { + // If this returns false, don't accept the coin for any purpose! + // Any ZEROCOIN_MINT with an invalid coin should NOT be + // accepted as a valid transaction in the block chain. + cout << "Error: coin is not valid!"; + } + + cout << "Deserialized and verified the coin." << endl; + + /********************************************************************/ + // What is it: Accumulator computation + // Who does it: ZEROCOIN CLIENTS & TRANSACTION VERIFIERS + // What it does: Collects a number of PublicCoin values drawn from + // the block chain and calculates an accumulator. + // This accumulator is incrementally computable; + // you can stop and serialize it at any point + // then continue accumulating new transactions. + // The accumulator is also order-independent, so + // the same coins can be accumulated in any order + // to give the same result. + // WARNING: do not accumulate the same coin twice! + /********************************************************************/ + + // Create an empty accumulator object + libzerocoin::Accumulator accumulator(params,libzerocoin::CoinDenomination::ZQ_ONE); + + // Add several coins to it (we'll generate them here on the fly). + for (uint32_t i = 0; i < COINS_TO_ACCUMULATE; i++) { + libzerocoin::PrivateCoin testCoin(params, libzerocoin::CoinDenomination::ZQ_ONE); + accumulator += testCoin.getPublicCoin(); + } + + // Serialize the accumulator object. + // + // If you're using Accumulator Checkpoints, each miner would + // start by deserializing the accumulator checkpoint from the + // previous block (or creating a new Accumulator if no previous + // block exists). It will then add all the coins in the new block, + // then serialize the resulting Accumulator object to obtain the + // new checkpoint. All block verifiers should do the same thing + // to check their work. + CDataStream serializedAccumulator(SER_NETWORK, PROTOCOL_VERSION); + serializedAccumulator << accumulator; + + // Deserialize the accumulator object + libzerocoin::Accumulator newAccumulator(params, serializedAccumulator); + + // We can now continue accumulating things into the accumulator + // we just deserialized. For example, let's put in the coin + // we generated up above. + newAccumulator += pubCoinNew; + + cout << "Successfully accumulated coins." << endl; + + /********************************************************************/ + // What is it: Coin spend + // Who does it: ZEROCOIN CLIENTS + // What it does: Create a new transaction that spends a Zerocoin. + // The user first authors a transaction specifying + // a set of destination addresses (outputs). They + // next compute an Accumulator over all coins in the + // block chain (see above) and a Witness based on the + // coin to be spent. Finally they instantiate a CoinSpend + // object that 'signs' the transaction with a special + // zero knowledge signature of knowledge over the coin + // data, Witness and Accumulator. + /********************************************************************/ + + // We are going to spend the coin "newCoin" that we generated at the + // top of this function. + // + // We'll use the accumulator we constructed above. This contains + // a set of coins, but does NOT include the coin "newCoin". + // + // To generate the witness, we start with this accumulator and + // add the public half of the coin we want to spend. + libzerocoin::AccumulatorWitness witness(params, accumulator, newCoin.getPublicCoin()); + + // Add the public half of "newCoin" to the Accumulator itself. + accumulator += newCoin.getPublicCoin(); + + // At this point we should generate a ZEROCOIN_SPEND transaction to + // send to the network. This network should include a set of outputs + // totalling to the value of one zerocoin (minus transaction fees). + + // Construct the CoinSpend object. This acts like a signature on the + // transaction. + libzerocoin::CoinSpend spend(params, newCoin, accumulator, 0, witness, 0);//(0) - Presstab + + // This is a sanity check. The CoinSpend object should always verify, + // but why not check before we put it onto the wire? + if (!spend.Verify(accumulator)) { + 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; + + /********************************************************************/ + // What is it: Coin spend verification + // Who does it: ALL PARTIES + // What it does: Verifies that a CoinSpend signature is correct + // with respect to a ZEROCOIN_SPEND transaction hash. + // The client must also extract the serial number from + // the CoinSpend and verify that this serial number has + // not previously appeared in another ZEROCOIN_SPEND + // transaction. + /********************************************************************/ + + // Deserialize the CoinSpend intro a fresh object + libzerocoin::CoinSpend newSpend(params, serializedCoinSpend); + + // 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. + // + // Verify that the spend is valid with respect to the Accumulator + // and the Metadata + if (!newSpend.Verify(accumulator)) { + cout << "ERROR: The CoinSpend transaction did not verify!" << endl; + return false; + } + + // Pull the serial number out of the CoinSpend object. If we + // were a real Zerocoin client we would now check that the serial number + // has not been spent before (in another ZEROCOIN_SPEND) transaction. + // The serial number is stored as a CBigNum. + CBigNum serialNumber = newSpend.getCoinSerialNumber(); + + cout << "Successfully verified a coin spend transaction." << endl; + cout << endl << "Coin serial number is:" << endl << serialNumber << endl; + + // We're done + return true; + + } catch (runtime_error &e) { + cout << e.what() << endl; + return false; + } + + return false; +} + +BOOST_AUTO_TEST_SUITE(tutorial_libzerocoin) +BOOST_AUTO_TEST_CASE(tutorial_libzerocoin_tests) +{ + cout << "libzerocoin v" << ZEROCOIN_VERSION_STRING << " tutorial." << endl << endl; + + ZerocoinTutorial(); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp index 23bc5f6b1..dc215cf66 100644 --- a/src/test/univalue_tests.cpp +++ b/src/test/univalue_tests.cpp @@ -6,7 +6,7 @@ #include #include #include -#include "univalue/univalue.h" +#include #include @@ -62,6 +62,48 @@ BOOST_AUTO_TEST_CASE(univalue_constructor) BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); } +BOOST_AUTO_TEST_CASE(univalue_typecheck) +{ + UniValue v1; + BOOST_CHECK(v1.setNumStr("1")); + BOOST_CHECK(v1.isNum()); + BOOST_CHECK_THROW(v1.get_bool(), runtime_error); + + UniValue v2; + BOOST_CHECK(v2.setBool(true)); + BOOST_CHECK_EQUAL(v2.get_bool(), true); + BOOST_CHECK_THROW(v2.get_int(), runtime_error); + + UniValue v3; + BOOST_CHECK(v3.setNumStr("32482348723847471234")); + BOOST_CHECK_THROW(v3.get_int64(), runtime_error); + BOOST_CHECK(v3.setNumStr("1000")); + BOOST_CHECK_EQUAL(v3.get_int64(), 1000); + + UniValue v4; + BOOST_CHECK(v4.setNumStr("2147483648")); + BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648); + BOOST_CHECK_THROW(v4.get_int(), runtime_error); + BOOST_CHECK(v4.setNumStr("1000")); + BOOST_CHECK_EQUAL(v4.get_int(), 1000); + BOOST_CHECK_THROW(v4.get_str(), runtime_error); + BOOST_CHECK_EQUAL(v4.get_real(), 1000); + BOOST_CHECK_THROW(v4.get_array(), runtime_error); + BOOST_CHECK_THROW(v4.getKeys(), runtime_error); + BOOST_CHECK_THROW(v4.getValues(), runtime_error); + BOOST_CHECK_THROW(v4.get_obj(), runtime_error); + + UniValue v5; + BOOST_CHECK(v5.read("[true, 10]")); + BOOST_CHECK_NO_THROW(v5.get_array()); + std::vector vals = v5.getValues(); + BOOST_CHECK_THROW(vals[0].get_int(), runtime_error); + BOOST_CHECK_EQUAL(vals[0].get_bool(), true); + + BOOST_CHECK_EQUAL(vals[1].get_int(), 10); + BOOST_CHECK_THROW(vals[1].get_bool(), runtime_error); +} + BOOST_AUTO_TEST_CASE(univalue_set) { UniValue v(UniValue::VSTR, "foo"); @@ -71,13 +113,13 @@ BOOST_AUTO_TEST_CASE(univalue_set) BOOST_CHECK(v.setObject()); BOOST_CHECK(v.isObject()); - BOOST_CHECK_EQUAL(v.count(), 0); + BOOST_CHECK_EQUAL(v.size(), 0); BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ); BOOST_CHECK(v.empty()); BOOST_CHECK(v.setArray()); BOOST_CHECK(v.isArray()); - BOOST_CHECK_EQUAL(v.count(), 0); + BOOST_CHECK_EQUAL(v.size(), 0); BOOST_CHECK(v.setStr("zum")); BOOST_CHECK(v.isStr()); @@ -144,7 +186,7 @@ BOOST_AUTO_TEST_CASE(univalue_array) BOOST_CHECK(arr.push_backV(vec)); BOOST_CHECK_EQUAL(arr.empty(), false); - BOOST_CHECK_EQUAL(arr.count(), 5); + BOOST_CHECK_EQUAL(arr.size(), 5); BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023"); BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy"); @@ -156,7 +198,7 @@ BOOST_AUTO_TEST_CASE(univalue_array) arr.clear(); BOOST_CHECK(arr.empty()); - BOOST_CHECK_EQUAL(arr.count(), 0); + BOOST_CHECK_EQUAL(arr.size(), 0); } BOOST_AUTO_TEST_CASE(univalue_object) @@ -196,7 +238,7 @@ BOOST_AUTO_TEST_CASE(univalue_object) BOOST_CHECK(obj.pushKVs(obj2)); BOOST_CHECK_EQUAL(obj.empty(), false); - BOOST_CHECK_EQUAL(obj.count(), 9); + BOOST_CHECK_EQUAL(obj.size(), 9); BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100"); BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John"); @@ -239,11 +281,11 @@ BOOST_AUTO_TEST_CASE(univalue_object) obj.clear(); BOOST_CHECK(obj.empty()); - BOOST_CHECK_EQUAL(obj.count(), 0); + BOOST_CHECK_EQUAL(obj.size(), 0); } static const char *json1 = -"[1.1,{\"key1\":\"str\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]"; +"[1.10000000,{\"key1\":\"str\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]"; BOOST_AUTO_TEST_CASE(univalue_readwrite) { @@ -254,13 +296,13 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite) BOOST_CHECK(v.read(strJson1)); BOOST_CHECK(v.isArray()); - BOOST_CHECK_EQUAL(v.count(), 2); + BOOST_CHECK_EQUAL(v.size(), 2); - BOOST_CHECK_EQUAL(v[0].getValStr(), "1.1"); + BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000"); UniValue obj = v[1]; BOOST_CHECK(obj.isObject()); - BOOST_CHECK_EQUAL(obj.count(), 3); + BOOST_CHECK_EQUAL(obj.size(), 3); BOOST_CHECK(obj["key1"].isStr()); BOOST_CHECK_EQUAL(obj["key1"].getValStr(), "str"); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index db9ee120b..ed2bbece3 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -331,6 +331,64 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32) BOOST_CHECK(!ParseInt32("32482348723847471234", NULL)); } +BOOST_AUTO_TEST_CASE(test_ParseInt64) +{ + int64_t n; + // Valid values + BOOST_CHECK(ParseInt64("1234", NULL)); + BOOST_CHECK(ParseInt64("0", &n) && n == 0LL); + BOOST_CHECK(ParseInt64("1234", &n) && n == 1234LL); + BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal + BOOST_CHECK(ParseInt64("2147483647", &n) && n == 2147483647LL); + BOOST_CHECK(ParseInt64("-2147483648", &n) && n == -2147483648LL); + BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == 9223372036854775807LL); + BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == -9223372036854775808LL); + BOOST_CHECK(ParseInt64("-1234", &n) && n == -1234LL); + // Invalid values + BOOST_CHECK(!ParseInt64("", &n)); + BOOST_CHECK(!ParseInt64(" 1", &n)); // no padding inside + BOOST_CHECK(!ParseInt64("1 ", &n)); + BOOST_CHECK(!ParseInt64("1a", &n)); + BOOST_CHECK(!ParseInt64("aap", &n)); + BOOST_CHECK(!ParseInt64("0x1", &n)); // no hex + const char test_bytes[] = {'1', 0, '1'}; + std::string teststr(test_bytes, sizeof(test_bytes)); + BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs + // Overflow and underflow + BOOST_CHECK(!ParseInt64("-9223372036854775809", NULL)); + BOOST_CHECK(!ParseInt64("9223372036854775808", NULL)); + BOOST_CHECK(!ParseInt64("-32482348723847471234", NULL)); + BOOST_CHECK(!ParseInt64("32482348723847471234", NULL)); +} + +BOOST_AUTO_TEST_CASE(test_ParseDouble) +{ + double n; + // Valid values + BOOST_CHECK(ParseDouble("1234", NULL)); + BOOST_CHECK(ParseDouble("0", &n) && n == 0.0); + BOOST_CHECK(ParseDouble("1234", &n) && n == 1234.0); + BOOST_CHECK(ParseDouble("01234", &n) && n == 1234.0); // no octal + BOOST_CHECK(ParseDouble("2147483647", &n) && n == 2147483647.0); + BOOST_CHECK(ParseDouble("-2147483648", &n) && n == -2147483648.0); + BOOST_CHECK(ParseDouble("-1234", &n) && n == -1234.0); + BOOST_CHECK(ParseDouble("1e6", &n) && n == 1e6); + BOOST_CHECK(ParseDouble("-1e6", &n) && n == -1e6); + // Invalid values + BOOST_CHECK(!ParseDouble("", &n)); + BOOST_CHECK(!ParseDouble(" 1", &n)); // no padding inside + BOOST_CHECK(!ParseDouble("1 ", &n)); + BOOST_CHECK(!ParseDouble("1a", &n)); + BOOST_CHECK(!ParseDouble("aap", &n)); + BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex + const char test_bytes[] = {'1', 0, '1'}; + std::string teststr(test_bytes, sizeof(test_bytes)); + BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs + // Overflow and underflow + BOOST_CHECK(!ParseDouble("-1e10000", NULL)); + BOOST_CHECK(!ParseDouble("1e10000", NULL)); +} + BOOST_AUTO_TEST_CASE(test_FormatParagraph) { BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), ""); diff --git a/src/test/zerocoin_denomination_tests.cpp b/src/test/zerocoin_denomination_tests.cpp new file mode 100644 index 000000000..0bd8e78a9 --- /dev/null +++ b/src/test/zerocoin_denomination_tests.cpp @@ -0,0 +1,497 @@ +// Copyright (c) 2012-2014 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 "amount.h" +#include "chainparams.h" +#include "coincontrol.h" +#include "denomination_functions.h" +#include "main.h" +#include "txdb.h" +#include "wallet.h" +#include "walletdb.h" +#include +#include + +using namespace libzerocoin; + +BOOST_AUTO_TEST_SUITE(zerocoin_denom_tests) + + +//translation from bwk quantity to zerocoin denomination +BOOST_AUTO_TEST_CASE(amount_to_denomination_test) +{ + cout << "Running amount_to_denomination_test...\n"; + + //valid amount (min edge) + CAmount amount = 1 * COIN; + BOOST_CHECK_MESSAGE(AmountToZerocoinDenomination(amount) == ZQ_ONE, "For COIN denomination should be ZQ_ONE"); + + //valid amount (max edge) + CAmount amount1 = 1000 * COIN; + BOOST_CHECK_MESSAGE(AmountToZerocoinDenomination(amount1) == ZQ_ONE_THOUSAND, "For 1000*COIN denomination should be ZQ_ONE_THOUSAND"); + + //invalid amount (too much) + CAmount amount2 = 7000 * COIN; + BOOST_CHECK_MESSAGE(AmountToZerocoinDenomination(amount2) == ZQ_ERROR, "For 7000*COIN denomination should be Invalid -> ZQ_ERROR"); + + //invalid amount (not enough) + CAmount amount3 = 1; + BOOST_CHECK_MESSAGE(AmountToZerocoinDenomination(amount3) == ZQ_ERROR, "For 1 denomination should be Invalid -> ZQ_ERROR"); +} + +BOOST_AUTO_TEST_CASE(denomination_to_value_test) +{ + cout << "Running ZerocoinDenominationToValue_test...\n"; + + int64_t Value = 1 * COIN; + CoinDenomination denomination = ZQ_ONE; + BOOST_CHECK_MESSAGE(ZerocoinDenominationToAmount(denomination) == Value, "Wrong Value - should be 1"); + + Value = 10 * COIN; + denomination = ZQ_TEN; + BOOST_CHECK_MESSAGE(ZerocoinDenominationToAmount(denomination) == Value, "Wrong Value - should be 10"); + + Value = 50 * COIN; + denomination = ZQ_FIFTY; + BOOST_CHECK_MESSAGE(ZerocoinDenominationToAmount(denomination) == Value, "Wrong Value - should be 50"); + + Value = 500 * COIN; + denomination = ZQ_FIVE_HUNDRED; + BOOST_CHECK_MESSAGE(ZerocoinDenominationToAmount(denomination) == Value, "Wrong Value - should be 500"); + + Value = 100 * COIN; + denomination = ZQ_ONE_HUNDRED; + BOOST_CHECK_MESSAGE(ZerocoinDenominationToAmount(denomination) == Value, "Wrong Value - should be 100"); + + Value = 0 * COIN; + denomination = ZQ_ERROR; + BOOST_CHECK_MESSAGE(ZerocoinDenominationToAmount(denomination) == Value, "Wrong Value - should be 0"); +} + +BOOST_AUTO_TEST_CASE(zerocoin_spend_test241) +{ + const int nMaxNumberOfSpends = 4; + const bool fMinimizeChange = false; + const int DenomAmounts[] = {1, 2, 3, 4, 0, 0, 0, 0}; + CAmount nSelectedValue; + std::list listMints; + std::map mapDenom; + + int j = 0; + CAmount nTotalAmount = 0; + int CoinsHeld = 0; + + // Create a set of Minted coins that fits profile given by DenomAmounts + // Also setup Map array corresponding to DenomAmount which is the current set of coins available + + for (const auto& denom : zerocoinDenomList) { + for (int i = 0; i < DenomAmounts[j]; i++) { + CAmount currentAmount = ZerocoinDenominationToAmount(denom); + nTotalAmount += currentAmount; + CBigNum value; + CBigNum rand; + CBigNum serial; + bool isUsed = false; + CZerocoinMint mint(denom, value, rand, serial, isUsed); + listMints.push_back(mint); + } + mapDenom.insert(std::pair(denom, DenomAmounts[j])); + j++; + } + CoinsHeld = nTotalAmount / COIN; + std::cout << "Curremt Amount held = " << CoinsHeld << ": "; + + // Show what we have + j = 0; + for (const auto& denom : zerocoinDenomList) + std::cout << DenomAmounts[j++] << "*" << ZerocoinDenominationToAmount(denom) / COIN << " + "; + std::cout << "\n"; + + // For DenomAmounts[] = {1,2,3,4,0,0,0,0}; we can spend up to 200 without requiring more than 4 Spends + // Amounts above this can not be met + CAmount MaxLimit = 200; + CAmount OneCoinAmount = ZerocoinDenominationToAmount(ZQ_ONE); + CAmount nValueTarget = OneCoinAmount; + int nCoinsReturned; + int nNeededSpends = 0; // Number of spends which would be needed if selection failed + + bool fDebug = 0; + + // Go through all possible spend between 1 and 241 and see if it's possible or not + for (int i = 0; i < CoinsHeld; i++) { + std::vector vSpends = SelectMintsFromList(nValueTarget, nSelectedValue, + nMaxNumberOfSpends, + fMinimizeChange, + nCoinsReturned, + listMints, + mapDenom, + nNeededSpends); + + if (fDebug) { + if (vSpends.size() > 0) { + std::cout << "SUCCESS : Coins = " << nValueTarget / COIN << " # spends used = " << vSpends.size() + << " # of coins returned = " << nCoinsReturned + << " Spend Amount = " << nSelectedValue / COIN << " Held = " << CoinsHeld << "\n"; + } else { + std::cout << "FAILED : Coins = " << nValueTarget / COIN << " Held = " << CoinsHeld << "\n"; + } + } + + if (i < MaxLimit) { + BOOST_CHECK_MESSAGE(vSpends.size() < 5, "Too many spends"); + BOOST_CHECK_MESSAGE(vSpends.size() > 0, "No spends"); + } else { + bool spends_not_ok = ((vSpends.size() >= 4) || (vSpends.size() == 0)); + BOOST_CHECK_MESSAGE(spends_not_ok, "Expected to fail but didn't"); + } + nValueTarget += OneCoinAmount; + } + //std::cout << "241 Test done!\n"; +} +BOOST_AUTO_TEST_CASE(zerocoin_spend_test115) +{ + const int nMaxNumberOfSpends = 4; + const bool fMinimizeChange = false; + const int DenomAmounts[] = {0, 1, 1, 2, 0, 0, 0, 0}; + CAmount nSelectedValue; + std::list listMints; + std::map mapDenom; + + int j = 0; + CAmount nTotalAmount = 0; + int CoinsHeld = 0; + + // Create a set of Minted coins that fits profile given by DenomAmounts + // Also setup Map array corresponding to DenomAmount which is the current set of coins available + for (const auto& denom : zerocoinDenomList) { + for (int i = 0; i < DenomAmounts[j]; i++) { + CAmount currentAmount = ZerocoinDenominationToAmount(denom); + nTotalAmount += currentAmount; + CBigNum value; + CBigNum rand; + CBigNum serial; + bool isUsed = false; + CZerocoinMint mint(denom, value, rand, serial, isUsed); + listMints.push_back(mint); + } + mapDenom.insert(std::pair(denom, DenomAmounts[j])); + j++; + } + CoinsHeld = nTotalAmount / COIN; + std::cout << "Curremt Amount held = " << CoinsHeld << ": "; + + // Show what we have + j = 0; + for (const auto& denom : zerocoinDenomList) + std::cout << DenomAmounts[j++] << "*" << ZerocoinDenominationToAmount(denom) / COIN << " + "; + std::cout << "\n"; + + CAmount OneCoinAmount = ZerocoinDenominationToAmount(ZQ_ONE); + CAmount nValueTarget = OneCoinAmount; + + bool fDebug = 0; + int nCoinsReturned; + int nNeededSpends = 0; // Number of spends which would be needed if selection failed + + std::vector vSpends = SelectMintsFromList(nValueTarget, nSelectedValue, + nMaxNumberOfSpends, + fMinimizeChange, + nCoinsReturned, + listMints, + mapDenom, + nNeededSpends); + + if (fDebug) { + if (vSpends.size() > 0) { + std::cout << "SUCCESS : Coins = " << nValueTarget / COIN << " # spends used = " << vSpends.size() + << " # of coins returned = " << nCoinsReturned + << " Spend Amount = " << nSelectedValue / COIN << " Held = " << CoinsHeld << "\n"; + } else { + std::cout << "FAILED : Coins = " << nValueTarget / COIN << " Held = " << CoinsHeld << "\n"; + } + } + + BOOST_CHECK_MESSAGE(vSpends.size() < 5, "Too many spends"); + BOOST_CHECK_MESSAGE(vSpends.size() > 0, "No spends"); + nValueTarget += OneCoinAmount; +} +BOOST_AUTO_TEST_CASE(zerocoin_spend_test_from_245) +{ + const int nMaxNumberOfSpends = 5; + // For 36: + // const int nSpendValue = 36; + // Here have a 50 so use for 36 since can't meet exact amount + // const int DenomAmounts[] = {0,1,4,1,0,0,0,0}; + // Here have 45 so use 4*10 for 36 since can't meet exact amount + // const int DenomAmounts[] = {0, 1, 4, 0, 0, 0, 0, 0}; + // For 51 + //const int nSpendValue = 51; + + // CoinsHeld = 245 + const int DenomAmounts[] = {0, 1, 4, 2, 1, 0, 0, 0}; + // We can spend up to this amount for above set for less 6 spends + // Otherwise, 6 spends are required + const int nMaxSpendAmount = 220; + CAmount nSelectedValue; + std::list listMints; + std::map mapOfDenomsHeld; + + int j = 0; + CAmount nTotalAmount = 0; + int CoinsHeld = 0; + + // Create a set of Minted coins that fits profile given by DenomAmounts + // Also setup Map array corresponding to DenomAmount which is the current set of coins available + for (const auto& denom : zerocoinDenomList) { + for (int i = 0; i < DenomAmounts[j]; i++) { + CAmount currentAmount = ZerocoinDenominationToAmount(denom); + nTotalAmount += currentAmount; + CBigNum value; + CBigNum rand; + CBigNum serial; + bool isUsed = false; + CZerocoinMint mint(denom, value, rand, serial, isUsed); + listMints.push_back(mint); + } + mapOfDenomsHeld.insert(std::pair(denom, DenomAmounts[j])); + j++; + } + CoinsHeld = nTotalAmount / COIN; + std::cout << "Curremt Amount held = " << CoinsHeld << ": "; + + // Show what we have + j = 0; + for (const auto& denom : zerocoinDenomList) + std::cout << DenomAmounts[j++] << "*" << ZerocoinDenominationToAmount(denom) / COIN << " + "; + std::cout << "\n"; + + CAmount OneCoinAmount = ZerocoinDenominationToAmount(ZQ_ONE); + CAmount nValueTarget = OneCoinAmount; + + bool fDebug = 0; + int nCoinsReturned; + int nNeededSpends = 0; // Number of spends which would be needed if selection failed + + // Go through all possible spend between 1 and 241 and see if it's possible or not + for (int i = 0; i < CoinsHeld; i++) { + std::vector vSpends = SelectMintsFromList(nValueTarget, nSelectedValue, + nMaxNumberOfSpends, + false, + nCoinsReturned, + listMints, + mapOfDenomsHeld, + nNeededSpends); + + if (fDebug) { + if (vSpends.size() > 0) { + std::cout << "SUCCESS : Coins = " << nValueTarget / COIN << " # spends = " << vSpends.size() + << " # coins returned = " << nCoinsReturned + << " Amount = " << nSelectedValue / COIN << " Held = " << CoinsHeld << " "; + } else { + std::cout << "UNABLE TO SPEND : Coins = " << nValueTarget / COIN << " Held = " << CoinsHeld << "\n"; + } + } + + bool spends_not_ok = ((vSpends.size() > nMaxNumberOfSpends) || (vSpends.size() == 0)); + if (i < nMaxSpendAmount) BOOST_CHECK_MESSAGE(!spends_not_ok, "Too many spends"); + else BOOST_CHECK_MESSAGE(spends_not_ok, "Expected to fail but didn't"); + + std::vector vSpendsAlt = SelectMintsFromList(nValueTarget, nSelectedValue, + nMaxNumberOfSpends, + true, + nCoinsReturned, + listMints, + mapOfDenomsHeld, + nNeededSpends); + + + if (fDebug) { + if (vSpendsAlt.size() > 0) { + std::cout << "# spends = " << vSpendsAlt.size() + << " # coins returned = " << nCoinsReturned + << " Amount = " << nSelectedValue / COIN << "\n"; + } else { + std::cout << "UNABLE TO SPEND : Coins = " << nValueTarget / COIN << " Held = " << CoinsHeld << "\n"; + } + } + + spends_not_ok = ((vSpendsAlt.size() > nMaxNumberOfSpends) || (vSpendsAlt.size() == 0)); + if (i < nMaxSpendAmount) BOOST_CHECK_MESSAGE(!spends_not_ok, "Too many spends"); + else BOOST_CHECK_MESSAGE(spends_not_ok, "Expected to fail but didn't"); + + nValueTarget += OneCoinAmount; + } +} + + +BOOST_AUTO_TEST_CASE(zerocoin_spend_test_from_145) +{ + const int nMaxNumberOfSpends = 5; + // CoinsHeld = 145 + const int DenomAmounts[] = {0, 1, 4, 2, 0, 0, 0, 0}; + CAmount nSelectedValue; + std::list listMints; + std::map mapOfDenomsHeld; + + int j = 0; + CAmount nTotalAmount = 0; + int CoinsHeld = 0; + + // Create a set of Minted coins that fits profile given by DenomAmounts + // Also setup Map array corresponding to DenomAmount which is the current set of coins available + for (const auto& denom : zerocoinDenomList) { + for (int i = 0; i < DenomAmounts[j]; i++) { + CAmount currentAmount = ZerocoinDenominationToAmount(denom); + nTotalAmount += currentAmount; + CBigNum value; + CBigNum rand; + CBigNum serial; + bool isUsed = false; + CZerocoinMint mint(denom, value, rand, serial, isUsed); + listMints.push_back(mint); + } + mapOfDenomsHeld.insert(std::pair(denom, DenomAmounts[j])); + j++; + } + CoinsHeld = nTotalAmount / COIN; + std::cout << "Curremt Amount held = " << CoinsHeld << ": "; + // We can spend up to this amount for above set for less 6 spends + // Otherwise, 6 spends are required + const int nMaxSpendAmount = 130; + + // Show what we have + j = 0; + for (const auto& denom : zerocoinDenomList) + std::cout << DenomAmounts[j++] << "*" << ZerocoinDenominationToAmount(denom) / COIN << " + "; + std::cout << "\n"; + + CAmount OneCoinAmount = ZerocoinDenominationToAmount(ZQ_ONE); + CAmount nValueTarget = OneCoinAmount; + + bool fDebug = 0; + int nCoinsReturned; + int nNeededSpends = 0; // Number of spends which would be needed if selection failed + + // Go through all possible spend between 1 and 241 and see if it's possible or not + for (int i = 0; i < CoinsHeld; i++) { + std::vector vSpends = SelectMintsFromList(nValueTarget, nSelectedValue, + nMaxNumberOfSpends, + false, + nCoinsReturned, + listMints, + mapOfDenomsHeld, + nNeededSpends); + + if (fDebug) { + if (vSpends.size() > 0) { + std::cout << "SUCCESS : Coins = " << nValueTarget / COIN << " # spends = " << vSpends.size() + << " # coins returned = " << nCoinsReturned + << " Amount = " << nSelectedValue / COIN << " Held = " << CoinsHeld << " "; + } else { + std::cout << "UNABLE TO SPEND : Coins = " << nValueTarget / COIN << " Held = " << CoinsHeld << "\n"; + } + } + + bool spends_not_ok = ((vSpends.size() > nMaxNumberOfSpends) || (vSpends.size() == 0)); + if (i < nMaxSpendAmount) BOOST_CHECK_MESSAGE(!spends_not_ok, "Too many spends"); + else BOOST_CHECK_MESSAGE(spends_not_ok, "Expected to fail but didn't"); + + std::vector vSpendsAlt = SelectMintsFromList(nValueTarget, nSelectedValue, + nMaxNumberOfSpends, + true, + nCoinsReturned, + listMints, + mapOfDenomsHeld, + nNeededSpends); + + + if (fDebug) { + if (vSpendsAlt.size() > 0) { + std::cout << "# spends = " << vSpendsAlt.size() + << " # coins returned = " << nCoinsReturned + << " Amount = " << nSelectedValue / COIN << "\n"; + } else { + std::cout << "UNABLE TO SPEND : Coins = " << nValueTarget / COIN << " Held = " << CoinsHeld << "\n"; + } + } + + spends_not_ok = ((vSpendsAlt.size() > nMaxNumberOfSpends) || (vSpendsAlt.size() == 0)); + if (i < nMaxSpendAmount) BOOST_CHECK_MESSAGE(!spends_not_ok, "Too many spends"); + else BOOST_CHECK_MESSAGE(spends_not_ok, "Expected to fail but didn't"); + + + nValueTarget += OneCoinAmount; + } +} + + +BOOST_AUTO_TEST_CASE(zerocoin_spend_test99) +{ + const int nMaxNumberOfSpends = 4; + const bool fMinimizeChange = false; + const int DenomAmounts[] = {0, 1, 4, 2, 1, 0, 0, 0}; + CAmount nSelectedValue; + std::list listMints; + std::map mapOfDenomsHeld; + + int j = 0; + CAmount nTotalAmount = 0; + int CoinsHeld = 0; + + // Create a set of Minted coins that fits profile given by DenomAmounts + // Also setup Map array corresponding to DenomAmount which is the current set of coins available + for (const auto& denom : zerocoinDenomList) { + for (int i = 0; i < DenomAmounts[j]; i++) { + CAmount currentAmount = ZerocoinDenominationToAmount(denom); + nTotalAmount += currentAmount; + CBigNum value; + CBigNum rand; + CBigNum serial; + bool isUsed = false; + CZerocoinMint mint(denom, value, rand, serial, isUsed); + listMints.push_back(mint); + } + mapOfDenomsHeld.insert(std::pair(denom, DenomAmounts[j])); + j++; + } + CoinsHeld = nTotalAmount / COIN; + std::cout << "Curremt Amount held = " << CoinsHeld << ": "; + + // Show what we have + j = 0; + for (const auto& denom : zerocoinDenomList) + std::cout << DenomAmounts[j++] << "*" << ZerocoinDenominationToAmount(denom) / COIN << " + "; + std::cout << "\n"; + + CAmount OneCoinAmount = ZerocoinDenominationToAmount(ZQ_ONE); + CAmount nValueTarget = 99 * OneCoinAmount; + + bool fDebug = 0; + int nCoinsReturned; + int nNeededSpends = 0; // Number of spends which would be needed if selection failed + + std::vector vSpends = SelectMintsFromList(nValueTarget, nSelectedValue, + nMaxNumberOfSpends, + fMinimizeChange, + nCoinsReturned, + listMints, + mapOfDenomsHeld, + nNeededSpends); + + if (fDebug) { + if (vSpends.size() > 0) { + std::cout << "SUCCESS : Coins = " << nValueTarget / COIN << " # spends used = " << vSpends.size() + << " # of coins returned = " << nCoinsReturned + << " Spend Amount = " << nSelectedValue / COIN << " Held = " << CoinsHeld << "\n"; + } else { + std::cout << "FAILED : Coins = " << nValueTarget / COIN << " Held = " << CoinsHeld << "\n"; + } + } + + BOOST_CHECK_MESSAGE(vSpends.size() < 5, "Too many spends"); + BOOST_CHECK_MESSAGE(vSpends.size() > 0, "No spends"); + nValueTarget += OneCoinAmount; +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/zerocoin_implementation_tests.cpp b/src/test/zerocoin_implementation_tests.cpp new file mode 100644 index 000000000..46e7f3d7f --- /dev/null +++ b/src/test/zerocoin_implementation_tests.cpp @@ -0,0 +1,352 @@ +// Copyright (c) 2012-2014 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 "libzerocoin/Denominations.h" +#include "amount.h" +#include "chainparams.h" +#include "main.h" +#include "txdb.h" +#include +#include +#include + +using namespace libzerocoin; + +extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); + +BOOST_AUTO_TEST_SUITE(zerocoin_implementation_tests) + +BOOST_AUTO_TEST_CASE(zcparams_test) +{ + cout << "Running zcparams_test...\n"; + + bool fPassed = true; + try{ + SelectParams(CBaseChainParams::MAIN); + ZerocoinParams *ZCParams = Params().Zerocoin_Params(); + (void)ZCParams; + } catch(std::exception& e) { + fPassed = false; + std::cout << e.what() << "\n"; + } + BOOST_CHECK(fPassed); +} + +std::string zerocoinModulus = "25195908475657893494027183240048398571429282126204032027777137836043662020707595556264018525880784" + "4069182906412495150821892985591491761845028084891200728449926873928072877767359714183472702618963750149718246911" + "6507761337985909570009733045974880842840179742910064245869181719511874612151517265463228221686998754918242243363" + "7259085141865462043576798423387184774447920739934236584823824281198163815010674810451660377306056201619676256133" + "8441436038339044149526344321901146575444541784240209246165157233507787077498171257724679629263863563732899121548" + "31438167899885040445364023527381951378636564391212010397122822120720357"; +CBigNum bnTrustedModulus(zerocoinModulus); +libzerocoin::ZerocoinParams zerocoinParams = libzerocoin::ZerocoinParams(bnTrustedModulus); + +//ZQ_ONE mints +std::string rawTx1 = "0100000001983d5fd91685bb726c0ebc3676f89101b16e663fd896fea53e19972b95054c49000000006a473044022010fbec3e78f9c46e58193d481caff715ceb984df44671d30a2c0bde95c54055f0220446a97d9340da690eaf2658e5b2bf6a0add06f1ae3f1b40f37614c7079ce450d012103cb666bd0f32b71cbf4f32e95fa58e05cd83869ac101435fcb8acee99123ccd1dffffffff0200e1f5050000000086c10280004c80c3a01f94e71662f2ae8bfcd88dfc5b5e717136facd6538829db0c7f01e5fd793cccae7aa1958564518e0223d6d9ce15b1e38e757583546e3b9a3f85bd14408120cd5192a901bb52152e8759fdd194df230d78477706d0e412a66398f330be38a23540d12ab147e9fb19224913f3fe552ae6a587fb30a68743e52577150ff73042c0f0d8f000000001976a914d6042025bd1fff4da5da5c432d85d82b3f26a01688ac00000000"; +std::string rawTxpub1 = "473ff507157523e74680ab37f586aae52e53f3f912492b19f7e14ab120d54238ae30b338f39662a410e6d707784d730f24d19dd9f75e85221b51b902a19d50c120844d15bf8a3b9e346355857e7381e5be19c6d3d22e01845565819aae7cacc93d75f1ef0c7b09d823865cdfa3671715e5bfc8dd8fc8baef26216e7941fa0c3"; +std::string rawTxRand1 = "9fc222b16be09eb88affbdfbcc02d1c8b28f5e843c72eb06c89dd7aff0c60838"; +std::string rawTxSerial1 = "b87754b165892c0f9634e3d03780ede24824125249cb8dfd4ad2c0be055cbead"; + +std::string rawTx2 = "01000000018c52504b2822c39dd7f4bd93e30562dc9d246e0b0dd4ee401ec2c24e9378be12000000006b483045022100e2628dbcd284dd4858e2c2d8e2d2d31eb222773b3026d39c79c489f5daf4ae2302200e0b1cb9a6d534dc86ea33afb8153a5a4c7cd4fb497c889fb991fbac8bf86802012103836a4868020f52f2ab9e5ec3634d2cd38794677fab47ae7a7128ea8102972ae0ffffffff022c0f0d8f000000001976a914e2e8e36a1a35da051341775315b1168494921acd88ac00e1f5050000000086c10280004c809d49caa17c3f1fb8bc93eabf54462c8ad1717ab646c8130ca0863ca5613f34751445cd7bde8ef1dd833645c7c205dd9b36171dc25209f46b04a34b5e06caa655eea9bd95b46f7d03ae60a97961dd6632c1050090ec1b6748199f0721eeec0822dd288c663020dd88ecda7c8abf8a409fa5c500c4188e52bfbe2ca77ce7b2700700000000"; +std::string rawTxpub2 = "770b2e77ca72cbebf528e18c400c5a59f408abf8a7cdaec88dd2030668c28dd2208ecee21079f1948671bec900005c13266dd6179a960ae037d6fb495bda9ee55a6ca065e4ba3046bf40952c21d17369bdd05c2c7453683ddf18ede7bcd451475343f61a53c86a00c13c846b67a71d18a2c4654bfea93bcb81f3f7ca1ca499d"; +std::string rawTxRand2 = "23040b1d889ca4a41cf50b88a380f3f3acffac750e221a268fedf700f063a886"; +std::string rawTxSerial2 = "37393797cb39e5f22bdc4fba8108edb5ea497ba0d22aba0781e58a8555df285c"; + +std::string rawTx3 = "01000000014651d7ed09c01d26679dd8ad1ee1f704f63167544ca48bdd3b4577444d540514010000006a47304402207995f8e30a87b74f36146d80ab02198319240a2eb3f93018c740e91b6812ff23022002677250aa9f9c7b6c1258647b0b0c03f89c7495b82b9c4dd2dcdb0ced82412801210236e3e30dbb1d62c8872413b2a771cd611b8042dfb5d06feb6805ba934ba534ffffffffff0200e1f5050000000086c10280004c803dac1997d38ee8650bb87fae490f4684a7b023744c95cd5ef025bc7f4d1414aff96947cebf342cfbfaf217ec0088e489d722d494409494a011a452af55a8cd4d2cef97f3b0307b66238623ab02b148a9e20f36782c8b7ea47c0c0b8226ddb91ee8f1f94c8c04df5c834993f27175b20b1da99d8338c674b1741a696c54def8012c0f0d8f000000001976a914c7f81b8e5650af548f5d56ef064da5c2d1ee09ae88ac00000000"; +std::string rawTxpub3 = "1f8de546c691a74b174c638839da91d0bb27571f29349835cdf048c4cf9f1e81eb9dd26820b0c7ca47e8b2c78360fe2a948b102ab238623667b30b0f397ef2c4dcda855af52a411a094944094d422d789e48800ec17f2fafb2c34bfce4769f9af14144d7fbc25f05ecd954c7423b0a784460f49ae7fb80b65e88ed39719ac3d"; +std::string rawTxRand3 = "1953c2919d658c3f654566400ace91563105ad5acc4e4151bca1e762c0877d7b"; +std::string rawTxSerial3 = "3abf349844720512325d129c95402edbc85d86fff89632a05dc18970560047a5"; + +std::vector > vecRawMints = {std::make_pair(rawTx1, rawTxSerial1), std::make_pair(rawTx2, rawTxSerial2), std::make_pair(rawTx3, rawTxSerial3)}; + +//create a zerocoin mint from vecsend +BOOST_AUTO_TEST_CASE(checkzerocoinmint_test) +{ + cout << "Running check_zerocoinmint_test...\n"; + CTransaction tx; + BOOST_CHECK(DecodeHexTx(tx, rawTx1)); + + 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()) { + BOOST_CHECK(CheckZerocoinMint(tx.GetHash(), tx.vout[i], state, true)); + fFoundMint = true; + } + } + + BOOST_CHECK(fFoundMint); +} + +bool CheckZerocoinSpendNoDB(const CTransaction tx, string& strError) +{ + //max needed non-mint outputs should be 2 - one for redemption address and a possible 2nd for change + if (tx.vout.size() > 2){ + int outs = 0; + for (const CTxOut out : tx.vout) { + if (out.IsZerocoinMint()) + continue; + outs++; + } + if (outs > 2) { + strError = "CheckZerocoinSpend(): over two non-mint outputs in a zerocoinspend transaction"; + return false; + } + + } + + //compute the txout hash that is used for the zerocoinspend signatures + CMutableTransaction txTemp; + for (const CTxOut out : tx.vout) { + txTemp.vout.push_back(out); + } + // uint256 hashTxOut = txTemp.GetHash(); + + bool fValidated = false; + set serials; + list vSpends; + CAmount nTotalRedeemed = 0; + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + + //only check txin that is a zcspend + if (!txin.scriptSig.IsZerocoinSpend()) + continue; + + CoinSpend newSpend = TxInToZerocoinSpend(txin); + vSpends.push_back(newSpend); + + //check that the denomination is valid + if (newSpend.getDenomination() == ZQ_ERROR) { + strError = "Zerocoinspend does not have the correct denomination"; + return false; + } + + //check that denomination is what it claims to be in nSequence + if (newSpend.getDenomination() != txin.nSequence) { + strError = "Zerocoinspend nSequence denomination does not match CoinSpend"; + } + + //make sure the txout has not changed +// if (newSpend.getTxOutHash() != hashTxOut) { +// strError = "Zerocoinspend does not use the same txout that was used in the SoK"; +// return false; +// } + + //see if we have record of the accumulator used in the spend tx + CBigNum bnAccumulatorValue = 0; + if (!GetAccumulatorValueFromChecksum(newSpend.getAccumulatorChecksum(), true, bnAccumulatorValue)) { + strError = "Zerocoinspend could not find accumulator associated with checksum"; + return false; + } + + Accumulator accumulator(Params().Zerocoin_Params(), newSpend.getDenomination(), bnAccumulatorValue); + + //Check that the coin is on the accumulator + if (!newSpend.Verify(accumulator)) { + strError = "CheckZerocoinSpend(): zerocoin spend did not verify"; + return false; + } + + if (serials.count(newSpend.getCoinSerialNumber())) { + strError = "Zerocoinspend serial is used twice in the same tx"; + return false; + } + serials.insert(newSpend.getCoinSerialNumber()); + + //cannot check this without database + // if(!IsZerocoinSpendUnknown(newSpend, tx.GetHash(), state)) + // return state.DoS(100, error("Zerocoinspend is already known")); + + //make sure that there is no over redemption of coins + nTotalRedeemed += ZerocoinDenominationToAmount(newSpend.getDenomination()); + fValidated = true; + } + + if (nTotalRedeemed < tx.GetValueOut()) { + strError = "Transaction spend more than was redeemed in zerocoins"; + return false; + } + + return fValidated; +} + +BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) +{ + cout << "Running check_zerocoinspend_test...\n"; + + //load our serialized pubcoin + CBigNum bnpubcoin; + BOOST_CHECK_MESSAGE(bnpubcoin.SetHexBool(rawTxpub1), "Failed to set CBigNum from hex string"); + PublicCoin pubCoin(Params().Zerocoin_Params(), bnpubcoin, CoinDenomination::ZQ_ONE); + BOOST_CHECK_MESSAGE(pubCoin.validate(), "Failed to validate pubCoin created from hex string"); + + //initialize and Accumulator and AccumulatorWitness + Accumulator accumulator(Params().Zerocoin_Params(), CoinDenomination::ZQ_ONE); + AccumulatorWitness witness(Params().Zerocoin_Params(), accumulator, pubCoin); + + //populate the witness and accumulators + CValidationState state; + for(pair raw : vecRawMints) { + CTransaction tx; + 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()) { + PublicCoin publicCoin(Params().Zerocoin_Params()); + BOOST_CHECK_MESSAGE(TxOutToPublicCoin(out, publicCoin, state), "Failed to convert CTxOut " << out.ToString() << " to PublicCoin"); + + accumulator += publicCoin; + witness += publicCoin; + } + } + } + + //spend our minted Zerocoin + CZerocoinMint zerocoinMint; + zerocoinMint.SetRandomness(CBigNum(rawTxRand1)); + zerocoinMint.SetSerialNumber(CBigNum(rawTxSerial1)); + // Create a New Zerocoin with specific denomination given by pubCoin + PrivateCoin privateCoin(Params().Zerocoin_Params(), pubCoin.getDenomination()); + privateCoin.setPublicCoin(pubCoin); + privateCoin.setRandomness(zerocoinMint.GetRandomness()); + privateCoin.setSerialNumber(zerocoinMint.GetSerialNumber()); + + //Get the checksum of the accumulator we use for the spend and also add it to our checksum map + uint32_t nChecksum = GetChecksum(accumulator.getValue()); + AddAccumulatorChecksum(nChecksum, accumulator.getValue(), true); + CoinSpend coinSpend(Params().Zerocoin_Params(), privateCoin, accumulator, nChecksum, witness, 0); + + CBigNum serial = coinSpend.getCoinSerialNumber(); + BOOST_CHECK_MESSAGE(serial, "Serial Number can't be 0"); + + CoinDenomination denom = coinSpend.getDenomination(); + BOOST_CHECK_MESSAGE(denom == pubCoin.getDenomination(), "Spend denomination must match original pubCoin"); + BOOST_CHECK_MESSAGE(coinSpend.Verify(accumulator), "CoinSpend object failed to validate"); + + //serialize the spend + CDataStream serializedCoinSpend2(SER_NETWORK, PROTOCOL_VERSION); + serializedCoinSpend2 << coinSpend; + std::vector data(serializedCoinSpend2.begin(), serializedCoinSpend2.end()); + + /** Check valid spend */ + CTxIn newTxIn; + newTxIn.nSequence = 1; + newTxIn.scriptSig = CScript() << OP_ZEROCOINSPEND << data.size(); + newTxIn.scriptSig.insert(newTxIn.scriptSig.end(), data.begin(), data.end()); + newTxIn.prevout.SetNull(); + + CScript script; + CTxOut txOut(1 * COIN, script); + + CTransaction txNew; + txNew.vin.push_back(newTxIn); + txNew.vout.push_back(txOut); + + CTransaction txMintFrom; + BOOST_CHECK_MESSAGE(DecodeHexTx(txMintFrom, rawTx1), "Failed to deserialize hex transaction"); + + string strError = ""; + if (!CheckZerocoinSpendNoDB(txNew, strError)) { + cout << state.GetRejectCode() << endl; + BOOST_CHECK_MESSAGE(false, strError); + } + + /**check an overspend*/ + CTxOut txOutOverSpend(100 * COIN, script); + CTransaction txOverSpend; + txOverSpend.vin.push_back(newTxIn); + txOverSpend.vout.push_back(txOutOverSpend); + strError = ""; + CheckZerocoinSpendNoDB(txOverSpend, strError); + string str = "Failed to detect overspend. Error Message: " + strError; + BOOST_CHECK_MESSAGE(strError == "Transaction spend more than was redeemed in zerocoins", str); +} + + +BOOST_AUTO_TEST_CASE(setup_exceptions_test) +{ + cout << "Running check_unitialized parameters,etc for setup exceptions...\n"; + + CBigNum bnpubcoin; + BOOST_CHECK(bnpubcoin.SetHexBool(rawTxpub1)); + + // Check Modulus > 1023 Exception + try { + ZerocoinParams ZCParams(bnpubcoin); + BOOST_CHECK_MESSAGE(false, "Didn't catch exception: ZerocoinException: Modulus must be at least 1023 bit"); + } + catch (...) { + BOOST_CHECK_MESSAGE(true, "Caught exception: ZerocoinException: Modulus must be at least 1023 bit"); + } + + // Check Security Level < 80 Exception + try { + ZerocoinParams ZCParams(bnpubcoin,1); + BOOST_CHECK_MESSAGE(false, "Didn't catch exception: Security Level >= 80"); + } + catch (...) { + BOOST_CHECK_MESSAGE(true, "Caught exception: ZerocoinException: Security Level >= 80"); + } + + // Check unitialized params Exception for PublicCoin + try { + zerocoinParams.initialized = false; + PublicCoin pubCoin(&zerocoinParams); + BOOST_CHECK_MESSAGE(false, "Didn't catch exception checking for uninitialized Params"); + } + catch (...) { + BOOST_CHECK_MESSAGE(true, "Caught exception checking for initalized Params"); + } + + // Check unitialized params Exception for PublicCoin (alternate constructor) + try { + zerocoinParams.initialized = false; + PublicCoin pubCoin(&zerocoinParams); + BOOST_CHECK_MESSAGE(false, "Didn't catch exception checking for uninitialized Params"); + } + catch (...) { + BOOST_CHECK_MESSAGE(true, "Caught exception checking for initalized Params"); + } + + // Check unitialized params Exception for PrivateCoin + try { + zerocoinParams.initialized = false; + PrivateCoin privCoin(&zerocoinParams, CoinDenomination::ZQ_ONE); + BOOST_CHECK_MESSAGE(false, "Didn't catch exception checking for uninitialized Params"); + } + catch (...) { + BOOST_CHECK_MESSAGE(true, "Caught exception checking for initalized Params"); + } + +} + +BOOST_AUTO_TEST_CASE(checksum_tests) +{ + cout << "Running checksum_tests\n"; + + uint256 checksum; + uint32_t c1 = 0xa3219ef1; + uint32_t c2 = 0xabcdef00; + uint32_t c3 = 0x101029f3; + uint32_t c4 = 0xaaaaaeee; + uint32_t c5 = 0xffffffff; + uint32_t c6 = 0xbbbbbbbb; + uint32_t c7 = 0x11111111; + uint32_t c8 = 0xeeeeeeee; + vector vChecksums {c1,c2,c3,c4,c5,c6,c7,c8}; + for(uint32_t c : vChecksums) + checksum = checksum << 32 | c; + + BOOST_CHECK_MESSAGE(checksum == uint256("a3219ef1abcdef00101029f3aaaaaeeeffffffffbbbbbbbb11111111eeeeeeee"), "checksum not properly concatenated"); + + int i = 0; + for (auto& denom : zerocoinDenomList){ + uint32_t checksumParsed = ParseChecksum(checksum, denom); + BOOST_CHECK_MESSAGE(checksumParsed == vChecksums[i], "checksum parse failed"); + i++; + } +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/zerocoin_transactions_tests.cpp b/src/test/zerocoin_transactions_tests.cpp new file mode 100644 index 000000000..a14488041 --- /dev/null +++ b/src/test/zerocoin_transactions_tests.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2012-2014 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 "libzerocoin/Denominations.h" +#include "amount.h" +#include "chainparams.h" +#include "coincontrol.h" +#include "main.h" +#include "wallet.h" +#include "walletdb.h" +#include "txdb.h" +#include +#include + +using namespace libzerocoin; + + +BOOST_AUTO_TEST_SUITE(zerocoin_transactions_tests) + +static CWallet cWallet("unlocked.dat"); + +BOOST_AUTO_TEST_CASE(zerocoin_spend_test) +{ + SelectParams(CBaseChainParams::MAIN); + ZerocoinParams *ZCParams = Params().Zerocoin_Params(); + (void)ZCParams; + + bool fFirstRun; + cWallet.LoadWallet(fFirstRun); + CMutableTransaction tx; + CWalletTx* wtx = new CWalletTx(&cWallet, tx); + bool fMintChange=true; + bool fMinimizeChange=true; + std::vector vSpends; + std::vector vMints; + CAmount nAmount = COIN; + int nSecurityLevel = 100; + + CZerocoinSpendReceipt receipt; + cWallet.SpendZerocoin(nAmount, nSecurityLevel, *wtx, receipt, vMints, fMintChange, fMinimizeChange); + + BOOST_CHECK_MESSAGE(receipt.GetStatus() == ZBWK_TRX_FUNDS_PROBLEMS, "Failed Invalid Amount Check"); + + nAmount = 1; + CZerocoinSpendReceipt receipt2; + cWallet.SpendZerocoin(nAmount, nSecurityLevel, *wtx, receipt2, vMints, fMintChange, fMinimizeChange); + + // 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() == ZBWK_TRX_FUNDS_PROBLEMS, "Failed Invalid Amount Check"); + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txdb.cpp b/src/txdb.cpp index 922903c55..5ad4191b5 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2016-2017 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,12 +9,14 @@ #include "main.h" #include "pow.h" #include "uint256.h" +#include "accumulators.h" #include #include using namespace std; +using namespace libzerocoin; void static BatchWriteCoins(CLevelDBBatch& batch, const uint256& hash, const CCoins& coins) { @@ -195,6 +198,16 @@ bool CBlockTreeDB::ReadFlag(const std::string& name, bool& fValue) return true; } +bool CBlockTreeDB::WriteInt(const std::string& name, int nValue) +{ + return Write(std::make_pair('I', name), nValue); +} + +bool CBlockTreeDB::ReadInt(const std::string& name, int& nValue) +{ + return Read(std::make_pair('I', name), nValue); +} + bool CBlockTreeDB::LoadBlockIndexGuts() { boost::scoped_ptr pcursor(NewIterator()); @@ -204,6 +217,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pcursor->Seek(ssKeySet.str()); // Load mapBlockIndex + uint256 nPreviousCheckpoint; while (pcursor->Valid()) { boost::this_thread::interruption_point(); try { @@ -233,6 +247,11 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; + //zerocoin + pindexNew->nAccumulatorCheckpoint = diskindex.nAccumulatorCheckpoint; + pindexNew->mapZerocoinSupply = diskindex.mapZerocoinSupply; + pindexNew->vMintDenominationsInBlock = diskindex.vMintDenominationsInBlock; + //Proof Of Stake pindexNew->nMint = diskindex.nMint; pindexNew->nMoneySupply = diskindex.nMoneySupply; @@ -242,6 +261,8 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nStakeTime = diskindex.nStakeTime; pindexNew->hashProofOfStake = diskindex.hashProofOfStake; + LogPrintf("%s: %s\n", pindexNew->hashMerkleRoot.ToString().c_str(), pindexNew->GetBlockHash().ToString().c_str()); + if (pindexNew->nHeight <= Params().LAST_POW_BLOCK()) { if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits)) return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString()); @@ -250,6 +271,12 @@ bool CBlockTreeDB::LoadBlockIndexGuts() if (pindexNew->IsProofOfStake()) setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); + //populate accumulator checksum map in memory + if(pindexNew->nAccumulatorCheckpoint != 0 && pindexNew->nAccumulatorCheckpoint != nPreviousCheckpoint) { + LoadAccumulatorValuesFromDB(pindexNew->nAccumulatorCheckpoint); + nPreviousCheckpoint = pindexNew->nAccumulatorCheckpoint; + } + pcursor->Next(); } else { break; // if shutdown requested or finished loading block index @@ -261,3 +288,79 @@ bool CBlockTreeDB::LoadBlockIndexGuts() return true; } + +CZerocoinDB::CZerocoinDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "zerocoin", nCacheSize, fMemory, fWipe) +{ +} + +bool CZerocoinDB::WriteCoinMint(const PublicCoin& pubCoin, const uint256& hashTx) +{ + CBigNum bnValue = pubCoin.getValue(); + CDataStream ss(SER_GETHASH, 0); + ss << pubCoin.getValue(); + uint256 hash = Hash(ss.begin(), ss.end()); + + return Write(make_pair('m', hash), hashTx, true); +} + +bool CZerocoinDB::ReadCoinMint(const CBigNum& bnPubcoin, uint256& hashTx) +{ + CDataStream ss(SER_GETHASH, 0); + ss << bnPubcoin; + uint256 hash = Hash(ss.begin(), ss.end()); + + return Read(make_pair('m', hash), hashTx); +} + +bool CZerocoinDB::EraseCoinMint(const CBigNum& bnPubcoin) +{ + CDataStream ss(SER_GETHASH, 0); + ss << bnPubcoin; + uint256 hash = Hash(ss.begin(), ss.end()); + + return Erase(make_pair('m', hash)); +} + +bool CZerocoinDB::WriteCoinSpend(const CBigNum& bnSerial, const uint256& txHash) +{ + CDataStream ss(SER_GETHASH, 0); + ss << bnSerial; + uint256 hash = Hash(ss.begin(), ss.end()); + + return Write(make_pair('s', hash), txHash, true); +} + +bool CZerocoinDB::ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash) +{ + CDataStream ss(SER_GETHASH, 0); + ss << bnSerial; + uint256 hash = Hash(ss.begin(), ss.end()); + + return Read(make_pair('s', hash), txHash); +} + +bool CZerocoinDB::EraseCoinSpend(const CBigNum& bnSerial) +{ + CDataStream ss(SER_GETHASH, 0); + ss << bnSerial; + uint256 hash = Hash(ss.begin(), ss.end()); + + return Erase(make_pair('s', hash)); +} + +bool CZerocoinDB::WriteAccumulatorValue(const uint32_t& nChecksum, const CBigNum& bnValue) +{ + LogPrint("zero","%s : checksum:%d val:%s\n", __func__, nChecksum, bnValue.GetHex()); + return Write(make_pair('a', nChecksum), bnValue); +} + +bool CZerocoinDB::ReadAccumulatorValue(const uint32_t& nChecksum, CBigNum& bnValue) +{ + return Read(make_pair('a', nChecksum), bnValue); +} + +bool CZerocoinDB::EraseAccumulatorValue(const uint32_t& nChecksum) +{ + LogPrint("zero", "%s : checksum:%d\n", __func__, nChecksum); + return Erase(make_pair('a', nChecksum)); +} diff --git a/src/txdb.h b/src/txdb.h index 42a2c9aed..e0b79c909 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin 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. @@ -8,6 +9,7 @@ #include "leveldbwrapper.h" #include "main.h" +#include "primitives/zerocoin.h" #include #include @@ -62,7 +64,30 @@ class CBlockTreeDB : public CLevelDBWrapper bool WriteTxIndex(const std::vector >& list); bool WriteFlag(const std::string& name, bool fValue); bool ReadFlag(const std::string& name, bool& fValue); + bool WriteInt(const std::string& name, int nValue); + bool ReadInt(const std::string& name, int& nValue); bool LoadBlockIndexGuts(); }; +class CZerocoinDB : public CLevelDBWrapper +{ +public: + CZerocoinDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); + +private: + CZerocoinDB(const CZerocoinDB&); + void operator=(const CZerocoinDB&); + +public: + bool WriteCoinMint(const libzerocoin::PublicCoin& pubCoin, const uint256& txHash); + bool ReadCoinMint(const CBigNum& bnPubcoin, uint256& txHash); + bool WriteCoinSpend(const CBigNum& bnSerial, const uint256& txHash); + bool ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash); + bool EraseCoinMint(const CBigNum& bnPubcoin); + bool EraseCoinSpend(const CBigNum& bnSerial); + bool WriteAccumulatorValue(const uint32_t& nChecksum, const CBigNum& bnValue); + bool ReadAccumulatorValue(const uint32_t& nChecksum, CBigNum& bnValue); + bool EraseAccumulatorValue(const uint32_t& nChecksum); +}; + #endif // BITCOIN_TXDB_H diff --git a/src/txmempool.cpp b/src/txmempool.cpp index c670be92a..b1c7b124b 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin 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. @@ -410,8 +411,10 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry) { mapTx[hash] = entry; const CTransaction& tx = mapTx[hash].GetTx(); - for (unsigned int i = 0; i < tx.vin.size(); i++) - mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); + if(!tx.IsZerocoinSpend()) { + for (unsigned int i = 0; i < tx.vin.size(); i++) + mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i); + } nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); } @@ -476,7 +479,7 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache* pcoins, unsigned in continue; const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); if (fSanityCheck) assert(coins); - if (!coins || ((coins->IsCoinBase() || coins->IsCoinStake()) && nMemPoolHeight - coins->nHeight < Params().COINBASE_MATURITY())) { + if (!coins || ((coins->IsCoinBase() || coins->IsCoinStake()) && nMemPoolHeight - coins->nHeight < (unsigned)Params().COINBASE_MATURITY())) { transactionsToRemove.push_back(tx); break; } diff --git a/src/txmempool.h b/src/txmempool.h index b936b6ea0..7e4911b9f 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin 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. @@ -17,7 +18,7 @@ class CAutoFile; inline double AllowFreeThreshold() { - return COIN * 576 / 250; + return COIN * 1440 / 250; } inline bool AllowFree(double dPriority) diff --git a/src/uint256.h b/src/uint256.h index 9975b0efa..6c2f62158 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -278,6 +278,11 @@ class base_uint { return pn[2 * n] | (uint64_t)pn[2 * n + 1] << 32; } + + uint32_t Get32(int n = 0) const + { + return pn[2 * n]; + } /** * Returns the position of the highest bit set plus one, or zero if the * value is zero. diff --git a/src/uint512.h b/src/uint512.h index 29a0a20b6..94dfda661 100644 --- a/src/uint512.h +++ b/src/uint512.h @@ -1,3 +1,7 @@ +// Copyright (c) 2017 The PIVX Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + #pragma once #include "arith_uint256.h" #include "uint256.h" diff --git a/src/univalue/.gitignore b/src/univalue/.gitignore new file mode 100644 index 000000000..19e42f814 --- /dev/null +++ b/src/univalue/.gitignore @@ -0,0 +1,32 @@ +.deps/ +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +compile +config.log +config.status +config.guess +config.sub +configure +depcomp +install-sh +missing +stamp-h1 +univalue-config.h* +test-driver +libtool +ltmain.sh +test-suite.log + +*.a +*.la +*.lo +*.logs +*.o +*.pc +*.trs + +.dirstamp +.libs diff --git a/src/univalue/.travis.yml b/src/univalue/.travis.yml new file mode 100644 index 000000000..132743d34 --- /dev/null +++ b/src/univalue/.travis.yml @@ -0,0 +1,52 @@ +language: cpp + +compiler: + - clang + - gcc + +os: + - linux + - osx + +sudo: false + +env: + global: + - MAKEJOBS=-j3 + - RUN_TESTS=true + - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out + +cache: + apt: true + +addons: + apt: + packages: + - pkg-config + +before_script: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall libtool; brew install libtool; fi + - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi + - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh + +script: + - if [ -n "$UNIVALUE_CONFIG" ]; then unset CC; unset CXX; fi + - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST + - UNIVALUE_CONFIG_ALL="--prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" + - ./configure --cache-file=config.cache $UNIVALUE_CONFIG_ALL $UNIVALUE_CONFIG || ( cat config.log && false) + - make -s $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL ; false ) + - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib + - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi + +matrix: + fast_finish: true + include: + - os: linux + compiler: gcc + env: UNIVALUE_CONFIG=--host=x86_64-w64-mingw32 RUN_TESTS=false + addons: + apt: + packages: + - g++-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - binutils-mingw-w64-x86-64 diff --git a/src/univalue/COPYING b/src/univalue/COPYING new file mode 100644 index 000000000..1fb429f35 --- /dev/null +++ b/src/univalue/COPYING @@ -0,0 +1,19 @@ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/src/univalue/Makefile.am b/src/univalue/Makefile.am new file mode 100644 index 000000000..287bb97fe --- /dev/null +++ b/src/univalue/Makefile.am @@ -0,0 +1,115 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 +.PHONY: gen +.INTERMEDIATE: $(GENBIN) + +include_HEADERS = include/univalue.h +noinst_HEADERS = lib/univalue_escapes.h lib/univalue_utffilter.h + +lib_LTLIBRARIES = libunivalue.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = pc/libunivalue.pc + +libunivalue_la_SOURCES = \ + lib/univalue.cpp \ + lib/univalue_read.cpp \ + lib/univalue_write.cpp + +libunivalue_la_LDFLAGS = \ + -version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \ + -no-undefined +libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include + +TESTS = test/object test/unitester test/no_nul + +GENBIN = gen/gen$(BUILD_EXEEXT) +GEN_SRCS = gen/gen.cpp + +$(GENBIN): $(GEN_SRCS) + @echo Building $@ + $(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $< + +gen: lib/univalue_escapes.h $(GENBIN) + @echo Updating $< + $(AM_V_at)$(GENBIN) > lib/univalue_escapes.h + +noinst_PROGRAMS = $(TESTS) test/test_json + +TEST_DATA_DIR=test + +test_unitester_SOURCES = test/unitester.cpp +test_unitester_LDADD = libunivalue.la +test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\" +test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +test_test_json_SOURCES = test/test_json.cpp +test_test_json_LDADD = libunivalue.la +test_test_json_CXXFLAGS = -I$(top_srcdir)/include +test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +test_no_nul_SOURCES = test/no_nul.cpp +test_no_nul_LDADD = libunivalue.la +test_no_nul_CXXFLAGS = -I$(top_srcdir)/include +test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +test_object_SOURCES = test/object.cpp +test_object_LDADD = libunivalue.la +test_object_CXXFLAGS = -I$(top_srcdir)/include +test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +TEST_FILES = \ + $(TEST_DATA_DIR)/fail10.json \ + $(TEST_DATA_DIR)/fail11.json \ + $(TEST_DATA_DIR)/fail12.json \ + $(TEST_DATA_DIR)/fail13.json \ + $(TEST_DATA_DIR)/fail14.json \ + $(TEST_DATA_DIR)/fail15.json \ + $(TEST_DATA_DIR)/fail16.json \ + $(TEST_DATA_DIR)/fail17.json \ + $(TEST_DATA_DIR)/fail18.json \ + $(TEST_DATA_DIR)/fail19.json \ + $(TEST_DATA_DIR)/fail1.json \ + $(TEST_DATA_DIR)/fail20.json \ + $(TEST_DATA_DIR)/fail21.json \ + $(TEST_DATA_DIR)/fail22.json \ + $(TEST_DATA_DIR)/fail23.json \ + $(TEST_DATA_DIR)/fail24.json \ + $(TEST_DATA_DIR)/fail25.json \ + $(TEST_DATA_DIR)/fail26.json \ + $(TEST_DATA_DIR)/fail27.json \ + $(TEST_DATA_DIR)/fail28.json \ + $(TEST_DATA_DIR)/fail29.json \ + $(TEST_DATA_DIR)/fail2.json \ + $(TEST_DATA_DIR)/fail30.json \ + $(TEST_DATA_DIR)/fail31.json \ + $(TEST_DATA_DIR)/fail32.json \ + $(TEST_DATA_DIR)/fail33.json \ + $(TEST_DATA_DIR)/fail34.json \ + $(TEST_DATA_DIR)/fail35.json \ + $(TEST_DATA_DIR)/fail36.json \ + $(TEST_DATA_DIR)/fail37.json \ + $(TEST_DATA_DIR)/fail38.json \ + $(TEST_DATA_DIR)/fail39.json \ + $(TEST_DATA_DIR)/fail40.json \ + $(TEST_DATA_DIR)/fail41.json \ + $(TEST_DATA_DIR)/fail42.json \ + $(TEST_DATA_DIR)/fail44.json \ + $(TEST_DATA_DIR)/fail3.json \ + $(TEST_DATA_DIR)/fail4.json \ + $(TEST_DATA_DIR)/fail5.json \ + $(TEST_DATA_DIR)/fail6.json \ + $(TEST_DATA_DIR)/fail7.json \ + $(TEST_DATA_DIR)/fail8.json \ + $(TEST_DATA_DIR)/fail9.json \ + $(TEST_DATA_DIR)/pass1.json \ + $(TEST_DATA_DIR)/pass2.json \ + $(TEST_DATA_DIR)/pass3.json \ + $(TEST_DATA_DIR)/round1.json \ + $(TEST_DATA_DIR)/round2.json \ + $(TEST_DATA_DIR)/round3.json \ + $(TEST_DATA_DIR)/round4.json \ + $(TEST_DATA_DIR)/round5.json \ + $(TEST_DATA_DIR)/round6.json \ + $(TEST_DATA_DIR)/round7.json + +EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS) diff --git a/src/univalue/README.md b/src/univalue/README.md new file mode 100644 index 000000000..36aa786a4 --- /dev/null +++ b/src/univalue/README.md @@ -0,0 +1,32 @@ + +# UniValue + +## Summary + +A universal value class, with JSON encoding and decoding. + +UniValue is an abstract data type that may be a null, boolean, string, +number, array container, or a key/value dictionary container, nested to +an arbitrary depth. + +This class is aligned with the JSON standard, [RFC +7159](https://tools.ietf.org/html/rfc7159.html). + +## Installation + +This project is a standard GNU +[autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html) +project. Build and install instructions are available in the `INSTALL` +file provided with GNU autotools. + +``` +$ ./autogen.sh +$ ./configure +$ make +``` + +## Design + +UniValue provides a single dynamic RAII C++ object class, +and minimizes template use (contra json_spirit). + diff --git a/src/univalue/TODO b/src/univalue/TODO new file mode 100644 index 000000000..5530048e9 --- /dev/null +++ b/src/univalue/TODO @@ -0,0 +1,10 @@ + +Rearrange tree for easier 'git subtree' style use + +Move towards C++11 etc. + +Namespace support - must come up with useful shorthand, avoiding +long Univalue::Univalue::Univalue usages forced upon library users. + +Improve test suite + diff --git a/src/univalue/autogen.sh b/src/univalue/autogen.sh new file mode 100755 index 000000000..4b38721fa --- /dev/null +++ b/src/univalue/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +srcdir="$(dirname $0)" +cd "$srcdir" +if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then + LIBTOOLIZE="${GLIBTOOLIZE}" + export LIBTOOLIZE +fi +autoreconf --install --force diff --git a/src/univalue/build-aux/m4/.gitignore b/src/univalue/build-aux/m4/.gitignore new file mode 100644 index 000000000..f06368652 --- /dev/null +++ b/src/univalue/build-aux/m4/.gitignore @@ -0,0 +1 @@ +/*.m4 diff --git a/src/univalue/configure.ac b/src/univalue/configure.ac new file mode 100644 index 000000000..8298332ac --- /dev/null +++ b/src/univalue/configure.ac @@ -0,0 +1,69 @@ +m4_define([libunivalue_major_version], [1]) +m4_define([libunivalue_minor_version], [1]) +m4_define([libunivalue_micro_version], [3]) +m4_define([libunivalue_interface_age], [3]) +# If you need a modifier for the version number. +# Normally empty, but can be used to make "fixup" releases. +m4_define([libunivalue_extraversion], []) + +dnl libtool versioning from libunivalue +m4_define([libunivalue_current], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version - libunivalue_interface_age)]) +m4_define([libunivalue_binary_age], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version)]) +m4_define([libunivalue_revision], [libunivalue_interface_age]) +m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_interface_age)]) +m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()]) + + +AC_INIT([univalue], [1.0.3], + [http://github.com/jgarzik/univalue/]) + +dnl make the compilation flags quiet unless V=1 is used +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_PREREQ(2.60) +AC_CONFIG_SRCDIR([lib/univalue.cpp]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CONFIG_HEADERS([univalue-config.h]) +AM_INIT_AUTOMAKE([subdir-objects foreign]) + +LIBUNIVALUE_MAJOR_VERSION=libunivalue_major_version +LIBUNIVALUE_MINOR_VERSION=libunivalue_minor_version +LIBUNIVALUE_MICRO_VERSION=libunivalue_micro_version +LIBUNIVALUE_INTERFACE_AGE=libunivalue_interface_age + +# ABI version +# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +LIBUNIVALUE_CURRENT=libunivalue_current +LIBUNIVALUE_REVISION=libunivalue_revision +LIBUNIVALUE_AGE=libunivalue_age + +AC_SUBST(LIBUNIVALUE_CURRENT) +AC_SUBST(LIBUNIVALUE_REVISION) +AC_SUBST(LIBUNIVALUE_AGE) + +LT_INIT +LT_LANG([C++]) + +case $host in + *mingw*) + LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static" + ;; +esac + +BUILD_EXEEXT= +case $build in + *mingw*) + BUILD_EXEEXT=".exe" + ;; +esac + +AC_CONFIG_FILES([ + Makefile + pc/libunivalue.pc + pc/libunivalue-uninstalled.pc]) + +AC_SUBST(LIBTOOL_APP_LDFLAGS) +AC_SUBST(BUILD_EXEEXT) +AC_OUTPUT + diff --git a/src/univalue/gen.cpp b/src/univalue/gen/gen.cpp similarity index 73% rename from src/univalue/gen.cpp rename to src/univalue/gen/gen.cpp index f0b352eef..17f361941 100644 --- a/src/univalue/gen.cpp +++ b/src/univalue/gen/gen.cpp @@ -1,5 +1,5 @@ // Copyright 2014 BitPay Inc. -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // @@ -8,7 +8,6 @@ // $ ./gen > univalue_escapes.h // -#include #include #include #include "univalue.h" @@ -16,18 +15,25 @@ using namespace std; static bool initEscapes; -static const char *escapes[256]; +static std::string escapes[256]; static void initJsonEscape() { + // Escape all lower control characters (some get overridden with smaller sequences below) + for (int ch=0x00; ch<0x20; ++ch) { + char tmpbuf[20]; + snprintf(tmpbuf, sizeof(tmpbuf), "\\u%04x", ch); + escapes[ch] = std::string(tmpbuf); + } + escapes[(int)'"'] = "\\\""; escapes[(int)'\\'] = "\\\\"; - escapes[(int)'/'] = "\\/"; escapes[(int)'\b'] = "\\b"; escapes[(int)'\f'] = "\\f"; escapes[(int)'\n'] = "\\n"; escapes[(int)'\r'] = "\\r"; escapes[(int)'\t'] = "\\t"; + escapes[(int)'\x7f'] = "\\u007f"; // U+007F DELETE initEscapes = true; } @@ -40,13 +46,13 @@ static void outputEscape() "static const char *escapes[256] = {\n"); for (unsigned int i = 0; i < 256; i++) { - if (!escapes[i]) { + if (escapes[i].empty()) { printf("\tNULL,\n"); } else { printf("\t\""); unsigned int si; - for (si = 0; si < strlen(escapes[i]); si++) { + for (si = 0; si < escapes[i].size(); si++) { char ch = escapes[i][si]; switch (ch) { case '"': diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h new file mode 100644 index 000000000..cc92cd2a9 --- /dev/null +++ b/src/univalue/include/univalue.h @@ -0,0 +1,296 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef __UNIVALUE_H__ +#define __UNIVALUE_H__ + +#include + +#include +#include +#include +#include + +#include // .get_int64() +#include // std::pair + +class UniValue { +public: + enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; + + UniValue() { typ = VNULL; } + UniValue(UniValue::VType initialType, const std::string& initialStr = "") { + typ = initialType; + val = initialStr; + } + UniValue(uint64_t val_) { + setInt(val_); + } + UniValue(int64_t val_) { + setInt(val_); + } + UniValue(bool val_) { + setBool(val_); + } + UniValue(int val_) { + setInt(val_); + } + UniValue(double val_) { + setFloat(val_); + } + UniValue(const std::string& val_) { + setStr(val_); + } + UniValue(const char *val_) { + std::string s(val_); + setStr(s); + } + ~UniValue() {} + + void clear(); + + bool setNull(); + bool setBool(bool val); + bool setNumStr(const std::string& val); + bool setInt(uint64_t val); + bool setInt(int64_t val); + bool setInt(int val_) { return setInt((int64_t)val_); } + bool setFloat(double val); + bool setStr(const std::string& val); + bool setArray(); + bool setObject(); + + enum VType getType() const { return typ; } + const std::string& getValStr() const { return val; } + bool empty() const { return (values.size() == 0); } + + size_t size() const { return values.size(); } + + bool getBool() const { return isTrue(); } + bool checkObject(const std::map& memberTypes); + const UniValue& operator[](const std::string& key) const; + const UniValue& operator[](size_t index) const; + bool exists(const std::string& key) const { size_t i; return findKey(key, i); } + + bool isNull() const { return (typ == VNULL); } + bool isTrue() const { return (typ == VBOOL) && (val == "1"); } + bool isFalse() const { return (typ == VBOOL) && (val != "1"); } + bool isBool() const { return (typ == VBOOL); } + bool isStr() const { return (typ == VSTR); } + bool isNum() const { return (typ == VNUM); } + bool isArray() const { return (typ == VARR); } + bool isObject() const { return (typ == VOBJ); } + + bool push_back(const UniValue& val); + bool push_back(const std::string& val_) { + UniValue tmpVal(VSTR, val_); + return push_back(tmpVal); + } + bool push_back(const char *val_) { + std::string s(val_); + return push_back(s); + } + bool push_back(uint64_t val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } + bool push_back(int64_t val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } + bool push_back(int val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } + bool push_backV(const std::vector& vec); + + bool pushKV(const std::string& key, const UniValue& val); + bool pushKV(const std::string& key, const std::string& val_) { + UniValue tmpVal(VSTR, val_); + return pushKV(key, tmpVal); + } + bool pushKV(const std::string& key, const char *val_) { + std::string _val(val_); + return pushKV(key, _val); + } + bool pushKV(const std::string& key, int64_t val_) { + UniValue tmpVal(val_); + return pushKV(key, tmpVal); + } + bool pushKV(const std::string& key, uint64_t val_) { + UniValue tmpVal(val_); + return pushKV(key, tmpVal); + } + bool pushKV(const std::string& key, int val_) { + UniValue tmpVal((int64_t)val_); + return pushKV(key, tmpVal); + } + bool pushKV(const std::string& key, double val_) { + UniValue tmpVal(val_); + return pushKV(key, tmpVal); + } + bool pushKVs(const UniValue& obj); + + std::string write(unsigned int prettyIndent = 0, + unsigned int indentLevel = 0) const; + + bool read(const char *raw, size_t len); + bool read(const char *raw); + bool read(const std::string& rawStr) { + return read(rawStr.data(), rawStr.size()); + } + +private: + UniValue::VType typ; + std::string val; // numbers are stored as C++ strings + std::vector keys; + std::vector values; + + bool findKey(const std::string& key, size_t& retIdx) const; + void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; + void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; + +public: + // Strict type-specific getters, these throw std::runtime_error if the + // value is of unexpected type + const std::vector& getKeys() const; + const std::vector& getValues() const; + bool get_bool() const; + const std::string& get_str() const; + int get_int() const; + int64_t get_int64() const; + double get_real() const; + const UniValue& get_obj() const; + const UniValue& get_array() const; + + enum VType type() const { return getType(); } + bool push_back(std::pair pear) { + return pushKV(pear.first, pear.second); + } + friend const UniValue& find_value( const UniValue& obj, const std::string& name); +}; + +// +// The following were added for compatibility with json_spirit. +// Most duplicate other methods, and should be removed. +// +static inline std::pair Pair(const char *cKey, const char *cVal) +{ + std::string key(cKey); + UniValue uVal(cVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, std::string strVal) +{ + std::string key(cKey); + UniValue uVal(strVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, uint64_t u64Val) +{ + std::string key(cKey); + UniValue uVal(u64Val); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, int64_t i64Val) +{ + std::string key(cKey); + UniValue uVal(i64Val); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, bool iVal) +{ + std::string key(cKey); + UniValue uVal(iVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, int iVal) +{ + std::string key(cKey); + UniValue uVal(iVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, double dVal) +{ + std::string key(cKey); + UniValue uVal(dVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, const UniValue& uVal) +{ + std::string key(cKey); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(std::string key, const UniValue& uVal) +{ + return std::make_pair(key, uVal); +} + +enum jtokentype { + JTOK_ERR = -1, + JTOK_NONE = 0, // eof + JTOK_OBJ_OPEN, + JTOK_OBJ_CLOSE, + JTOK_ARR_OPEN, + JTOK_ARR_CLOSE, + JTOK_COLON, + JTOK_COMMA, + JTOK_KW_NULL, + JTOK_KW_TRUE, + JTOK_KW_FALSE, + JTOK_NUMBER, + JTOK_STRING, +}; + +extern enum jtokentype getJsonToken(std::string& tokenVal, + unsigned int& consumed, const char *raw, const char *end); +extern const char *uvTypeName(UniValue::VType t); + +static inline bool jsonTokenIsValue(enum jtokentype jtt) +{ + switch (jtt) { + case JTOK_KW_NULL: + case JTOK_KW_TRUE: + case JTOK_KW_FALSE: + case JTOK_NUMBER: + case JTOK_STRING: + return true; + + default: + return false; + } + + // not reached +} + +static inline bool json_isspace(int ch) +{ + switch (ch) { + case 0x20: + case 0x09: + case 0x0a: + case 0x0d: + return true; + + default: + return false; + } + + // not reached +} + +extern const UniValue NullUniValue; + +const UniValue& find_value( const UniValue& obj, const std::string& name); + +#endif // __UNIVALUE_H__ diff --git a/src/univalue/lib/.gitignore b/src/univalue/lib/.gitignore new file mode 100644 index 000000000..ee7fc2851 --- /dev/null +++ b/src/univalue/lib/.gitignore @@ -0,0 +1,2 @@ +gen +.libs diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp new file mode 100644 index 000000000..b9491a967 --- /dev/null +++ b/src/univalue/lib/univalue.cpp @@ -0,0 +1,359 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "univalue.h" + +namespace +{ +static bool ParsePrechecks(const std::string& str) +{ + if (str.empty()) // No empty string allowed + return false; + if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed + return false; + if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed + return false; + return true; +} + +bool ParseInt32(const std::string& str, int32_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = NULL; + errno = 0; // strtol will not set errno if valid + long int n = strtol(str.c_str(), &endp, 10); + if(out) *out = (int32_t)n; + // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit + // platforms the size of these types may be different. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseInt64(const std::string& str, int64_t *out) +{ + if (!ParsePrechecks(str)) + return false; + char *endp = NULL; + errno = 0; // strtoll will not set errno if valid + long long int n = strtoll(str.c_str(), &endp, 10); + if(out) *out = (int64_t)n; + // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow + // we still have to check that the returned value is within the range of an *int64_t*. + return endp && *endp == 0 && !errno && + n >= std::numeric_limits::min() && + n <= std::numeric_limits::max(); +} + +bool ParseDouble(const std::string& str, double *out) +{ + if (!ParsePrechecks(str)) + return false; + if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed + return false; + std::istringstream text(str); + text.imbue(std::locale::classic()); + double result; + text >> result; + if(out) *out = result; + return text.eof() && !text.fail(); +} +} + +using namespace std; + +const UniValue NullUniValue; + +void UniValue::clear() +{ + typ = VNULL; + val.clear(); + keys.clear(); + values.clear(); +} + +bool UniValue::setNull() +{ + clear(); + return true; +} + +bool UniValue::setBool(bool val_) +{ + clear(); + typ = VBOOL; + if (val_) + val = "1"; + return true; +} + +static bool validNumStr(const string& s) +{ + string tokenVal; + unsigned int consumed; + enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size()); + return (tt == JTOK_NUMBER); +} + +bool UniValue::setNumStr(const string& val_) +{ + if (!validNumStr(val_)) + return false; + + clear(); + typ = VNUM; + val = val_; + return true; +} + +bool UniValue::setInt(uint64_t val_) +{ + ostringstream oss; + + oss << val_; + + return setNumStr(oss.str()); +} + +bool UniValue::setInt(int64_t val_) +{ + ostringstream oss; + + oss << val_; + + return setNumStr(oss.str()); +} + +bool UniValue::setFloat(double val_) +{ + ostringstream oss; + + oss << std::setprecision(16) << val_; + + bool ret = setNumStr(oss.str()); + typ = VNUM; + return ret; +} + +bool UniValue::setStr(const string& val_) +{ + clear(); + typ = VSTR; + val = val_; + return true; +} + +bool UniValue::setArray() +{ + clear(); + typ = VARR; + return true; +} + +bool UniValue::setObject() +{ + clear(); + typ = VOBJ; + return true; +} + +bool UniValue::push_back(const UniValue& val_) +{ + if (typ != VARR) + return false; + + values.push_back(val_); + return true; +} + +bool UniValue::push_backV(const std::vector& vec) +{ + if (typ != VARR) + return false; + + values.insert(values.end(), vec.begin(), vec.end()); + + return true; +} + +bool UniValue::pushKV(const std::string& key, const UniValue& val_) +{ + if (typ != VOBJ) + return false; + + keys.push_back(key); + values.push_back(val_); + return true; +} + +bool UniValue::pushKVs(const UniValue& obj) +{ + if (typ != VOBJ || obj.typ != VOBJ) + return false; + + for (unsigned int i = 0; i < obj.keys.size(); i++) { + keys.push_back(obj.keys[i]); + values.push_back(obj.values.at(i)); + } + + return true; +} + +bool UniValue::findKey(const std::string& key, size_t& retIdx) const +{ + for (size_t i = 0; i < keys.size(); i++) { + if (keys[i] == key) { + retIdx = i; + return true; + } + } + + return false; +} + +bool UniValue::checkObject(const std::map& t) +{ + for (std::map::const_iterator it = t.begin(); + it != t.end(); ++it) { + size_t idx = 0; + if (!findKey(it->first, idx)) + return false; + + if (values.at(idx).getType() != it->second) + return false; + } + + return true; +} + +const UniValue& UniValue::operator[](const std::string& key) const +{ + if (typ != VOBJ) + return NullUniValue; + + size_t index = 0; + if (!findKey(key, index)) + return NullUniValue; + + return values.at(index); +} + +const UniValue& UniValue::operator[](size_t index) const +{ + if (typ != VOBJ && typ != VARR) + return NullUniValue; + if (index >= values.size()) + return NullUniValue; + + return values.at(index); +} + +const char *uvTypeName(UniValue::VType t) +{ + switch (t) { + case UniValue::VNULL: return "null"; + case UniValue::VBOOL: return "bool"; + case UniValue::VOBJ: return "object"; + case UniValue::VARR: return "array"; + case UniValue::VSTR: return "string"; + case UniValue::VNUM: return "number"; + } + + // not reached + return NULL; +} + +const UniValue& find_value(const UniValue& obj, const std::string& name) +{ + for (unsigned int i = 0; i < obj.keys.size(); i++) + if (obj.keys[i] == name) + return obj.values.at(i); + + return NullUniValue; +} + +const std::vector& UniValue::getKeys() const +{ + if (typ != VOBJ) + throw std::runtime_error("JSON value is not an object as expected"); + return keys; +} + +const std::vector& UniValue::getValues() const +{ + if (typ != VOBJ && typ != VARR) + throw std::runtime_error("JSON value is not an object or array as expected"); + return values; +} + +bool UniValue::get_bool() const +{ + if (typ != VBOOL) + throw std::runtime_error("JSON value is not a boolean as expected"); + return getBool(); +} + +const std::string& UniValue::get_str() const +{ + if (typ != VSTR) + throw std::runtime_error("JSON value is not a string as expected"); + return getValStr(); +} + +int UniValue::get_int() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not an integer as expected"); + int32_t retval; + if (!ParseInt32(getValStr(), &retval)) + throw std::runtime_error("JSON integer out of range"); + return retval; +} + +int64_t UniValue::get_int64() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not an integer as expected"); + int64_t retval; + if (!ParseInt64(getValStr(), &retval)) + throw std::runtime_error("JSON integer out of range"); + return retval; +} + +double UniValue::get_real() const +{ + if (typ != VNUM) + throw std::runtime_error("JSON value is not a number as expected"); + double retval; + if (!ParseDouble(getValStr(), &retval)) + throw std::runtime_error("JSON double out of range"); + return retval; +} + +const UniValue& UniValue::get_obj() const +{ + if (typ != VOBJ) + throw std::runtime_error("JSON value is not an object as expected"); + return *this; +} + +const UniValue& UniValue::get_array() const +{ + if (typ != VARR) + throw std::runtime_error("JSON value is not an array as expected"); + return *this; +} + diff --git a/src/univalue/univalue_escapes.h b/src/univalue/lib/univalue_escapes.h similarity index 84% rename from src/univalue/univalue_escapes.h rename to src/univalue/lib/univalue_escapes.h index 051411828..74596aab6 100644 --- a/src/univalue/univalue_escapes.h +++ b/src/univalue/lib/univalue_escapes.h @@ -2,38 +2,38 @@ #ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H #define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H static const char *escapes[256] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + "\\u0000", + "\\u0001", + "\\u0002", + "\\u0003", + "\\u0004", + "\\u0005", + "\\u0006", + "\\u0007", "\\b", "\\t", "\\n", - NULL, + "\\u000b", "\\f", "\\r", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + "\\u000e", + "\\u000f", + "\\u0010", + "\\u0011", + "\\u0012", + "\\u0013", + "\\u0014", + "\\u0015", + "\\u0016", + "\\u0017", + "\\u0018", + "\\u0019", + "\\u001a", + "\\u001b", + "\\u001c", + "\\u001d", + "\\u001e", + "\\u001f", NULL, NULL, "\\\"", @@ -49,7 +49,6 @@ static const char *escapes[256] = { NULL, NULL, NULL, - "\\/", NULL, NULL, NULL, @@ -94,8 +93,8 @@ static const char *escapes[256] = { NULL, NULL, NULL, - "\\\\", NULL, + "\\\\", NULL, NULL, NULL, @@ -130,6 +129,7 @@ static const char *escapes[256] = { NULL, NULL, NULL, + "\\u007f", NULL, NULL, NULL, diff --git a/src/univalue/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp similarity index 60% rename from src/univalue/univalue_read.cpp rename to src/univalue/lib/univalue_read.cpp index 405be3e81..2bd83238b 100644 --- a/src/univalue/univalue_read.cpp +++ b/src/univalue/lib/univalue_read.cpp @@ -1,14 +1,20 @@ // Copyright 2014 BitPay Inc. -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include "univalue.h" +#include "univalue_utffilter.h" using namespace std; +static bool json_isdigit(int ch) +{ + return ((ch >= '0') && (ch <= '9')); +} + // convert hexadecimal string to unsigned integer static const char *hatoui(const char *first, const char *last, unsigned int& out) @@ -17,7 +23,7 @@ static const char *hatoui(const char *first, const char *last, for (; first != last; ++first) { int digit; - if (isdigit(*first)) + if (json_isdigit(*first)) digit = *first - '0'; else if (*first >= 'a' && *first <= 'f') @@ -37,21 +43,21 @@ static const char *hatoui(const char *first, const char *last, } enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, - const char *raw) + const char *raw, const char *end) { tokenVal.clear(); consumed = 0; const char *rawStart = raw; - while ((*raw) && (isspace(*raw))) // skip whitespace + while (raw < end && (json_isspace(*raw))) // skip whitespace raw++; - switch (*raw) { - - case 0: + if (raw >= end) return JTOK_NONE; + switch (*raw) { + case '{': raw++; consumed = (raw - rawStart); @@ -113,48 +119,48 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, const char *first = raw; const char *firstDigit = first; - if (!isdigit(*firstDigit)) + if (!json_isdigit(*firstDigit)) firstDigit++; - if ((*firstDigit == '0') && isdigit(firstDigit[1])) + if ((*firstDigit == '0') && json_isdigit(firstDigit[1])) return JTOK_ERR; numStr += *raw; // copy first char raw++; - if ((*first == '-') && (!isdigit(*raw))) + if ((*first == '-') && (raw < end) && (!json_isdigit(*raw))) return JTOK_ERR; - while ((*raw) && isdigit(*raw)) { // copy digits + while (raw < end && json_isdigit(*raw)) { // copy digits numStr += *raw; raw++; } // part 2: frac - if (*raw == '.') { + if (raw < end && *raw == '.') { numStr += *raw; // copy . raw++; - if (!isdigit(*raw)) + if (raw >= end || !json_isdigit(*raw)) return JTOK_ERR; - while ((*raw) && isdigit(*raw)) { // copy digits + while (raw < end && json_isdigit(*raw)) { // copy digits numStr += *raw; raw++; } } // part 3: exp - if (*raw == 'e' || *raw == 'E') { + if (raw < end && (*raw == 'e' || *raw == 'E')) { numStr += *raw; // copy E raw++; - if (*raw == '-' || *raw == '+') { // copy +/- + if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/- numStr += *raw; raw++; } - if (!isdigit(*raw)) + if (raw >= end || !json_isdigit(*raw)) return JTOK_ERR; - while ((*raw) && isdigit(*raw)) { // copy digits + while (raw < end && json_isdigit(*raw)) { // copy digits numStr += *raw; raw++; } @@ -169,44 +175,35 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, raw++; // skip " string valStr; + JSONUTF8StringFilter writer(valStr); - while (*raw) { - if (*raw < 0x20) + while (true) { + if (raw >= end || (unsigned char)*raw < 0x20) return JTOK_ERR; else if (*raw == '\\') { raw++; // skip backslash + if (raw >= end) + return JTOK_ERR; + switch (*raw) { - case '"': valStr += "\""; break; - case '\\': valStr += "\\"; break; - case '/': valStr += "/"; break; - case 'b': valStr += "\b"; break; - case 'f': valStr += "\f"; break; - case 'n': valStr += "\n"; break; - case 'r': valStr += "\r"; break; - case 't': valStr += "\t"; break; + case '"': writer.push_back('\"'); break; + case '\\': writer.push_back('\\'); break; + case '/': writer.push_back('/'); break; + case 'b': writer.push_back('\b'); break; + case 'f': writer.push_back('\f'); break; + case 'n': writer.push_back('\n'); break; + case 'r': writer.push_back('\r'); break; + case 't': writer.push_back('\t'); break; case 'u': { - char buf[4] = {0,0,0,0}; - char *last = &buf[0]; unsigned int codepoint; - if (hatoui(raw + 1, raw + 1 + 4, codepoint) != + if (raw + 1 + 4 >= end || + hatoui(raw + 1, raw + 1 + 4, codepoint) != raw + 1 + 4) return JTOK_ERR; - - if (codepoint <= 0x7f) - *last = (char)codepoint; - else if (codepoint <= 0x7FF) { - *last++ = (char)(0xC0 | (codepoint >> 6)); - *last = (char)(0x80 | (codepoint & 0x3F)); - } else if (codepoint <= 0xFFFF) { - *last++ = (char)(0xE0 | (codepoint >> 12)); - *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F)); - *last = (char)(0x80 | (codepoint & 0x3F)); - } - - valStr += buf; + writer.push_back_u(codepoint); raw += 4; break; } @@ -224,11 +221,13 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, } else { - valStr += *raw; + writer.push_back(*raw); raw++; } } + if (!writer.finalize()) + return JTOK_ERR; tokenVal = valStr; consumed = (raw - rawStart); return JTOK_STRING; @@ -239,26 +238,73 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed, } } -bool UniValue::read(const char *raw) +enum expect_bits { + EXP_OBJ_NAME = (1U << 0), + EXP_COLON = (1U << 1), + EXP_ARR_VALUE = (1U << 2), + EXP_VALUE = (1U << 3), + EXP_NOT_VALUE = (1U << 4), +}; + +#define expect(bit) (expectMask & (EXP_##bit)) +#define setExpect(bit) (expectMask |= EXP_##bit) +#define clearExpect(bit) (expectMask &= ~EXP_##bit) + +bool UniValue::read(const char *raw, size_t size) { clear(); - bool expectName = false; - bool expectColon = false; + uint32_t expectMask = 0; vector stack; + string tokenVal; + unsigned int consumed; enum jtokentype tok = JTOK_NONE; enum jtokentype last_tok = JTOK_NONE; - while (1) { + const char* end = raw + size; + do { last_tok = tok; - string tokenVal; - unsigned int consumed; - tok = getJsonToken(tokenVal, consumed, raw); + tok = getJsonToken(tokenVal, consumed, raw, end); if (tok == JTOK_NONE || tok == JTOK_ERR) - break; + return false; raw += consumed; + bool isValueOpen = jsonTokenIsValue(tok) || + tok == JTOK_OBJ_OPEN || tok == JTOK_ARR_OPEN; + + if (expect(VALUE)) { + if (!isValueOpen) + return false; + clearExpect(VALUE); + + } else if (expect(ARR_VALUE)) { + bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE); + if (!isArrValue) + return false; + + clearExpect(ARR_VALUE); + + } else if (expect(OBJ_NAME)) { + bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING); + if (!isObjName) + return false; + + } else if (expect(COLON)) { + if (tok != JTOK_COLON) + return false; + clearExpect(COLON); + + } else if (!expect(COLON) && (tok == JTOK_COLON)) { + return false; + } + + if (expect(NOT_VALUE)) { + if (isValueOpen) + return false; + clearExpect(NOT_VALUE); + } + switch (tok) { case JTOK_OBJ_OPEN: @@ -280,13 +326,15 @@ bool UniValue::read(const char *raw) } if (utyp == VOBJ) - expectName = true; + setExpect(OBJ_NAME); + else + setExpect(ARR_VALUE); break; } case JTOK_OBJ_CLOSE: case JTOK_ARR_CLOSE: { - if (!stack.size() || expectColon || (last_tok == JTOK_COMMA)) + if (!stack.size() || (last_tok == JTOK_COMMA)) return false; VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR); @@ -295,39 +343,39 @@ bool UniValue::read(const char *raw) return false; stack.pop_back(); - expectName = false; + clearExpect(OBJ_NAME); + setExpect(NOT_VALUE); break; } case JTOK_COLON: { - if (!stack.size() || expectName || !expectColon) + if (!stack.size()) return false; UniValue *top = stack.back(); if (top->getType() != VOBJ) return false; - expectColon = false; + setExpect(VALUE); break; } case JTOK_COMMA: { - if (!stack.size() || expectName || expectColon || + if (!stack.size() || (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN)) return false; UniValue *top = stack.back(); if (top->getType() == VOBJ) - expectName = true; + setExpect(OBJ_NAME); + else + setExpect(ARR_VALUE); break; } case JTOK_KW_NULL: case JTOK_KW_TRUE: case JTOK_KW_FALSE: { - if (!stack.size() || expectName || expectColon) - return false; - UniValue tmpVal; switch (tok) { case JTOK_KW_NULL: @@ -342,49 +390,65 @@ bool UniValue::read(const char *raw) default: /* impossible */ break; } + if (!stack.size()) { + *this = tmpVal; + break; + } + UniValue *top = stack.back(); top->values.push_back(tmpVal); + setExpect(NOT_VALUE); break; } case JTOK_NUMBER: { - if (!stack.size() || expectName || expectColon) - return false; - UniValue tmpVal(VNUM, tokenVal); + if (!stack.size()) { + *this = tmpVal; + break; + } + UniValue *top = stack.back(); top->values.push_back(tmpVal); + setExpect(NOT_VALUE); break; } case JTOK_STRING: { - if (!stack.size()) - return false; - - UniValue *top = stack.back(); - - if (expectName) { + if (expect(OBJ_NAME)) { + UniValue *top = stack.back(); top->keys.push_back(tokenVal); - expectName = false; - expectColon = true; + clearExpect(OBJ_NAME); + setExpect(COLON); } else { UniValue tmpVal(VSTR, tokenVal); + if (!stack.size()) { + *this = tmpVal; + break; + } + UniValue *top = stack.back(); top->values.push_back(tmpVal); } + setExpect(NOT_VALUE); break; } default: return false; } - } + } while (!stack.empty ()); - if (stack.size() != 0) + /* Check that nothing follows the initial construct (parsed above). */ + tok = getJsonToken(tokenVal, consumed, raw, end); + if (tok != JTOK_NONE) return false; return true; } +bool UniValue::read(const char *raw) { + return read(raw, strlen(raw)); +} diff --git a/src/univalue/lib/univalue_utffilter.h b/src/univalue/lib/univalue_utffilter.h new file mode 100644 index 000000000..b4a9ddc0a --- /dev/null +++ b/src/univalue/lib/univalue_utffilter.h @@ -0,0 +1,119 @@ +// Copyright 2016 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. +#ifndef UNIVALUE_UTFFILTER_H +#define UNIVALUE_UTFFILTER_H + +#include + +/** + * Filter that generates and validates UTF-8, as well as collates UTF-16 + * surrogate pairs as specified in RFC4627. + */ +class JSONUTF8StringFilter +{ +public: + JSONUTF8StringFilter(std::string &s): + str(s), is_valid(true), codepoint(0), state(0), surpair(0) + { + } + // Write single 8-bit char (may be part of UTF-8 sequence) + void push_back(unsigned char ch) + { + if (state == 0) { + if (ch < 0x80) // 7-bit ASCII, fast direct pass-through + str.push_back(ch); + else if (ch < 0xc0) // Mid-sequence character, invalid in this state + is_valid = false; + else if (ch < 0xe0) { // Start of 2-byte sequence + codepoint = (ch & 0x1f) << 6; + state = 6; + } else if (ch < 0xf0) { // Start of 3-byte sequence + codepoint = (ch & 0x0f) << 12; + state = 12; + } else if (ch < 0xf8) { // Start of 4-byte sequence + codepoint = (ch & 0x07) << 18; + state = 18; + } else // Reserved, invalid + is_valid = false; + } else { + if ((ch & 0xc0) != 0x80) // Not a continuation, invalid + is_valid = false; + state -= 6; + codepoint |= (ch & 0x3f) << state; + if (state == 0) + push_back_u(codepoint); + } + } + // Write codepoint directly, possibly collating surrogate pairs + void push_back_u(unsigned int codepoint_) + { + if (state) // Only accept full codepoints in open state + is_valid = false; + if (codepoint_ >= 0xD800 && codepoint_ < 0xDC00) { // First half of surrogate pair + if (surpair) // Two subsequent surrogate pair openers - fail + is_valid = false; + else + surpair = codepoint_; + } else if (codepoint_ >= 0xDC00 && codepoint_ < 0xE000) { // Second half of surrogate pair + if (surpair) { // Open surrogate pair, expect second half + // Compute code point from UTF-16 surrogate pair + append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint_ - 0xDC00)); + surpair = 0; + } else // Second half doesn't follow a first half - fail + is_valid = false; + } else { + if (surpair) // First half of surrogate pair not followed by second - fail + is_valid = false; + else + append_codepoint(codepoint_); + } + } + // Check that we're in a state where the string can be ended + // No open sequences, no open surrogate pairs, etc + bool finalize() + { + if (state || surpair) + is_valid = false; + return is_valid; + } +private: + std::string &str; + bool is_valid; + // Current UTF-8 decoding state + unsigned int codepoint; + int state; // Top bit to be filled in for next UTF-8 byte, or 0 + + // Keep track of the following state to handle the following section of + // RFC4627: + // + // To escape an extended character that is not in the Basic Multilingual + // Plane, the character is represented as a twelve-character sequence, + // encoding the UTF-16 surrogate pair. So, for example, a string + // containing only the G clef character (U+1D11E) may be represented as + // "\uD834\uDD1E". + // + // Two subsequent \u.... may have to be replaced with one actual codepoint. + unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0 + + void append_codepoint(unsigned int codepoint_) + { + if (codepoint_ <= 0x7f) + str.push_back((char)codepoint_); + else if (codepoint_ <= 0x7FF) { + str.push_back((char)(0xC0 | (codepoint_ >> 6))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } else if (codepoint_ <= 0xFFFF) { + str.push_back((char)(0xE0 | (codepoint_ >> 12))); + str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } else if (codepoint_ <= 0x1FFFFF) { + str.push_back((char)(0xF0 | (codepoint_ >> 18))); + str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F))); + str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } + } +}; + +#endif diff --git a/src/univalue/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp similarity index 86% rename from src/univalue/univalue_write.cpp rename to src/univalue/lib/univalue_write.cpp index 9565cfa11..cf2783599 100644 --- a/src/univalue/univalue_write.cpp +++ b/src/univalue/lib/univalue_write.cpp @@ -1,14 +1,13 @@ // Copyright 2014 BitPay Inc. -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include +#include +#include #include #include "univalue.h" #include "univalue_escapes.h" -// TODO: Using UTF8 - using namespace std; static string json_escape(const string& inS) @@ -22,15 +21,8 @@ static string json_escape(const string& inS) if (escStr) outS += escStr; - - else if (isprint(ch)) + else outS += ch; - - else { - char tmpesc[16]; - sprintf(tmpesc, "\\u%04x", ch); - outS += tmpesc; - } } return outS; @@ -87,8 +79,6 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s s += values[i].write(prettyIndent, indentLevel + 1); if (i != (values.size() - 1)) { s += ","; - if (prettyIndent) - s += " "; } if (prettyIndent) s += "\n"; @@ -111,7 +101,7 @@ void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, s += "\"" + json_escape(keys[i]) + "\":"; if (prettyIndent) s += " "; - s += values[i].write(prettyIndent, indentLevel + 1); + s += values.at(i).write(prettyIndent, indentLevel + 1); if (i != (values.size() - 1)) s += ","; if (prettyIndent) diff --git a/src/univalue/pc/libunivalue-uninstalled.pc.in b/src/univalue/pc/libunivalue-uninstalled.pc.in new file mode 100644 index 000000000..b7f53e875 --- /dev/null +++ b/src/univalue/pc/libunivalue-uninstalled.pc.in @@ -0,0 +1,9 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunivalue +Description: libunivalue, C++ universal value object and JSON library +Version: @VERSION@ +Libs: ${pc_top_builddir}/${pcfiledir}/libunivalue.la diff --git a/src/univalue/pc/libunivalue.pc.in b/src/univalue/pc/libunivalue.pc.in new file mode 100644 index 000000000..358a2d5f7 --- /dev/null +++ b/src/univalue/pc/libunivalue.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libunivalue +Description: libunivalue, C++ universal value object and JSON library +Version: @VERSION@ +Libs: -L${libdir} -lunivalue +Cflags: -I${includedir} diff --git a/src/univalue/test/.gitignore b/src/univalue/test/.gitignore new file mode 100644 index 000000000..7b27cf0da --- /dev/null +++ b/src/univalue/test/.gitignore @@ -0,0 +1,8 @@ + +object +unitester +test_json +no_nul + +*.trs +*.log diff --git a/src/univalue/test/fail1.json b/src/univalue/test/fail1.json new file mode 100644 index 000000000..8feb01a6d --- /dev/null +++ b/src/univalue/test/fail1.json @@ -0,0 +1 @@ +"This is a string that never ends, yes it goes on and on, my friends. diff --git a/src/univalue/test/fail10.json b/src/univalue/test/fail10.json new file mode 100644 index 000000000..5d8c0047b --- /dev/null +++ b/src/univalue/test/fail10.json @@ -0,0 +1 @@ +{"Extra value after close": true} "misplaced quoted value" \ No newline at end of file diff --git a/src/univalue/test/fail11.json b/src/univalue/test/fail11.json new file mode 100644 index 000000000..76eb95b45 --- /dev/null +++ b/src/univalue/test/fail11.json @@ -0,0 +1 @@ +{"Illegal expression": 1 + 2} \ No newline at end of file diff --git a/src/univalue/test/fail12.json b/src/univalue/test/fail12.json new file mode 100644 index 000000000..77580a452 --- /dev/null +++ b/src/univalue/test/fail12.json @@ -0,0 +1 @@ +{"Illegal invocation": alert()} \ No newline at end of file diff --git a/src/univalue/test/fail13.json b/src/univalue/test/fail13.json new file mode 100644 index 000000000..379406b59 --- /dev/null +++ b/src/univalue/test/fail13.json @@ -0,0 +1 @@ +{"Numbers cannot have leading zeroes": 013} \ No newline at end of file diff --git a/src/univalue/test/fail14.json b/src/univalue/test/fail14.json new file mode 100644 index 000000000..0ed366b38 --- /dev/null +++ b/src/univalue/test/fail14.json @@ -0,0 +1 @@ +{"Numbers cannot be hex": 0x14} \ No newline at end of file diff --git a/src/univalue/test/fail15.json b/src/univalue/test/fail15.json new file mode 100644 index 000000000..fc8376b60 --- /dev/null +++ b/src/univalue/test/fail15.json @@ -0,0 +1 @@ +["Illegal backslash escape: \x15"] \ No newline at end of file diff --git a/src/univalue/test/fail16.json b/src/univalue/test/fail16.json new file mode 100644 index 000000000..3fe21d4b5 --- /dev/null +++ b/src/univalue/test/fail16.json @@ -0,0 +1 @@ +[\naked] \ No newline at end of file diff --git a/src/univalue/test/fail17.json b/src/univalue/test/fail17.json new file mode 100644 index 000000000..62b9214ae --- /dev/null +++ b/src/univalue/test/fail17.json @@ -0,0 +1 @@ +["Illegal backslash escape: \017"] \ No newline at end of file diff --git a/src/univalue/test/fail18.json b/src/univalue/test/fail18.json new file mode 100644 index 000000000..edac92716 --- /dev/null +++ b/src/univalue/test/fail18.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/src/univalue/test/fail19.json b/src/univalue/test/fail19.json new file mode 100644 index 000000000..3b9c46fa9 --- /dev/null +++ b/src/univalue/test/fail19.json @@ -0,0 +1 @@ +{"Missing colon" null} \ No newline at end of file diff --git a/src/univalue/test/fail2.json b/src/univalue/test/fail2.json new file mode 100644 index 000000000..6b7c11e5a --- /dev/null +++ b/src/univalue/test/fail2.json @@ -0,0 +1 @@ +["Unclosed array" \ No newline at end of file diff --git a/src/univalue/test/fail20.json b/src/univalue/test/fail20.json new file mode 100644 index 000000000..27c1af3e7 --- /dev/null +++ b/src/univalue/test/fail20.json @@ -0,0 +1 @@ +{"Double colon":: null} \ No newline at end of file diff --git a/src/univalue/test/fail21.json b/src/univalue/test/fail21.json new file mode 100644 index 000000000..62474573b --- /dev/null +++ b/src/univalue/test/fail21.json @@ -0,0 +1 @@ +{"Comma instead of colon", null} \ No newline at end of file diff --git a/src/univalue/test/fail22.json b/src/univalue/test/fail22.json new file mode 100644 index 000000000..a7752581b --- /dev/null +++ b/src/univalue/test/fail22.json @@ -0,0 +1 @@ +["Colon instead of comma": false] \ No newline at end of file diff --git a/src/univalue/test/fail23.json b/src/univalue/test/fail23.json new file mode 100644 index 000000000..494add1ca --- /dev/null +++ b/src/univalue/test/fail23.json @@ -0,0 +1 @@ +["Bad value", truth] \ No newline at end of file diff --git a/src/univalue/test/fail24.json b/src/univalue/test/fail24.json new file mode 100644 index 000000000..caff239bf --- /dev/null +++ b/src/univalue/test/fail24.json @@ -0,0 +1 @@ +['single quote'] \ No newline at end of file diff --git a/src/univalue/test/fail25.json b/src/univalue/test/fail25.json new file mode 100644 index 000000000..8b7ad23e0 --- /dev/null +++ b/src/univalue/test/fail25.json @@ -0,0 +1 @@ +[" tab character in string "] \ No newline at end of file diff --git a/src/univalue/test/fail26.json b/src/univalue/test/fail26.json new file mode 100644 index 000000000..845d26a6a --- /dev/null +++ b/src/univalue/test/fail26.json @@ -0,0 +1 @@ +["tab\ character\ in\ string\ "] \ No newline at end of file diff --git a/src/univalue/test/fail27.json b/src/univalue/test/fail27.json new file mode 100644 index 000000000..6b01a2ca4 --- /dev/null +++ b/src/univalue/test/fail27.json @@ -0,0 +1,2 @@ +["line +break"] \ No newline at end of file diff --git a/src/univalue/test/fail28.json b/src/univalue/test/fail28.json new file mode 100644 index 000000000..621a0101c --- /dev/null +++ b/src/univalue/test/fail28.json @@ -0,0 +1,2 @@ +["line\ +break"] \ No newline at end of file diff --git a/src/univalue/test/fail29.json b/src/univalue/test/fail29.json new file mode 100644 index 000000000..47ec421bb --- /dev/null +++ b/src/univalue/test/fail29.json @@ -0,0 +1 @@ +[0e] \ No newline at end of file diff --git a/src/univalue/test/fail3.json b/src/univalue/test/fail3.json new file mode 100644 index 000000000..168c81eb7 --- /dev/null +++ b/src/univalue/test/fail3.json @@ -0,0 +1 @@ +{unquoted_key: "keys must be quoted"} \ No newline at end of file diff --git a/src/univalue/test/fail30.json b/src/univalue/test/fail30.json new file mode 100644 index 000000000..8ab0bc4b8 --- /dev/null +++ b/src/univalue/test/fail30.json @@ -0,0 +1 @@ +[0e+] \ No newline at end of file diff --git a/src/univalue/test/fail31.json b/src/univalue/test/fail31.json new file mode 100644 index 000000000..1cce602b5 --- /dev/null +++ b/src/univalue/test/fail31.json @@ -0,0 +1 @@ +[0e+-1] \ No newline at end of file diff --git a/src/univalue/test/fail32.json b/src/univalue/test/fail32.json new file mode 100644 index 000000000..45cba7396 --- /dev/null +++ b/src/univalue/test/fail32.json @@ -0,0 +1 @@ +{"Comma instead if closing brace": true, \ No newline at end of file diff --git a/src/univalue/test/fail33.json b/src/univalue/test/fail33.json new file mode 100644 index 000000000..ca5eb19dc --- /dev/null +++ b/src/univalue/test/fail33.json @@ -0,0 +1 @@ +["mismatch"} \ No newline at end of file diff --git a/src/univalue/test/fail34.json b/src/univalue/test/fail34.json new file mode 100644 index 000000000..3f8be1728 --- /dev/null +++ b/src/univalue/test/fail34.json @@ -0,0 +1 @@ +{} garbage \ No newline at end of file diff --git a/src/univalue/test/fail35.json b/src/univalue/test/fail35.json new file mode 100644 index 000000000..de30ca5c4 --- /dev/null +++ b/src/univalue/test/fail35.json @@ -0,0 +1 @@ +[ true true true [] [] [] ] diff --git a/src/univalue/test/fail36.json b/src/univalue/test/fail36.json new file mode 100644 index 000000000..f82eb8e1f --- /dev/null +++ b/src/univalue/test/fail36.json @@ -0,0 +1 @@ +{"a":} diff --git a/src/univalue/test/fail37.json b/src/univalue/test/fail37.json new file mode 100644 index 000000000..3294dc3a4 --- /dev/null +++ b/src/univalue/test/fail37.json @@ -0,0 +1 @@ +{"a":1 "b":2} diff --git a/src/univalue/test/fail38.json b/src/univalue/test/fail38.json new file mode 100644 index 000000000..b245e2e46 --- /dev/null +++ b/src/univalue/test/fail38.json @@ -0,0 +1 @@ +["\ud834"] diff --git a/src/univalue/test/fail39.json b/src/univalue/test/fail39.json new file mode 100644 index 000000000..7c9e263f2 --- /dev/null +++ b/src/univalue/test/fail39.json @@ -0,0 +1 @@ +["\udd61"] diff --git a/src/univalue/test/fail4.json b/src/univalue/test/fail4.json new file mode 100644 index 000000000..9de168bf3 --- /dev/null +++ b/src/univalue/test/fail4.json @@ -0,0 +1 @@ +["extra comma",] \ No newline at end of file diff --git a/src/univalue/test/fail40.json b/src/univalue/test/fail40.json new file mode 100644 index 000000000..664dc9e24 --- /dev/null +++ b/src/univalue/test/fail40.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/src/univalue/test/fail41.json b/src/univalue/test/fail41.json new file mode 100644 index 000000000..0de342a2b --- /dev/null +++ b/src/univalue/test/fail41.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/src/univalue/test/fail42.json b/src/univalue/test/fail42.json new file mode 100644 index 000000000..9c7565adb Binary files /dev/null and b/src/univalue/test/fail42.json differ diff --git a/src/univalue/test/fail44.json b/src/univalue/test/fail44.json new file mode 100644 index 000000000..80edceddf --- /dev/null +++ b/src/univalue/test/fail44.json @@ -0,0 +1 @@ +"This file ends without a newline or close-quote. \ No newline at end of file diff --git a/src/univalue/test/fail5.json b/src/univalue/test/fail5.json new file mode 100644 index 000000000..ddf3ce3d2 --- /dev/null +++ b/src/univalue/test/fail5.json @@ -0,0 +1 @@ +["double extra comma",,] \ No newline at end of file diff --git a/src/univalue/test/fail6.json b/src/univalue/test/fail6.json new file mode 100644 index 000000000..ed91580e1 --- /dev/null +++ b/src/univalue/test/fail6.json @@ -0,0 +1 @@ +[ , "<-- missing value"] \ No newline at end of file diff --git a/src/univalue/test/fail7.json b/src/univalue/test/fail7.json new file mode 100644 index 000000000..8a96af3e4 --- /dev/null +++ b/src/univalue/test/fail7.json @@ -0,0 +1 @@ +["Comma after the close"], \ No newline at end of file diff --git a/src/univalue/test/fail8.json b/src/univalue/test/fail8.json new file mode 100644 index 000000000..b28479c6e --- /dev/null +++ b/src/univalue/test/fail8.json @@ -0,0 +1 @@ +["Extra close"]] \ No newline at end of file diff --git a/src/univalue/test/fail9.json b/src/univalue/test/fail9.json new file mode 100644 index 000000000..5815574f3 --- /dev/null +++ b/src/univalue/test/fail9.json @@ -0,0 +1 @@ +{"Extra comma": true,} \ No newline at end of file diff --git a/src/univalue/test/no_nul.cpp b/src/univalue/test/no_nul.cpp new file mode 100644 index 000000000..83d292200 --- /dev/null +++ b/src/univalue/test/no_nul.cpp @@ -0,0 +1,8 @@ +#include "univalue.h" + +int main (int argc, char *argv[]) +{ + char buf[] = "___[1,2,3]___"; + UniValue val; + return val.read(buf + 3, 7) ? 0 : 1; +} diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp new file mode 100644 index 000000000..f1f2e63b3 --- /dev/null +++ b/src/univalue/test/object.cpp @@ -0,0 +1,365 @@ +// Copyright (c) 2014 BitPay Inc. +// Copyright (c) 2014-2016 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 +#include +#include +#include +#include +#include +#include + +#define BOOST_FIXTURE_TEST_SUITE(a, b) +#define BOOST_AUTO_TEST_CASE(funcName) void funcName() +#define BOOST_AUTO_TEST_SUITE_END() +#define BOOST_CHECK(expr) assert(expr) +#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2)) +#define BOOST_CHECK_THROW(stmt, excMatch) { \ + try { \ + (stmt); \ + } catch (excMatch & e) { \ + } catch (...) { \ + assert(0); \ + } \ + } +#define BOOST_CHECK_NO_THROW(stmt) { \ + try { \ + (stmt); \ + } catch (...) { \ + assert(0); \ + } \ + } + +BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(univalue_constructor) +{ + UniValue v1; + BOOST_CHECK(v1.isNull()); + + UniValue v2(UniValue::VSTR); + BOOST_CHECK(v2.isStr()); + + UniValue v3(UniValue::VSTR, "foo"); + BOOST_CHECK(v3.isStr()); + BOOST_CHECK_EQUAL(v3.getValStr(), "foo"); + + UniValue numTest; + BOOST_CHECK(numTest.setNumStr("82")); + BOOST_CHECK(numTest.isNum()); + BOOST_CHECK_EQUAL(numTest.getValStr(), "82"); + + uint64_t vu64 = 82; + UniValue v4(vu64); + BOOST_CHECK(v4.isNum()); + BOOST_CHECK_EQUAL(v4.getValStr(), "82"); + + int64_t vi64 = -82; + UniValue v5(vi64); + BOOST_CHECK(v5.isNum()); + BOOST_CHECK_EQUAL(v5.getValStr(), "-82"); + + int vi = -688; + UniValue v6(vi); + BOOST_CHECK(v6.isNum()); + BOOST_CHECK_EQUAL(v6.getValStr(), "-688"); + + double vd = -7.21; + UniValue v7(vd); + BOOST_CHECK(v7.isNum()); + BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21"); + + std::string vs("yawn"); + UniValue v8(vs); + BOOST_CHECK(v8.isStr()); + BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); + + const char *vcs = "zappa"; + UniValue v9(vcs); + BOOST_CHECK(v9.isStr()); + BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); +} + +BOOST_AUTO_TEST_CASE(univalue_typecheck) +{ + UniValue v1; + BOOST_CHECK(v1.setNumStr("1")); + BOOST_CHECK(v1.isNum()); + BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error); + + UniValue v2; + BOOST_CHECK(v2.setBool(true)); + BOOST_CHECK_EQUAL(v2.get_bool(), true); + BOOST_CHECK_THROW(v2.get_int(), std::runtime_error); + + UniValue v3; + BOOST_CHECK(v3.setNumStr("32482348723847471234")); + BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error); + BOOST_CHECK(v3.setNumStr("1000")); + BOOST_CHECK_EQUAL(v3.get_int64(), 1000); + + UniValue v4; + BOOST_CHECK(v4.setNumStr("2147483648")); + BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648); + BOOST_CHECK_THROW(v4.get_int(), std::runtime_error); + BOOST_CHECK(v4.setNumStr("1000")); + BOOST_CHECK_EQUAL(v4.get_int(), 1000); + BOOST_CHECK_THROW(v4.get_str(), std::runtime_error); + BOOST_CHECK_EQUAL(v4.get_real(), 1000); + BOOST_CHECK_THROW(v4.get_array(), std::runtime_error); + BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error); + BOOST_CHECK_THROW(v4.getValues(), std::runtime_error); + BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error); + + UniValue v5; + BOOST_CHECK(v5.read("[true, 10]")); + BOOST_CHECK_NO_THROW(v5.get_array()); + std::vector vals = v5.getValues(); + BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error); + BOOST_CHECK_EQUAL(vals[0].get_bool(), true); + + BOOST_CHECK_EQUAL(vals[1].get_int(), 10); + BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(univalue_set) +{ + UniValue v(UniValue::VSTR, "foo"); + v.clear(); + BOOST_CHECK(v.isNull()); + BOOST_CHECK_EQUAL(v.getValStr(), ""); + + BOOST_CHECK(v.setObject()); + BOOST_CHECK(v.isObject()); + BOOST_CHECK_EQUAL(v.size(), 0); + BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ); + BOOST_CHECK(v.empty()); + + BOOST_CHECK(v.setArray()); + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.size(), 0); + + BOOST_CHECK(v.setStr("zum")); + BOOST_CHECK(v.isStr()); + BOOST_CHECK_EQUAL(v.getValStr(), "zum"); + + BOOST_CHECK(v.setFloat(-1.01)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-1.01"); + + BOOST_CHECK(v.setInt((int)1023)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "1023"); + + BOOST_CHECK(v.setInt((int64_t)-1023LL)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-1023"); + + BOOST_CHECK(v.setInt((uint64_t)1023ULL)); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "1023"); + + BOOST_CHECK(v.setNumStr("-688")); + BOOST_CHECK(v.isNum()); + BOOST_CHECK_EQUAL(v.getValStr(), "-688"); + + BOOST_CHECK(v.setBool(false)); + BOOST_CHECK_EQUAL(v.isBool(), true); + BOOST_CHECK_EQUAL(v.isTrue(), false); + BOOST_CHECK_EQUAL(v.isFalse(), true); + BOOST_CHECK_EQUAL(v.getBool(), false); + + BOOST_CHECK(v.setBool(true)); + BOOST_CHECK_EQUAL(v.isBool(), true); + BOOST_CHECK_EQUAL(v.isTrue(), true); + BOOST_CHECK_EQUAL(v.isFalse(), false); + BOOST_CHECK_EQUAL(v.getBool(), true); + + BOOST_CHECK(!v.setNumStr("zombocom")); + + BOOST_CHECK(v.setNull()); + BOOST_CHECK(v.isNull()); +} + +BOOST_AUTO_TEST_CASE(univalue_array) +{ + UniValue arr(UniValue::VARR); + + UniValue v((int64_t)1023LL); + BOOST_CHECK(arr.push_back(v)); + + std::string vStr("zippy"); + BOOST_CHECK(arr.push_back(vStr)); + + const char *s = "pippy"; + BOOST_CHECK(arr.push_back(s)); + + std::vector vec; + v.setStr("boing"); + vec.push_back(v); + + v.setStr("going"); + vec.push_back(v); + + BOOST_CHECK(arr.push_backV(vec)); + + BOOST_CHECK_EQUAL(arr.empty(), false); + BOOST_CHECK_EQUAL(arr.size(), 5); + + BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023"); + BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy"); + BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy"); + BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing"); + BOOST_CHECK_EQUAL(arr[4].getValStr(), "going"); + + BOOST_CHECK_EQUAL(arr[999].getValStr(), ""); + + arr.clear(); + BOOST_CHECK(arr.empty()); + BOOST_CHECK_EQUAL(arr.size(), 0); +} + +BOOST_AUTO_TEST_CASE(univalue_object) +{ + UniValue obj(UniValue::VOBJ); + std::string strKey, strVal; + UniValue v; + + strKey = "age"; + v.setInt(100); + BOOST_CHECK(obj.pushKV(strKey, v)); + + strKey = "first"; + strVal = "John"; + BOOST_CHECK(obj.pushKV(strKey, strVal)); + + strKey = "last"; + const char *cVal = "Smith"; + BOOST_CHECK(obj.pushKV(strKey, cVal)); + + strKey = "distance"; + BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25)); + + strKey = "time"; + BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600)); + + strKey = "calories"; + BOOST_CHECK(obj.pushKV(strKey, (int) 12)); + + strKey = "temperature"; + BOOST_CHECK(obj.pushKV(strKey, (double) 90.012)); + + UniValue obj2(UniValue::VOBJ); + BOOST_CHECK(obj2.pushKV("cat1", 9000)); + BOOST_CHECK(obj2.pushKV("cat2", 12345)); + + BOOST_CHECK(obj.pushKVs(obj2)); + + BOOST_CHECK_EQUAL(obj.empty(), false); + BOOST_CHECK_EQUAL(obj.size(), 9); + + BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100"); + BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John"); + BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith"); + BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25"); + BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600"); + BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12"); + BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012"); + BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000"); + BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345"); + + BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), ""); + + BOOST_CHECK(obj.exists("age")); + BOOST_CHECK(obj.exists("first")); + BOOST_CHECK(obj.exists("last")); + BOOST_CHECK(obj.exists("distance")); + BOOST_CHECK(obj.exists("time")); + BOOST_CHECK(obj.exists("calories")); + BOOST_CHECK(obj.exists("temperature")); + BOOST_CHECK(obj.exists("cat1")); + BOOST_CHECK(obj.exists("cat2")); + + BOOST_CHECK(!obj.exists("nyuknyuknyuk")); + + std::map objTypes; + objTypes["age"] = UniValue::VNUM; + objTypes["first"] = UniValue::VSTR; + objTypes["last"] = UniValue::VSTR; + objTypes["distance"] = UniValue::VNUM; + objTypes["time"] = UniValue::VNUM; + objTypes["calories"] = UniValue::VNUM; + objTypes["temperature"] = UniValue::VNUM; + objTypes["cat1"] = UniValue::VNUM; + objTypes["cat2"] = UniValue::VNUM; + BOOST_CHECK(obj.checkObject(objTypes)); + + objTypes["cat2"] = UniValue::VSTR; + BOOST_CHECK(!obj.checkObject(objTypes)); + + obj.clear(); + BOOST_CHECK(obj.empty()); + BOOST_CHECK_EQUAL(obj.size(), 0); +} + +static const char *json1 = +"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]"; + +BOOST_AUTO_TEST_CASE(univalue_readwrite) +{ + UniValue v; + BOOST_CHECK(v.read(json1)); + + std::string strJson1(json1); + BOOST_CHECK(v.read(strJson1)); + + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.size(), 2); + + BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000"); + + UniValue obj = v[1]; + BOOST_CHECK(obj.isObject()); + BOOST_CHECK_EQUAL(obj.size(), 3); + + BOOST_CHECK(obj["key1"].isStr()); + std::string correctValue("str"); + correctValue.push_back('\0'); + BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue); + BOOST_CHECK(obj["key2"].isNum()); + BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800"); + BOOST_CHECK(obj["key3"].isObject()); + + BOOST_CHECK_EQUAL(strJson1, v.write()); + + /* Check for (correctly reporting) a parsing error if the initial + JSON construct is followed by more stuff. Note that whitespace + is, of course, exempt. */ + + BOOST_CHECK(v.read(" {}\n ")); + BOOST_CHECK(v.isObject()); + BOOST_CHECK(v.read(" []\n ")); + BOOST_CHECK(v.isArray()); + + BOOST_CHECK(!v.read("@{}")); + BOOST_CHECK(!v.read("{} garbage")); + BOOST_CHECK(!v.read("[]{}")); + BOOST_CHECK(!v.read("{}[]")); + BOOST_CHECK(!v.read("{} 42")); +} + +BOOST_AUTO_TEST_SUITE_END() + +int main (int argc, char *argv[]) +{ + univalue_constructor(); + univalue_typecheck(); + univalue_set(); + univalue_array(); + univalue_object(); + univalue_readwrite(); + return 0; +} + diff --git a/src/univalue/test/pass1.json b/src/univalue/test/pass1.json new file mode 100644 index 000000000..70e268543 --- /dev/null +++ b/src/univalue/test/pass1.json @@ -0,0 +1,58 @@ +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"] \ No newline at end of file diff --git a/src/univalue/test/pass2.json b/src/univalue/test/pass2.json new file mode 100644 index 000000000..d3c63c7ad --- /dev/null +++ b/src/univalue/test/pass2.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/src/univalue/test/pass3.json b/src/univalue/test/pass3.json new file mode 100644 index 000000000..4528d51f1 --- /dev/null +++ b/src/univalue/test/pass3.json @@ -0,0 +1,6 @@ +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} diff --git a/src/univalue/test/round1.json b/src/univalue/test/round1.json new file mode 100644 index 000000000..a711e7308 --- /dev/null +++ b/src/univalue/test/round1.json @@ -0,0 +1 @@ +["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f"] diff --git a/src/univalue/test/round2.json b/src/univalue/test/round2.json new file mode 100644 index 000000000..b766cccc6 --- /dev/null +++ b/src/univalue/test/round2.json @@ -0,0 +1 @@ +["a§■𐎒𝅘𝅥𝅯"] diff --git a/src/univalue/test/round3.json b/src/univalue/test/round3.json new file mode 100644 index 000000000..7182dc2f9 --- /dev/null +++ b/src/univalue/test/round3.json @@ -0,0 +1 @@ +"abcdefghijklmnopqrstuvwxyz" diff --git a/src/univalue/test/round4.json b/src/univalue/test/round4.json new file mode 100644 index 000000000..7f8f011eb --- /dev/null +++ b/src/univalue/test/round4.json @@ -0,0 +1 @@ +7 diff --git a/src/univalue/test/round5.json b/src/univalue/test/round5.json new file mode 100644 index 000000000..27ba77dda --- /dev/null +++ b/src/univalue/test/round5.json @@ -0,0 +1 @@ +true diff --git a/src/univalue/test/round6.json b/src/univalue/test/round6.json new file mode 100644 index 000000000..c508d5366 --- /dev/null +++ b/src/univalue/test/round6.json @@ -0,0 +1 @@ +false diff --git a/src/univalue/test/round7.json b/src/univalue/test/round7.json new file mode 100644 index 000000000..19765bd50 --- /dev/null +++ b/src/univalue/test/round7.json @@ -0,0 +1 @@ +null diff --git a/src/univalue/test/test_json.cpp b/src/univalue/test/test_json.cpp new file mode 100644 index 000000000..2943bae2b --- /dev/null +++ b/src/univalue/test/test_json.cpp @@ -0,0 +1,24 @@ +// Test program that can be called by the JSON test suite at +// https://github.com/nst/JSONTestSuite. +// +// It reads JSON input from stdin and exits with code 0 if it can be parsed +// successfully. It also pretty prints the parsed JSON value to stdout. + +#include +#include +#include "univalue.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + UniValue val; + if (val.read(string(istreambuf_iterator(cin), + istreambuf_iterator()))) { + cout << val.write(1 /* prettyIndent */, 4 /* indentLevel */) << endl; + return 0; + } else { + cerr << "JSON Parse Error." << endl; + return 1; + } +} diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp new file mode 100644 index 000000000..2c37794a4 --- /dev/null +++ b/src/univalue/test/unitester.cpp @@ -0,0 +1,170 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include "univalue.h" + +#ifndef JSON_TEST_SRC +#error JSON_TEST_SRC must point to test source directory +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +using namespace std; +string srcdir(JSON_TEST_SRC); +static bool test_failed = false; + +#define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", filename.c_str()); } } +#define f_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", __func__); } } + +static std::string rtrim(std::string s) +{ + s.erase(s.find_last_not_of(" \n\r\t")+1); + return s; +} + +static void runtest(string filename, const string& jdata) +{ + string prefix = filename.substr(0, 4); + + bool wantPass = (prefix == "pass") || (prefix == "roun"); + bool wantFail = (prefix == "fail"); + bool wantRoundTrip = (prefix == "roun"); + assert(wantPass || wantFail); + + UniValue val; + bool testResult = val.read(jdata); + + if (wantPass) { + d_assert(testResult == true); + } else { + d_assert(testResult == false); + } + + if (wantRoundTrip) { + std::string odata = val.write(0, 0); + assert(odata == rtrim(jdata)); + } +} + +static void runtest_file(const char *filename_) +{ + string basename(filename_); + string filename = srcdir + "/" + basename; + FILE *f = fopen(filename.c_str(), "r"); + assert(f != NULL); + + string jdata; + + char buf[4096]; + while (!feof(f)) { + int bread = fread(buf, 1, sizeof(buf), f); + assert(!ferror(f)); + + string s(buf, bread); + jdata += s; + } + + assert(!ferror(f)); + fclose(f); + + runtest(basename, jdata); +} + +static const char *filenames[] = { + "fail10.json", + "fail11.json", + "fail12.json", + "fail13.json", + "fail14.json", + "fail15.json", + "fail16.json", + "fail17.json", + //"fail18.json", // investigate + "fail19.json", + "fail1.json", + "fail20.json", + "fail21.json", + "fail22.json", + "fail23.json", + "fail24.json", + "fail25.json", + "fail26.json", + "fail27.json", + "fail28.json", + "fail29.json", + "fail2.json", + "fail30.json", + "fail31.json", + "fail32.json", + "fail33.json", + "fail34.json", + "fail35.json", + "fail36.json", + "fail37.json", + "fail38.json", // invalid unicode: only first half of surrogate pair + "fail39.json", // invalid unicode: only second half of surrogate pair + "fail40.json", // invalid unicode: broken UTF-8 + "fail41.json", // invalid unicode: unfinished UTF-8 + "fail42.json", // valid json with garbage following a nul byte + "fail44.json", // unterminated string + "fail3.json", + "fail4.json", // extra comma + "fail5.json", + "fail6.json", + "fail7.json", + "fail8.json", + "fail9.json", // extra comma + "pass1.json", + "pass2.json", + "pass3.json", + "round1.json", // round-trip test + "round2.json", // unicode + "round3.json", // bare string + "round4.json", // bare number + "round5.json", // bare true + "round6.json", // bare false + "round7.json", // bare null +}; + +// Test \u handling +void unescape_unicode_test() +{ + UniValue val; + bool testResult; + // Escaped ASCII (quote) + testResult = val.read("[\"\\u0022\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\""); + // Escaped Basic Plane character, two-byte UTF-8 + testResult = val.read("[\"\\u0191\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\xc6\x91"); + // Escaped Basic Plane character, three-byte UTF-8 + testResult = val.read("[\"\\u2191\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\xe2\x86\x91"); + // Escaped Supplementary Plane character U+1d161 + testResult = val.read("[\"\\ud834\\udd61\"]"); + f_assert(testResult); + f_assert(val[0].get_str() == "\xf0\x9d\x85\xa1"); +} + +int main (int argc, char *argv[]) +{ + for (unsigned int fidx = 0; fidx < ARRAY_SIZE(filenames); fidx++) { + runtest_file(filenames[fidx]); + } + + unescape_unicode_test(); + + return test_failed ? 1 : 0; +} + diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp deleted file mode 100644 index b0171e48c..000000000 --- a/src/univalue/univalue.cpp +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include -#include -#include -#include "univalue.h" - -using namespace std; - -static const UniValue nullValue; - -void UniValue::clear() -{ - typ = VNULL; - val.clear(); - keys.clear(); - values.clear(); -} - -bool UniValue::setNull() -{ - clear(); - return true; -} - -bool UniValue::setBool(bool val_) -{ - clear(); - typ = VBOOL; - if (val_) - val = "1"; - return true; -} - -static bool validNumStr(const string& s) -{ - string tokenVal; - unsigned int consumed; - enum jtokentype tt = getJsonToken(tokenVal, consumed, s.c_str()); - return (tt == JTOK_NUMBER); -} - -bool UniValue::setNumStr(const string& val_) -{ - if (!validNumStr(val_)) - return false; - - clear(); - typ = VNUM; - val = val_; - return true; -} - -bool UniValue::setInt(uint64_t val) -{ - string s; - ostringstream oss; - - oss << val; - - return setNumStr(oss.str()); -} - -bool UniValue::setInt(int64_t val) -{ - string s; - ostringstream oss; - - oss << val; - - return setNumStr(oss.str()); -} - -bool UniValue::setFloat(double val) -{ - string s; - ostringstream oss; - - oss << val; - - return setNumStr(oss.str()); -} - -bool UniValue::setStr(const string& val_) -{ - clear(); - typ = VSTR; - val = val_; - return true; -} - -bool UniValue::setArray() -{ - clear(); - typ = VARR; - return true; -} - -bool UniValue::setObject() -{ - clear(); - typ = VOBJ; - return true; -} - -bool UniValue::push_back(const UniValue& val) -{ - if (typ != VARR) - return false; - - values.push_back(val); - return true; -} - -bool UniValue::push_backV(const std::vector& vec) -{ - if (typ != VARR) - return false; - - values.insert(values.end(), vec.begin(), vec.end()); - - return true; -} - -bool UniValue::pushKV(const std::string& key, const UniValue& val) -{ - if (typ != VOBJ) - return false; - - keys.push_back(key); - values.push_back(val); - return true; -} - -bool UniValue::pushKVs(const UniValue& obj) -{ - if (typ != VOBJ || obj.typ != VOBJ) - return false; - - for (unsigned int i = 0; i < obj.keys.size(); i++) { - keys.push_back(obj.keys[i]); - values.push_back(obj.values[i]); - } - - return true; -} - -int UniValue::findKey(const std::string& key) const -{ - for (unsigned int i = 0; i < keys.size(); i++) { - if (keys[i] == key) - return (int) i; - } - - return -1; -} - -bool UniValue::checkObject(const std::map& t) -{ - for (std::map::const_iterator it = t.begin(); - it != t.end(); it++) { - int idx = findKey(it->first); - if (idx < 0) - return false; - - if (values[idx].getType() != it->second) - return false; - } - - return true; -} - -const UniValue& UniValue::operator[](const std::string& key) const -{ - if (typ != VOBJ) - return nullValue; - - int index = findKey(key); - if (index < 0) - return nullValue; - - return values[index]; -} - -const UniValue& UniValue::operator[](unsigned int index) const -{ - if (typ != VOBJ && typ != VARR) - return nullValue; - if (index >= values.size()) - return nullValue; - - return values[index]; -} - -const char *uvTypeName(UniValue::VType t) -{ - switch (t) { - case UniValue::VNULL: return "null"; - case UniValue::VBOOL: return "bool"; - case UniValue::VOBJ: return "object"; - case UniValue::VARR: return "array"; - case UniValue::VSTR: return "string"; - case UniValue::VNUM: return "number"; - } - - // not reached - return NULL; -} - diff --git a/src/univalue/univalue.h b/src/univalue/univalue.h deleted file mode 100644 index 5ac301d9e..000000000 --- a/src/univalue/univalue.h +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2014 BitPay Inc. -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef BITCOIN_UNIVALUE_UNIVALUE_H -#define BITCOIN_UNIVALUE_UNIVALUE_H - -#include -#include -#include -#include -#include - -class UniValue { -public: - enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; - - UniValue() { typ = VNULL; } - UniValue(UniValue::VType initialType, const std::string& initialStr = "") { - typ = initialType; - val = initialStr; - } - UniValue(uint64_t val_) { - setInt(val_); - } - UniValue(int64_t val_) { - setInt(val_); - } - UniValue(int val_) { - setInt(val_); - } - UniValue(double val_) { - setFloat(val_); - } - UniValue(const std::string& val_) { - setStr(val_); - } - UniValue(const char *val_) { - std::string s(val_); - setStr(s); - } - ~UniValue() {} - - void clear(); - - bool setNull(); - bool setBool(bool val); - bool setNumStr(const std::string& val); - bool setInt(uint64_t val); - bool setInt(int64_t val); - bool setInt(int val) { return setInt((int64_t)val); } - bool setFloat(double val); - bool setStr(const std::string& val); - bool setArray(); - bool setObject(); - - enum VType getType() const { return typ; } - std::string getValStr() const { return val; } - bool empty() const { return (values.size() == 0); } - - size_t count() const { return values.size(); } - - bool getBool() const { return isTrue(); } - bool checkObject(const std::map& memberTypes); - const UniValue& operator[](const std::string& key) const; - const UniValue& operator[](unsigned int index) const; - bool exists(const std::string& key) const { return (findKey(key) >= 0); } - - bool isNull() const { return (typ == VNULL); } - bool isTrue() const { return (typ == VBOOL) && (val == "1"); } - bool isFalse() const { return (!isTrue()); } - bool isBool() const { return (typ == VBOOL); } - bool isStr() const { return (typ == VSTR); } - bool isNum() const { return (typ == VNUM); } - bool isArray() const { return (typ == VARR); } - bool isObject() const { return (typ == VOBJ); } - - bool push_back(const UniValue& val); - bool push_back(const std::string& val_) { - UniValue tmpVal(VSTR, val_); - return push_back(tmpVal); - } - bool push_back(const char *val_) { - std::string s(val_); - return push_back(s); - } - bool push_backV(const std::vector& vec); - - bool pushKV(const std::string& key, const UniValue& val); - bool pushKV(const std::string& key, const std::string& val) { - UniValue tmpVal(VSTR, val); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, const char *val_) { - std::string val(val_); - return pushKV(key, val); - } - bool pushKV(const std::string& key, int64_t val) { - UniValue tmpVal(val); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, uint64_t val) { - UniValue tmpVal(val); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, int val) { - UniValue tmpVal((int64_t)val); - return pushKV(key, tmpVal); - } - bool pushKV(const std::string& key, double val) { - UniValue tmpVal(val); - return pushKV(key, tmpVal); - } - bool pushKVs(const UniValue& obj); - - std::string write(unsigned int prettyIndent = 0, - unsigned int indentLevel = 0) const; - - bool read(const char *raw); - bool read(const std::string& rawStr) { - return read(rawStr.c_str()); - } - -private: - UniValue::VType typ; - std::string val; // numbers are stored as C++ strings - std::vector keys; - std::vector values; - - int findKey(const std::string& key) const; - void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; - void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; -}; - -enum jtokentype { - JTOK_ERR = -1, - JTOK_NONE = 0, // eof - JTOK_OBJ_OPEN, - JTOK_OBJ_CLOSE, - JTOK_ARR_OPEN, - JTOK_ARR_CLOSE, - JTOK_COLON, - JTOK_COMMA, - JTOK_KW_NULL, - JTOK_KW_TRUE, - JTOK_KW_FALSE, - JTOK_NUMBER, - JTOK_STRING, -}; - -extern enum jtokentype getJsonToken(std::string& tokenVal, - unsigned int& consumed, const char *raw); -extern const char *uvTypeName(UniValue::VType t); - -#endif // BITCOIN_UNIVALUE_UNIVALUE_H diff --git a/src/util.cpp b/src/util.cpp index 1fb4081ce..2a9bcbf23 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -111,15 +111,20 @@ bool fMasterNode = false; string strMasterNodePrivKey = ""; string strMasterNodeAddr = ""; bool fLiteMode = false; +// SwiftX bool fEnableSwiftTX = true; int nSwiftTXDepth = 5; -int nObfuscationRounds = 2; +// Automatic Zerocoin minting +bool fEnableZeromint = true; +int nZeromintPercentage = 10; +int nPreferredDenom = 0; +const int64_t AUTOMINT_DELAY = (60 * 5); // Wait at least 5 minutes until Automint starts + int nAnonymizeBulwarkAmount = 1000; int nLiquidityProvider = 0; /** Spork enforcement enabled time */ int64_t enforceMasternodePaymentsTime = 4085657524; bool fSucessfullyLoaded = false; -bool fEnableObfuscation = false; /** All denominations used by obfuscation */ std::vector obfuScationDenominations; string strBudgetMode = ""; @@ -235,9 +240,10 @@ bool LogAcceptCategory(const char* category) // "bulwark" is a composite category enabling all Bulwark-related debug output if (ptrCategory->count(string("bulwark"))) { ptrCategory->insert(string("obfuscation")); - ptrCategory->insert(string("swifttx")); + ptrCategory->insert(string("swiftx")); ptrCategory->insert(string("masternode")); ptrCategory->insert(string("mnpayments")); + ptrCategory->insert(string("zero")); ptrCategory->insert(string("mnbudget")); } } @@ -289,19 +295,21 @@ int LogPrintStr(const std::string& str) return ret; } +/** Interpret string as boolean, for argument parsing */ static bool InterpretBool(const std::string& strValue) { - if (strValue.empty()) - return true; - return (atoi(strValue) != 0); + if (strValue.empty()) + return true; + return (atoi(strValue) != 0); } +/** Turn -noX into -X=0 */ static void InterpretNegativeSetting(std::string& strKey, std::string& strValue) { - if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o') { - strKey = "-" + strKey.substr(3); - strValue = InterpretBool(strValue) ? "0" : "1"; - } + if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o') { + strKey = "-" + strKey.substr(3); + strValue = InterpretBool(strValue) ? "0" : "1"; + } } void ParseParameters(int argc, const char* const argv[]) @@ -330,12 +338,11 @@ void ParseParameters(int argc, const char* const argv[]) // If both --foo and -foo are set, the last takes effect. if (str.length() > 1 && str[1] == '-') str = str.substr(1); - InterpretNegativeSetting(str, strValue); + InterpretNegativeSetting(str, strValue); mapArgs[str] = strValue; mapMultiArgs[str].push_back(strValue); } - } std::string GetArg(const std::string& strArg, const std::string& strDefault) @@ -347,16 +354,16 @@ std::string GetArg(const std::string& strArg, const std::string& strDefault) int64_t GetArg(const std::string& strArg, int64_t nDefault) { - if (mapArgs.count(strArg)) - return atoi64(mapArgs[strArg]); - return nDefault; + if (mapArgs.count(strArg)) + return atoi64(mapArgs[strArg]); + return nDefault; } bool GetBoolArg(const std::string& strArg, bool fDefault) { - if (mapArgs.count(strArg)) - return InterpretBool(mapArgs[strArg]); - return fDefault; + if (mapArgs.count(strArg)) + return InterpretBool(mapArgs[strArg]); + return fDefault; } bool SoftSetArg(const std::string& strArg, const std::string& strValue) @@ -517,12 +524,11 @@ void ReadConfigFile(map& mapSettingsRet, for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) { // Don't overwrite existing settings so command line settings override bulwark.conf string strKey = string("-") + it->string_key; - string strValue = it->value[0]; - InterpretNegativeSetting(strKey, strValue); - if (mapSettingsRet.count(strKey) == 0) - mapSettingsRet[strKey] = strValue; - mapMultiSettingsRet[strKey].push_back(strValue); - + string strValue = it->value[0]; + InterpretNegativeSetting(strKey, strValue); + if (mapSettingsRet.count(strKey) == 0) + mapSettingsRet[strKey] = strValue; + mapMultiSettingsRet[strKey].push_back(strValue); } // If datadir is changed in .conf file: ClearDatadirCache(); diff --git a/src/util.h b/src/util.h index fbb348076..5b11469f6 100644 --- a/src/util.h +++ b/src/util.h @@ -36,10 +36,12 @@ extern bool fMasterNode; extern bool fLiteMode; extern bool fEnableSwiftTX; extern int nSwiftTXDepth; -extern int nObfuscationRounds; +extern int nZeromintPercentage; +extern const int64_t AUTOMINT_DELAY; +extern int nPreferredDenom; extern int nAnonymizeBulwarkAmount; extern int nLiquidityProvider; -extern bool fEnableObfuscation; +extern bool fEnableZeromint; extern int64_t enforceMasternodePaymentsTime; extern std::string strMasterNodeAddr; extern int keysLoaded; @@ -83,7 +85,7 @@ int LogPrintStr(const std::string& str); template \ static inline bool error(const char* format, TINYFORMAT_VARARGS(n)) \ { \ - LogPrintStr("ERROR: " + tfm::format(format, TINYFORMAT_PASSARGS(n)) + "\n"); \ + LogPrintStr(std::string("ERROR: ") + tfm::format(format, TINYFORMAT_PASSARGS(n)) + "\n"); \ return false; \ } diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index bf0b116ad..238b42f94 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin 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. diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 5fc4c2ed0..fd13a0cb3 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -104,7 +104,7 @@ inline std::string ReverseEndianString(std::string in) return out; } -/** +/** * Format a paragraph of text to a fixed width, adding spaces for * indentation to any added line. */ diff --git a/src/utiltime.h b/src/utiltime.h index 3f5ced6a5..b1447f7df 100644 --- a/src/utiltime.h +++ b/src/utiltime.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin 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. diff --git a/src/version.h b/src/version.h index 6c8dcd2d5..086b0e249 100644 --- a/src/version.h +++ b/src/version.h @@ -11,8 +11,7 @@ /** * network protocol versioning */ -// [oldschool] FIX: updated protocol version. -static const int PROTOCOL_VERSION = 70840; +static const int PROTOCOL_VERSION = 70850; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; @@ -21,7 +20,7 @@ static const int INIT_PROTO_VERSION = 209; static const int GETHEADERS_VERSION = 70077; //! disconnect from peers older than this proto version -static const int MIN_PEER_PROTO_VERSION_BEFORE_ENFORCEMENT = 70830; +static const int MIN_PEER_PROTO_VERSION_BEFORE_ENFORCEMENT = 70840; static const int MIN_PEER_PROTO_VERSION_AFTER_ENFORCEMENT15 = 70820; static const int MIN_PEER_PROTO_VERSION_AFTER_ENFORCEMENT17 = 70830; static const int MIN_PEER_PROTO_VERSION_AFTER_ENFORCEMENT18 = 70840; @@ -30,10 +29,6 @@ static const int MIN_PEER_PROTO_VERSION_AFTER_ENFORCEMENT18 = 70840; //! if possible, avoid requesting addresses nodes older than this static const int CADDR_TIME_VERSION = 31402; -//! only request blocks from nodes outside this range of versions -static const int NOBLKS_VERSION_START = 32000; -static const int NOBLKS_VERSION_END = 70910; - //! BIP 0031, pong message, is enabled for all versions AFTER this one static const int BIP0031_VERSION = 60000; diff --git a/src/wallet.cpp b/src/wallet.cpp index 74e01cfe0..ead572ad5 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -8,12 +8,14 @@ #include "wallet.h" +#include "accumulators.h" #include "base58.h" #include "checkpoints.h" #include "coincontrol.h" #include "kernel.h" #include "masternode-budget.h" #include "net.h" +#include "primitives/transaction.h" #include "script/script.h" #include "script/sign.h" #include "spork.h" @@ -22,12 +24,14 @@ #include "util.h" #include "utilmoneystr.h" +#include "denomination_functions.h" +#include "libzerocoin/Denominations.h" #include #include #include #include - +#include using namespace std; @@ -38,16 +42,18 @@ CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; unsigned int nTxConfirmTarget = 1; bool bSpendZeroConfChange = true; +bool bdisableSystemnotifications = false; // Those bubbles can be annoying and slow down the UI when you get lots of trx bool fSendFreeTransactions = false; bool fPayAtLeastCustomFee = true; -/** - * Fees smaller than this (in duffs) are considered zero fee (for transaction creation) +/** + * Fees smaller than this (in ubwk) are considered zero fee (for transaction creation) * We are ~100 times smaller then bitcoin now (2015-06-23), set minTxFee 10 times higher * so it's still 10 times lower comparing to bitcoin. * Override with -mintxfee */ CFeeRate CWallet::minTxFee = CFeeRate(10000); +int64_t nStartupTime = GetAdjustedTime(); /** @defgroup mapWallet * @@ -241,7 +247,6 @@ bool CWallet::LoadMultiSig(const CScript& dest) return CCryptoKeyStore::AddMultiSig(dest); } - bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool anonymizeOnly) { SecureString strWalletPassphraseFinal; @@ -252,7 +257,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool anonymizeOnly } strWalletPassphraseFinal = strWalletPassphrase; - + CCrypter crypter; CKeyingMaterial vMasterKey; @@ -277,7 +282,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, { bool fWasLocked = IsLocked(); SecureString strOldWalletPassphraseFinal = strOldWalletPassphrase; - + { LOCK(cs_wallet); Lock(); @@ -376,7 +381,7 @@ set CWallet::GetConflicts(const uint256& txid) const std::pair range; BOOST_FOREACH (const CTxIn& txin, wtx.vin) { - if (mapTxSpends.count(txin.prevout) <= 1) + if (mapTxSpends.count(txin.prevout) <= 1 || wtx.IsZerocoinSpend()) 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) @@ -605,8 +610,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) // Need to completely rewrite the wallet file; if we don't, bdb might keep // bits of the unencrypted private key in slack space in the database file. CDB::Rewrite(strWalletFile); - - } + } NotifyStatusChanged(this); return true; @@ -791,7 +795,7 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) // available of the outputs it spends. So force those to be // recomputed, also: BOOST_FOREACH (const CTxIn& txin, tx.vin) { - if (mapWallet.count(txin.prevout.hash)) + if (!tx.IsZerocoinSpend() && mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); } } @@ -823,6 +827,11 @@ isminetype CWallet::IsMine(const CTxIn& txin) const return ISMINE_NO; } +bool CWallet::IsMyZerocoinSpend(const CBigNum& bnSerial) const +{ + return CWalletDB(strWalletFile).ReadZerocoinSpendSerialEntry(bnSerial); +} + CAmount CWallet::GetDebit(const CTxIn& txin, const isminefilter& filter) const { { @@ -922,7 +931,7 @@ int CWallet::GetInputObfuscationRounds(CTxIn in) const { LOCK(cs_wallet); int realObfuscationRounds = GetRealInputObfuscationRounds(in, 0); - return realObfuscationRounds > nObfuscationRounds ? nObfuscationRounds : realObfuscationRounds; + return realObfuscationRounds > nZeromintPercentage ? nZeromintPercentage : realObfuscationRounds; } bool CWallet::IsDenominated(const CTxIn& txin) const @@ -988,6 +997,18 @@ int64_t CWalletTx::GetTxTime() const return n ? n : nTimeReceived; } +int64_t CWalletTx::GetComputedTxTime() const +{ + int64_t nTime = GetTxTime(); + if (IsZerocoinSpend() || IsZerocoinMint()) { + if (IsInMainChain()) + return mapBlockIndex.at(hashBlock)->GetBlockTime(); + else + return nTimeReceived; + } + return nTime; +} + int CWalletTx::GetRequestCount() const { // Returns -1 if it wasn't being tracked @@ -1051,14 +1072,17 @@ void CWalletTx::GetAmounts(list& listReceived, // Don't report 'change' txouts if (pwallet->IsChange(txout)) continue; - } else if (!(fIsMine & filter)) + } else if (!(fIsMine & filter) && !IsZerocoinSpend()) continue; // In either case, we need to get the destination address CTxDestination address; - if (!ExtractDestination(txout.scriptPubKey, address)) { - LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", - this->GetHash().ToString()); + if (txout.scriptPubKey.IsZerocoinMint()) { + address = CNoDestination(); + } else if (!ExtractDestination(txout.scriptPubKey, address)) { + if (!IsCoinStake() && !IsCoinBase()) { + LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", this->GetHash().ToString()); + } address = CNoDestination(); } @@ -1268,6 +1292,125 @@ CAmount CWallet::GetBalance() const return nTotal; } +CAmount CWallet::GetZerocoinBalance(bool fMatureOnly) const +{ + CAmount nTotal = 0; + //! zerocoin specific fields + std::map myZerocoinSupply; + for (auto& denom : libzerocoin::zerocoinDenomList) { + myZerocoinSupply.insert(make_pair(denom, 0)); + } + + { + LOCK2(cs_main, cs_wallet); + // Get Unused coins + list listPubCoin = CWalletDB(strWalletFile).ListMintedCoins(true, fMatureOnly, true); + for (auto& mint : listPubCoin) { + libzerocoin::CoinDenomination denom = mint.GetDenomination(); + nTotal += libzerocoin::ZerocoinDenominationToAmount(denom); + myZerocoinSupply.at(denom)++; + } + } + for (auto& denom : libzerocoin::zerocoinDenomList) { + LogPrint("zero","%s My coins for denomination %d pubcoin %s\n", __func__,denom, myZerocoinSupply.at(denom)); + } + LogPrint("zero","Total value of coins %d\n",nTotal); + + if (nTotal < 0 ) nTotal = 0; // Sanity never hurts + + return nTotal; +} + +CAmount CWallet::GetImmatureZerocoinBalance() const +{ + return GetZerocoinBalance(false) - GetZerocoinBalance(true); +} + +CAmount CWallet::GetUnconfirmedZerocoinBalance() const +{ + CAmount nUnconfirmed = 0; + CWalletDB walletdb(pwalletMain->strWalletFile); + list listMints = walletdb.ListMintedCoins(true, false, true); + + std::map mapUnconfirmed; + for (const auto& denom : libzerocoin::zerocoinDenomList){ + mapUnconfirmed.insert(make_pair(denom, 0)); + } + + { + LOCK2(cs_main, cs_wallet); + for (auto& mint : listMints){ + if (!mint.GetHeight() || mint.GetHeight() > chainActive.Height() - Params().Zerocoin_MintRequiredConfirmations()) { + libzerocoin::CoinDenomination denom = mint.GetDenomination(); + nUnconfirmed += libzerocoin::ZerocoinDenominationToAmount(denom); + mapUnconfirmed.at(denom)++; + } + } + } + + for (auto& denom : libzerocoin::zerocoinDenomList) { + LogPrint("zero","%s My unconfirmed coins for denomination %d pubcoin %s\n", __func__,denom, mapUnconfirmed.at(denom)); + } + + LogPrint("zero","Total value of unconfirmed coins %ld\n", nUnconfirmed); + + if (nUnconfirmed < 0 ) nUnconfirmed = 0; // Sanity never hurts + + return nUnconfirmed; +} + +CAmount CWallet::GetUnlockedCoins() 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() && pcoin->GetDepthInMainChain() > 0) + nTotal += pcoin->GetUnlockedCredit(); + } + } + + return nTotal; +} + +CAmount CWallet::GetLockedCoins() 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() && pcoin->GetDepthInMainChain() > 0) + nTotal += pcoin->GetLockedCredit(); + } + } + + return nTotal; +} + +// Get a Map pairing the Denominations with the amount of Zerocoin for each Denomination +std::map CWallet::GetMyZerocoinDistribution() const +{ + std::map spread; + for (const auto& denom : libzerocoin::zerocoinDenomList) + spread.insert(std::pair(denom, 0)); + { + LOCK2(cs_main, cs_wallet); + list listPubCoin = CWalletDB(strWalletFile).ListMintedCoins(true, true, true); + for (auto& mint : listPubCoin) + spread.at(mint.GetDenomination())++; + } + return spread; +} + + CAmount CWallet::GetAnonymizableBalance() const { if (fLiteMode) return 0; @@ -1359,7 +1502,7 @@ CAmount CWallet::GetNormalizedAnonymizedBalance() const if (pcoin->GetDepthInMainChain() < 0) continue; int rounds = GetInputObfuscationRounds(vin); - nTotal += pcoin->vout[i].nValue * rounds / nObfuscationRounds; + nTotal += pcoin->vout[i].nValue * rounds / nZeromintPercentage; } } } @@ -1502,6 +1645,11 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const } if (!found) continue; + if (nCoinType == STAKABLE_COINS) { + if (pcoin->vout[i].IsZerocoinMint()) + continue; + } + isminetype mine = IsMine(pcoin->vout[i]); if (IsSpent(wtxid, i)) continue; @@ -1608,26 +1756,47 @@ bool less_then_denom(const COutput& out1, const COutput& out2) bool CWallet::SelectStakeCoins(std::set >& setCoins, CAmount nTargetAmount) const { vector vCoins; - AvailableCoins(vCoins, true); - int64_t nAmountSelected = 0; + AvailableCoins(vCoins, true, NULL, false, STAKABLE_COINS); + CAmount nAmountSelected = 0; + + // On protocol change update the staking requirements. + CAmount nStakeAmount = 0; + int nStakeDepth = Params().COINBASE_MATURITY(); + if (ActiveProtocol() >= Params().Stake_MinProtocol()) { + nStakeAmount = Params().Stake_MinAmount(); + nStakeDepth = Params().Stake_MinConfirmations(); + } BOOST_FOREACH (const COutput& out, vCoins) { //make sure not to outrun target amount if (nAmountSelected + out.tx->vout[out.i].nValue > nTargetAmount) continue; - - //check for min age - if (GetTime() - out.tx->GetTxTime() < nStakeMinAge) + + //require a minimum amount to stake + if (out.tx->vout[out.i].nValue < nStakeAmount) continue; //check that it is matured - if (out.nDepth < (out.tx->IsCoinStake() ? Params().COINBASE_MATURITY() : 10)) + if (out.nDepth < (out.tx->IsCoinStake() ? nStakeDepth : 10)) + continue; + + //if zerocoinspend, then use the block time + int64_t nTxTime = out.tx->GetTxTime(); + if (out.tx->IsZerocoinSpend()) { + if (!out.tx->IsInMainChain()) + continue; + nTxTime = mapBlockIndex.at(out.tx->hashBlock)->GetBlockTime(); + } + + //check for min age + if (GetAdjustedTime() - nTxTime < nStakeMinAge) continue; //add to our stake set setCoins.insert(make_pair(out.tx, out.i)); nAmountSelected += out.tx->vout[out.i].nValue; } + return true; } @@ -1642,8 +1811,15 @@ bool CWallet::MintableCoins() vector vCoins; AvailableCoins(vCoins, true); - BOOST_FOREACH (const COutput& out, vCoins) { - if (GetTime() - out.tx->GetTxTime() > nStakeMinAge) + for (const COutput& out : vCoins) { + int64_t nTxTime = out.tx->GetTxTime(); + if (out.tx->IsZerocoinSpend()) { + if (!out.tx->IsInMainChain()) + continue; + nTxTime = mapBlockIndex.at(out.tx->hashBlock)->GetBlockTime(); + } + + if (GetAdjustedTime() - nTxTime > nStakeMinAge) return true; } @@ -1774,7 +1950,7 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, setGetHash(), out.i); int rounds = GetInputObfuscationRounds(vin); // make sure it's actually anonymized - if (rounds < nObfuscationRounds) continue; + if (rounds < nZeromintPercentage) continue; } nValueRet += out.tx->vout[out.i].nValue; @@ -1794,7 +1970,7 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, setGetHash(), out.i); int rounds = GetInputObfuscationRounds(vin); // make sure it's actually anonymized - if (rounds < nObfuscationRounds) continue; + if (rounds < nZeromintPercentage) continue; nValueRet += out.tx->vout[out.i].nValue; setCoinsRet.insert(make_pair(out.tx, out.i)); } @@ -1992,7 +2168,7 @@ bool CWallet::SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nV int CWallet::CountInputsWithAmount(CAmount nInputAmount) { - int64_t nTotal = 0; + CAmount nTotal = 0; { LOCK(cs_wallet); for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { @@ -2224,7 +2400,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, } if (useIX) { - strFailReason += " " + _("SwiftTX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again."); + strFailReason += " " + _("SwiftX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again."); } return false; @@ -2563,15 +2739,17 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, std: AddToWallet(wtxNew); // Notify that old coins are spent - set updated_hahes; - BOOST_FOREACH (const CTxIn& txin, wtxNew.vin) { - // notify only once - if (updated_hahes.find(txin.prevout.hash) != updated_hahes.end()) continue; - - CWalletTx& coin = mapWallet[txin.prevout.hash]; - coin.BindWallet(this); - NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED); - updated_hahes.insert(txin.prevout.hash); + if (!wtxNew.IsZerocoinSpend()) { + set updated_hahes; + BOOST_FOREACH (const CTxIn& txin, wtxNew.vin) { + // notify only once + if (updated_hahes.find(txin.prevout.hash) != updated_hahes.end()) continue; + + CWalletTx& coin = mapWallet[txin.prevout.hash]; + coin.BindWallet(this); + NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED); + updated_hahes.insert(txin.prevout.hash); + } } if (fFileBacked) delete pwalletdb; @@ -3365,6 +3543,110 @@ bool CWallet::GetDestData(const CTxDestination& dest, const std::string& key, st return false; } +// CWallet::AutoZeromint() gets called with each new incoming block +void CWallet::AutoZeromint() +{ + // Don't bother Autominting if Zerocoin Protocol isn't active + if (!IsSporkActive(SPORK_21_ENABLE_ZEROCOIN)) return; + if (GetAdjustedTime() > GetSporkValue(SPORK_22_ZEROCOIN_MAINTENANCE_MODE)) return; + + // Wait until blockchain + masternodes are fully synced and wallet is unlocked. + if (!masternodeSync.IsSynced() || IsLocked()){ + // Re-adjust startup time in case syncing needs a long time. + nStartupTime = GetAdjustedTime(); + return; + } + + // After sync wait even more to reduce load when wallet was just started + int64_t nWaitTime = GetAdjustedTime() - nStartupTime; + if (nWaitTime < AUTOMINT_DELAY){ + LogPrint("zero", "CWallet::AutoZeromint(): time since sync-completion or last Automint (%ld sec) < default waiting time (%ld sec). Waiting again...\n", nWaitTime, AUTOMINT_DELAY); + return; + } + + CAmount nZerocoinBalance = GetZerocoinBalance(false); //false includes both pending and mature zerocoins. Need total balance for this so nothing is overminted. + CAmount nBalance = GetUnlockedCoins(); // We only consider unlocked coins, this also excludes masternode-vins + // from being accidentally minted + CAmount nMintAmount = 0; + CAmount nToMintAmount = 0; + + // zBWK are integers > 0, so we can't mint 10% of 9 BWK + if (nBalance < 10){ + LogPrint("zero", "CWallet::AutoZeromint(): available balance (%ld) too small for minting zBWK\n", nBalance); + return; + } + + // Percentage of zBWK we already have + double dPercentage = 100 * (double)nZerocoinBalance / (double)(nZerocoinBalance + nBalance); + + // Check if minting is actually needed + if(dPercentage >= nZeromintPercentage){ + LogPrint("zero", "CWallet::AutoZeromint() @block %ld: percentage of existing zBWK (%lf%%) already >= configured percentage (%d%%). No minting needed...\n", + chainActive.Tip()->nHeight, dPercentage, nZeromintPercentage); + return; + } + + // zBWK amount needed for the target percentage + nToMintAmount = ((nZerocoinBalance + nBalance) * nZeromintPercentage / 100); + + // zBWK amount missing from target (must be minted) + nToMintAmount = (nToMintAmount - nZerocoinBalance) / COIN; + + // Use the biggest denomination smaller than the needed zBWK We'll only mint exact denomination to make minting faster. + // Exception: for big amounts use 1666 (1666 = 1*1000 + 1*500 + 1*100 + 1*50 + 1*10 + 1*5 + 1) to create all + // possible denominations to avoid having 1000 denominations only. + // If a preferred denomination is used (means nPreferredDenom != 0) do nothing until we have enough BWK to mint this denomination + + if (nPreferredDenom > 0){ + if (nToMintAmount >= nPreferredDenom) + nToMintAmount = nPreferredDenom; // Enough coins => mint preferred denomination + else + nToMintAmount = 0; // Not enough coins => do nothing and wait for more coins + } + + if (nToMintAmount >= ZQ_1666){ + nMintAmount = ZQ_1666; + } else if (nToMintAmount >= libzerocoin::CoinDenomination::ZQ_ONE_THOUSAND){ + nMintAmount = libzerocoin::CoinDenomination::ZQ_ONE_THOUSAND; + } else if (nToMintAmount >= libzerocoin::CoinDenomination::ZQ_FIVE_HUNDRED){ + nMintAmount = libzerocoin::CoinDenomination::ZQ_FIVE_HUNDRED; + } else if (nToMintAmount >= libzerocoin::CoinDenomination::ZQ_ONE_HUNDRED){ + nMintAmount = libzerocoin::CoinDenomination::ZQ_ONE_HUNDRED; + } else if (nToMintAmount >= libzerocoin::CoinDenomination::ZQ_FIFTY){ + nMintAmount = libzerocoin::CoinDenomination::ZQ_FIFTY; + } else if (nToMintAmount >= libzerocoin::CoinDenomination::ZQ_TEN){ + nMintAmount = libzerocoin::CoinDenomination::ZQ_TEN; + } else if (nToMintAmount >= libzerocoin::CoinDenomination::ZQ_FIVE){ + nMintAmount = libzerocoin::CoinDenomination::ZQ_FIVE; + } else if (nToMintAmount >= libzerocoin::CoinDenomination::ZQ_ONE){ + nMintAmount = libzerocoin::CoinDenomination::ZQ_ONE; + } else { + nMintAmount = 0; + } + + if (nMintAmount > 0){ + CWalletTx wtx; + vector vMints; + string strError = pwalletMain->MintZerocoin(nMintAmount*COIN, wtx, vMints); + + // Return if something went wrong during minting + if (strError != ""){ + LogPrintf("CWallet::AutoZeromint(): auto minting failed with error: %s\n", strError); + return; + } + nZerocoinBalance = GetZerocoinBalance(false); + nBalance = GetUnlockedCoins(); + dPercentage = 100 * (double)nZerocoinBalance / (double)(nZerocoinBalance + nBalance); + LogPrintf("CWallet::AutoZeromint() @ block %ld: successfully minted %ld zBWK. Current percentage of zBWK: %lf%%\n", + chainActive.Tip()->nHeight, nMintAmount, dPercentage); + // Re-adjust startup time to delay next Automint for 5 minutes + nStartupTime = GetAdjustedTime(); + } + else { + LogPrintf("CWallet::AutoZeromint(): Nothing minted because either not enough funds available or the requested denomination size (%d) is not yet reached.\n", nPreferredDenom); + } +} + void CWallet::AutoCombineDust() { if (IsInitialBlockDownload() || IsLocked()) { @@ -3452,7 +3734,7 @@ bool CWallet::MultiSend() bool mnSent = false; for (const COutput& out : vCoins) { //need output with precise confirm count - this is how we identify which is the output to send - if (out.tx->GetDepthInMainChain() != Params().COINBASE_MATURITY() + 1) + if (out.tx->GetDepthInMainChain() != COINBASE_MATURITY + 1) continue; COutPoint outpoint(out.tx->GetHash(), out.i); @@ -3520,7 +3802,7 @@ bool CWallet::MultiSend() CreateTransaction(vecSend, wtxdummy, keyChange, nFeeRet, strErr, &cControl, ALL_COINS, false, CAmount(0)); CAmount nLastSendAmount = vecSend[vecSend.size() - 1].second; if (nLastSendAmount < nFeeRet + 500) { - LogPrintf("%s: fee of %s is too large to insert into last output\n"); + LogPrintf("%s: fee of %d is too large to insert into last output\n", __func__, nFeeRet + 500); return false; } vecSend[vecSend.size() - 1].second = nLastSendAmount - nFeeRet - 500; @@ -3677,7 +3959,10 @@ int CMerkleTx::GetBlocksToMaturity() const bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectInsaneFee, bool ignoreFees) { CValidationState state; - return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectInsaneFee, ignoreFees); + bool fAccepted = ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectInsaneFee, ignoreFees); + if (!fAccepted) + LogPrintf("%s : %s\n", __func__, state.GetRejectReason()); + return fAccepted; } int CMerkleTx::GetTransactionLockSignatures() const @@ -3707,3 +3992,694 @@ bool CMerkleTx::IsTransactionLockTimedOut() const return false; } + +// Given a set of inputs, find the public key that contributes the most coins to the input set +CScript GetLargestContributor(set >& setCoins) +{ + map mapScriptsOut; + for (const std::pair& coin : setCoins) { + CTxOut out = coin.first->vout[coin.second]; + mapScriptsOut[out.scriptPubKey] += out.nValue; + } + + CScript scriptLargest; + CAmount nLargestContributor = 0; + for (auto it : mapScriptsOut) { + if (it.second > nLargestContributor) { + scriptLargest = it.first; + nLargestContributor = it.second; + } + } + + return scriptLargest; +} + +bool CWallet::CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransaction& txNew, vector& vMints, CReserveKey* reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl, const bool isZCSpendChange) +{ + if (IsLocked()) { + strFailReason = _("Error: Wallet locked, unable to create transaction!"); + LogPrintf("SpendZerocoin() : %s", strFailReason.c_str()); + return false; + } + + //add multiple mints that will fit the amount requested as closely as possible + CAmount nMintingValue = 0; + CAmount nValueRemaining = 0; + while (true) { + //mint a coin with the closest denomination to what is being requested + nFeeRet = max(static_cast(txNew.vout.size()), 1) * Params().Zerocoin_MintFee(); + nValueRemaining = nValue - nMintingValue - (isZCSpendChange ? nFeeRet : 0); + + // if this is change of a zerocoinspend, then we can't mint all change, at least something must be given as a fee + if (isZCSpendChange && nValueRemaining <= 1 * COIN) + break; + + libzerocoin::CoinDenomination denomination = libzerocoin::AmountToClosestDenomination(nValueRemaining, nValueRemaining); + if (denomination == libzerocoin::ZQ_ERROR) + break; + + CAmount nValueNewMint = libzerocoin::ZerocoinDenominationToAmount(denomination); + nMintingValue += nValueNewMint; + + // mint a new coin (create Pedersen Commitment) and extract PublicCoin that is shareable from it + libzerocoin::PrivateCoin newCoin(Params().Zerocoin_Params(), denomination); + libzerocoin::PublicCoin pubCoin = newCoin.getPublicCoin(); + + // Validate + if(!pubCoin.validate()) { + strFailReason = _("failed to validate zerocoin"); + return false; + } + + CScript scriptSerializedCoin = CScript() << OP_ZEROCOINMINT << pubCoin.getValue().getvch().size() << pubCoin.getValue().getvch(); + CTxOut outMint(nValueNewMint, scriptSerializedCoin); + txNew.vout.push_back(outMint); + + //store as CZerocoinMint for later use + CZerocoinMint mint(denomination, pubCoin.getValue(), newCoin.getRandomness(), newCoin.getSerialNumber(), false); + vMints.push_back(mint); + } + + // calculate fee + CAmount nFee = Params().Zerocoin_MintFee() * txNew.vout.size(); + + // no ability to select more coins if this is a ZCSpend change mint + CAmount nTotalValue = (isZCSpendChange ? nValue : (nValue + nFee)); + + // check for a zerocoinspend that mints the change + CAmount nValueIn = 0; + set > setCoins; + if (isZCSpendChange) { + nValueIn = nValue; + } else { + // select UTXO's to use + if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl)) { + strFailReason = _("Insufficient or insufficient confirmed funds, you might need to wait a few minutes and try again."); + return false; + } + + // Fill vin + for (const std::pair& coin : setCoins) + txNew.vin.push_back(CTxIn(coin.first->GetHash(), coin.second)); + } + + //any change that is less than 0.0100000 will be ignored and given as an extra fee + //also assume that a zerocoinspend that is minting the change will not have any change that goes to BWK + CAmount nChange = nValueIn - nTotalValue; // Fee already accounted for in nTotalValue + if (nChange > 1 * CENT && !isZCSpendChange) { + // Fill a vout to ourself using the largest contributing address + CScript scriptChange = GetLargestContributor(setCoins); + + //add to the transaction + CTxOut outChange(nChange, scriptChange); + txNew.vout.push_back(outChange); + } else { + if (reservekey) + reservekey->ReturnKey(); + } + + // Sign if these are bwk outputs - NOTE that zBWK outputs are signed later in SoK + if (!isZCSpendChange) { + int nIn = 0; + for (const std::pair& coin : setCoins) { + if (!SignSignature(*this, *coin.first, txNew, nIn++)) { + strFailReason = _("Signing transaction failed"); + return false; + } + } + } + + return true; +} + +bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt) +{ + // Default error status if not changed below + receipt.SetStatus(_("Transaction Mint Started"), ZBWK_TXMINT_GENERAL); + + libzerocoin::CoinDenomination denomination = zerocoinSelected.GetDenomination(); + // 2. Get pubcoin from the private coin + libzerocoin::PublicCoin pubCoinSelected(Params().Zerocoin_Params(), zerocoinSelected.GetValue(), denomination); + LogPrintf("%s : pubCoinSelected:\n denom=%d\n value%s\n", __func__, denomination, pubCoinSelected.getValue().GetHex()); + if (!pubCoinSelected.validate()) { + receipt.SetStatus(_("The selected mint coin is an invalid coin"), ZBWK_INVALID_COIN); + return false; + } + + // 3. Compute Accumulator and Witness + libzerocoin::Accumulator accumulator(Params().Zerocoin_Params(), pubCoinSelected.getDenomination()); + libzerocoin::AccumulatorWitness witness(Params().Zerocoin_Params(), accumulator, pubCoinSelected); + string strFailReason = ""; + int nMintsAdded = 0; + if (!GenerateAccumulatorWitness(pubCoinSelected, accumulator, witness, nSecurityLevel, nMintsAdded, strFailReason)) { + receipt.SetStatus(_("Try to spend with a higher security level to include more coins"), ZBWK_FAILED_ACCUMULATOR_INITIALIZATION); + LogPrintf("%s : %s \n", __func__, receipt.GetStatusMessage()); + return false; + } + + // Construct the CoinSpend object. This acts like a signature on the transaction. + libzerocoin::PrivateCoin privateCoin(Params().Zerocoin_Params(), denomination); + privateCoin.setPublicCoin(pubCoinSelected); + privateCoin.setRandomness(zerocoinSelected.GetRandomness()); + privateCoin.setSerialNumber(zerocoinSelected.GetSerialNumber()); + uint32_t nChecksum = GetChecksum(accumulator.getValue()); + + try { + libzerocoin::CoinSpend spend(Params().Zerocoin_Params(), privateCoin, accumulator, nChecksum, witness, hashTxOut); + + if (!spend.Verify(accumulator)) { + receipt.SetStatus(_("The new spend coin transaction did not verify"), ZBWK_INVALID_WITNESS); + return false; + } + + // Deserialize the CoinSpend intro a fresh object + CDataStream serializedCoinSpend(SER_NETWORK, PROTOCOL_VERSION); + serializedCoinSpend << spend; + std::vector data(serializedCoinSpend.begin(), serializedCoinSpend.end()); + + //Add the coin spend into a bwk transaction + newTxIn.scriptSig = CScript() << OP_ZEROCOINSPEND << data.size(); + newTxIn.scriptSig.insert(newTxIn.scriptSig.end(), data.begin(), data.end()); + newTxIn.prevout.SetNull(); + + //use nSequence as a shorthand lookup of denomination + //NOTE that this should never be used in place of checking the value in the final blockchain acceptance/verification + //of the transaction + newTxIn.nSequence = denomination; + + CDataStream serializedCoinSpendChecking(SER_NETWORK, PROTOCOL_VERSION); + try { + serializedCoinSpendChecking << spend; + } + catch (...) { + receipt.SetStatus(_("Failed to deserialize"), ZBWK_BAD_SERIALIZATION); + return false; + } + + libzerocoin::CoinSpend newSpendChecking(Params().Zerocoin_Params(), serializedCoinSpendChecking); + if (!newSpendChecking.Verify(accumulator)) { + receipt.SetStatus(_("The transaction did not verify"), ZBWK_BAD_SERIALIZATION); + return false; + } + + std::list listCoinSpendSerial = CWalletDB(strWalletFile).ListSpentCoinsSerial(); + for (const CBigNum& item : listCoinSpendSerial) { + if (spend.getCoinSerialNumber() == item) { + //Tried to spend an already spent zBWK + zerocoinSelected.SetUsed(true); + if (!CWalletDB(strWalletFile).WriteZerocoinMint(zerocoinSelected)) + LogPrintf("%s failed to write zerocoinmint\n", __func__); + + pwalletMain->NotifyZerocoinChanged(pwalletMain, zerocoinSelected.GetValue().GetHex(), "Used", CT_UPDATED); + receipt.SetStatus(_("The coin spend has been used"), ZBWK_SPENT_USED_ZBWK); + return false; + } + } + + uint32_t nAccumulatorChecksum = GetChecksum(accumulator.getValue()); + CZerocoinSpend zcSpend(spend.getCoinSerialNumber(), 0, zerocoinSelected.GetValue(), zerocoinSelected.GetDenomination(), nAccumulatorChecksum); + zcSpend.SetMintCount(nMintsAdded); + receipt.AddSpend(zcSpend); + } + catch (const std::exception&) { + receipt.SetStatus(_("CoinSpend: Accumulator witness does not verify"), ZBWK_INVALID_WITNESS); + return false; + } + + receipt.SetStatus(_("Spend Valid"), ZBWK_SPEND_OKAY); // Everything okay + + return true; +} + +bool CWallet::CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, CWalletTx& wtxNew, CReserveKey& reserveKey, CZerocoinSpendReceipt& receipt, vector& vSelectedMints, vector& vNewMints, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* address) +{ + // Check available funds + int nStatus = ZBWK_TRX_FUNDS_PROBLEMS; + if (nValue > GetZerocoinBalance(true)) { + receipt.SetStatus(_("You don't have enough Zerocoins in your wallet"), nStatus); + return false; + } + + if (nValue < 1) { + receipt.SetStatus(_("Value is below the the smallest available denomination (= 1) of zBWK"), nStatus); + return false; + } + + // Create transaction + nStatus = ZBWK_TRX_CREATE; + + // If not already given pre-selected mints, then select mints from the wallet + CWalletDB walletdb(pwalletMain->strWalletFile); + list listMints; + 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 zBWK transaction + if (vSelectedMints.empty()) { + listMints = walletdb.ListMintedCoins(true, true, true); // need to find mints to spend + if(listMints.empty()) { + receipt.SetStatus(_("Failed to find Zerocoins in in wallet.dat"), nStatus); + return false; + } + + // If the input value is not an int, then we want the selection algorithm to round up to the next highest int + double dValue = static_cast(nValue) / static_cast(COIN); + bool fWholeNumber = floor(dValue) == dValue; + CAmount nValueToSelect = nValue; + if(!fWholeNumber) + nValueToSelect = static_cast(ceil(dValue) * COIN); + + // Select the zBWK mints to use in this spend + std::map DenomMap = GetMyZerocoinDistribution(); + vSelectedMints = SelectMintsFromList(nValueToSelect, nValueSelected, nMaxSpends, fMinimizeChange, + nCoinsReturned, listMints, DenomMap, nNeededSpends); + } else { + for (const CZerocoinMint mint : vSelectedMints) + nValueSelected += ZerocoinDenominationToAmount(mint.GetDenomination()); + } + + listSpends(vSelectedMints); + + int nArchived = 0; + for (CZerocoinMint mint : vSelectedMints) { + // see if this serial has already been spent + if (IsSerialKnown(mint.GetSerialNumber())) { + receipt.SetStatus(_("Trying to spend an already spent serial #, try again."), nStatus); + + mint.SetUsed(true); + walletdb.WriteZerocoinMint(mint); + + return false; + } + + //check that this mint made it into the blockchain + CTransaction txMint; + uint256 hashBlock; + bool fArchive = false; + if (!GetTransaction(mint.GetTxHash(), txMint, hashBlock)) { + receipt.SetStatus(_("Unable to find transaction containing mint"), nStatus); + fArchive = true; + } else if (mapBlockIndex.count(hashBlock) < 1) { + receipt.SetStatus(_("Mint did not make it into blockchain"), nStatus); + fArchive = true; + } + + // archive this mint as an orphan + if (fArchive) { + walletdb.ArchiveMintOrphan(mint); + nArchived++; + } + } + if (nArchived) + return false; + + if (vSelectedMints.empty()) { + if(nNeededSpends > 0){ + // Too much spends needed, so abuse nStatus to report back the number of needed spends + receipt.SetStatus(_("Too many spends needed"), nStatus, nNeededSpends); + } + else { + receipt.SetStatus(_("Failed to select a zerocoin"), nStatus); + } + return false; + } + + if ((static_cast(vSelectedMints.size()) > Params().Zerocoin_MaxSpendsPerTransaction())) { + receipt.SetStatus(_("Failed to find coin set amongst held coins with less than maxNumber of Spends"), nStatus); + return false; + } + + // Create change if needed + nStatus = ZBWK_TRX_CHANGE; + + CMutableTransaction txNew; + wtxNew.BindWallet(this); + { + LOCK2(cs_main, cs_wallet); + { + txNew.vin.clear(); + txNew.vout.clear(); + + //if there is an address to send to then use it, if not generate a new address to send to + CScript scriptZerocoinSpend; + CScript scriptChange; + CAmount nChange = nValueSelected - nValue; + if (nChange && !address) { + receipt.SetStatus(_("Need address because change is not exact"), nStatus); + return false; + } + + if (address) { + scriptZerocoinSpend = GetScriptForDestination(address->Get()); + if (nChange) { + // Reserve a new key pair from key pool + CPubKey vchPubKey; + assert(reserveKey.GetReservedKey(vchPubKey)); // should never fail + scriptChange = GetScriptForDestination(vchPubKey.GetID()); + } + } else { + // Reserve a new key pair from key pool + CPubKey vchPubKey; + assert(reserveKey.GetReservedKey(vchPubKey)); // should never fail + scriptZerocoinSpend = GetScriptForDestination(vchPubKey.GetID()); + } + + //add change output if we are spending too much (only applies to spending multiple at once) + if (nChange) { + //mint change as zerocoins + if (fMintChange) { + CAmount nFeeRet = 0; + string strFailReason = ""; + if (!CreateZerocoinMintTransaction(nChange, txNew, vNewMints, &reserveKey, nFeeRet, strFailReason, NULL, true)) { + receipt.SetStatus(_("Failed to create mint"), nStatus); + return false; + } + } else { + CTxOut txOutChange(nValueSelected - nValue, scriptChange); + txNew.vout.push_back(txOutChange); + } + } + + //add output to bwk address to the transaction (the actual primary spend taking place) + CTxOut txOutZerocoinSpend(nValue, scriptZerocoinSpend); + txNew.vout.push_back(txOutZerocoinSpend); + + //hash with only the output info in it to be used in Signature of Knowledge + uint256 hashTxOut = txNew.GetHash(); + + //add all of the mints to the transaction as inputs + for (CZerocoinMint mint : vSelectedMints) { + CTxIn newTxIn; + if (!MintToTxIn(mint, nSecurityLevel, hashTxOut, newTxIn, receipt)) { + return false; + } + txNew.vin.push_back(newTxIn); + } + + // Limit size + unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); + if (nBytes >= MAX_ZEROCOIN_TX_SIZE) { + receipt.SetStatus(_("In rare cases, a spend with 7 coins exceeds our maximum allowable transaction size, please retry spend using 6 or less coins"), ZBWK_TX_TOO_LARGE); + return false; + } + + //now that all inputs have been added, add full tx hash to zerocoinspend records and write to db + uint256 txHash = txNew.GetHash(); + for (CZerocoinSpend spend : receipt.GetSpends()) { + spend.SetTxHash(txHash); + + if (!CWalletDB(strWalletFile).WriteZerocoinSpendSerialEntry(spend)) { + receipt.SetStatus(_("Failed to write coin serial number into wallet"), nStatus); + } + } + + //turn the finalized transaction into a wallet transaction + wtxNew = CWalletTx(this, txNew); + wtxNew.fFromMe = true; + wtxNew.fTimeReceivedIsTxTime = true; + wtxNew.nTimeReceived = GetAdjustedTime(); + } + } + + receipt.SetStatus(_("Transaction Created"), ZBWK_SPEND_OKAY); // Everything okay + + return true; +} + +string CWallet::ResetMintZerocoin(bool fExtendedSearch) +{ + long updates = 0; + long deletions = 0; + CWalletDB walletdb(pwalletMain->strWalletFile); + + list listMints = walletdb.ListMintedCoins(false, false, true); + vector vMintsToFind{ std::make_move_iterator(std::begin(listMints)), std::make_move_iterator(std::end(listMints)) }; + vector vMintsMissing; + vector vMintsToUpdate; + + // search all of our available data for these mints + FindMints(vMintsToFind, vMintsToUpdate, vMintsMissing, fExtendedSearch); + + // Update the meta data of mints that were marked for updating + for (CZerocoinMint mint : vMintsToUpdate) { + updates++; + walletdb.WriteZerocoinMint(mint); + } + + // Delete any mints that were unable to be located on the blockchain + for (CZerocoinMint mint : vMintsMissing) { + deletions++; + walletdb.ArchiveMintOrphan(mint); + } + + string strResult = _("ResetMintZerocoin finished: ") + to_string(updates) + _(" mints updated, ") + to_string(deletions) + _(" mints deleted\n"); + return strResult; +} + +string CWallet::ResetSpentZerocoin() +{ + long removed = 0; + CWalletDB walletdb(pwalletMain->strWalletFile); + + list listMints = walletdb.ListMintedCoins(false, false, false); + list listSpends = walletdb.ListSpentCoins(); + list listUnconfirmedSpends; + + for (CZerocoinSpend spend : listSpends) { + CTransaction tx; + uint256 hashBlock = 0; + if (!GetTransaction(spend.GetTxHash(), tx, hashBlock)) { + listUnconfirmedSpends.push_back(spend); + continue; + } + + //no confirmations + if (hashBlock == 0) + listUnconfirmedSpends.push_back(spend); + } + + for (CZerocoinSpend spend : listUnconfirmedSpends) { + for (CZerocoinMint mint : listMints) { + if (mint.GetSerialNumber() == spend.GetSerial()) { + removed++; + mint.SetUsed(false); + RemoveSerialFromDB(spend.GetSerial()); + walletdb.WriteZerocoinMint(mint); + walletdb.EraseZerocoinSpendSerialEntry(spend.GetSerial()); + continue; + } + } + } + + string strResult = _("ResetSpentZerocoin finished: ") + to_string(removed) + _(" unconfirmed transactions removed\n"); + return strResult; +} + +void CWallet::ReconsiderZerocoins(std::list& listMintsRestored) +{ + CWalletDB walletdb(pwalletMain->strWalletFile); + list listMints = walletdb.ListArchivedZerocoins(); + + if (listMints.empty()) + return; + + for (CZerocoinMint mint : listMints) { + if (IsSerialKnown(mint.GetSerialNumber())) + continue; + + uint256 txHash; + if (!GetZerocoinMint(mint.GetValue(), txHash)) + continue; + + uint256 hashBlock = 0; + CTransaction tx; + if (!GetTransaction(txHash, tx, hashBlock)) + continue; + + mint.SetTxHash(txHash); + mint.SetHeight(mapBlockIndex.at(hashBlock)->nHeight); + if (!walletdb.UnarchiveZerocoin(mint)) { + LogPrintf("%s : failed to unarchive mint %s\n", __func__, mint.GetValue().GetHex()); + } + listMintsRestored.emplace_back(mint); + } +} + + +void CWallet::ZBWKBackupWallet() +{ + filesystem::path backupDir = GetDataDir() / "backups"; + filesystem::path backupPath; + string strNewBackupName; + + for (int i = 0; i < 10; i++) { + strNewBackupName = strprintf("wallet-autozbwkbackup-%d.dat", i); + backupPath = backupDir / strNewBackupName; + + if (filesystem::exists(backupPath)) { + //Keep up to 10 backups + if (i <= 8) { + //If the next file backup exists and is newer, then iterate + filesystem::path nextBackupPath = backupDir / strprintf("wallet-autozbwkbackup-%d.dat", i + 1); + if (filesystem::exists(nextBackupPath)) { + time_t timeThis = filesystem::last_write_time(backupPath); + time_t timeNext = filesystem::last_write_time(nextBackupPath); + if (timeThis > timeNext) { + //The next backup is created before this backup was + //The next backup is the correct path to use + backupPath = nextBackupPath; + break; + } + } + //Iterate to the next filename/number + continue; + } + //reset to 0 because name with 9 already used + strNewBackupName = strprintf("wallet-autozbwkbackup-%d.dat", 0); + backupPath = backupDir / strNewBackupName; + break; + } + //This filename is fresh, break here and backup + break; + } + + BackupWallet(*this, backupPath.string()); +} + +string CWallet::MintZerocoin(CAmount nValue, CWalletTx& wtxNew, vector& vMints, const CCoinControl* coinControl) +{ + // Check amount + if (nValue <= 0) + return _("Invalid amount"); + + if (nValue + Params().Zerocoin_MintFee() > GetBalance()) + return _("Insufficient funds"); + + CReserveKey reservekey(this); + int64_t nFeeRequired; + + if (IsLocked()) { + string strError = _("Error: Wallet locked, unable to create transaction!"); + LogPrintf("MintZerocoin() : %s", strError.c_str()); + return strError; + } + + string strError; + CMutableTransaction txNew; + if (!CreateZerocoinMintTransaction(nValue, txNew, vMints, &reservekey, nFeeRequired, strError, coinControl)) { + if (nValue + nFeeRequired > GetBalance()) + return strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!"), FormatMoney(nFeeRequired).c_str()); + return strError; + } + + wtxNew = CWalletTx(this, txNew); + wtxNew.fFromMe = true; + wtxNew.fTimeReceivedIsTxTime = true; + + // Limit size + unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); + if (nBytes >= MAX_ZEROCOIN_TX_SIZE) { + return _("Error: The transaction is larger than the maximum allowed transaction size!"); + } + + //commit the transaction to the network + if (!CommitTransaction(wtxNew, reservekey)) { + return _("Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); + } else { + //update mints with full transaction hash and then database them + CWalletDB walletdb(pwalletMain->strWalletFile); + for (CZerocoinMint mint : vMints) { + mint.SetTxHash(wtxNew.GetHash()); + walletdb.WriteZerocoinMint(mint); + pwalletMain->NotifyZerocoinChanged(pwalletMain, mint.GetValue().GetHex(), "Used", CT_UPDATED); + } + } + + //Create a backup of the wallet + if (fBackupMints) + ZBWKBackupWallet(); + + return ""; +} + +bool CWallet::SpendZerocoin(CAmount nAmount, int nSecurityLevel, CWalletTx& wtxNew, CZerocoinSpendReceipt& receipt, vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* addressTo) +{ + // Default: assume something goes wrong. Depending on the problem this gets more specific below + int nStatus = ZBWK_SPEND_ERROR; + + if (IsLocked()) { + receipt.SetStatus("Error: Wallet locked, unable to create transaction!", ZBWK_WALLET_LOCKED); + return false; + } + + CReserveKey reserveKey(this); + vector vNewMints; + if (!CreateZerocoinSpendTransaction(nAmount, nSecurityLevel, wtxNew, reserveKey, receipt, vMintsSelected, vNewMints, fMintChange, fMinimizeChange, addressTo)) { + return false; + } + + if (fMintChange && fBackupMints) + ZBWKBackupWallet(); + + CWalletDB walletdb(pwalletMain->strWalletFile); + if (!CommitTransaction(wtxNew, reserveKey)) { + LogPrintf("%s: failed to commit\n", __func__); + nStatus = ZBWK_COMMIT_FAILED; + + //reset all mints + for (CZerocoinMint mint : vMintsSelected) { + mint.SetUsed(false); // having error, so set to false, to be able to use again + walletdb.WriteZerocoinMint(mint); + pwalletMain->NotifyZerocoinChanged(pwalletMain, mint.GetValue().GetHex(), "New", CT_UPDATED); + } + + //erase spends + for (CZerocoinSpend spend : receipt.GetSpends()) { + if (!walletdb.EraseZerocoinSpendSerialEntry(spend.GetSerial())) { + receipt.SetStatus("Error: It cannot delete coin serial number in wallet", ZBWK_ERASE_SPENDS_FAILED); + } + + //Remove from public zerocoinDB + RemoveSerialFromDB(spend.GetSerial()); + } + + // erase new mints + for (auto& mint : vNewMints) { + if (!walletdb.EraseZerocoinMint(mint)) { + receipt.SetStatus("Error: Unable to cannot delete zerocoin mint in wallet", ZBWK_ERASE_NEW_MINTS_FAILED); + } + } + + receipt.SetStatus("Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.", nStatus); + return false; + } + + for (CZerocoinMint mint : vMintsSelected) { + mint.SetUsed(true); + if (!walletdb.WriteZerocoinMint(mint)) { + receipt.SetStatus("Failed to write mint to db", nStatus); + return false; + } + + CZerocoinMint mintCheck; + if (!walletdb.ReadZerocoinMint(mint.GetValue(), mintCheck)) { + receipt.SetStatus("failed to read mintcheck", nStatus); + return false; + } + + if (!mintCheck.IsUsed()) { + receipt.SetStatus("Error, the mint did not get marked as used", nStatus); + return false; + } + } + + // write new Mints to db + for (CZerocoinMint mint : vNewMints) { + mint.SetTxHash(wtxNew.GetHash()); + walletdb.WriteZerocoinMint(mint); + } + + receipt.SetStatus("Spend Successful", ZBWK_SPEND_OKAY); // When we reach this point spending zBWK was successful + + return true; +} diff --git a/src/wallet.h b/src/wallet.h index 2434ac519..3b03e6e9e 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -18,6 +18,7 @@ #include "main.h" #include "primitives/block.h" #include "primitives/transaction.h" +#include "primitives/zerocoin.h" #include "ui_interface.h" #include "util.h" #include "validationinterface.h" @@ -40,6 +41,7 @@ extern CFeeRate payTxFee; extern CAmount maxTxFee; extern unsigned int nTxConfirmTarget; extern bool bSpendZeroConfChange; +extern bool bdisableSystemnotifications; extern bool fSendFreeTransactions; extern bool fPayAtLeastCustomFee; @@ -54,6 +56,10 @@ static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWa //! Largest (in bytes) free transaction we're willing to create static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; +// Zerocoin denomination which creates exactly one of each denominations: +// 1666 = 1*1000 + 1*500 + 1*100 + 1*50 + 1*10 + 1*5 + 1 +static const int ZQ_1666 = 1666; + class CAccountingEntry; class CCoinControl; class COutput; @@ -76,7 +82,28 @@ enum AvailableCoinsType { ONLY_DENOMINATED = 2, ONLY_NOT10000IFMN = 3, ONLY_NONDENOMINATED_NOT10000IFMN = 4, // ONLY_NONDENOMINATED and not 10000 BWK at the same time - ONLY_10000 = 5 // find masternode outputs including locked ones (use with caution) + ONLY_10000 = 5, // find masternode outputs including locked ones (use with caution) + STAKABLE_COINS = 6 // UTXO's that are valid for staking +}; + +// Possible states for zBWK send +enum ZerocoinSpendStatus { + ZBWK_SPEND_OKAY = 0, // No error + ZBWK_SPEND_ERROR = 1, // Unspecified class of errors, more details are (hopefully) in the returning text + ZBWK_WALLET_LOCKED = 2, // Wallet was locked + ZBWK_COMMIT_FAILED = 3, // Commit failed, reset status + ZBWK_ERASE_SPENDS_FAILED = 4, // Erasing spends during reset failed + ZBWK_ERASE_NEW_MINTS_FAILED = 5, // Erasing new mints during reset failed + ZBWK_TRX_FUNDS_PROBLEMS = 6, // Everything related to available funds + ZBWK_TRX_CREATE = 7, // Everything related to create the transaction + ZBWK_TRX_CHANGE = 8, // Everything related to transaction change + ZBWK_TXMINT_GENERAL = 9, // General errors in MintToTxIn + ZBWK_INVALID_COIN = 10, // Selected mint coin is not valid + ZBWK_FAILED_ACCUMULATOR_INITIALIZATION = 11, // Failed to initialize witness + ZBWK_INVALID_WITNESS = 12, // Spend coin transaction did not verify + ZBWK_BAD_SERIALIZATION = 13, // Transaction verification failed + ZBWK_SPENT_USED_ZBWK = 14, // Coin has already been spend + ZBWK_TX_TOO_LARGE = 15 // The transaction is larger than the max tx size }; struct CompactTallyItem { @@ -127,7 +154,7 @@ class CAddressBookData StringMap destdata; }; -/** +/** * A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, * and provides the ability to create new transactions. */ @@ -173,6 +200,21 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool SelectCoinsCollateral(std::vector& setCoinsRet, CAmount& nValueRet) const; + // Zerocoin additions + bool CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransaction& txNew, vector& vMints, CReserveKey* reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl = NULL, const bool isZCSpendChange = false); + bool CreateZerocoinSpendTransaction(CAmount nValue, int nSecurityLevel, CWalletTx& wtxNew, CReserveKey& reserveKey, CZerocoinSpendReceipt& receipt, vector& vSelectedMints, vector& vNewMints, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* address = NULL); + bool MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt); + std::string MintZerocoin(CAmount nValue, CWalletTx& wtxNew, vector& vMints, const CCoinControl* coinControl = NULL); + bool SpendZerocoin(CAmount nValue, int nSecurityLevel, CWalletTx& wtxNew, CZerocoinSpendReceipt& receipt, vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* addressTo = NULL); + std::string ResetMintZerocoin(bool fExtendedSearch); + std::string ResetSpentZerocoin(); + void ReconsiderZerocoins(std::list& listMintsRestored); + void ZBWKBackupWallet(); + + /** Zerocin entry changed. + * @note called with lock cs_wallet held. + */ + boost::signals2::signal NotifyZerocoinChanged; /* * Main wallet lock. * This lock protects all the fields added by CWallet @@ -185,6 +227,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool fFileBacked; bool fWalletUnlockAnonymizeOnly; std::string strWalletFile; + bool fBackupMints; std::set setKeyPool; std::map mapKeyMetadata; @@ -242,6 +285,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface nLastResend = 0; nTimeFirstKey = 0; fWalletUnlockAnonymizeOnly = false; + fBackupMints = false; // Stake Settings nHashDrift = 45; @@ -263,6 +307,21 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface nAutoCombineThreshold = 0; } + int getZeromintPercentage() + { + return nZeromintPercentage; + } + + bool isZeromintEnabled() + { + return fEnableZeromint; + } + + void setZBWKAutoBackups(bool fEnabled) + { + fBackupMints = fEnabled; + } + bool isMultiSendEnabled() { return fMultiSendMasternodeReward || fMultiSendStake; @@ -367,7 +426,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface void GetKeyBirthTimes(std::map& mapKeyBirth) const; - /** + /** * Increment the next transaction order id * @return next transaction order id */ @@ -392,6 +451,12 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface void ReacceptWalletTransactions(); void ResendWalletTransactions(); CAmount GetBalance() const; + CAmount GetZerocoinBalance(bool fMatureOnly) const; + CAmount GetUnconfirmedZerocoinBalance() const; + CAmount GetImmatureZerocoinBalance() const; + CAmount GetLockedCoins() const; + CAmount GetUnlockedCoins() const; + std::map GetMyZerocoinDistribution() const; CAmount GetUnconfirmedBalance() const; CAmount GetImmatureBalance() const; CAmount GetAnonymizableBalance() const; @@ -402,6 +467,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface CAmount GetWatchOnlyBalance() const; CAmount GetUnconfirmedWatchOnlyBalance() const; CAmount GetImmatureWatchOnlyBalance() const; + bool CreateTransaction(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl); bool CreateTransaction(const std::vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, @@ -422,6 +488,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool isMSAddressEnabled(std::string address); int indexOfMSAddress(std::string address); void AutoCombineDust(); + void AutoZeromint(); static CFeeRate minTxFee; static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool); @@ -451,7 +518,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface bool IsDenominated(const CTxIn& txin) const; bool IsDenominated(const CTransaction& tx) const; - bool IsDenominatedAmount(int64_t nInputAmount) const; + bool IsDenominatedAmount(CAmount nInputAmount) const; isminetype IsMine(const CTxIn& txin) const; CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const; @@ -459,6 +526,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface { return ::IsMine(*this, txout.scriptPubKey); } + bool IsMyZerocoinSpend(const CBigNum& bnSerial) const; CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const { if (!MoneyRange(txout.nValue)) @@ -559,13 +627,13 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface //! Get wallet transactions that conflict with given transaction (spend same outputs) std::set GetConflicts(const uint256& txid) const; - /** + /** * Address book entry changed. * @note called with lock cs_wallet held. */ boost::signals2::signal NotifyAddressBookChanged; - /** + /** * Wallet transaction added, removed or updated. * @note called with lock cs_wallet held. */ @@ -703,7 +771,7 @@ class CMerkleTx : public CTransaction bool IsTransactionLockTimedOut() const; }; -/** +/** * A transaction with a bunch of additional info that only the owner cares about. * It includes any unrecorded transactions needed to link it back to the block chain. */ @@ -995,7 +1063,7 @@ class CWalletTx : public CMerkleTx if (fMasterNode && vout[i].nValue == 5000 * COIN) continue; // do not count MN-like outputs const int rounds = pwallet->GetInputObfuscationRounds(vin); - if (rounds >= -2 && rounds < nObfuscationRounds) { + if (rounds >= -2 && rounds < nZeromintPercentage) { nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); if (!MoneyRange(nCredit)) throw std::runtime_error("CWalletTx::GetAnonamizableCredit() : value out of range"); @@ -1028,7 +1096,7 @@ class CWalletTx : public CMerkleTx if (pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominated(vin)) continue; const int rounds = pwallet->GetInputObfuscationRounds(vin); - if (rounds >= nObfuscationRounds) { + if (rounds >= nZeromintPercentage) { nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); if (!MoneyRange(nCredit)) throw std::runtime_error("CWalletTx::GetAnonymizedCredit() : value out of range"); @@ -1040,6 +1108,67 @@ class CWalletTx : public CMerkleTx return nCredit; } + // Return sum of unlocked coins + CAmount GetUnlockedCredit() 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; + + 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->IsLockedCoin(hashTx, i)) continue; + if (fMasterNode && vout[i].nValue == 10000 * COIN) continue; // do not count MN-like outputs + + nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); + if (!MoneyRange(nCredit)) + throw std::runtime_error("CWalletTx::GetUnlockedCredit() : value out of range"); + } + + return nCredit; + } + + // Return sum of unlocked coins + CAmount GetLockedCredit() 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; + + CAmount nCredit = 0; + uint256 hashTx = GetHash(); + for (unsigned int i = 0; i < vout.size(); i++) { + const CTxOut& txout = vout[i]; + + // Skip spent coins + if (pwallet->IsSpent(hashTx, i)) continue; + + // Add locked coins + if (pwallet->IsLockedCoin(hashTx, i)) { + nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); + } + + // Add masternode collaterals which are handled likc locked coins + if (fMasterNode && vout[i].nValue == 10000 * COIN) { + nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); + } + + if (!MoneyRange(nCredit)) + throw std::runtime_error("CWalletTx::GetLockedCredit() : value out of range"); + } + + return nCredit; + } + CAmount GetDenominatedCredit(bool unconfirmed, bool fUseCache = true) const { if (pwallet == 0) @@ -1177,6 +1306,7 @@ class CWalletTx : public CMerkleTx bool WriteToDisk(); int64_t GetTxTime() const; + int64_t GetComputedTxTime() const; int GetRequestCount() const; void RelayWalletTransaction(std::string strCommand = "tx"); @@ -1249,7 +1379,7 @@ class CWalletKey }; -/** +/** * Account information. * Stored in wallet with key "acc"+string account name. */ @@ -1280,7 +1410,7 @@ class CAccount }; -/** +/** * Internal transfers. * Database key is acentry. */ diff --git a/src/wallet_ismine.cpp b/src/wallet_ismine.cpp index 1d85b8a9d..226d612f5 100644 --- a/src/wallet_ismine.cpp +++ b/src/wallet_ismine.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin 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. @@ -37,17 +38,17 @@ isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest) isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) { if(keystore.HaveWatchOnly(scriptPubKey)) - return ISMINE_WATCH_ONLY; + return ISMINE_WATCH_ONLY; if(keystore.HaveMultiSig(scriptPubKey)) - return ISMINE_MULTISIG; + return ISMINE_MULTISIG; vector vSolutions; txnouttype whichType; if(!Solver(scriptPubKey, whichType, vSolutions)) { - if(keystore.HaveWatchOnly(scriptPubKey)) + if(keystore.HaveWatchOnly(scriptPubKey)) return ISMINE_WATCH_ONLY; - if(keystore.HaveMultiSig(scriptPubKey)) - return ISMINE_MULTISIG; + if(keystore.HaveMultiSig(scriptPubKey)) + return ISMINE_MULTISIG; return ISMINE_NO; } @@ -57,6 +58,7 @@ isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) case TX_NONSTANDARD: case TX_NULL_DATA: break; + case TX_ZEROCOINMINT: case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); if(keystore.HaveKey(keyID)) @@ -72,7 +74,7 @@ isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) CScript subscript; if(keystore.GetCScript(scriptID, subscript)) { isminetype ret = IsMine(keystore, subscript); - if (ret != ISMINE_NO) + if(ret != ISMINE_NO) return ret; } break; @@ -93,7 +95,7 @@ isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey) if(keystore.HaveWatchOnly(scriptPubKey)) return ISMINE_WATCH_ONLY; if(keystore.HaveMultiSig(scriptPubKey)) - return ISMINE_MULTISIG; + return ISMINE_MULTISIG; return ISMINE_NO; } diff --git a/src/walletdb.cpp b/src/walletdb.cpp index baefcfa26..201e84942 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -434,7 +434,8 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CW CWalletTx wtx; ssValue >> wtx; CValidationState state; - if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid())) + // false because there is no reason to go through the zerocoin checks for our own wallet + if (!(CheckTransaction(wtx, false, false, state) && (wtx.GetHash() == hash) && state.IsValid())) return false; // Undo serialize changes in 31600 @@ -482,17 +483,17 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CW // Watch-only addresses have no birthday information for now, // so set the wallet birthday to the beginning of time. pwallet->nTimeFirstKey = 1; - } else if (strType == "multisig") { - CScript script; - ssKey >> script; - char fYes; - ssValue >> fYes; - if (fYes == '1') - pwallet->LoadMultiSig(script); - - // MultiSig addresses have no birthday information for now, - // so set the wallet birthday to the beginning of time. - pwallet->nTimeFirstKey = 1; + } else if (strType == "multisig") { + CScript script; + ssKey >> script; + char fYes; + ssValue >> fYes; + if (fYes == '1') + pwallet->LoadMultiSig(script); + + // MultiSig addresses have no birthday information for now, + // so set the wallet birthday to the beginning of time. + pwallet->nTimeFirstKey = 1; } else if (strType == "key" || strType == "wkey") { CPubKey vchPubKey; ssKey >> vchPubKey; @@ -1019,3 +1020,306 @@ bool CWalletDB::EraseDestData(const std::string& address, const std::string& key nWalletDBUpdated++; return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key))); } + +bool CWalletDB::WriteZerocoinSpendSerialEntry(const CZerocoinSpend& zerocoinSpend) +{ + return Write(make_pair(string("zcserial"), zerocoinSpend.GetSerial()), zerocoinSpend, true); +} +bool CWalletDB::EraseZerocoinSpendSerialEntry(const CBigNum& serialEntry) +{ + return Erase(make_pair(string("zcserial"), serialEntry)); +} + +bool CWalletDB::ReadZerocoinSpendSerialEntry(const CBigNum& bnSerial) +{ + CZerocoinSpend spend; + return Read(make_pair(string("zcserial"), bnSerial), spend); +} + +bool CWalletDB::WriteZerocoinMint(const CZerocoinMint& zerocoinMint) +{ + CDataStream ss(SER_GETHASH, 0); + ss << zerocoinMint.GetValue(); + uint256 hash = Hash(ss.begin(), ss.end()); + + Erase(make_pair(string("zerocoin"), hash)); + return Write(make_pair(string("zerocoin"), hash), zerocoinMint, true); +} + +bool CWalletDB::ReadZerocoinMint(const CBigNum &bnPubCoinValue, CZerocoinMint& zerocoinMint) +{ + CDataStream ss(SER_GETHASH, 0); + ss << bnPubCoinValue; + uint256 hash = Hash(ss.begin(), ss.end()); + + return Read(make_pair(string("zerocoin"), hash), zerocoinMint); +} + +bool CWalletDB::EraseZerocoinMint(const CZerocoinMint& zerocoinMint) +{ + CDataStream ss(SER_GETHASH, 0); + ss << zerocoinMint.GetValue(); + uint256 hash = Hash(ss.begin(), ss.end()); + + return Erase(make_pair(string("zerocoin"), hash)); +} + +bool CWalletDB::ArchiveMintOrphan(const CZerocoinMint& zerocoinMint) +{ + CDataStream ss(SER_GETHASH, 0); + ss << zerocoinMint.GetValue(); + uint256 hash = Hash(ss.begin(), ss.end());; + + if (!Write(make_pair(string("zco"), hash), zerocoinMint)) { + LogPrintf("%s : failed to database orphaned zerocoin mint\n", __func__); + return false; + } + + if (!Erase(make_pair(string("zerocoin"), hash))) { + LogPrintf("%s : failed to erase orphaned zerocoin mint\n", __func__); + return false; + } + + return true; +} + +bool CWalletDB::UnarchiveZerocoin(const CZerocoinMint& mint) +{ + CDataStream ss(SER_GETHASH, 0); + ss << mint.GetValue(); + uint256 hash = Hash(ss.begin(), ss.end());; + + if (!Erase(make_pair(string("zco"), hash))) { + LogPrintf("%s : failed to erase archived zerocoin mint\n", __func__); + return false; + } + + return WriteZerocoinMint(mint); +} + +std::list CWalletDB::ListMintedCoins(bool fUnusedOnly, bool fMaturedOnly, bool fUpdateStatus) +{ + std::list listPubCoin; + Dbc* pcursor = GetCursor(); + if (!pcursor) + throw runtime_error(std::string(__func__)+" : cannot create DB cursor"); + unsigned int fFlags = DB_SET_RANGE; + vector vOverWrite; + vector vArchive; + for (;;) + { + // Read next record + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + if (fFlags == DB_SET_RANGE) + ssKey << make_pair(string("zerocoin"), uint256(0)); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); + fFlags = DB_NEXT; + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + { + pcursor->close(); + throw runtime_error(std::string(__func__)+" : error scanning DB"); + } + + // Unserialize + string strType; + ssKey >> strType; + if (strType != "zerocoin") + break; + + uint256 value; + ssKey >> value; + + CZerocoinMint mint; + ssValue >> mint; + + if (fUnusedOnly) { + if (mint.IsUsed()) + continue; + + //double check that we have no record of this serial being used + if (ReadZerocoinSpendSerialEntry(mint.GetSerialNumber())) { + mint.SetUsed(true); + vOverWrite.emplace_back(mint); + continue; + } + } + + if (fMaturedOnly || fUpdateStatus) { + //if there is not a record of the block height, then look it up and assign it + if (!mint.GetHeight()) { + CTransaction tx; + uint256 hashBlock; + if(!GetTransaction(mint.GetTxHash(), tx, hashBlock, true)) { + LogPrintf("%s failed to find tx for mint txid=%s\n", __func__, mint.GetTxHash().GetHex()); + vArchive.emplace_back(mint); + continue; + } + + //if not in the block index, most likely is unconfirmed tx + if (mapBlockIndex.count(hashBlock)) { + mint.SetHeight(mapBlockIndex[hashBlock]->nHeight); + vOverWrite.emplace_back(mint); + } else if (fMaturedOnly){ + continue; + } + } + + //not mature + if (mint.GetHeight() > chainActive.Height() - Params().Zerocoin_MintRequiredConfirmations()) { + if (!fMaturedOnly) + listPubCoin.emplace_back(mint); + continue; + } + + //if only requesting an update (fUpdateStatus) then skip the rest and add to list + if (fMaturedOnly) { + // check to make sure there are at least 3 other mints added to the accumulators after this + if (chainActive.Height() < mint.GetHeight() + 1) + continue; + + CBlockIndex *pindex = chainActive[mint.GetHeight() + 1]; + int nMintsAdded = 0; + while(pindex->nHeight < chainActive.Height() - 30) { // 30 just to make sure that its at least 2 checkpoints from the top block + nMintsAdded += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), mint.GetDenomination()); + if(nMintsAdded >= Params().Zerocoin_RequiredAccumulation()) + break; + pindex = chainActive[pindex->nHeight + 1]; + } + + if(nMintsAdded < Params().Zerocoin_RequiredAccumulation()) + continue; + } + } + listPubCoin.emplace_back(mint); + } + + pcursor->close(); + + //overwrite any updates + for (CZerocoinMint mint : vOverWrite) { + if(!this->WriteZerocoinMint(mint)) + LogPrintf("%s failed to update mint from tx %s\n", __func__, mint.GetTxHash().GetHex()); + } + + // archive mints + for (CZerocoinMint mint : vArchive) { + if (!this->ArchiveMintOrphan(mint)) + LogPrintf("%s failed to archive mint from %s\n", __func__, mint.GetTxHash().GetHex()); + } + + return listPubCoin; +} +// Just get the Serial Numbers +std::list CWalletDB::ListMintedCoinsSerial() +{ + std::list listPubCoin; + std::list listCoins = ListMintedCoins(true, false, false); + + for ( auto& coin : listCoins) { + listPubCoin.push_back(coin.GetSerialNumber()); + } + return listPubCoin; +} + + +std::list CWalletDB::ListSpentCoins() +{ + std::list listCoinSpend; + Dbc* pcursor = GetCursor(); + if (!pcursor) + throw runtime_error(std::string(__func__)+" : cannot create DB cursor"); + unsigned int fFlags = DB_SET_RANGE; + for (;;) + { + // Read next record + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + if (fFlags == DB_SET_RANGE) + ssKey << make_pair(string("zcserial"), CBigNum(0)); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); + fFlags = DB_NEXT; + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + { + pcursor->close(); + throw runtime_error(std::string(__func__)+" : error scanning DB"); + } + + // Unserialize + string strType; + ssKey >> strType; + if (strType != "zcserial") + break; + + CBigNum value; + ssKey >> value; + + CZerocoinSpend zerocoinSpendItem; + ssValue >> zerocoinSpendItem; + + listCoinSpend.push_back(zerocoinSpendItem); + } + + pcursor->close(); + return listCoinSpend; +} + +// Just get the Serial Numbers +std::list CWalletDB::ListSpentCoinsSerial() +{ + std::list listPubCoin; + std::list listCoins = ListSpentCoins(); + + for ( auto& coin : listCoins) { + listPubCoin.push_back(coin.GetSerial()); + } + return listPubCoin; +} + +std::list CWalletDB::ListArchivedZerocoins() +{ + std::list listMints; + Dbc* pcursor = GetCursor(); + if (!pcursor) + throw runtime_error(std::string(__func__)+" : cannot create DB cursor"); + unsigned int fFlags = DB_SET_RANGE; + for (;;) + { + // Read next record + CDataStream ssKey(SER_DISK, CLIENT_VERSION); + if (fFlags == DB_SET_RANGE) + ssKey << make_pair(string("zco"), CBigNum(0)); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); + fFlags = DB_NEXT; + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) + { + pcursor->close(); + throw runtime_error(std::string(__func__)+" : error scanning DB"); + } + + // Unserialize + string strType; + ssKey >> strType; + if (strType != "zco") + break; + + uint256 value; + ssKey >> value; + + CZerocoinMint mint; + ssValue >> mint; + + listMints.push_back(mint); + } + + pcursor->close(); + return listMints; +} + diff --git a/src/walletdb.h b/src/walletdb.h index 3a352e8a2..004441058 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin developers +// Copyright (c) 2016-2017 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,6 +11,9 @@ #include "db.h" #include "key.h" #include "keystore.h" +#include "primitives/zerocoin.h" +#include "libzerocoin/Accumulator.h" +#include "libzerocoin/Denominations.h" #include #include @@ -25,6 +29,8 @@ class CMasterKey; class CScript; class CWallet; class CWalletTx; +class CZerocoinMint; +class CZerocoinSpend; class uint160; class uint256; @@ -142,6 +148,20 @@ class CWalletDB : public CDB static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys); static bool Recover(CDBEnv& dbenv, std::string filename); + bool WriteZerocoinMint(const CZerocoinMint& zerocoinMint); + bool EraseZerocoinMint(const CZerocoinMint& zerocoinMint); + bool ReadZerocoinMint(const CBigNum &bnSerial, CZerocoinMint& zerocoinMint); + bool ArchiveMintOrphan(const CZerocoinMint& zerocoinMint); + bool UnarchiveZerocoin(const CZerocoinMint& mint); + std::list ListMintedCoins(bool fUnusedOnly, bool fMaturedOnly, bool fUpdateStatus); + std::list ListSpentCoins(); + std::list ListMintedCoinsSerial(); + std::list ListSpentCoinsSerial(); + std::list ListArchivedZerocoins(); + bool WriteZerocoinSpendSerialEntry(const CZerocoinSpend& zerocoinSpend); + bool EraseZerocoinSpendSerialEntry(const CBigNum& serialEntry); + bool ReadZerocoinSpendSerialEntry(const CBigNum& bnSerial); + private: CWalletDB(const CWalletDB&); void operator=(const CWalletDB&);